units/ example scripts

Hi,

In fixing the recursion bug in the units support, I went through the examples in
units/ and found two broken examples (broken before I fixed the recursion bug):

1) artist_tests.py
Traceback (most recent call last):
  File "artist_tests.py", line 30, in <module>
    lc = collections.LineCollection(verts, axes=ax)
  File
"/home/rmay/.local/lib64/python2.5/site-packages/matplotlib/collections.py", line
917, in __init__
    self.set_segments(segments)
  File
"/home/rmay/.local/lib64/python2.5/site-packages/matplotlib/collections.py", line
927, in set_segments
    seg = np.asarray(seg, np.float_)
  File "/home/rmay/.local/lib64/python2.5/site-packages/numpy/core/numeric.py",
line 230, in asarray
    return array(a, dtype, copy=False, order=order)
ValueError: setting an array element with a sequence.

2) bar_unit_demo.py
Traceback (most recent call last):
  File "bar_unit_demo.py", line 15, in <module>
    p1 = ax.bar(ind, menMeans, width, color='r', bottom=0*cm, yerr=menStd)
  File "/home/rmay/.local/lib64/python2.5/site-packages/matplotlib/axes.py", line
4134, in bar
    fmt=None, ecolor=ecolor, capsize=capsize)
  File "/home/rmay/.local/lib64/python2.5/site-packages/matplotlib/axes.py", line
4678, in errorbar
    in cbook.safezip(y,yerr)]
TypeError: unsupported operand type(s) for -: 'int' and 'TaggedValue'

If anyone has any quick ideas on what might have gone wrong (or if these are just
outdated), let me know. Otherwise, I'll start digging...

Ryan

···

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma

Hi,

In fixing the recursion bug in the units support, I went through the examples in
units/ and found two broken examples (broken before I fixed the recursion bug):

1) artist_tests.py
Traceback (most recent call last):
File "artist_tests.py", line 30, in <module>
   lc = collections.LineCollection(verts, axes=ax)
File
"/home/rmay/.local/lib64/python2.5/site-packages/matplotlib/collections.py", line
917, in __init__
   self.set_segments(segments)
File
"/home/rmay/.local/lib64/python2.5/site-packages/matplotlib/collections.py", line
927, in set_segments
   seg = np.asarray(seg, np.float_)
File "/home/rmay/.local/lib64/python2.5/site-packages/numpy/core/numeric.py",
line 230, in asarray
   return array(a, dtype, copy=False, order=order)
ValueError: setting an array element with a sequence.

The collection is trying to explicitly cast to a float when creating
the array instead of doing a conversion of the unit type first. The
set_segments method should convert to float using the
ax.convert_xunits before setting the array, and register to listen for
a unit change so that if for example the axis units are changed from
inches to cm, the segments are reset. Eg in Line2D, the set_axes
method calls:

    def set_axes(self, ax):
        Artist.set_axes(self, ax)
        if ax.xaxis is not None:
            self._xcid = ax.xaxis.callbacks.connect('units', self.recache)
        if ax.yaxis is not None:
            self._ycid = ax.yaxis.callbacks.connect('units', self.recache)

and later "recache"::

    def recache(self):
        #if self.axes is None: print 'recache no axes'
        #else: print 'recache units', self.axes.xaxis.units,
self.axes.yaxis.units
        if ma.isMaskedArray(self._xorig) or ma.isMaskedArray(self._yorig):
            x = ma.asarray(self.convert_xunits(self._xorig), float)
            y = ma.asarray(self.convert_yunits(self._yorig), float)
            x = ma.ravel(x)
            y = ma.ravel(y)

So the artist has to keep track of the original units data, and the
converted value. For simple "unit" types like datetime, this is not
so important because you convert once and you are done. For true
unitized types like basic_unit where we can switch the axis from
inches to cm, someone has to track the original unit data to convert
it to floats on a unit change. In a prior thread, I indicated I
thought the current implementation needs a rethinking, because it may
be easier for everyone concerned if the original data storage and
conversion happens at a higher layer, eg the hypothetical PlotItem
layer. As Eric pointed out, this would have the added benefit of
significantly thinning out the axes.py module code.

2) bar_unit_demo.py
Traceback (most recent call last):
File "bar_unit_demo.py", line 15, in <module>
   p1 = ax.bar(ind, menMeans, width, color='r', bottom=0*cm, yerr=menStd)
File "/home/rmay/.local/lib64/python2.5/site-packages/matplotlib/axes.py", line
4134, in bar
   fmt=None, ecolor=ecolor, capsize=capsize)
File "/home/rmay/.local/lib64/python2.5/site-packages/matplotlib/axes.py", line
4678, in errorbar
   in cbook.safezip(y,yerr)]
TypeError: unsupported operand type(s) for -: 'int' and 'TaggedValue'

If anyone has any quick ideas on what might have gone wrong (or if these are just
outdated), let me know. Otherwise, I'll start digging...

The code is trying to add a non-unitized quantity (eg an errorbar
width but just guessing) of int type with a unitized quantity
TaggedValue (this is from the mockup basic_units testing package).
You'd have to dig a little bit to find out where the non-unitized
quantity is entering. errorbar is a complex example that was once
(and I think still is) working on the 91 branch. You may want to
compare the errorbar function on the branch vs the trunk and see what
new feature and code change broke the units support. Again, it might
be cleaner to have an ErrorbarItem that stores the errorbar function
inputs and updates artist primitives on unit change rather than try
and propagate the original unitized data down to the artist layer. As
Eric suggested, doing these one at a time is probably a good idea, and
errorbar is a good test case because it is so damned hairy :slight_smile:

JDH

···

On Fri, Jan 16, 2009 at 2:02 PM, Ryan May <rmay31@...149...> wrote:

John Hunter wrote:

The code is trying to add a non-unitized quantity (eg an errorbar
width but just guessing) of int type with a unitized quantity
TaggedValue (this is from the mockup basic_units testing package).
You'd have to dig a little bit to find out where the non-unitized
quantity is entering. errorbar is a complex example that was once
(and I think still is) working on the 91 branch. You may want to
compare the errorbar function on the branch vs the trunk and see what
new feature and code change broke the units support. Again, it might
be cleaner to have an ErrorbarItem that stores the errorbar function
inputs and updates artist primitives on unit change rather than try
and propagate the original unitized data down to the artist layer. As
Eric suggested, doing these one at a time is probably a good idea, and
errorbar is a good test case because it is so damned hairy :slight_smile:

Ok, so what I'm taking from your responses is that it's not a waste of time to
fix these, but that it is likely more involved than something I can do when I
have only a short time to hack. I'll file these away (though if anyone else
feels motivated, feel free!) :slight_smile:

Ryan

···

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma

John Hunter wrote:
[...]

The code is trying to add a non-unitized quantity (eg an errorbar
width but just guessing) of int type with a unitized quantity
TaggedValue (this is from the mockup basic_units testing package).
You'd have to dig a little bit to find out where the non-unitized
quantity is entering. errorbar is a complex example that was once
(and I think still is) working on the 91 branch. You may want to
compare the errorbar function on the branch vs the trunk and see what
new feature and code change broke the units support. Again, it might
be cleaner to have an ErrorbarItem that stores the errorbar function
inputs and updates artist primitives on unit change rather than try
and propagate the original unitized data down to the artist layer. As
Eric suggested, doing these one at a time is probably a good idea, and
errorbar is a good test case because it is so damned hairy :slight_smile:

One of the reasons for doing all the conversions at the higher level than the primitive artist is that often one *has* to do the conversion at that higher level in order to do the calculations required to draw the item; so a consequence of putting the conversion in the primitive artists is that the conversion facilities have to live at *both* levels, which makes the code harder to understand and maintain. The only penalty in taking the conversion out of the primitive artists is that a user who wants to support units in a custom plot type, using primitive artists, must include the unit conversion etc. I don't think this is a big problem for new code, though, because if the conversion is at that higher level only, then it is easy to show how to do it (there will be plenty of examples), and to ensure that there are enough helper functions to make it easy to code. Maybe there already are. Or maybe deriving from a PlotItem base class would make it easier. (Or maybe this is a place where decorators would simplify things? Just a random idea, not thought out.)

Eric