Eric,

Eric Firing wrote:
Manuel,

Sorry for the delay in looking at your patch.

I am not familiar with this type of plot, as opposed to ordinary errorbars. What is it used for? What is the meaning of the upper and lower limits?

Sometimes physicist or astronomers want to indicate that a certain
measurement only given an upper- or lower-limit for a _measured value_,
which means that the true value can not directly be measured.
One example is the mass of the (electron)-neutrino which is not known, but some experiments indicate that it has to be smaller than some M +- dM. In such a case one would use an arrow pointing downwards to indicate that this measurement only gives an upper limit for the mass. Another example is the inferred mass of satellite galaxies of the Milky Way. Here some measurements give the minimum mass of the galaxies, while its total mass might be larger; in this case one wants to indicate a lower limit, i.e. use an error-bar with an arrow pointing upwards.

So, the basic meaning is: you can derive a value and its formal
uncertainties, but you *know* that this value is only an
upper-/lower-limit of the true value; this is indicated by the arrow.

The errorbar docstring will need to be modified to explain the new kwargs. Additional comments are interspersed below.
>
Manuel Metz wrote:
Hello,
I have attached a patch that adds the ability to draw upper/lower limits indicators for errorbars. New keyword args had to be introduced to the errorbar command, and I also had to add new plot styles. I chose 'y','Y','z' and 'Z' as new linestyles for arrowheads pointing up,down, left, right (see lines.py).

These markers seem to me to be very special, more similar to the TICKLEFT and friends than to the general-use markers for which letters are assigned. Since there is nothing mnemonic about your suggested letter assignments, I think it would be better not to further clutter that list of letters, and instead to extend the list of tick-like things. I suggest calling them CARETUP, CARETDOWN, etc, since they seem to me more like carets than anything else. The change to names from single characters will make the code in the errorbar method more readable.


An example and its output is also attached.

Eric: I know, I don't use masked array in this patch ;_) . The reason was that errorbar() also doesn't use them, and a did not want to completely change that function but just add the new feature. Switching to masked arrays should be straight forward, I think :-)

Manuel


------------------------------------------------------------------------

Index: axes.py
===================================================================
--- axes.py    (revision 3727)
+++ axes.py    (working copy)
@@ -3554,7 +3554,30 @@
             lines_kw['linewidth']=kwargs['linewidth']
         if 'lw' in kwargs:
             lines_kw['lw']=kwargs['lw']
-
+        +        lolims = uplims = False
+        xlolims = xuplims = False
+        if 'lowerlimits' in kwargs:
+            lolims = kwargs.pop('lowerlimits')
+        if 'upperlimits' in kwargs:
+            uplims = kwargs.pop('upperlimits')
+        if 'xlowerlimits' in kwargs:
+            xlolims = kwargs.pop('xlowerlimits')
+        if 'xupperlimits' in kwargs:
+            xuplims = kwargs.pop('xupperlimits')

Instead of using **kwargs and popping them, the new kwargs should be part of the signature. This would be consistent with the present signature, in which **kwargs is used only to pass additional marker parameters.

+ + if not iterable(lolims): lolims = npy.asarray([lolims]*len(x), bool)
Minor point: here (above) you *know* you are not starting with an array, so it would be clearer and more efficient to use npy.array, reserving npy.asarray for the case below where you *don't* know whether the argument is an array or not.
+        else: lolims = npy.asarray(lolims, bool)

[...]

The main thing I need from you is the modified docstring, although a new patch incorporating that and the other suggested changes would be even better.

Eric

I modified the docstring, but I'm also sure that it might need some further adjustments ... ;-)

I also tried to incorporate all your suggestions made about the marker-symbols, keywords and usage of asarray<->array.

Manuel

Index: axes.py
===================================================================
--- axes.py	(revision 3767)
+++ axes.py	(working copy)
@@ -3522,10 +3522,13 @@
 
     def errorbar(self, x, y, yerr=None, xerr=None,
                  fmt='-', ecolor=None, capsize=3,
-                 barsabove=False, **kwargs):
+                 barsabove=False, lolims=False, uplims=False,
+                 xlolims=False, xuplims=False, **kwargs):
         """
         ERRORBAR(x, y, yerr=None, xerr=None,
-                 fmt='b-', ecolor=None, capsize=3, barsabove=False)
+                 fmt='b-', ecolor=None, capsize=3, barsabove=False,
+                 lolims=False, uplims=False,
+                 xlolims=False, xuplims=False)
 
         Plot x versus y with error deltas in yerr and xerr.
         Vertical errorbars are plotted if yerr is not None
@@ -3553,6 +3556,11 @@
 
             barsabove, if True, will plot the errorbars above the plot symbols
             - default is below
+            
+            lolims, uplims, xlolims, xuplims: These arguments can be used
+             to indicate that a values gives only upper/lower limits. In
+             that case a caret symbol is used to indicate this. lims-arguments
+             may be of the same type as xerr and yerr.
 
             kwargs are passed on to the plot command for the markers.
               So you can add additional key=value pairs to control the
@@ -3579,18 +3587,18 @@
         if not self._hold: self.cla()
 
         # make sure all the args are iterable arrays
-        if not iterable(x): x = npy.asarray([x])
+        if not iterable(x): x = npy.array([x])
         else: x = npy.asarray(x)
 
-        if not iterable(y): y = npy.asarray([y])
+        if not iterable(y): y = npy.array([y])
         else: y = npy.asarray(y)
 
         if xerr is not None:
-            if not iterable(xerr): xerr = npy.asarray([xerr])
+            if not iterable(xerr): xerr = npy.array([xerr])
             else: xerr = npy.asarray(xerr)
 
         if yerr is not None:
-            if not iterable(yerr): yerr = npy.asarray([yerr])
+            if not iterable(yerr): yerr = npy.array([yerr])
             else: yerr = npy.asarray(yerr)
 
         l0 = None
@@ -3606,7 +3614,19 @@
             lines_kw['linewidth']=kwargs['linewidth']
         if 'lw' in kwargs:
             lines_kw['lw']=kwargs['lw']
-
+        
+        if not iterable(lolims): lolims = npy.array([lolims]*len(x), bool)
+        else: lolims = npy.asarray(lolims, bool)
+        
+        if not iterable(uplims): uplims = npy.array([uplims]*len(x), bool)
+        else: uplims = npy.asarray(uplims, bool)
+        
+        if not iterable(xlolims): xlolims = npy.array([xlolims]*len(x), bool)
+        else: xlolims = npy.asarray(xlolims, bool)
+        
+        if not iterable(xuplims): xuplims = npy.array([xuplims]*len(x), bool)
+        else: xuplims = npy.asarray(xuplims, bool)
+            
         if capsize > 0:
             plot_kw = {
                 'ms':2*capsize,
@@ -3626,8 +3646,19 @@
 
             barcols.append( self.hlines(y, left, right, **lines_kw ) )
             if capsize > 0:
-                caplines.extend( self.plot(left, y, 'k|', **plot_kw) )
-                caplines.extend( self.plot(right, y, 'k|', **plot_kw) )
+                if xlolims.any():
+                    caplines.extend( self.plot(left[xlolims], y[xlolims], ls='None', marker=mlines.CARETLEFT, **plot_kw) )
+                    xlolims = ~xlolims
+                    caplines.extend( self.plot(left[xlolims], y[xlolims], 'k|', **plot_kw) )
+                else:
+                    caplines.extend( self.plot(left, y, 'k|', **plot_kw) )
+                    
+                if xuplims.any():
+                    caplines.extend( self.plot(right[xuplims],  y[xuplims], ls='None', marker=mlines.CARETRIGHT, **plot_kw) )
+                    xuplims = ~xuplims
+                    caplines.extend( self.plot(right[xuplims],  y[xuplims], 'k|', **plot_kw) )
+                else:
+                    caplines.extend( self.plot(right, y, 'k|', **plot_kw) )
 
         if yerr is not None:
             if len(yerr.shape) == 1:
@@ -3639,8 +3670,20 @@
 
             barcols.append( self.vlines(x, lower, upper, **lines_kw) )
             if capsize > 0:
-                caplines.extend( self.plot(x, lower, 'k_', **plot_kw) )
-                caplines.extend( self.plot(x, upper, 'k_', **plot_kw) )
+                
+                if lolims.any():
+                    caplines.extend( self.plot(x[lolims], lower[lolims], ls='None', marker=mlines.CARETDOWN, **plot_kw) )
+                    lolims = ~lolims
+                    caplines.extend( self.plot(x[lolims], lower[lolims], 'k_', **plot_kw) )
+                else:
+                    caplines.extend( self.plot(x, lower, 'k_', **plot_kw) )
+                    
+                if uplims.any():
+                    caplines.extend( self.plot(x[uplims], upper[uplims], ls='None', marker=mlines.CARETUP, **plot_kw) )
+                    uplims = ~uplims
+                    caplines.extend( self.plot(x[uplims], upper[uplims], 'k_', **plot_kw) )
+                else:
+                    caplines.extend( self.plot(x, upper, 'k_', **plot_kw) )
 
         if not barsabove and fmt is not None:
             l0, = self.plot(x,y,fmt,**kwargs)
Index: lines.py
===================================================================
--- lines.py	(revision 3767)
+++ lines.py	(working copy)
@@ -21,7 +21,8 @@
 from transforms import lbwh_to_bbox, LOG10
 from matplotlib import rcParams
 
-TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN = range(4)
+TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, \
+CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN = range(8)
 
 def unmasked_index_ranges(mask, compressed = True):
     '''
@@ -147,6 +148,10 @@
         TICKRIGHT   : '_draw_tickright',
         TICKUP      : '_draw_tickup',
         TICKDOWN    : '_draw_tickdown',
+        CARETLEFT   : '_draw_arr_left',
+        CARETRIGHT  : '_draw_arr_right',
+        CARETUP     : '_draw_arr_up',
+        CARETDOWN   : '_draw_arr_down',
         'None' : '_draw_nothing',
         ' ' : '_draw_nothing',
         '' : '_draw_nothing',
@@ -1143,7 +1148,7 @@
                 renderer.draw_line(gc, x, y, x, y-offset)
                 renderer.draw_line(gc, x, y, x+offset1, y+offset2)
                 renderer.draw_line(gc, x, y, x-offset1, y+offset2)
-
+        
     def _draw_tri_up(self, renderer, gc, xt, yt):
         offset = 0.5*renderer.points_to_pixels(self._markersize)
         offset1 = offset*0.8
@@ -1200,7 +1205,63 @@
                 renderer.draw_line(gc, x, y, x+offset, y)
                 renderer.draw_line(gc, x, y, x-offset2, y+offset1)
                 renderer.draw_line(gc, x, y, x-offset2, y-offset1)
-
+    
+    def _draw_arr_down(self, renderer, gc, xt, yt):
+        offset = 0.5*renderer.points_to_pixels(self._markersize)
+        offset1 = 1.5*offset
+        if self._newstyle:
+            path = agg.path_storage()
+            path.move_to(-offset, offset1)
+            path.line_to(0, 0)
+            path.line_to(+offset, offset1)
+            renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
+        else:
+            for (x,y) in zip(xt, yt):
+                renderer.draw_line(gc, x-offset, y+offset1, x, y)
+                renderer.draw_line(gc, x, y, x+offset, y+offset1)
+    
+    def _draw_arr_up(self, renderer, gc, xt, yt):
+        offset = 0.5*renderer.points_to_pixels(self._markersize)
+        offset1 = 1.5*offset
+        if self._newstyle:
+            path = agg.path_storage()
+            path.move_to(-offset, -offset1)
+            path.line_to(0, 0)
+            path.line_to(+offset, -offset1)
+            renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
+        else:
+            for (x,y) in zip(xt, yt):
+                renderer.draw_line(gc, x-offset, y-offset1, x, y)
+                renderer.draw_line(gc, x, y, x+offset, y-offset1)
+    
+    def _draw_arr_left(self, renderer, gc, xt, yt):
+        offset = 0.5*renderer.points_to_pixels(self._markersize)
+        offset1 = 1.5*offset
+        if self._newstyle:
+            path = agg.path_storage()
+            path.move_to(offset1, -offset)
+            path.line_to(0, 0)
+            path.line_to(offset1, offset)
+            renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
+        else:
+            for (x,y) in zip(xt, yt):
+                renderer.draw_line(gc, x+offset1, y-offset, x, y)
+                renderer.draw_line(gc, x, y, x+offset1, y+offset)
+    
+    def _draw_arr_right(self, renderer, gc, xt, yt):
+        offset = 0.5*renderer.points_to_pixels(self._markersize)
+        offset1 = 1.5*offset
+        if self._newstyle:
+            path = agg.path_storage()
+            path.move_to(-offset1, -offset)
+            path.line_to(0, 0)
+            path.line_to(-offset1, offset)
+            renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
+        else:
+            for (x,y) in zip(xt, yt):
+                renderer.draw_line(gc, x-offset1, y-offset, x, y)
+                renderer.draw_line(gc, x, y, x-offset1, y+offset)
+    
     def _draw_x(self, renderer, gc, xt, yt):
         offset = 0.5*renderer.points_to_pixels(self._markersize)
 
from numpy import *
import pylab as P

fig = P.figure()
x = arange(10.)
y = sin(arange(10.)/20.*math.pi)

P.errorbar(x,y,yerr=0.1,capsize=3)

y = sin(arange(10.)/20.*math.pi) + 1
P.errorbar(x,y,yerr=0.1, uplims=True)

y = sin(arange(10.)/20.*math.pi) + 2
upperlimits = array( [1,0]*5 )
lowerlimits = array( [0,1]*5 )
P.errorbar(x,y,yerr=0.1, uplims=upperlimits, lolims=lowerlimits)

P.xlim(-1,10)

fig = P.figure()
x = arange(10.)/10.
y = (x+0.1)**2

P.errorbar(x,y, xerr=0.1, xlolims=True)
y = (x+0.1)**3

P.errorbar(x+0.6,y, xerr=0.1, xuplims=upperlimits, xlolims=lowerlimits)

y = (x+0.1)**4
P.errorbar(x+1.2,y, xerr=0.1, xuplims=True)

P.xlim(-0.2,2.4)
P.ylim(-0.1,1.3)

P.show()
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
Matplotlib-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Reply via email to