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