Hello community,

here is the log from the commit of package python3-veusz for openSUSE:Factory 
checked in at 2016-01-05 09:41:24
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-veusz (Old)
 and      /work/SRC/openSUSE:Factory/.python3-veusz.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-veusz"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-veusz/python3-veusz.changes      
2015-06-23 11:59:14.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python3-veusz.new/python3-veusz.changes 
2016-01-05 09:41:52.000000000 +0100
@@ -1,0 +2,14 @@
+Thu Dec 31 20:10:07 UTC 2015 - [email protected]
+
+- Update to version 1.23.2:
+  * Add data clipping dataset plugin
+  * Fix boxplot with manual settings
+  * Fix plugin normalize and divide by maximum for new numpy versions
+  * Avoid error in 2d data creation
+  * Fix problems with unicode characters in plugins in Python 2.x
+  * Clip axis to sensible range -1e100->1e100
+  * Handle unicode errors from operating system in Veusz scripts
+  * Handle unicode errors in error reports
+  * Fix crash in \color
+
+-------------------------------------------------------------------

Old:
----
  veusz-1.23.1.tar.gz

New:
----
  veusz-1.23.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-veusz.spec ++++++
--- /var/tmp/diff_new_pack.1WNYT0/_old  2016-01-05 09:41:53.000000000 +0100
+++ /var/tmp/diff_new_pack.1WNYT0/_new  2016-01-05 09:41:53.000000000 +0100
@@ -19,7 +19,7 @@
 %define appname veusz3
 
 Name:           python3-veusz
-Version:        1.23.1
+Version:        1.23.2
 Release:        0
 Summary:        Scientific plotting library for Python
 License:        GPL-2.0+ and Python-2.0

++++++ veusz-1.23.1.tar.gz -> veusz-1.23.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/ChangeLog new/veusz-1.23.2/ChangeLog
--- old/veusz-1.23.1/ChangeLog  2015-06-14 12:28:08.000000000 +0200
+++ new/veusz-1.23.2/ChangeLog  2015-12-23 12:37:33.000000000 +0100
@@ -1,3 +1,14 @@
+Changes in 1.23.2:
+ * Add data clipping dataset plugin
+ * Fix boxplot with manual settings
+ * Fix plugin normalize and divide by maximum for new numpy versions
+ * Avoid error in 2d data creation
+ * Fix problems with unicode characters in plugins in Python 2.x
+ * Clip axis to sensible range -1e100->1e100
+ * Handle unicode errors from operating system in Veusz scripts
+ * Handle unicode errors in error reports
+ * Fix crash in \color
+
 Changes in 1.23.1:
  * Enable compression in exported files (Benjamin K. Stuhl)
  * Fix saving histogram datasets
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/INSTALL new/veusz-1.23.2/INSTALL
--- old/veusz-1.23.1/INSTALL    2015-06-13 10:22:03.000000000 +0200
+++ new/veusz-1.23.2/INSTALL    2015-12-23 12:37:30.000000000 +0100
@@ -36,7 +36,7 @@
 
 To install on linux to the standard location on the hard disk
 
-# cd veusz-1.23.1
+# cd veusz-1.23.2
 # python setup.py build
 # su
 [enter root password]
@@ -94,8 +94,8 @@
 If you don't want to install veusz fully or are doing development, it
 can currently be run from its own directory. Do
 
-# tar xzf veusz-1.23.1.tar.gz                [change version here]
-# cd veusz-1.23.1
+# tar xzf veusz-1.23.2.tar.gz                [change version here]
+# cd veusz-1.23.2
 # ./run_veusz_inplace
 
 Certain features will be disabled if you do this. You will not be able
@@ -117,8 +117,8 @@
 incompatibilities. Simply unpack the tar file and run the main
 executable:
 
-# tar xzf veusz-linux-i386-1.23.1.tar.gz     [change version here]
-# cd veusz-linux-i386-1.23.1
+# tar xzf veusz-linux-i386-1.23.2.tar.gz     [change version here]
+# cd veusz-linux-i386-1.23.2
 # ./veusz
 
 2.2 Installing in Windows
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/PKG-INFO new/veusz-1.23.2/PKG-INFO
--- old/veusz-1.23.1/PKG-INFO   2015-06-14 12:37:53.000000000 +0200
+++ new/veusz-1.23.2/PKG-INFO   2015-12-23 13:55:21.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: veusz
-Version: 1.23.1
+Version: 1.23.2
 Summary: A scientific plotting package
 Home-page: http://home.gna.org/veusz/
 Author: Jeremy Sanders
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/README new/veusz-1.23.2/README
--- old/veusz-1.23.1/README     2015-06-14 12:28:11.000000000 +0200
+++ new/veusz-1.23.2/README     2015-12-23 12:37:16.000000000 +0100
@@ -1,4 +1,4 @@
-Veusz 1.23.1
+Veusz 1.23.2
 ------------
 http://home.gna.org/veusz/
 
@@ -12,6 +12,17 @@
 manipulation and editing of datasets. Data can be captured from
 external sources such as Internet sockets or other programs.
 
+Changes in 1.23.2:
+ * Add data clipping dataset plugin
+ * Fix boxplot with manual settings
+ * Fix plugin normalize and divide by maximum for new numpy versions
+ * Avoid error in 2d data creation
+ * Fix problems with unicode characters in plugins in Python 2.x
+ * Clip axis to sensible range -1e100->1e100
+ * Handle unicode errors from operating system in Veusz scripts
+ * Handle unicode errors in error reports
+ * Fix crash in \color
+
 Changes in 1.23.1:
  * Enable compression in exported files (Benjamin K. Stuhl)
  * Fix saving histogram datasets
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/VERSION new/veusz-1.23.2/VERSION
--- old/veusz-1.23.1/VERSION    2015-06-13 10:20:39.000000000 +0200
+++ new/veusz-1.23.2/VERSION    2015-12-23 12:36:35.000000000 +0100
@@ -1 +1 @@
-1.23.1
+1.23.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/ui/exceptionlist.ui 
new/veusz-1.23.2/ui/exceptionlist.ui
--- old/veusz-1.23.1/ui/exceptionlist.ui        2014-12-22 13:42:32.000000000 
+0100
+++ new/veusz-1.23.2/ui/exceptionlist.ui        2015-08-30 10:44:35.000000000 
+0200
@@ -82,6 +82,13 @@
         </widget>
        </item>
        <item>
+        <widget class="QPushButton" name="saveButton">
+         <property name="text">
+          <string>Save report</string>
+         </property>
+        </widget>
+       </item>
+       <item>
         <widget class="QPushButton" name="cancelButton">
          <property name="text">
           <string>&amp;Ignore this time</string>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/compat.py 
new/veusz-1.23.2/veusz/compat.py
--- old/veusz-1.23.1/veusz/compat.py    2015-04-05 14:38:55.000000000 +0200
+++ new/veusz-1.23.2/veusz/compat.py    2015-11-22 12:56:22.000000000 +0100
@@ -80,6 +80,12 @@
     # exec function
     cexec = getattr(cbuiltins, 'exec')
 
+    # execfile
+    def cexecfile(filename, globaldict):
+        with open(filename) as f:
+            code = compile(f.read(), filename, 'exec')
+        cexec(code, globaldict)
+
     # convert strerror exception to string
     def cstrerror(ex):
         return ex.strerror
@@ -90,6 +96,10 @@
             return 'u' + repr(v)
         return repr(v)
 
+    # convert exception to a user string
+    def cexceptionuser(ex):
+        return str(ex)
+
 else:
     # py2
 
@@ -152,15 +162,28 @@
         code = 'exec text in globdict'
         exec(code)
 
+    # execfile
+    def cexecfile(filename, globaldict):
+        execfile(filename, globaldict)
+
     # convert strerror exception to string
     def cstrerror(ex):
         if isinstance(ex.strerror, str):
-            deflocale = locale.getdefaultlocale()[1]
-            if deflocale is None:
-                deflocale = 'ascii'
+            deflocale = locale.getdefaultlocale()[1] or 'ascii'
             return ex.strerror.decode(deflocale)
         else:
             return ex.strerror
 
+    # sometimes exceptions come as unicode, sometimes as strings
+    # encoded in ascii, so we have to decode
+    def cexceptionuser(ex):
+        if hasattr(ex, 'strerror') and isinstance(ex.strerror, str):
+            # comes from operating system as encoded
+            deflocale = locale.getdefaultlocale()[1] or 'ascii'
+            return str(ex).decode(deflocale)
+        else:
+            # let's hope this works
+            return unicode(ex)
+
     # py2/3 repr
     crepr = repr
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/dialogs/datacreate2d.py 
new/veusz-1.23.2/veusz/dialogs/datacreate2d.py
--- old/veusz-1.23.1/veusz/dialogs/datacreate2d.py      2015-04-22 
19:41:20.000000000 +0200
+++ new/veusz-1.23.2/veusz/dialogs/datacreate2d.py      2015-11-22 
11:20:19.000000000 +0100
@@ -19,7 +19,7 @@
 """Dataset creation dialog for 2d data."""
 
 from __future__ import division
-from ..compat import crange, citems
+from ..compat import crange, citems, cstr
 from .. import qtall as qt4
 from .. import utils
 from .. import document
@@ -95,7 +95,7 @@
             if ds.datatype == 'numeric':
                 datasets[ds.dimensions-1].append(name)
         datasets[0].sort()
-        datasets[1].sort()        
+        datasets[1].sort()
 
         # make sure names are escaped if they have funny characters
         self.escapeDatasets(datasets[0])
@@ -163,7 +163,7 @@
         disable = False
         # need name and zexpr
         disable = disable or not text['name'] or not text['zexpr']
-        
+
         if self.mode == 'xyzexpr':
             # need x and yexpr
             disable = disable or not text['xexpr'] or not text['yexpr']
@@ -171,7 +171,7 @@
         elif self.mode == '2dexpr':
             # nothing else
             pass
-                
+
         elif self.mode == 'xyfunc':
             # need x and yexpr in special step format min:max:step
             disable = disable or ( checkGetStep(text['xexpr']) is None or
@@ -179,7 +179,7 @@
 
         # finally check button
         self.createbutton.setDisabled(disable)
-        
+
     def createButtonClickedSlot(self):
         """Create button pressed."""
 
@@ -188,29 +188,30 @@
             text[name] = getattr(self, name+'combo').currentText().strip()
 
         link = self.linkcheckbox.checkState() == qt4.Qt.Checked
-        if self.mode == 'xyzexpr':
-            # build operation
-            op = document.OperationDataset2DCreateExpressionXYZ(
-                text['name'],
-                text['xexpr'], text['yexpr'], text['zexpr'],
-                link)
-
-        elif self.mode == '2dexpr': 
-            op = document.OperationDataset2DCreateExpression(
-                text['name'], text['zexpr'], link)
-
-        elif self.mode == 'xyfunc':
-            xstep = checkGetStep(text['xexpr'])
-            ystep = checkGetStep(text['yexpr'])
 
-            # build operation
-            op = document.OperationDataset2DXYFunc(
-                text['name'],
-                xstep, ystep,
-                text['zexpr'], link)
-
-        # apply operation, catching evaluation errors
+        # create and apply operation, catching evaluation errors
         try:
+            if self.mode == 'xyzexpr':
+                # build operation
+                op = document.OperationDataset2DCreateExpressionXYZ(
+                    text['name'],
+                    text['xexpr'], text['yexpr'], text['zexpr'],
+                    link)
+
+            elif self.mode == '2dexpr':
+                op = document.OperationDataset2DCreateExpression(
+                    text['name'], text['zexpr'], link)
+
+            elif self.mode == 'xyfunc':
+                xstep = checkGetStep(text['xexpr'])
+                ystep = checkGetStep(text['yexpr'])
+
+                # build operation
+                op = document.OperationDataset2DXYFunc(
+                    text['name'],
+                    xstep, ystep,
+                    text['zexpr'], link)
+
             # check expression is okay
             op.validateExpression(self.document)
 
@@ -218,15 +219,20 @@
             self.document.applyOperation(op)
             # forces an evaluation
             self.document.data[text['name']].data
+
         except (document.CreateDatasetException,
-                document.DatasetException):
+                document.DatasetException) as e:
+
             msg = _("Failed to create dataset '%s'") % text['name']
+            s = cstr(e)
+            if s:
+                msg += ' (%s)' % s
         else:
             msg = _("Created dataset '%s'") % text['name']
 
         self.notifylabel.setText(msg)
         qt4.QTimer.singleShot(4000, self.notifylabel.clear)
-        
+
 def recreateDataset(mainwindow, document, dataset, datasetname):
     """Open dialog to recreate a DatasetExpression / DatasetRange."""
     dialog = DataCreate2DDialog(mainwindow, document)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/dialogs/exceptiondialog.py 
new/veusz-1.23.2/veusz/dialogs/exceptiondialog.py
--- old/veusz-1.23.1/veusz/dialogs/exceptiondialog.py   2015-04-05 
14:38:55.000000000 +0200
+++ new/veusz-1.23.2/veusz/dialogs/exceptiondialog.py   2015-11-22 
14:05:29.000000000 +0100
@@ -15,7 +15,7 @@
 #    with this program; if not, write to the Free Software Foundation, Inc.,
 #    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 ##############################################################################
- 
+
 '''Dialog to pop up if an exception occurs in Veusz.
 This allows the user to send a bug report in via email.'''
 
@@ -29,7 +29,7 @@
 import numpy
 import sip
 
-from ..compat import citems, curlrequest
+from ..compat import citems, curlrequest, cexceptionuser
 from .. import qtall as qt4
 from .. import utils
 from .veuszdialog import VeuszDialog
@@ -38,6 +38,8 @@
     """Translate text."""
     return qt4.QCoreApplication.translate(context, text, disambiguation)
 
+_emailUrl ='http://barmag.net/veusz-mail.php'
+
 _reportformat = \
 '''Veusz version: %s
 Python version: %s
@@ -63,25 +65,28 @@
 %s
 '''
 
+def createReportText(exception):
+    return _reportformat % (
+                utils.version(),
+                sys.version,
+                sys.platform,
+                numpy.__version__,
+                qt4.qVersion(),
+                qt4.PYQT_VERSION_STR,
+                sip.SIP_VERSION_STR,
+                time.strftime('%a, %d %b %Y %H:%M:%S +0000', time.gmtime()),
+                cexceptionuser(exception),
+            )
+
 class ExceptionSendDialog(VeuszDialog):
     """Dialog to send debugging report."""
-    
+
     def __init__(self, exception, parent):
 
         VeuszDialog.__init__(self, parent, 'exceptionsend.ui')
 
         # debugging report text
-        self.text = _reportformat % (
-            utils.version(),
-            sys.version,
-            sys.platform,
-            numpy.__version__,
-            qt4.qVersion(),
-            qt4.PYQT_VERSION_STR,
-            sip.SIP_VERSION_STR,
-            time.strftime('%a, %d %b %Y %H:%M:%S +0000', time.gmtime()),
-            exception
-            )
+        self.text = createReportText(exception)
         self.detailstosend.setPlainText(self.text)
 
     def accept(self):
@@ -98,9 +103,8 @@
 
         try:
             # send the message
-            curlrequest.urlopen('http://barmag.net/veusz-mail.php',
+            curlrequest.urlopen(_emailUrl,
                                 'message=%s' % text)
-
         except:
             # something went wrong...
             qt4.QMessageBox.critical(None, _("Veusz"),
@@ -170,7 +174,7 @@
 
 class ExceptionDialog(VeuszDialog):
     """Choose an exception to send to developers."""
-    
+
     ignore_exceptions = set()
 
     def __init__(self, exception, parent):
@@ -189,9 +193,13 @@
         self.erroriconlabel.setPixmap(icon.pixmap(32))
 
         self.ignoreSessionButton.clicked.connect(self.ignoreSessionSlot)
-       
+        self.saveButton.clicked.connect(self.saveButtonSlot)
+
         self.checkVeuszVersion()
 
+        if not _emailUrl:
+            self.okButton.hide()
+
     def checkVeuszVersion(self):
         """See whether there is a later version of veusz and inform the
         user."""
@@ -225,12 +233,21 @@
         d = ExceptionSendDialog(self.backtrace, self)
         if d.exec_() == qt4.QDialog.Accepted:
             VeuszDialog.accept(self)
-        
+
     def ignoreSessionSlot(self):
         """Ignore exception for session."""
         ExceptionDialog.ignore_exceptions.add(self.fmtexcept)
         self.reject()
 
+    def saveButtonSlot(self):
+        filename = qt4.QFileDialog.getSaveFileName(self, 'Save File')
+        if filename:
+            f = open(filename, 'w')
+            f.write(createReportText(self.backtrace))
+            f.close()
+
+            self.close()
+
     def exec_(self):
         """Exec dialog if exception is not ignored."""
         if self.fmtexcept not in ExceptionDialog.ignore_exceptions:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/document/datasets.py 
new/veusz-1.23.2/veusz/document/datasets.py
--- old/veusz-1.23.1/veusz/document/datasets.py 2015-06-14 12:15:17.000000000 
+0200
+++ new/veusz-1.23.2/veusz/document/datasets.py 2015-11-22 11:15:10.000000000 
+0100
@@ -1692,14 +1692,19 @@
 
         Dataset2DBase.__init__(self)
 
+        if xstep is None or ystep is None:
+            raise DatasetException('Steps are not set')
+
         self.xstep = xstep
         self.ystep = ystep
         self.expr = expr
 
-        self.xrange = (self.xstep[0] - self.xstep[2]*0.5,
-                       self.xstep[1] + self.xstep[2]*0.5)
-        self.yrange = (self.ystep[0] - self.ystep[2]*0.5,
-                       self.ystep[1] + self.ystep[2]*0.5)
+        self.xrange = (
+            self.xstep[0] - self.xstep[2]*0.5,
+            self.xstep[1] + self.xstep[2]*0.5)
+        self.yrange = (
+            self.ystep[0] - self.ystep[2]*0.5,
+            self.ystep[1] + self.ystep[2]*0.5)
         self.xedge = self.yedge = self.xcent = self.ycent = None
 
         self.cacheddata = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/document/doc.py 
new/veusz-1.23.2/veusz/document/doc.py
--- old/veusz-1.23.1/veusz/document/doc.py      2015-06-08 19:39:31.000000000 
+0200
+++ new/veusz-1.23.2/veusz/document/doc.py      2015-11-22 11:35:07.000000000 
+0100
@@ -36,7 +36,7 @@
 except ImportError:
     h5py = None
 
-from ..compat import crange, citems, cvalues, cstr, cexec, CStringIO
+from ..compat import crange, citems, cvalues, cstr, cexec, CStringIO, cexecfile
 from .. import qtall as qt4
 
 from . import widgetfactory
@@ -415,7 +415,7 @@
 
         for plugin in pluginlist:
             try:
-                cexec(compile(open(plugin).read(), plugin, 'exec'), dict())
+                cexecfile(plugin, {})
             except Exception:
                 err = _('Error loading plugin %s\n\n%s') % (
                     plugin, traceback.format_exc())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/document/loader.py 
new/veusz-1.23.2/veusz/document/loader.py
--- old/veusz-1.23.1/veusz/document/loader.py   2015-04-22 19:41:20.000000000 
+0200
+++ new/veusz-1.23.2/veusz/document/loader.py   2015-11-22 13:02:21.000000000 
+0100
@@ -28,7 +28,7 @@
 from .. import setting
 from .. import utils
 
-from ..compat import cexec, cstr, cstrerror, cbytes
+from ..compat import cexec, cstr, cstrerror, cbytes, cexceptionuser
 from .commandinterface import CommandInterface
 from . import datasets
 
@@ -69,7 +69,7 @@
     def genexception(exc):
         info = sys.exc_info()
         backtrace = ''.join(traceback.format_exception(*info))
-        return LoadError(cstr(exc), backtrace=backtrace)
+        return LoadError(cexceptionuser(exc), backtrace=backtrace)
 
     # compile script and check for security (if reqd)
     unsafe = [setting.transient_settings['unsafe_mode']]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/plugins/datasetplugin.py 
new/veusz-1.23.2/veusz/plugins/datasetplugin.py
--- old/veusz-1.23.1/veusz/plugins/datasetplugin.py     2015-06-12 
20:18:17.000000000 +0200
+++ new/veusz-1.23.2/veusz/plugins/datasetplugin.py     2015-11-22 
10:53:56.000000000 +0100
@@ -20,7 +20,7 @@
 
 """Plugins for creating datasets."""
 
-from __future__ import division
+from __future__ import division, print_function
 import numpy as N
 from . import field
 
@@ -212,7 +212,7 @@
 # class to pass to plugin to give parameters
 class DatasetPluginHelper(object):
     """Helpers to get existing datasets for plugins."""
-    
+
     def __init__(self, doc):
         """Construct helper object to pass to DatasetPlugins."""
         self._doc = doc
@@ -287,7 +287,7 @@
         if isinstance(ds, document.DatasetDateTime):
             return DatasetDateTime(name, data=ds.data)
         elif ds.dimensions == 1:
-            return Dataset1D(name, data=ds.data, serr=ds.serr, 
+            return Dataset1D(name, data=ds.data, serr=ds.serr,
                              perr=ds.perr, nerr=ds.nerr)
         elif ds.dimensions == 2:
             return Dataset2D(name, ds.data,
@@ -327,7 +327,7 @@
         doc - document instance
         fields - fields to pass to plugin
         """
-        
+
         self.plugin = plugin
         self.document = doc
         self.helper = DatasetPluginHelper(doc)
@@ -487,7 +487,7 @@
         f = N.isfinite(d.data)
 
         if errortype == 'symmetric' and d.serr is not None:
-            serr[f] += d.serr[f]**2 
+            serr[f] += d.serr[f]**2
         elif errortype == 'asymmetric':
             if d.serr is not None:
                 v = (d.serr[f])**2
@@ -521,7 +521,7 @@
             f = f[:length]
 
         if errortype == 'symmetric' and d.serr is not None:
-            serr[f] += (d.serr[f]/d.data[f])**2 
+            serr[f] += (d.serr[f]/d.data[f])**2
         elif errortype == 'asymmetric':
             if d.serr is not None:
                 v = (d.serr[f]/d.data[f])**2
@@ -548,7 +548,7 @@
     description_short = _('Multiply dataset by a constant')
     description_full = _('Multiply a dataset by a factor. '
                          'Error bars are also scaled.')
-    
+
     def __init__(self):
         """Define fields."""
         self.fields = [
@@ -579,7 +579,7 @@
     description_short = _('Add a constant to a dataset')
     description_full = _('Add a dataset by adding a value. '
                          'Error bars remain the same.')
-    
+
     def __init__(self):
         """Define fields."""
         self.fields = [
@@ -948,7 +948,7 @@
     description_short = _('Subtract two datasets')
     description_full = _('Subtract two datasets. '
                          'Combined error bars are also calculated.')
-    
+
     def __init__(self):
         """Define fields."""
         self.fields = [
@@ -1063,7 +1063,7 @@
     description_short = _('Multiply two or more datasets')
     description_full = _('Multiply two or more datasets. '
                          'Combined error bars are also calculated.')
-    
+
     def __init__(self):
         """Define fields."""
         self.fields = [
@@ -1103,7 +1103,7 @@
                           ' between two datasets')
     description_full = _('Divide or compute fractional difference'
                          ' between two datasets')
-    
+
     def __init__(self):
         """Define fields."""
         self.fields = [
@@ -1162,9 +1162,9 @@
         data = data / maxval
         # divide error bars
         serr = perr = nerr = None
-        if inds.serr: serr = inds.serr / maxval
-        if inds.perr: perr = inds.perr / maxval
-        if inds.nerr: nerr = inds.nerr / maxval
+        if inds.serr is not None: serr = inds.serr / maxval
+        if inds.perr is not None: perr = inds.perr / maxval
+        if inds.nerr is not None: nerr = inds.nerr / maxval
 
         self.dsout.update(data=data, serr=serr, perr=perr, nerr=nerr)
 
@@ -1198,9 +1198,9 @@
         data = data / tot
         # divide error bars
         serr = perr = nerr = None
-        if inds.serr: serr = inds.serr / tot
-        if inds.perr: perr = inds.perr / tot
-        if inds.nerr: nerr = inds.nerr / tot
+        if inds.serr is not None: serr = inds.serr / tot
+        if inds.perr is not None: perr = inds.perr / tot
+        if inds.nerr is not None: nerr = inds.nerr / tot
 
         self.dsout.update(data=data, serr=serr, perr=perr, nerr=nerr)
 
@@ -1427,7 +1427,7 @@
     description_short = _('Filter a dataset using an expression')
     description_full = _('Filter a dataset using an expression, '
                          'e.g. "x>10" or "(x>1) & (y<2)"')
-    
+
     def __init__(self):
         """Define fields."""
         self.fields = [
@@ -1482,7 +1482,7 @@
     description_full = _('Compute moving average for regularly spaced data.'
                          'Average is computed either\nside of each data point '
                          'by number of points given.')
-    
+
     def __init__(self):
         """Define fields."""
         self.fields = [
@@ -1493,7 +1493,7 @@
                             default=True),
             field.FieldDataset('ds_out', _('Output dataset')),
             ]
-    
+
     def updateDatasets(self, fields, helper):
         """Do shifting of dataset."""
         ds_in = helper.getDataset(fields['ds_in'])
@@ -1873,6 +1873,68 @@
 
         self.dsout.update(data=data)
 
+class ClipPlugin(_OneOutputDatasetPlugin):
+    """Compute moving average for dataset."""
+
+    menu = (_('Compute'), _('Clipped dataset'),)
+    name = 'Clip'
+    description_short = _('Clip data between a minimum and maximum')
+    description_full = _('Clip data points to minimum and/or maximum values')
+
+    def __init__(self):
+        """Define fields."""
+        self.fields = [
+            field.FieldDataset('ds_in', _('Input dataset')),
+            field.FieldFloat('minimum', _('Minimum'), default=0.),
+            field.FieldBool('disablemin', _('Disable minimum')),
+            field.FieldFloat('maximum', _('Maximum'), default=1.),
+            field.FieldBool('disablemax', _('Disable maximum')),
+            field.FieldBool('cliperrs', _('Clip error bars'), default=True),
+            field.FieldDataset('ds_out', _('Output dataset')),
+            ]
+
+    def updateDatasets(self, fields, helper):
+        """Do shifting of dataset."""
+        ds_in = helper.getDataset(fields['ds_in'])
+        data = N.array(ds_in.data)
+        perr = getattr(ds_in, 'perr')
+        nerr = getattr(ds_in, 'nerr')
+        serr = getattr(ds_in, 'serr')
+
+        cliperrs = fields['cliperrs']
+        # force asymmetric errors if clipping error bars
+        if cliperrs and serr is not None and (nerr is None or perr is None):
+            perr = serr
+            nerr = -serr
+            serr = None
+
+        # we have to clip the ranges, so calculate these first
+        upper = (data+perr) if (cliperrs and perr is not None) else None
+        lower = (data+nerr) if (cliperrs and nerr is not None) else None
+
+        # note: this preserves nan values
+        if not fields['disablemin']:
+            minv = fields['minimum']
+            data[data<minv] = minv
+            if upper is not None:
+                upper[upper<minv] = minv
+            if lower is not None:
+                lower[lower<minv] = minv
+        if not fields['disablemax']:
+            maxv = fields['maximum']
+            data[data>maxv] = maxv
+            if upper is not None:
+                upper[upper>maxv] = maxv
+            if lower is not None:
+                lower[lower>maxv] = maxv
+
+        if upper is not None:
+            perr = upper-data
+        if lower is not None:
+            nerr = lower-data
+
+        self.dsout.update(data=data, serr=serr, perr=perr, nerr=nerr)
+
 datasetpluginregistry += [
     AddDatasetPlugin,
     AddDatasetsPlugin,
@@ -1887,6 +1949,7 @@
     MeanDatasetPlugin,
     ExtremesDatasetPlugin,
     CumulativePlugin,
+    ClipPlugin,
 
     ConcatenateDatasetPlugin,
     InterleaveDatasetPlugin,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/utils/textrender.py 
new/veusz-1.23.2/veusz/utils/textrender.py
--- old/veusz-1.23.1/veusz/utils/textrender.py  2015-04-05 14:38:55.000000000 
+0200
+++ new/veusz-1.23.2/veusz/utils/textrender.py  2015-11-28 16:32:26.000000000 
+0100
@@ -1004,7 +1004,7 @@
     def __init__(self, children):
         try:
             self.colorname = children[0].text
-        except AttributeError:
+        except (AttributeError, IndexError):
             self.colorname = ''
         self.children = children[1:]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/utils/version.py 
new/veusz-1.23.2/veusz/utils/version.py
--- old/veusz-1.23.1/veusz/utils/version.py     2015-04-05 14:38:55.000000000 
+0200
+++ new/veusz-1.23.2/veusz/utils/version.py     2015-07-09 20:01:34.000000000 
+0200
@@ -29,21 +29,22 @@
 
 from . import utilfuncs
 
-def version():
-    """Return the version number as a string."""
-
-    try:
-        f = open( os.path.join(utilfuncs.resourceDirectory, 'VERSION') )
-    except EnvironmentError:
-        sys.stderr.write('''
-Failed to find VERSION file.
+_errmsg = """Failed to find VERSION file.
 
 This is probably because the resource files are not installed in the
 python module directory. You may need to set the environment variable
 VEUSZ_RESOURCE_DIR or add a "resources" symlink in the main veusz
 module directory pointing to the directory where resources are
 located. See INSTALL for details.
-'''.lstrip())
-        sys.exit(1)
+"""
 
-    return f.readline().strip()
+def version():
+    """Return the version number as a string."""
+
+    filename = os.path.join(utilfuncs.resourceDirectory, "VERSION")
+    try:
+        with open(filename) as f:
+            return f.readline().strip()
+    except EnvironmentError:
+        sys.stderr.write(_errmsg)
+        sys.exit(1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/widgets/axisfunction.py 
new/veusz-1.23.2/veusz/widgets/axisfunction.py
--- old/veusz-1.23.1/veusz/widgets/axisfunction.py      2015-04-05 
14:38:55.000000000 +0200
+++ new/veusz-1.23.2/veusz/widgets/axisfunction.py      2015-08-11 
16:11:44.000000000 +0200
@@ -508,7 +508,7 @@
 
     def _linearInterpolWarning(self, vals, xcoords, ycoords):
         '''Linear interpolation, giving out of bounds warning.'''
-        if any(vals < xcoords[0]) or any(vals > xcoords[-1]):
+        if N.any(vals < xcoords[0]) or N.any(vals > xcoords[-1]):
             self.document.log(
                 _('Warning: values exceed bounds in axis-function'))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/widgets/axisticks.py 
new/veusz-1.23.2/veusz/widgets/axisticks.py
--- old/veusz-1.23.1/veusz/widgets/axisticks.py 2015-04-05 14:38:55.000000000 
+0200
+++ new/veusz-1.23.2/veusz/widgets/axisticks.py 2015-11-22 12:30:21.000000000 
+0100
@@ -54,8 +54,11 @@
          is tuple as returned in self.interval after calling getTicks()
         """
 
-        self.minval = minval
-        self.maxval = maxval
+        # clip to sensible range
+        self.minval = max(min(minval, 1e100), -1e100)
+        self.maxval = max(min(maxval, 1e100), -1e100)
+
+        # tick parameters
         self.numticks = numticks
         self.numminorticks = numminorticks
         self.logaxis = logaxis
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/widgets/boxplot.py 
new/veusz-1.23.2/veusz/widgets/boxplot.py
--- old/veusz-1.23.1/veusz/widgets/boxplot.py   2015-04-22 19:41:20.000000000 
+0200
+++ new/veusz-1.23.2/veusz/widgets/boxplot.py   2015-11-14 14:08:33.000000000 
+0100
@@ -405,7 +405,7 @@
             datasets = [ s.get(x).getData(doc) for x in
                          ('whiskermin', 'whiskermax', 'boxmin',
                           'boxmax', 'mean', 'median') ]
-            if N.any((d is None for d in datasets)):
+            if any((d is None for d in datasets)):
                 return
 
         # get axes widgets
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/veusz-1.23.1/veusz/windows/plotwindow.py 
new/veusz-1.23.2/veusz/windows/plotwindow.py
--- old/veusz-1.23.1/veusz/windows/plotwindow.py        2015-04-22 
19:41:20.000000000 +0200
+++ new/veusz-1.23.2/veusz/windows/plotwindow.py        2015-10-27 
19:35:12.000000000 +0100
@@ -1,6 +1,6 @@
 # plotwindow.py
 # the main window for showing plots
- 
+
 #    Copyright (C) 2004 Jeremy S. Sanders
 #    Email: Jeremy Sanders <[email protected]>
 #
@@ -527,7 +527,7 @@
             pt1.x(), pt1.y(), widgets.Graph)
         if widget is None:
             return
-        
+
         # convert points on plotter to points on axis for each axis
         # we also add a neighbouring pixel for the rounding calculation
         xpts = N.array( [pt1.x(), pt2.x(), pt1.x()+1, pt2.x()-1] )
@@ -535,7 +535,7 @@
 
         # build up operation list to do zoom
         operations = []
-        
+
         axes = {}
         # iterate over children, to look for plotters
         for c in [i for i in widget.children if
@@ -853,7 +853,7 @@
     def locateClickWidget(self, x, y):
         """Work out which widget was clicked, and if necessary send
         a sigWidgetClicked(widget) signal."""
-        
+
         if self.document.getNumberPages() == 0:
             return
 
@@ -907,7 +907,7 @@
 
             # print >>sys.stderr, "updating"
             self.pickeritem.hide()
-            
+
             self.pagenumber = min( self.document.getNumberPages() - 1,
                                    self.pagenumber )
             self.oldpagenumber = self.pagenumber
@@ -1077,10 +1077,10 @@
         if aspectwin > aspectplot:
             # take account of scroll bar
             width -= self.verticalScrollBar().width()
-            
+
         mult = width / r.width()
         self.setZoomFactor(self.zoomfactor * mult)
-        
+
     def slotViewZoomHeight(self):
         """Make the zoom factor so that the plot fills the whole width."""
 
@@ -1094,7 +1094,7 @@
         if aspectwin < aspectplot:
             # take account of scroll bar
             height -= self.horizontalScrollBar().height()
-            
+
         mult = height / r.height()
         self.setZoomFactor(self.zoomfactor * mult)
 
@@ -1115,7 +1115,7 @@
     def slotViewPreviousPage(self):
         """View the previous page."""
         self.setPageNumber( self.pagenumber - 1 )
- 
+
     def slotViewNextPage(self):
         """View the next page."""
         self.setPageNumber( self.pagenumber + 1 )
@@ -1135,7 +1135,7 @@
         modecnvt = { self.vzactions['view.select'] : 'select',
                      self.vzactions['view.pick'] : 'pick',
                      self.vzactions['view.zoomgraph'] : 'graphzoom' }
-        
+
         # close the current picker
         self.pickeritem.hide()
         self.sigPickerEnabled.emit(False)
@@ -1145,14 +1145,12 @@
 
         if self.clickmode == 'select':
             self.pixmapitem.unsetCursor()
-            #self.label.setCursor(qt4.Qt.ArrowCursor)
         elif self.clickmode == 'graphzoom':
-            self.pixmapitem.unsetCursor()
-            #self.label.setCursor(qt4.Qt.CrossCursor)
+            self.pixmapitem.setCursor(qt4.Qt.CrossCursor)
         elif self.clickmode == 'pick':
             self.pixmapitem.setCursor(qt4.Qt.CrossCursor)
             self.sigPickerEnabled.emit(True)
-        
+
     def getClick(self):
         """Return a click point from the graph."""
 
@@ -1173,7 +1171,7 @@
             pt.x(), pt.y(), widgets.Graph)
         if widget is None:
             return []
-        
+
         # convert points on plotter to points on axis for each axis
         xpts = N.array( [pt.x()] )
         ypts = N.array( [pt.y()] )



Reply via email to