You can subscribe to this list here.
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(115) |
Aug
(120) |
Sep
(137) |
Oct
(170) |
Nov
(461) |
Dec
(263) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2008 |
Jan
(120) |
Feb
(74) |
Mar
(35) |
Apr
(74) |
May
(245) |
Jun
(356) |
Jul
(240) |
Aug
(115) |
Sep
(78) |
Oct
(225) |
Nov
(98) |
Dec
(271) |
2009 |
Jan
(132) |
Feb
(84) |
Mar
(74) |
Apr
(56) |
May
(90) |
Jun
(79) |
Jul
(83) |
Aug
(296) |
Sep
(214) |
Oct
(76) |
Nov
(82) |
Dec
(66) |
2010 |
Jan
(46) |
Feb
(58) |
Mar
(51) |
Apr
(77) |
May
(58) |
Jun
(126) |
Jul
(128) |
Aug
(64) |
Sep
(50) |
Oct
(44) |
Nov
(48) |
Dec
(54) |
2011 |
Jan
(68) |
Feb
(52) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
|
1
(7) |
2
(14) |
3
(6) |
4
(8) |
5
(6) |
6
(3) |
7
(2) |
8
(22) |
9
(9) |
10
(23) |
11
(14) |
12
(22) |
13
(7) |
14
(3) |
15
(22) |
16
(13) |
17
(18) |
18
(21) |
19
(9) |
20
|
21
(3) |
22
(6) |
23
(5) |
24
|
25
|
26
(3) |
27
|
28
(1) |
29
(11) |
30
(1) |
31
(12) |
|
|
|
Revision: 6465 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6465&view=rev Author: mdboom Date: 2008年12月01日 19:35:39 +0000 (2008年12月01日) Log Message: ----------- Non-affine transformation invalidation wasn't propagating correctly. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/transforms.py Modified: trunk/matplotlib/lib/matplotlib/transforms.py =================================================================== --- trunk/matplotlib/lib/matplotlib/transforms.py 2008年12月01日 19:07:08 UTC (rev 6464) +++ trunk/matplotlib/lib/matplotlib/transforms.py 2008年12月01日 19:35:39 UTC (rev 6465) @@ -115,12 +115,12 @@ return # Invalidate all ancestors of self using pseudo-recursion. - parent = None stack = [self] while len(stack): root = stack.pop() # Stop at subtrees that have already been invalidated if root._invalid != value or root.pass_through: + value |= root._invalid root._invalid = value stack.extend(root._parents.keys()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6464 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6464&view=rev Author: ryanmay Date: 2008年12月01日 19:07:08 +0000 (2008年12月01日) Log Message: ----------- Typo in docstring. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/mlab.py Modified: trunk/matplotlib/lib/matplotlib/mlab.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mlab.py 2008年12月01日 16:27:15 UTC (rev 6463) +++ trunk/matplotlib/lib/matplotlib/mlab.py 2008年12月01日 19:07:08 UTC (rev 6464) @@ -351,7 +351,7 @@ is 0 (no overlap). *pad_to*: integer - The number of points to which the data segment is padd when + The number of points to which the data segment is padded when performing the FFT. This can be different from *NFFT*, which specifies the number of data points used. While not increasing the actual resolution of the psd (the minimum distance between This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6463 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6463&view=rev Author: mdboom Date: 2008年12月01日 16:27:15 +0000 (2008年12月01日) Log Message: ----------- [ 2316591 ] assertion is always true Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/config/verbose.py Modified: trunk/matplotlib/lib/matplotlib/config/verbose.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/verbose.py 2008年12月01日 15:23:49 UTC (rev 6462) +++ trunk/matplotlib/lib/matplotlib/config/verbose.py 2008年12月01日 16:27:15 UTC (rev 6463) @@ -69,7 +69,7 @@ if always is True, the report will occur on every function call; otherwise only on the first time the function is called """ - assert(callable, func) + assert callable(func) def wrapper(*args, **kwargs): ret = func(*args, **kwargs) @@ -86,4 +86,4 @@ return self.vald[self.level]>=self.vald[level] -verbose=Verbose() \ No newline at end of file +verbose=Verbose() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6462 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6462&view=rev Author: mdboom Date: 2008年12月01日 15:23:49 +0000 (2008年12月01日) Log Message: ----------- Fix disappearing small markers problem. Modified Paths: -------------- trunk/matplotlib/src/_backend_agg.cpp Modified: trunk/matplotlib/src/_backend_agg.cpp =================================================================== --- trunk/matplotlib/src/_backend_agg.cpp 2008年12月01日 14:51:35 UTC (rev 6461) +++ trunk/matplotlib/src/_backend_agg.cpp 2008年12月01日 15:23:49 UTC (rev 6462) @@ -493,9 +493,11 @@ trans *= agg::trans_affine_translation(0.0, (double)height); PathIterator marker_path(marker_path_obj); - // The built-in markers look better if snapping is turned on. - const bool marker_snap = true; - // bool marker_snap = should_snap(marker_path, marker_trans); + // The built-in markers look better if snapping is turned on, but + // unfortunately, it can cause really small things to disappear. + // Disabling for now to revisit at a later date. + // const bool marker_snap = true; + bool marker_snap = should_snap(marker_path, marker_trans); transformed_path_t marker_path_transformed(marker_path, marker_trans); simplify_t marker_path_simplified(marker_path_transformed, marker_snap, false, width, height); curve_t marker_path_curve(marker_path_simplified); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6461 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6461&view=rev Author: jdh2358 Date: 2008年12月01日 14:51:35 +0000 (2008年12月01日) Log Message: ----------- added Jae Joon's legend and offsetbox implementation Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/legend.py trunk/matplotlib/lib/matplotlib/rcsetup.py Added Paths: ----------- trunk/matplotlib/examples/pylab_examples/legend_demo3.py trunk/matplotlib/lib/matplotlib/offsetbox.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008年12月01日 14:06:49 UTC (rev 6460) +++ trunk/matplotlib/CHANGELOG 2008年12月01日 14:51:35 UTC (rev 6461) @@ -1,3 +1,6 @@ +2008年11月30日 Reimplementaion of the legend which supports baseline alignement, + multi-column, and expand mode. - JJL + 2008年12月01日 Fixed histogram autoscaling bug when bins or range are given explicitly (fixes Debian bug 503148) - MM Added: trunk/matplotlib/examples/pylab_examples/legend_demo3.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/legend_demo3.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/legend_demo3.py 2008年12月01日 14:51:35 UTC (rev 6461) @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +import matplotlib.pyplot as plt +import numpy as np + +def myplot(ax): + t1 = np.arange(0.0, 1.0, 0.1) + for n in [1, 2, 3, 4]: + ax.plot(t1, t1**n, label="n=%d"%(n,)) + +ax1 = plt.subplot(3,1,1) +ax1.plot([1], label="multi\nline") +ax1.plot([1], label="2ドル^{2^2}$") +ax1.plot([1], label=r"$\frac{1}{2}\pi$") +ax1.legend(loc=1, ncol=3, shadow=True) + +ax2 = plt.subplot(3,1,2) +myplot(ax2) +ax2.legend(loc=1, ncol=2, shadow=True) + + +ax3 = plt.subplot(3,1,3) +myplot(ax3) +ax3.legend(loc=1, ncol=4, mode="expand", shadow=True) + + +#title('Damped oscillation') + +plt.draw() +plt.show() + +#plt.savefig("legend_demo3") + + Modified: trunk/matplotlib/lib/matplotlib/legend.py =================================================================== --- trunk/matplotlib/lib/matplotlib/legend.py 2008年12月01日 14:06:49 UTC (rev 6460) +++ trunk/matplotlib/lib/matplotlib/legend.py 2008年12月01日 14:51:35 UTC (rev 6461) @@ -26,16 +26,21 @@ import numpy as np from matplotlib import rcParams -from artist import Artist -from cbook import is_string_like, iterable, silent_list, safezip -from font_manager import FontProperties -from lines import Line2D -from mlab import segments_intersect -from patches import Patch, Rectangle, Shadow, bbox_artist -from collections import LineCollection, RegularPolyCollection -from text import Text -from transforms import Affine2D, Bbox, BboxTransformTo +from matplotlib.artist import Artist +from matplotlib.cbook import is_string_like, iterable, silent_list, safezip +from matplotlib.font_manager import FontProperties +from matplotlib.lines import Line2D +from matplotlib.mlab import segments_intersect +from matplotlib.patches import Patch, Rectangle, Shadow, bbox_artist, FancyBboxPatch +from matplotlib.collections import LineCollection, RegularPolyCollection +from matplotlib.text import Text +from matplotlib.transforms import Affine2D, Bbox, BboxTransformTo +from itertools import cycle, izip + +from matplotlib.offsetbox import HPacker, VPacker, TextArea, DrawingArea + + class Legend(Artist): """ Place a legend on the axes at location loc. Labels are a @@ -75,7 +80,6 @@ } - zorder = 5 def __str__(self): return "Legend" @@ -83,72 +87,132 @@ def __init__(self, parent, handles, labels, loc = None, numpoints = None, # the number of points in the legend line + markerscale = None, # the relative size of legend markers vs. original scatterpoints = 3, # TODO: may be an rcParam - prop = None, - pad = None, # the fractional whitespace inside the legend border - borderpad = None, - markerscale = None, # the relative size of legend markers vs. original + scatteryoffsets=None, + prop = None, # properties for the legend texts + # the following dimensions are in axes coords - labelsep = None, # the vertical space between the legend entries - handlelen = None, # the length of the legend lines - handletextsep = None, # the space between the legend line and legend text - axespad = None, # the border between the axes and legend edge + pad = None, # deprecated; use borderpad + labelsep = None, # deprecated; use labelspacing + handlelen = None, # deprecated; use handlelength + handletextsep = None, # deprecated; use handletextpad + axespad = None, # deprecated; use borderaxespad + + # spacing & pad defined as a fractionof the font-size + borderpad = None, # the fractional whitespace inside the legend border + labelspacing=None, #the vertical space between the legend entries + handlelength=None, # the length of the legend handles + handletextpad=None, # the pad between the legend handle and text + borderaxespad=None, # the pad between the axes and legend border + columnspacing=None, # spacing between columns + + ncol=1, # number of columns + mode=None, # mode for horizontal distribution of columns. None, "expand" + shadow = None, - scatteryoffsets=None, ): """ - parent # the artist that contains the legend - handles # a list of artists (lines, patches) to add to the legend - labels # a list of strings to label the legend - loc # a location code - numpoints = 4 # the number of points in the legend line - scatterpoints = 3 # the number of points for the scatterplot legend - prop = FontProperties(size='smaller') # the font property - pad = 0.2 # the fractional whitespace inside the legend border - markerscale = 0.6 # the relative size of legend markers vs. original - shadow # if True, draw a shadow behind legend - scatteryoffsets # a list of yoffsets for scatter symbols in legend + - *parent* : the artist that contains the legend + - *handles* : a list of artists (lines, patches) to add to the legend + - *labels* : a list of strings to label the legend -The following dimensions are in axes coords - labelsep = 0.005 # the vertical space between the legend entries - handlelen = 0.05 # the length of the legend lines - handletextsep = 0.02 # the space between the legend line and legend text - axespad = 0.02 # the border between the axes and legend edge + Optional keyword arguments: + + ================ ========================================= + Keyword Description + ================ ========================================= + + loc a location code + numpoints the number of points in the legend line + prop the font property + markerscale the relative size of legend markers vs. original + shadow if True, draw a shadow behind legend + scatteryoffsets a list of yoffsets for scatter symbols in legend + + borderpad the fractional whitespace inside the legend border + labelspacing the vertical space between the legend entries + handlelength the length of the legend handles + handletextpad the pad between the legend handle and text + borderaxespad the pad between the axes and legend border + columnspacing the spacing between columns + +The dimensions of pad and spacing are given as a fraction of the +fontsize. Values from rcParams will be used if None. + """ - from axes import Axes # local import only to avoid circularity - from figure import Figure # local import only to avoid circularity + from matplotlib.axes import Axes # local import only to avoid circularity + from matplotlib.figure import Figure # local import only to avoid circularity Artist.__init__(self) - proplist=[numpoints, scatterpoints, pad, borderpad, markerscale, labelsep, - handlelen, handletextsep, axespad, shadow] - propnames=['numpoints','scatterpoints', 'pad', 'borderpad', 'markerscale', - 'labelsep', 'handlelen', 'handletextsep', 'axespad', 'shadow'] - for name, value in safezip(propnames,proplist): - if value is None: - value=rcParams["legend."+name] - setattr(self,name,value) - if pad: - warnings.warn("Use 'borderpad' instead of 'pad'.", DeprecationWarning) - # 2008年10月04日 - if self.numpoints <= 0: - raise ValueError("numpoints must be > 0; it was %d"% numpoints) - if self.scatterpoints <= 0: - raise ValueError("scatterpoints must be > 0; it was %d"% numpoints) if prop is None: self.prop=FontProperties(size=rcParams["legend.fontsize"]) else: self.prop=prop self.fontsize = self.prop.get_size_in_points() + propnames=['numpoints', 'markerscale', 'shadow', "columnspacing", + "scatterpoints"] + + localdict = locals() + + for name in propnames: + if localdict[name] is None: + value = rcParams["legend."+name] + else: + value = localdict[name] + setattr(self, name, value) + + # Take care the deprecated keywords + deprecated_kwds = {"pad":"borderpad", + "labelsep":"labelspacing", + "handlelen":"handlelength", + "handletextsep":"handletextpad", + "axespad":"borderaxespad"} + + # convert values of deprecated keywords (ginve in axes coords) + # to new vaules in a fraction of the font size + + # conversion factor + bbox = parent.bbox + axessize_fontsize = min(bbox.width, bbox.height)/self.fontsize + + for k, v in deprecated_kwds.items(): + # use deprecated value if not None and if their newer + # counter part is None. + if localdict[k] is not None and localdict[v] is None: + warnings.warn("Use '%s' instead of '%s'." % (v, k), + DeprecationWarning) + setattr(self, v, localdict[k]*axessize_fontsize) + continue + + # Otherwise, use new keywords + if localdict[v] is None: + setattr(self, v, rcParams["legend."+v]) + else: + setattr(self, v, localdict[v]) + + del localdict + + self._ncol = ncol + + if self.numpoints <= 0: + raise ValueError("numpoints must be >= 0; it was %d"% numpoints) + # introduce y-offset for handles of the scatter plot if scatteryoffsets is None: - self._scatteryoffsets = np.array([4./8., 5./8., 3./8.]) + self._scatteryoffsets = np.array([3./8., 4./8., 2.5/8.]) else: self._scatteryoffsets = np.asarray(scatteryoffsets) - reps = int(self.scatterpoints / len(self._scatteryoffsets)) + 1 + reps = int(self.numpoints / len(self._scatteryoffsets)) + 1 self._scatteryoffsets = np.tile(self._scatteryoffsets, reps)[:self.scatterpoints] + # _legend_box is an OffsetBox instance that contains all + # legend items and will be initialized from _init_legend_box() + # method. + self._legend_box = None + if isinstance(parent,Axes): self.isaxes = True self.set_figure(parent.figure) @@ -158,9 +222,6 @@ else: raise TypeError("Legend needs either Axes or Figure as parent") self.parent = parent - self._offsetTransform = Affine2D() - self._parentTransform = BboxTransformTo(parent.bbox) - Artist.set_transform(self, self._offsetTransform + self._parentTransform) if loc is None: loc = rcParams["legend.loc"] @@ -186,100 +247,165 @@ loc = 1 self._loc = loc + self._mode = mode - self.legendPatch = Rectangle( - xy=(0.0, 0.0), width=0.5, height=0.5, + # We use FancyBboxPatch to draw a legend frame. The location + # and size of the box will be updated during the drawing time. + self.legendPatch = FancyBboxPatch( + xy=(0.0, 0.0), width=1., height=1., facecolor='w', edgecolor='k', + mutation_scale=self.fontsize, ) + + # The width and height of the legendPatch will be set (in the + # draw()) to the length that includes the padding. Thus we set + # pad=0 here. + self.legendPatch.set_boxstyle("round",pad=0, #self.borderpad, + rounding_size=0.2) + self._set_artist_props(self.legendPatch) - # make a trial box in the middle of the axes. relocate it - # based on it's bbox - left, top = 0.5, 0.5 - textleft = left+ self.handlelen+self.handletextsep - self.texts = self._get_texts(labels, textleft, top) - self.legendHandles = self._get_handles(handles, self.texts) - self._drawFrame = True + # populate the legend_box with legend items. + self._init_legend_box(handles, labels) + self._legend_box.set_figure(self.figure) + + def _set_artist_props(self, a): + """ + set the boilerplate props for artists added to axes + """ a.set_figure(self.figure) + + for c in self.get_children(): + c.set_figure(self.figure) + a.set_transform(self.get_transform()) - def _approx_text_height(self): - return self.fontsize/72.0*self.figure.dpi/self.parent.bbox.height + def _findoffset_best(self, width, height, xdescent, ydescent): + "Heper function to locate the legend" + ox, oy = self._find_best_position(width, height) + return ox+xdescent, oy+ydescent + def _findoffset_loc(self, width, height, xdescent, ydescent): + "Heper function to locate the legend" + bbox = Bbox.from_bounds(0, 0, width, height) + x, y = self._get_anchored_bbox(self._loc, bbox, self.parent.bbox) + return x+xdescent, y+ydescent def draw(self, renderer): + "Draw everything that belongs to the legend" if not self.get_visible(): return + renderer.open_group('legend') - self._update_positions(renderer) + + # find_offset function will be provided to _legend_box and + # _legend_box will draw itself at the location of the return + # value of the find_offset. + if self._loc == 0: + self._legend_box.set_offset(self._findoffset_best) + else: + self._legend_box.set_offset(self._findoffset_loc) + + # if mode == fill, set the width of the legend_box to the + # width of the paret (minus pads) + if self._mode in ["expand"]: + pad = 2*(self.borderaxespad+self.borderpad)*self.fontsize + self._legend_box.set_width(self.parent.bbox.width-pad) + if self._drawFrame: + # update the location and size of the legend + bbox = self._legend_box.get_window_extent(renderer) + self.legendPatch.set_bounds(bbox.x0, bbox.y0, + bbox.width, bbox.height) + if self.shadow: - shadow = Shadow(self.legendPatch, -0.005, -0.005) + shadow = Shadow(self.legendPatch, 2, -2) shadow.draw(renderer) + self.legendPatch.draw(renderer) + self._legend_box.draw(renderer) - if not len(self.legendHandles) and not len(self.texts): return - for h in self.legendHandles: - if h is not None: - h.draw(renderer) - if hasattr(h, '_legmarker'): - h._legmarker.draw(renderer) - if 0: bbox_artist(h, renderer) - - for t in self.texts: - if 0: bbox_artist(t, renderer) - t.draw(renderer) renderer.close_group('legend') - #draw_bbox(self.save, renderer, 'g') - #draw_bbox(self.ibox, renderer, 'r', self.get_transform()) - def _get_handle_text_bbox(self, renderer): - 'Get a bbox for the text and lines in axes coords' - bboxesText = [t.get_window_extent(renderer) for t in self.texts] - bboxesHandles = [h.get_window_extent(renderer) for h in self.legendHandles if h is not None] + def _approx_text_height(self): + """ + Return the approximate height of the text. This is used to place + the legend handle. + """ + return self.fontsize/72.0*self.figure.dpi - bboxesAll = bboxesText - bboxesAll.extend(bboxesHandles) - bbox = Bbox.union(bboxesAll) - self.save = bbox + def _init_legend_box(self, handles, labels): + """ + Initiallize the legend_box. The legend_box is an instance of + the OffsetBox, which is packed with legend handles and + texts. Once packed, their location is calculated during the + drawing time. + """ - ibox = bbox.inverse_transformed(self.get_transform()) - self.ibox = ibox + # legend_box is a HPacker, horizontally packed with + # columns. Each column is a VPacker, vertically packed with + # legend items. Each legend item is HPacker packed with + # legend handleBox and labelBox. handleBox is an instance of + # offsetbox.DrawingArea which contains legend handle. labelBox + # is an instance of offsetbox.TextArea which contains legend + # text. - return ibox + + text_list = [] # the list of text instances + handle_list = [] # the list of text instances - def _get_handles(self, handles, texts): - handles = list(handles) - texts = list(texts) - HEIGHT = self._approx_text_height() - left = 0.5 + label_prop = dict(verticalalignment='baseline', + horizontalalignment='left', + fontproperties=self.prop, + ) - ret = [] # the returned legend lines + labelboxes = [] - # we need to pad the text with empties for the numpoints=1 - # centered marker proxy + for l in labels: + textbox = TextArea(l, textprops=label_prop) + text_list.append(textbox._text) + labelboxes.append(textbox) - for handle, label in safezip(handles, texts): + handleboxes = [] + + + # The approximate height and descent of text. These values are + # only used for plotting the legend handle. + height = self._approx_text_height() * 0.6 + descent = 0. #height/6. + + # each handle needs to be drawn inside a box of + # (x, y, w, h) = (0, -descent, width, height). + # And their corrdinates should be given in the display coordinates. + + # The transformation of each handle will be automatically set + # to self.get_trasnform(). If the artist does not uses its + # default trasnform (eg, Collections), you need to + # manually set their transform to the self.get_transform(). + + for handle in handles: if isinstance(handle, RegularPolyCollection): npoints = self.scatterpoints else: npoints = self.numpoints if npoints > 1: - xdata = np.linspace(left, left + self.handlelen, npoints) + # we put some pad here to compensate the size of the + # marker + xdata = np.linspace(0.3*self.fontsize, + (self.handlelength-0.3)*self.fontsize, + npoints) xdata_marker = xdata elif npoints == 1: - xdata = np.linspace(left, left + self.handlelen, 2) - xdata_marker = [left + 0.5*self.handlelen] + xdata = np.linspace(0, self.handlelength, 2) + xdata_marker = [0.5*self.handlelength*self.fontsize] - x, y = label.get_position() - x -= self.handlelen + self.handletextsep if isinstance(handle, Line2D): - ydata = (y-HEIGHT/2)*np.ones(xdata.shape, float) + ydata = ((height-descent)/2.)*np.ones(xdata.shape, float) legline = Line2D(xdata, ydata) legline.update_from(handle) @@ -288,8 +414,9 @@ legline.set_clip_path(None) legline.set_drawstyle('default') legline.set_marker('None') - ret.append(legline) + handle_list.append(legline) + legline_marker = Line2D(xdata_marker, ydata[:len(xdata_marker)]) legline_marker.update_from(handle) self._set_artist_props(legline_marker) @@ -302,16 +429,17 @@ legline._legmarker = legline_marker elif isinstance(handle, Patch): - p = Rectangle(xy=(min(xdata), y-3/4*HEIGHT), - width = self.handlelen, height=HEIGHT/2, + p = Rectangle(xy=(0, -0.*descent), + width = self.handlelength*self.fontsize, + height=0.*descent+(height-descent)*.9, ) p.update_from(handle) self._set_artist_props(p) p.set_clip_box(None) p.set_clip_path(None) - ret.append(p) + handle_list.append(p) elif isinstance(handle, LineCollection): - ydata = (y-HEIGHT/2)*np.ones(xdata.shape, float) + ydata = ((height-descent)/2.)*np.ones(xdata.shape, float) legline = Line2D(xdata, ydata) self._set_artist_props(legline) legline.set_clip_box(None) @@ -322,13 +450,13 @@ legline.set_color(color) legline.set_linewidth(lw) legline.set_dashes(dashes) - ret.append(legline) + handle_list.append(legline) elif isinstance(handle, RegularPolyCollection): - # the ydata values set here have no effects as it will - # be updated in the _update_positions() method. - ydata = (y-HEIGHT/2)*np.ones(np.asarray(xdata_marker).shape, float) + #ydata = self._scatteryoffsets + ydata = height*self._scatteryoffsets + size_max, size_min = max(handle.get_sizes()),\ min(handle.get_sizes()) # we may need to scale these sizes by "markerscale" @@ -338,32 +466,86 @@ sizes = [.5*(size_max+size_min), size_max, size_min] else: - sizes = size_max*np.linspace(0,1,self.scatterpoints)+size_min - + sizes = (size_max-size_min)*np.linspace(0,1,self.scatterpoints)+size_min + p = type(handle)(handle.get_numsides(), rotation=handle.get_rotation(), sizes=sizes, offsets=zip(xdata_marker,ydata), - transOffset=self.get_transform()) - + transOffset=self.get_transform(), + ) + p.update_from(handle) p.set_figure(self.figure) p.set_clip_box(None) p.set_clip_path(None) - ret.append(p) + handle_list.append(p) else: - ret.append(None) + handle_list.append(None) - return ret + handlebox = DrawingArea(width=self.handlelength*self.fontsize, + height=height, + xdescent=0., ydescent=descent) + handle = handle_list[-1] + handlebox.add_artist(handle) + if hasattr(handle, "_legmarker"): + handlebox.add_artist(handle._legmarker) + handleboxes.append(handlebox) + + + # We calculate number of lows in each column. The first + # (num_largecol) columns will have (nrows+1) rows, and remaing + # (num_smallcol) columns will have (nrows) rows. + nrows, num_largecol = divmod(len(handleboxes), self._ncol) + num_smallcol = self._ncol-num_largecol + + # starting index of each column and number of rows in it. + largecol = zip(range(0, num_largecol*(nrows+1), (nrows+1)), + [nrows+1] * num_largecol) + smallcol = zip(range(num_largecol*(nrows+1), len(handleboxes), nrows), + [nrows] * num_smallcol) + + handle_label = zip(handleboxes, labelboxes) + columnbox = [] + for i0, di in largecol+smallcol: + # pack handleBox and labelBox into itemBox + itemBoxes = [HPacker(pad=0, + sep=self.handletextpad*self.fontsize, + children=[h, t], align="baseline") + for h, t in handle_label[i0:i0+di]] + + # pack columnBox + columnbox.append(VPacker(pad=0, + sep=self.labelspacing*self.fontsize, + align="baseline", + children=itemBoxes)) + + if self._mode == "expand": + mode = "expand" + else: + mode = "fixed" + + sep = self.columnspacing*self.fontsize + + self._legend_box = HPacker(pad=self.borderpad*self.fontsize, + sep=sep, align="baseline", + mode=mode, + children=columnbox) + + self.texts = text_list + self.legendHandles = handle_list + + def _auto_legend_data(self): - """ Returns list of vertices and extents covered by the plot. + """ + Returns list of vertices and extents covered by the plot. Returns a two long list. First element is a list of (x, y) vertices (in - axes-coordinates) covered by all the lines and line + display-coordinates) covered by all the lines and line collections, in the legend's handles. Second element is a list of bounding boxes for all the patches in @@ -377,24 +559,21 @@ bboxes = [] lines = [] - inverse_transform = ax.transAxes.inverted() - for handle in ax.lines: assert isinstance(handle, Line2D) path = handle.get_path() trans = handle.get_transform() tpath = trans.transform_path(path) - apath = inverse_transform.transform_path(tpath) - lines.append(apath) + lines.append(tpath) for handle in ax.patches: assert isinstance(handle, Patch) if isinstance(handle, Rectangle): - transform = handle.get_data_transform() + inverse_transform + transform = handle.get_data_transform() bboxes.append(handle.get_bbox().transformed(transform)) else: - transform = handle.get_transform() + inverse_transform + transform = handle.get_transform() bboxes.append(handle.get_path().get_extents(transform)) return [vertices, bboxes, lines] @@ -404,9 +583,10 @@ self._drawFrame = b def get_children(self): + 'return a list of child artists' children = [] - children.extend(self.legendHandles) - children.extend(self.texts) + if self._legend_box: + children.append(self._legend_box) return children def get_frame(self): @@ -425,51 +605,61 @@ 'return a list of text.Text instance in the legend' return silent_list('Text', self.texts) - def _get_texts(self, labels, left, upper): + def get_window_extent(self): + 'return a extent of the the legend' + return self.legendPatch.get_window_extent() - # height in axes coords - HEIGHT = self._approx_text_height() - pos = upper - x = left - ret = [] # the returned list of text instances - for l in labels: - text = Text( - x=x, y=pos, - text=l, - fontproperties=self.prop, - verticalalignment='top', - horizontalalignment='left' - ) - self._set_artist_props(text) - ret.append(text) - pos -= HEIGHT + def _get_anchored_bbox(self, loc, bbox, parentbbox): + """ + Place the *bbox* inside the *parentbbox* according to a given + location code. Return the (x,y) coordinate of the bbox. - return ret + - loc: a location code in range(1, 11). + This corresponds to the possible values for self._loc, excluding "best". + - bbox: bbox to be placed, display coodinate units. + - parentbbox: a parent box which will contain the bbox. In + display coordinates. + """ + assert loc in range(1,11) # called only internally - def get_window_extent(self): - return self.legendPatch.get_window_extent() + BEST, UR, UL, LL, LR, R, CL, CR, LC, UC, C = range(11) + anchor_coefs={UR:"NE", + UL:"NW", + LL:"SW", + LR:"SE", + R:"E", + CL:"W", + CR:"E", + LC:"S", + UC:"N", + C:"C"} + + c = anchor_coefs[loc] - def _offset(self, ox, oy): - 'Move all the artists by ox,oy (axes coords)' - self._offsetTransform.clear().translate(ox, oy) + container = parentbbox.padded(-(self.borderaxespad) * self.fontsize) + anchored_box = bbox.anchored(c, container=container) + return anchored_box.x0, anchored_box.y0 + def _find_best_position(self, width, height, consider=None): - """Determine the best location to place the legend. + """ + Determine the best location to place the legend. `consider` is a list of (x, y) pairs to consider as a potential - lower-left corner of the legend. All are axes coords. + lower-left corner of the legend. All are display coords. """ assert self.isaxes # should always hold because function is only called internally verts, bboxes, lines = self._auto_legend_data() - consider = [self._loc_to_axes_coords(x, width, height) for x in range(1, len(self.codes))] + bbox = Bbox.from_bounds(0, 0, width, height) + consider = [self._get_anchored_bbox(x, bbox, self.parent.bbox) for x in range(1, len(self.codes))] - tx, ty = self.legendPatch.get_x(), self.legendPatch.get_y() + #tx, ty = self.legendPatch.get_x(), self.legendPatch.get_y() candidates = [] for l, b in consider: @@ -481,15 +671,16 @@ if line.intersects_bbox(legendBox): badness += 1 - ox, oy = l-tx, b-ty + ox, oy = l, b if badness == 0: return ox, oy - candidates.append((badness, (ox, oy))) + candidates.append((badness, (l, b))) # rather than use min() or list.sort(), do this so that we are assured # that in the case of two equal badnesses, the one first considered is # returned. + # NOTE: list.sort() is stable.But leave as it is for now. -JJL minCandidate = candidates[0] for candidate in candidates: if candidate[0] < minCandidate[0]: @@ -499,103 +690,3 @@ return ox, oy - - def _loc_to_axes_coords(self, loc, width, height): - """Convert a location code to axes coordinates. - - - loc: a location code in range(1, 11). - This corresponds to the possible values for self._loc, excluding "best". - - - width, height: the final size of the legend, axes units. - """ - assert loc in range(1,11) # called only internally - - BEST, UR, UL, LL, LR, R, CL, CR, LC, UC, C = range(11) - - if loc in (UL, LL, CL): # left - x = self.axespad - elif loc in (UR, LR, CR, R): # right - x = 1.0 - (width + self.axespad) - elif loc in (LC, UC, C): # center x - x = (0.5 - width/2.0) - - if loc in (UR, UL, UC): # upper - y = 1.0 - (height + self.axespad) - elif loc in (LL, LR, LC): # lower - y = self.axespad - elif loc in (CL, CR, C, R): # center y - y = (0.5 - height/2.0) - - return x,y - - - def _update_positions(self, renderer): - # called from renderer to allow more precise estimates of - # widths and heights with get_window_extent - - if not len(self.legendHandles) and not len(self.texts): return - def get_tbounds(text): #get text bounds in axes coords - bbox = text.get_window_extent(renderer) - bboxa = bbox.inverse_transformed(self.get_transform()) - return bboxa.bounds - - hpos = [] - for t, tabove in safezip(self.texts[1:], self.texts[:-1]): - x,y = t.get_position() - l,b,w,h = get_tbounds(tabove) - b -= self.labelsep - h += 2*self.labelsep - hpos.append( (b,h) ) - t.set_position( (x, b-0.1*h) ) - - # now do the same for last line - - l,b,w,h = get_tbounds(self.texts[-1]) - b -= self.labelsep - h += 2*self.labelsep - hpos.append( (b,h) ) - - for handle, tup in safezip(self.legendHandles, hpos): - y,h = tup - if isinstance(handle, Line2D): - ydata = y*np.ones(handle.get_xdata().shape, float) - handle.set_ydata(ydata+h/2.) - if hasattr(handle, '_legmarker'): - handle._legmarker.set_ydata(ydata+h/2.) - elif isinstance(handle, Rectangle): - handle.set_y(y+1/4*h) - handle.set_height(h/2) - elif isinstance(handle,RegularPolyCollection): - offsets = handle.get_offsets() - offsets[:,1] = y+h*self._scatteryoffsets - handle.set_offsets(offsets) - - # Set the data for the legend patch - bbox = self._get_handle_text_bbox(renderer) - - if self.pad: - bbox = bbox.expanded(1 + self.pad, 1 + self.pad) - else: - bbox = bbox.transformed(self.get_transform()) - bbox = bbox.padded(self.borderpad*self.fontsize) - bbox = bbox.inverse_transformed(self.get_transform()) - l, b, w, h = bbox.bounds - - self.legendPatch.set_bounds(l, b, w, h) - - ox, oy = 0, 0 # center - - if iterable(self._loc) and len(self._loc)==2: - xo = self.legendPatch.get_x() - yo = self.legendPatch.get_y() - x, y = self._loc - ox, oy = x-xo, y-yo - elif self._loc == 0: # "best" - ox, oy = self._find_best_position(w, h) - else: - x, y = self._loc_to_axes_coords(self._loc, w, h) - ox, oy = x-l, y-b - - self._offset(ox, oy) - -#artist.kwdocd['Legend'] = kwdoc(Legend) Added: trunk/matplotlib/lib/matplotlib/offsetbox.py =================================================================== --- trunk/matplotlib/lib/matplotlib/offsetbox.py (rev 0) +++ trunk/matplotlib/lib/matplotlib/offsetbox.py 2008年12月01日 14:51:35 UTC (rev 6461) @@ -0,0 +1,532 @@ +""" +The OffsetBox is a simple container artist. The child artist are meant +to be drawn at a relative position to its parent. The [VH]Packer, +DrawingArea and TextArea are derived from the OffsetBox. + +The [VH]Packer automatically adjust the relative postisions of their +children, which should be instances of the OffsetBox. This is used to +align similar artists together, e.g., in legend. + +The DrawingArea can contain any Artist as a child. The +DrawingArea has a fixed width and height. The position of children +relative to the parent is fixed. The TextArea is contains a single +Text instance. The width and height of the TextArea instance is the +width and height of the its child text. +""" + + +import matplotlib.transforms as mtransforms +import matplotlib.artist as martist +import matplotlib.text as mtext +import numpy as np + +from matplotlib.patches import bbox_artist as mbbox_artist +DEBUG=False +# for debuging use +def bbox_artist(*kl, **kw): + if DEBUG: + mbbox_artist(*kl, **kw) + + +# _get_packed_offsets() and _get_aligned_offsets() are coded assuming +# that we are packing boxes horizontally. But same function will be +# used with vertical packing. + +def _get_packed_offsets(wd_list, total, sep, mode="fixed"): + """ + Geiven a list of (width, xdescent) of each boxes, calculate the + total width and the x-offset positions of each items according to + *mode*. xdescent is analagous to the usual descent, but along the + x-direction. xdescent values are currently ignored. + + *wd_list* : list of (width, xdescent) of boxes to be packed. + *sep* : spacing between boxes + *total* : Intended total length. None if not used. + *mode* : packing mode. 'fixed', 'expand', or 'equal'. + """ + + w_list, d_list = zip(*wd_list) + # d_list is currently not used. + + if mode == "fixed": + offsets_ = np.add.accumulate([0]+[w + sep for w in w_list]) + offsets = offsets_[:-1] + + if total is None: + total = offsets_[-1] - sep + + return total, offsets + + elif mode == "expand": + sep = (total - sum(w_list))/(len(w_list)-1.) + offsets_ = np.add.accumulate([0]+[w + sep for w in w_list]) + offsets = offsets_[:-1] + + return total, offsets + + elif mode == "equal": + maxh = max(w_list) + if total is None: + total = (maxh+sep)*len(w_list) + else: + sep = float(total)/(len(w_list)) - maxh + + offsets = np.array([(maxh+sep)*i for i in range(len(w_list))]) + + return total, offsets + + else: + raise ValueError("Unknown mode : %s" % (mode,)) + + +def _get_aligned_offsets(hd_list, height, align="baseline"): + """ + Geiven a list of (height, descent) of each boxes, align the boxes + with *align* and calculate the y-offsets of each boxes. + total width and the offset positions of each items according to + *mode*. xdescent is analagous to the usual descent, but along the + x-direction. xdescent values are currently ignored. + + *hd_list* : list of (width, xdescent) of boxes to be aligned. + *sep* : spacing between boxes + *height* : Intended total length. None if not used. + *align* : align mode. 'baseline', 'top', 'bottom', or 'center'. + """ + + if height is None: + height = max([h for h, d in hd_list]) + + if align == "baseline": + height_descent = max([h-d for h, d in hd_list]) + descent = max([d for h, d in hd_list]) + height = height_descent + descent + offsets = [0. for h, d in hd_list] + elif align in ["left","top"]: + descent=0. + offsets = [d for h, d in hd_list] + elif align in ["right","bottom"]: + descent=0. + offsets = [height-h+d for h, d in hd_list] + elif align == "center": + descent=0. + offsets = [(height-h)*.5+d for h, d in hd_list] + else: + raise ValueError("Unknown Align mode : %s" % (align,)) + + return height, descent, offsets + + + +class OffsetBox(martist.Artist): + """ + The OffsetBox is a simple container artist. The child artist are meant + to be drawn at a relative position to its parent. + """ + def __init__(self, *kl, **kw): + + super(OffsetBox, self).__init__(*kl, **kw) + + self._children = [] + self._offset = (0, 0) + + def set_figure(self, fig): + """ + Set the figure + + accepts a class:`~matplotlib.figure.Figure` instance + """ + martist.Artist.set_figure(self, fig) + for c in self.get_children(): + c.set_figure(fig) + + def set_offset(self, xy): + """ + Set the offset + + accepts x, y, tuple, or a callable object. + """ + self._offset = xy + + def get_offset(self, width, height, xdescent, ydescent): + """ + Get the offset + + accepts extent of the box + """ + if callable(self._offset): + return self._offset(width, height, xdescent, ydescent) + else: + return self._offset + + def set_width(self, width): + """ + Set the width + + accepts float + """ + self._width = width + + def set_height(self, height): + """ + Set the height + + accepts float + """ + self._height = height + + def get_children(self): + """ + Return a list of artists it contains. + """ + return self._children + + def get_extent_offsets(self, renderer): + raise Exception("") + + def get_extent(self, renderer): + """ + Return with, height, xdescent, ydescent of box + """ + w, h, xd, yd, offsets = self.get_extent_offsets(renderer) + return w, h, xd, yd + + def get_window_extent(self, renderer): + ''' + get the bounding box in display space. + ''' + w, h, xd, yd, offsets = self.get_extent_offsets(renderer) + px, py = self.get_offset(w, h, xd, yd) + return mtransforms.Bbox.from_bounds(px-xd, py-yd, w, h) + + def draw(self, renderer): + """ + Update the location of children if necessary and draw them + to the given *renderer*. + """ + + width, height, xdescent, ydescent, offsets = self.get_extent_offsets(renderer) + + px, py = self.get_offset(width, height, xdescent, ydescent) + + for c, (ox, oy) in zip(self.get_children(), offsets): + c.set_offset((px+ox, py+oy)) + c.draw(renderer) + + bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + + +class VPacker(OffsetBox): + """ + The VPacker has its children packed vertically. It automatically + adjust the relative postisions of children in the drawing time. + """ + def __init__(self, pad=None, sep=None, width=None, height=None, + align="baseline", mode="fixed", + children=None): + """ + *pad* : boundary pad + *sep* : spacing between items + *width*, *height* : width and height of the container box. + calculated if None. + *align* : alignment of boxes + *mode* : packing mode + """ + super(VPacker, self).__init__() + + self._height = height + self._width = width + self._align = align + self._sep = sep + self._pad = pad + self._mode = mode + + self._children = children + + + def get_extent_offsets(self, renderer): + """ + update offset of childrens and return the extents of the box + """ + + whd_list = [c.get_extent(renderer) for c in self.get_children()] + whd_list = [(w, h, xd, (h-yd)) for w, h, xd, yd in whd_list] + + + wd_list = [(w, xd) for w, h, xd, yd in whd_list] + width, xdescent, xoffsets = _get_aligned_offsets(wd_list, + self._width, + self._align) + + pack_list = [(h, yd) for w,h,xd,yd in whd_list] + height, yoffsets_ = _get_packed_offsets(pack_list, self._height, + self._sep, self._mode) + + yoffsets = yoffsets_ + [yd for w,h,xd,yd in whd_list] + ydescent = height - yoffsets[0] + yoffsets = height - yoffsets + + #w, h, xd, h_yd = whd_list[-1] + yoffsets = yoffsets - ydescent + + return width + 2*self._pad, height + 2*self._pad, \ + xdescent+self._pad, ydescent+self._pad, \ + zip(xoffsets, yoffsets) + + + +class HPacker(OffsetBox): + """ + The HPacker has its children packed horizontally. It automatically + adjust the relative postisions of children in the drawing time. + """ + def __init__(self, pad=None, width=None, height=None, sep=None, + align="baseline", mode="fixed", + children=None): + """ + *pad* : boundary pad + *sep* : spacing between items + *width*, *height* : width and height of the container box. + calculated if None. + *align* : alignment of boxes + *mode* : packing mode + """ + super(HPacker, self).__init__() + + self._height = height + self._width = width + self._align = align + + self._sep = sep + self._pad = pad + self._mode = mode + + self._children = children + + + def get_extent_offsets(self, renderer): + """ + update offset of childrens and return the extents of the box + """ + + whd_list = [c.get_extent(renderer) for c in self.get_children()] + + if self._height is None: + height_descent = max([h-yd for w,h,xd,yd in whd_list]) + ydescent = max([yd for w,h,xd,yd in whd_list]) + height = height_descent + ydescent + else: + height = self._height - 2*self._pad # width w/o pad + + hd_list = [(h, yd) for w, h, xd, yd in whd_list] + height, ydescent, yoffsets = _get_aligned_offsets(hd_list, + self._height, + self._align) + + + pack_list = [(w, xd) for w,h,xd,yd in whd_list] + width, xoffsets_ = _get_packed_offsets(pack_list, self._width, + self._sep, self._mode) + + xoffsets = xoffsets_ + [xd for w,h,xd,yd in whd_list] + + xdescent=whd_list[0][2] + xoffsets = xoffsets - xdescent + + return width + 2*self._pad, height + 2*self._pad, \ + xdescent + self._pad, ydescent + self._pad, \ + zip(xoffsets, yoffsets) + + + +class DrawingArea(OffsetBox): + """ + The DrawingArea can contain any Artist as a child. The DrawingArea + has a fixed width and height. The position of children relative to + the parent is fixed. + """ + + def __init__(self, width, height, xdescent=0., + ydescent=0., clip=True): + """ + *width*, *height* : width and height of the container box. + *xdescent*, *ydescent* : descent of the box in x- and y-direction. + """ + + super(DrawingArea, self).__init__() + + self.width = width + self.height = height + self.xdescent = xdescent + self.ydescent = ydescent + + self.offset_transform = mtransforms.Affine2D() + self.offset_transform.clear() + self.offset_transform.translate(0, 0) + + + def get_transform(self): + """ + Return the :class:`~matplotlib.transforms.Transform` applied + to the children + """ + return self.offset_transform + + def set_transform(self, t): + """ + set_transform is ignored. + """ + pass + + + def set_offset(self, xy): + """ + set offset of the container. + + Accept : tuple of x,y cooridnate in disokay units. + """ + self._offset = xy + + self.offset_transform.clear() + self.offset_transform.translate(xy[0], xy[1]) + + + def get_offset(self): + """ + return offset of the container. + """ + return self._offset + + + def get_window_extent(self, renderer): + ''' + get the bounding box in display space. + ''' + w, h, xd, yd = self.get_extent(renderer) + ox, oy = self.get_offset() #w, h, xd, yd) + return mtransforms.Bbox.from_bounds(ox-xd, oy-yd, w, h) + + + def get_extent(self, renderer): + """ + Return with, height, xdescent, ydescent of box + """ + return self.width, self.height, self.xdescent, self.ydescent + + + + def add_artist(self, a): + 'Add any :class:`~matplotlib.artist.Artist` to the container box' + self._children.append(a) + a.set_transform(self.get_transform()) + + + def draw(self, renderer): + """ + Draw the children + """ + + for c in self._children: + c.draw(renderer) + + bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + + +class TextArea(OffsetBox): + """ + The TextArea is contains a single Text instance. The text is + placed at (0,0) with baseline+left alignment. The width and height + of the TextArea instance is the width and height of the its child + text. + """ + + + + def __init__(self, s, textprops=None, **kw): + """ + *s* : a string to be displayer. + *trnaspose* : transformation matrrix + """ + if textprops is None: + textprops = {} + + if not textprops.has_key("va"): + textprops["va"]="baseline" + + self._text = mtext.Text(0, 0, s, **textprops) + + OffsetBox.__init__(self) + + self._children = [self._text] + + + self.offset_transform = mtransforms.Affine2D() + self.offset_transform.clear() + self.offset_transform.translate(0, 0) + self._text.set_transform(self.offset_transform) + + + def set_transform(self, t): + """ + set_transform is ignored. + """ + pass + + + def set_offset(self, xy): + """ + set offset of the container. + + Accept : tuple of x,y cooridnate in disokay units. + """ + self._offset = xy + + self.offset_transform.clear() + self.offset_transform.translate(xy[0], xy[1]) + + + def get_offset(self): + """ + return offset of the container. + """ + return self._offset + + + def get_window_extent(self, renderer): + ''' + get the bounding box in display space. + ''' + w, h, xd, yd = self.get_extent(renderer) + ox, oy = self.get_offset() #w, h, xd, yd) + return mtransforms.Bbox.from_bounds(ox-xd, oy-yd, w, h) + + + def get_extent(self, renderer): + ismath = self._text.is_math_text(self._text._text) + _, h_, d_ = renderer.get_text_width_height_descent( + "lp", self._text._fontproperties, ismath=False) + + bbox, info = self._text._get_layout(renderer) + w, h = bbox.width, bbox.height + line = info[0][0] # first line + + _, hh, dd = renderer.get_text_width_height_descent( + line, self._text._fontproperties, ismath=ismath) + d = h-(hh-dd) # the baseline of the first line + + # for multiple lines, h or d may greater than h_ or d_. + h_d = max(h_ - d_, h-d) + d = max(d, d_) + h = h_d + d + + return w, h, 0., d + + + def draw(self, renderer): + """ + Draw the children + """ + + self._text.draw(renderer) + + bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/rcsetup.py 2008年12月01日 14:06:49 UTC (rev 6460) +++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2008年12月01日 14:51:35 UTC (rev 6461) @@ -422,7 +422,7 @@ 'legend.numpoints' : [2, validate_int], # the number of points in the legend line 'legend.fontsize' : ['large', validate_fontsize], 'legend.pad' : [0, validate_float], # was 0.2, deprecated; the fractional whitespace inside the legend border - 'legend.borderpad' : [0.5, validate_float], # units are fontsize + 'legend.borderpad' : [0.4, validate_float], # units are fontsize 'legend.markerscale' : [1.0, validate_float], # the relative size of legend markers vs. original # the following dimensions are in axes coords @@ -433,6 +433,25 @@ 'legend.shadow' : [False, validate_bool], + 'legend.labelspacing' : [0.5, validate_float], # the vertical space between the legend entries + 'legend.handlelength' : [2., validate_float], # the length of the legend lines + 'legend.handletextpad' : [.8, validate_float], # the space between the legend line and legend text + 'legend.borderaxespad' : [0.5, validate_float], # the border between the axes and legend edge + 'legend.columnspacing' : [2., validate_float], # the border between the axes and legend edge + + + 'legend.markerscale' : [1.0, validate_float], # the relative size of legend markers vs. original + + # the following dimensions are in axes coords + 'legend.labelsep' : [0.010, validate_float], # the vertical space between the legend entries + 'legend.handlelen' : [0.05, validate_float], # the length of the legend lines + 'legend.handletextsep' : [0.02, validate_float], # the space between the legend line and legend text + 'legend.axespad' : [0.5, validate_float], # the border between the axes and legend edge + 'legend.shadow' : [False, validate_bool], + + + + # tick properties 'xtick.major.size' : [4, validate_float], # major xtick size in points 'xtick.minor.size' : [2, validate_float], # minor xtick size in points This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6460 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6460&view=rev Author: mmetz_bn Date: 2008年12月01日 14:06:49 +0000 (2008年12月01日) Log Message: ----------- typo, close bug #2358133 Modified Paths: -------------- trunk/matplotlib/doc/users/pyplot_tutorial.rst Modified: trunk/matplotlib/doc/users/pyplot_tutorial.rst =================================================================== --- trunk/matplotlib/doc/users/pyplot_tutorial.rst 2008年12月01日 10:10:39 UTC (rev 6459) +++ trunk/matplotlib/doc/users/pyplot_tutorial.rst 2008年12月01日 14:06:49 UTC (rev 6460) @@ -17,7 +17,7 @@ You may be wondering why the x-axis ranges from 0-2 and the y-axis from 1-3. If you provide a single list or array to the -:func:`~matplotlib.pyplot.plot` command, matplotlib assumes it a +:func:`~matplotlib.pyplot.plot` command, matplotlib assumes it is a sequence of y values, and automatically generates the x values for you. Since python ranges start with 0, the default x vector has the same length as y but starts with 0. Hence the x data are This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6459 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6459&view=rev Author: mmetz_bn Date: 2008年12月01日 10:10:39 +0000 (2008年12月01日) Log Message: ----------- Fixed histogram autoscaling bug when bins or range are given explicitly Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/axes.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008年11月30日 18:33:55 UTC (rev 6458) +++ trunk/matplotlib/CHANGELOG 2008年12月01日 10:10:39 UTC (rev 6459) @@ -1,3 +1,6 @@ +2008年12月01日 Fixed histogram autoscaling bug when bins or range are given + explicitly (fixes Debian bug 503148) - MM + 2008年11月25日 Added rcParam axes.unicode_minus which allows plain hypen for minus when False - JDH Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2008年11月30日 18:33:55 UTC (rev 6458) +++ trunk/matplotlib/lib/matplotlib/axes.py 2008年12月01日 10:10:39 UTC (rev 6459) @@ -6510,6 +6510,9 @@ """ if not self._hold: self.cla() + # NOTE: the range keyword overwrites the built-in func range !!! + # needs to be fixed in with numpy !!! + if kwargs.get('width') is not None: raise DeprecationWarning( 'hist now uses the rwidth to give relative width ' @@ -6531,6 +6534,10 @@ tx.append( np.array(x[i]) ) x = tx + # Check whether bins or range are given explicitly. In that + # case do not autoscale axes. + binsgiven = (cbook.iterable(bins) or range != None) + n = [] for i in xrange(len(x)): # this will automatically overwrite bins, @@ -6541,9 +6548,8 @@ if cumulative: slc = slice(None) - if cbook.is_numlike(cumulative): - if cumulative < 0: - slc = slice(None,None,-1) + if cbook.is_numlike(cumulative) and cumulative < 0: + slc = slice(None,None,-1) if normed: n = [(m * np.diff(bins))[slc].cumsum()[slc] for m in n] @@ -6675,6 +6681,16 @@ p.set_label(label) label = '_nolegend_' + if binsgiven: + self.set_autoscale_on(False) + if orientation == 'vertical': + self.autoscale_view(scalex=False, scaley=True) + XL = self.xaxis.get_major_locator().view_limits(bins[0], bins[-1]) + self.set_xbound(XL) + else: + self.autoscale_view(scalex=True, scaley=False) + YL = self.yaxis.get_major_locator().view_limits(bins[0], bins[-1]) + self.set_ybound(YL) if len(n)==1: return n[0], bins, cbook.silent_list('Patch', patches[0]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.