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: 6504 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6504&view=rev Author: leejjoon Date: 2008年12月07日 20:52:13 +0000 (2008年12月07日) Log Message: ----------- axes.py : a slight change in the numpy version checking code Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axes.py Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2008年12月07日 20:40:12 UTC (rev 6503) +++ trunk/matplotlib/lib/matplotlib/axes.py 2008年12月07日 20:52:13 UTC (rev 6504) @@ -6551,8 +6551,7 @@ binsgiven = (cbook.iterable(bins) or range != None) # check the version of the numpy - np_version = float(".".join(np.__version__.split(".")[:2])) - if np_version < 1.2: # version 1.1 + if np.__version__ < "1.2": # version 1.1 hist_kwargs = dict(range=range, normed=bool(normed), new=True) else: # version 1.2 and later, drop new=True This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6503 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6503&view=rev Author: leejjoon Date: 2008年12月07日 20:40:12 +0000 (2008年12月07日) Log Message: ----------- drop "new" keyword of np.histogram() for numpy 1.2 or later Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/axes.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008年12月06日 23:17:10 UTC (rev 6502) +++ trunk/matplotlib/CHANGELOG 2008年12月07日 20:40:12 UTC (rev 6503) @@ -1,3 +1,6 @@ +2008年12月07日 drop the deprecated "new" keyword of np.histogram() for + numpy 1.2 or later. -JJL + 2008年12月06日 Fixed a bug in svg backend that new_figure_manager() ignores keywords arguments such as figsize, etc. -JJL Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2008年12月06日 23:17:10 UTC (rev 6502) +++ trunk/matplotlib/lib/matplotlib/axes.py 2008年12月07日 20:40:12 UTC (rev 6503) @@ -6550,12 +6550,20 @@ # case do not autoscale axes. binsgiven = (cbook.iterable(bins) or range != None) + # check the version of the numpy + np_version = float(".".join(np.__version__.split(".")[:2])) + if np_version < 1.2: # version 1.1 + hist_kwargs = dict(range=range, + normed=bool(normed), new=True) + else: # version 1.2 and later, drop new=True + hist_kwargs = dict(range=range, + normed=bool(normed)) + n = [] for i in xrange(len(x)): # this will automatically overwrite bins, # so that each histogram uses the same bins - m, bins = np.histogram(x[i], bins, range=range, - normed=bool(normed), new=True) + m, bins = np.histogram(x[i], bins, **hist_kwargs) n.append(m) if cumulative: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6502 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6502&view=rev Author: leejjoon Date: 2008年12月06日 23:17:10 +0000 (2008年12月06日) Log Message: ----------- Fixed a small bug in svg backend Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/backends/backend_svg.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008年12月06日 14:36:35 UTC (rev 6501) +++ trunk/matplotlib/CHANGELOG 2008年12月06日 23:17:10 UTC (rev 6502) @@ -1,3 +1,6 @@ +2008年12月06日 Fixed a bug in svg backend that new_figure_manager() + ignores keywords arguments such as figsize, etc. -JJL + 2008年12月05日 Fixed a bug that the handlelength of the new legend class set too short when numpoints=1 -JJL Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008年12月06日 14:36:35 UTC (rev 6501) +++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008年12月06日 23:17:10 UTC (rev 6502) @@ -27,7 +27,7 @@ def new_figure_manager(num, *args, **kwargs): FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args) + thisFig = FigureClass(*args, **kwargs) canvas = FigureCanvasSVG(thisFig) manager = FigureManagerSVG(canvas, num) return manager This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6501 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6501&view=rev Author: jswhit Date: 2008年12月06日 14:36:35 +0000 (2008年12月06日) Log Message: ----------- update blue marble URL Modified Paths: -------------- trunk/toolkits/basemap/examples/warpimage.py Modified: trunk/toolkits/basemap/examples/warpimage.py =================================================================== --- trunk/toolkits/basemap/examples/warpimage.py 2008年12月06日 14:35:51 UTC (rev 6500) +++ trunk/toolkits/basemap/examples/warpimage.py 2008年12月06日 14:36:35 UTC (rev 6501) @@ -66,7 +66,7 @@ # define orthographic projection centered on Europe. m = Basemap(projection='ortho',lat_0=40,lon_0=40,resolution='l') # plot a gray-scale image specified from a URL. -im = m.warpimage("http://earthobservatory.nasa.gov/Newsroom/BlueMarble/Images/gebco_bathy.5400x2700.jpg") +im = m.warpimage("http://earthobservatory.nasa.gov/Features/BlueMarble/Images/gebco_bathy.5400x2700.jpg") # draw coastlines. m.drawcoastlines(linewidth=0.5,color='0.5') # draw lat/lon grid lines every 30 degrees. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6500 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6500&view=rev Author: jswhit Date: 2008年12月06日 14:35:51 +0000 (2008年12月06日) Log Message: ----------- updated blue marble URL Modified Paths: -------------- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py =================================================================== --- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008年12月05日 21:09:42 UTC (rev 6499) +++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008年12月06日 14:35:51 UTC (rev 6500) @@ -3167,7 +3167,7 @@ Specified image must have pixels covering the whole globe in a regular lat/lon grid, starting and -180W and the South Pole. Works with the global images from - http://earthobservatory.nasa.gov/Newsroom/BlueMarble/BlueMarble_monthlies.html. + http://earthobservatory.nasa.gov/Features/BlueMarble/BlueMarble_monthlies.php. Extra keyword ``ax`` can be used to override the default axis instance. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6499 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6499&view=rev Author: leejjoon Date: 2008年12月05日 21:09:42 +0000 (2008年12月05日) Log Message: ----------- Fixed a handlelegth bug in the legend class Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/legend.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008年12月05日 19:30:28 UTC (rev 6498) +++ trunk/matplotlib/CHANGELOG 2008年12月05日 21:09:42 UTC (rev 6499) @@ -1,3 +1,6 @@ +2008年12月05日 Fixed a bug that the handlelength of the new legend class + set too short when numpoints=1 -JJL + 2008年12月04日 Added support for data with units (e.g. dates) to Axes.fill_between. -RM Modified: trunk/matplotlib/lib/matplotlib/legend.py =================================================================== --- trunk/matplotlib/lib/matplotlib/legend.py 2008年12月05日 19:30:28 UTC (rev 6498) +++ trunk/matplotlib/lib/matplotlib/legend.py 2008年12月05日 21:09:42 UTC (rev 6499) @@ -418,7 +418,7 @@ npoints) xdata_marker = xdata elif npoints == 1: - xdata = np.linspace(0, self.handlelength, 2) + xdata = np.linspace(0, self.handlelength*self.fontsize, 2) xdata_marker = [0.5*self.handlelength*self.fontsize] if isinstance(handle, Line2D): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6498 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6498&view=rev Author: ryanmay Date: 2008年12月05日 19:30:28 +0000 (2008年12月05日) Log Message: ----------- Forgot to update Changelog. Modified Paths: -------------- trunk/matplotlib/CHANGELOG Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008年12月05日 15:56:26 UTC (rev 6497) +++ trunk/matplotlib/CHANGELOG 2008年12月05日 19:30:28 UTC (rev 6498) @@ -1,3 +1,6 @@ +2008年12月04日 Added support for data with units (e.g. dates) to + Axes.fill_between. -RM + 2008年12月04日 Added fancybox keyword to legend. Also applied some changes for better look, including baseline adjustment of the multiline texts so that it is center aligned. -JJL This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6497 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6497&view=rev Author: ryanmay Date: 2008年12月05日 15:56:26 +0000 (2008年12月05日) Log Message: ----------- Add support for data with units to Axes.fill_between(). Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axes.py Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2008年12月05日 14:48:45 UTC (rev 6496) +++ trunk/matplotlib/lib/matplotlib/axes.py 2008年12月05日 15:56:26 UTC (rev 6497) @@ -5578,7 +5578,15 @@ %(PolyCollection)s """ - x = np.asarray(x) + # Handle united data, such as dates + self._process_unit_info(xdata=x, ydata=y1, kwargs=kwargs) + self._process_unit_info(ydata=y2) + + # Convert the arrays so we can work with them + x = np.asarray(self.convert_xunits(x)) + y1 = np.asarray(self.convert_yunits(y1)) + y2 = np.asarray(self.convert_yunits(y2)) + if not cbook.iterable(y1): y1 = np.ones_like(x)*y1 @@ -5588,8 +5596,6 @@ if where is None: where = np.ones(len(x), np.bool) - y1 = np.asarray(y1) - y2 = np.asarray(y2) where = np.asarray(where) assert( (len(x)==len(y1)) and (len(x)==len(y2)) and len(x)==len(where)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6496 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6496&view=rev Author: mmetz_bn Date: 2008年12月05日 14:48:45 +0000 (2008年12月05日) Log Message: ----------- hist docstring updated & exception added Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axes.py Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2008年12月05日 00:08:43 UTC (rev 6495) +++ trunk/matplotlib/lib/matplotlib/axes.py 2008年12月05日 14:48:45 UTC (rev 6496) @@ -6430,6 +6430,10 @@ are ignored. If not provided, *range* is (x.min(), x.max()). Range has no effect if *bins* is a sequence. + If *bins* is a sequence or *range* is specified, autoscaling is + set off (*autoscale_on* is set to *False*) and the xaxis limits + are set to encompass the full specified bin range. + *normed*: If *True*, the first element of the return tuple will be the counts normalized to form a probability density, i.e., @@ -6533,6 +6537,8 @@ for i in xrange(len(x)): tx.append( np.array(x[i]) ) x = tx + else: + raise ValueError, 'Can not use providet data to create a histogram' # Check whether bins or range are given explicitly. In that # case do not autoscale axes. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6495 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6495&view=rev Author: leejjoon Date: 2008年12月05日 00:08:43 +0000 (2008年12月05日) Log Message: ----------- minor fix for legend.py Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/legend.py Modified: trunk/matplotlib/lib/matplotlib/legend.py =================================================================== --- trunk/matplotlib/lib/matplotlib/legend.py 2008年12月05日 00:06:26 UTC (rev 6494) +++ trunk/matplotlib/lib/matplotlib/legend.py 2008年12月05日 00:08:43 UTC (rev 6495) @@ -383,7 +383,7 @@ labelboxes = [] for l in labels: - textbox = TextArea(l, textprops=label_prop + textbox = TextArea(l, textprops=label_prop, multilinebaseline=True, minimumdescent=True) text_list.append(textbox._text) labelboxes.append(textbox) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6494 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6494&view=rev Author: leejjoon Date: 2008年12月05日 00:06:26 +0000 (2008年12月05日) Log Message: ----------- some minor changes for the legend Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/pylab_examples/legend_demo3.py trunk/matplotlib/lib/matplotlib/legend.py trunk/matplotlib/lib/matplotlib/offsetbox.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008年12月04日 22:13:57 UTC (rev 6493) +++ trunk/matplotlib/CHANGELOG 2008年12月05日 00:06:26 UTC (rev 6494) @@ -1,3 +1,7 @@ +2008年12月04日 Added fancybox keyword to legend. Also applied some changes + for better look, including baseline adjustment of the + multiline texts so that it is center aligned. -JJL + 2008年12月02日 The transmuter classes in the patches.py are reorganized as subclasses of the Style classes. A few more box and arrow styles are added. -JJL Modified: trunk/matplotlib/examples/pylab_examples/legend_demo3.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/legend_demo3.py 2008年12月04日 22:13:57 UTC (rev 6493) +++ trunk/matplotlib/examples/pylab_examples/legend_demo3.py 2008年12月05日 00:06:26 UTC (rev 6494) @@ -2,6 +2,7 @@ import matplotlib.pyplot as plt import numpy as np +import pylab def myplot(ax): t1 = np.arange(0.0, 1.0, 0.1) @@ -21,7 +22,7 @@ ax3 = plt.subplot(3,1,3) myplot(ax3) -ax3.legend(loc=1, ncol=4, mode="expand", shadow=True) +ax3.legend(loc=1, ncol=4, mode="expand", fancybox=False, shadow=True) #title('Damped oscillation') Modified: trunk/matplotlib/lib/matplotlib/legend.py =================================================================== --- trunk/matplotlib/lib/matplotlib/legend.py 2008年12月04日 22:13:57 UTC (rev 6493) +++ trunk/matplotlib/lib/matplotlib/legend.py 2008年12月05日 00:06:26 UTC (rev 6494) @@ -113,6 +113,7 @@ ncol=1, # number of columns mode=None, # mode for horizontal distribution of columns. None, "expand" + fancybox=True, shadow = None, ): """ @@ -130,6 +131,7 @@ numpoints the number of points in the legend line prop the font property markerscale the relative size of legend markers vs. original + fancybox if True, draw a frame with a round fancybox. shadow if True, draw a shadow behind legend scatteryoffsets a list of yoffsets for scatter symbols in legend @@ -263,8 +265,11 @@ # 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) + if fancybox == True: + self.legendPatch.set_boxstyle("round",pad=0, + rounding_size=0.2) + else: + self.legendPatch.set_boxstyle("square",pad=0) self._set_artist_props(self.legendPatch) @@ -378,7 +383,8 @@ labelboxes = [] for l in labels: - textbox = TextArea(l, textprops=label_prop) + textbox = TextArea(l, textprops=label_prop + multilinebaseline=True, minimumdescent=True) text_list.append(textbox._text) labelboxes.append(textbox) @@ -387,8 +393,8 @@ # 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. + height = self._approx_text_height() * 0.7 + descent = 0. # each handle needs to be drawn inside a box of # (x, y, w, h) = (0, -descent, width, height). @@ -440,9 +446,9 @@ legline._legmarker = legline_marker elif isinstance(handle, Patch): - p = Rectangle(xy=(0, -0.*descent), + p = Rectangle(xy=(0., 0.), width = self.handlelength*self.fontsize, - height=0.*descent+(height-descent)*.9, + height=(height-descent), ) p.update_from(handle) self._set_artist_props(p) @@ -513,12 +519,12 @@ 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) + largecol = safezip(range(0, num_largecol*(nrows+1), (nrows+1)), + [nrows+1] * num_largecol) + smallcol = safezip(range(num_largecol*(nrows+1), len(handleboxes), nrows), + [nrows] * num_smallcol) - handle_label = zip(handleboxes, labelboxes) + handle_label = safezip(handleboxes, labelboxes) columnbox = [] for i0, di in largecol+smallcol: # pack handleBox and labelBox into itemBox @@ -526,6 +532,8 @@ sep=self.handletextpad*self.fontsize, children=[h, t], align="baseline") for h, t in handle_label[i0:i0+di]] + # minimumdescent=False for the text of the last row of the column + itemBoxes[-1].get_children()[1].set_minimumdescent(False) # pack columnBox columnbox.append(VPacker(pad=0, Modified: trunk/matplotlib/lib/matplotlib/offsetbox.py =================================================================== --- trunk/matplotlib/lib/matplotlib/offsetbox.py 2008年12月04日 22:13:57 UTC (rev 6493) +++ trunk/matplotlib/lib/matplotlib/offsetbox.py 2008年12月05日 00:06:26 UTC (rev 6494) @@ -23,9 +23,9 @@ from matplotlib.patches import bbox_artist as mbbox_artist DEBUG=False # for debuging use -def bbox_artist(*kl, **kw): +def bbox_artist(*args, **kwargs): if DEBUG: - mbbox_artist(*kl, **kw) + mbbox_artist(*args, **kwargs) # _get_packed_offsets() and _get_aligned_offsets() are coded assuming @@ -122,9 +122,9 @@ 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): + def __init__(self, *args, **kwargs): - super(OffsetBox, self).__init__(*kl, **kw) + super(OffsetBox, self).__init__(*args, **kwargs) self._children = [] self._offset = (0, 0) @@ -441,10 +441,18 @@ - def __init__(self, s, textprops=None, **kw): + def __init__(self, s, + textprops=None, + multilinebaseline=None, + minimumdescent=True, + ): """ - *s* : a string to be displayer. - *trnaspose* : transformation matrrix + *s* : a string to be displayed. + *textprops* : property dictionary for the text + *multilinebaseline* : If True, baseline for multiline text is + adjusted so that it is (approximatedly) + center-aligned with singleline text. + *minimumdescent* : If True, the box has a minimum descent of "p". """ if textprops is None: textprops = {} @@ -462,9 +470,48 @@ self.offset_transform = mtransforms.Affine2D() self.offset_transform.clear() self.offset_transform.translate(0, 0) - self._text.set_transform(self.offset_transform) + self._baseline_transform = mtransforms.Affine2D() + self._text.set_transform(self.offset_transform+self._baseline_transform) + self._multilinebaseline = multilinebaseline + self._minimumdescent = minimumdescent + + def set_multilinebaseline(self, t): + """ + Set multilinebaseline . + + If True, baseline for multiline text is + adjusted so that it is (approximatedly) center-aligned with + singleline text. + """ + self._multilinebaseline = t + + + def get_multilinebaseline(self): + """ + get multilinebaseline . + """ + return self._multilinebaseline + + + def set_minimumdescent(self, t): + """ + Set minimumdescent . + + If True, extent of the single line text is adjusted so that + it has minimum descent of "p" + """ + self._minimumdescent = t + + + def get_minimumdescent(self): + """ + get minimumdescent. + """ + return self._minimumdescent + + def set_transform(self, t): """ set_transform is ignored. @@ -507,17 +554,34 @@ 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 + self._baseline_transform.clear() + if len(info) > 1 and self._multilinebaseline: # multi line + d = h-(hh-dd) # the baseline of the first line + d_new = 0.5 * h - 0.5 * (h_ - d_) + + self._baseline_transform.translate(0, d - d_new) + d = d_new + + else: # single line + + h_d = max(h_ - d_, h-dd) + + if self.get_minimumdescent(): + ## to have a minimum descent, #i.e., "l" and "p" have same + ## descents. + d = max(dd, d_) + else: + d = dd + + h = h_d + d + return w, h, 0., d This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6493 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6493&view=rev Author: ryanmay Date: 2008年12月04日 22:13:57 +0000 (2008年12月04日) Log Message: ----------- Replace tabs in indentation with spaces. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axes.py Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2008年12月04日 21:02:36 UTC (rev 6492) +++ trunk/matplotlib/lib/matplotlib/axes.py 2008年12月04日 22:13:57 UTC (rev 6493) @@ -5579,14 +5579,14 @@ """ x = np.asarray(x) - if not cbook.iterable(y1): - y1 = np.ones_like(x)*y1 + if not cbook.iterable(y1): + y1 = np.ones_like(x)*y1 - if not cbook.iterable(y2): - y2 = np.ones_like(x)*y2 + if not cbook.iterable(y2): + y2 = np.ones_like(x)*y2 - if where is None: - where = np.ones(len(x), np.bool) + if where is None: + where = np.ones(len(x), np.bool) y1 = np.asarray(y1) y2 = np.asarray(y2) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6492 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6492&view=rev Author: mdboom Date: 2008年12月04日 21:02:36 +0000 (2008年12月04日) Log Message: ----------- Trivial change Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/mathtext.py Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2008年12月04日 20:05:40 UTC (rev 6491) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2008年12月04日 21:02:36 UTC (rev 6492) @@ -2735,7 +2735,7 @@ hlist = Hlist(parts) return hlist -#### +### ############################################################################## # MAIN This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6491 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6491&view=rev Author: astraw Date: 2008年12月04日 20:05:40 +0000 (2008年12月04日) Log Message: ----------- git documentation: actually make 'install from git' section describe how to install Modified Paths: -------------- trunk/matplotlib/doc/faq/installing_faq.rst Modified: trunk/matplotlib/doc/faq/installing_faq.rst =================================================================== --- trunk/matplotlib/doc/faq/installing_faq.rst 2008年12月04日 19:02:48 UTC (rev 6490) +++ trunk/matplotlib/doc/faq/installing_faq.rst 2008年12月04日 20:05:40 UTC (rev 6491) @@ -125,6 +125,9 @@ .. _matplotlib github mirror: http://github.com/astraw/matplotlib +To install from this cloned repository, use the commands in the +:ref:`svn installation <install-svn>` section. + To update your git repository with the latest svn updates from SourceForge:: git svn rebase This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6490 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6490&view=rev Author: astraw Date: 2008年12月04日 19:02:48 +0000 (2008年12月04日) Log Message: ----------- fix minor typo Modified Paths: -------------- trunk/matplotlib/doc/faq/installing_faq.rst Modified: trunk/matplotlib/doc/faq/installing_faq.rst =================================================================== --- trunk/matplotlib/doc/faq/installing_faq.rst 2008年12月04日 19:01:44 UTC (rev 6489) +++ trunk/matplotlib/doc/faq/installing_faq.rst 2008年12月04日 19:02:48 UTC (rev 6490) @@ -110,8 +110,8 @@ ================ There is an experimental `matplotlib github mirror`_ of the subversion -repository. To make a local clone it the directory ``mpl.git``, enter -the following commands:: +repository. To make a local clone of it in the directory ``mpl.git``, +enter the following commands:: # This will create your copy in the mpl.git directory git clone git://github.com/astraw/matplotlib.git mpl.git This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6489 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6489&view=rev Author: mdboom Date: 2008年12月04日 19:01:44 +0000 (2008年12月04日) Log Message: ----------- Fix autosized angle brackets in mathtext. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/mathtext.py Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2008年12月04日 18:49:16 UTC (rev 6488) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2008年12月04日 19:01:44 UTC (rev 6489) @@ -737,7 +737,9 @@ r'\widehat' : [('rm', '\x5e'), ('ex', '\x62'), ('ex', '\x63'), ('ex', '\x64')], r'\widetilde': [('rm', '\x7e'), ('ex', '\x65'), ('ex', '\x66'), - ('ex', '\x67')] + ('ex', '\x67')], + r'<' : [('cal', 'h'), ('ex', 'D')], + r'>' : [('cal', 'i'), ('ex', 'E')] } for alias, target in [('\leftparen', '('), @@ -843,8 +845,7 @@ if fontname == 'it' and isinstance(self, StixFonts): return self._get_glyph('rm', font_class, sym, fontsize) warn("Font '%s' does not have a glyph for '%s'" % - (cached_font.font.postscript_name, - sym.encode('ascii', 'backslashreplace')), + (fontname, sym.encode('ascii', 'backslashreplace')), MathTextWarning) warn("Substituting with a dummy symbol.", MathTextWarning) fontname = 'rm' @@ -956,6 +957,12 @@ except ValueError: return [(fontname, sym)] + fix_ups = { + ord('<'): 0x27e8, + ord('>'): 0x27e9 } + + uniindex = fix_ups.get(uniindex, uniindex) + for i in range(6): cached_font = self._get_font(i) glyphindex = cached_font.charmap.get(uniindex) @@ -2068,9 +2075,9 @@ | \| / \backslash \uparrow \downarrow \updownarrow \Uparrow \Downarrow \Updownarrow .""".split()) - _leftDelim = set(r"( [ { \lfloor \langle \lceil".split()) + _leftDelim = set(r"( [ { < \lfloor \langle \lceil".split()) - _rightDelim = set(r") ] } \rfloor \rangle \rceil".split()) + _rightDelim = set(r") ] } > \rfloor \rangle \rceil".split()) def __init__(self): # All forward declarations are here This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6488 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6488&view=rev Author: astraw Date: 2008年12月04日 18:49:16 +0000 (2008年12月04日) Log Message: ----------- git documentation: remove README.git and add to FAQ Modified Paths: -------------- trunk/matplotlib/doc/faq/installing_faq.rst Removed Paths: ------------- trunk/matplotlib/README.git Deleted: trunk/matplotlib/README.git =================================================================== --- trunk/matplotlib/README.git 2008年12月04日 01:58:58 UTC (rev 6487) +++ trunk/matplotlib/README.git 2008年12月04日 18:49:16 UTC (rev 6488) @@ -1,29 +0,0 @@ -There is an experimental `matplotlib github mirror`_ of the subversion -repository. To make a local clone it the directory ``mpl.git``, enter -the following commands. These instructions assume you already have a -github login (-- they use the personal gi...@gi... clone URL -instead of the git://github.com clone URL):: - - # This will create your copy in the mpl.git directory - git clone gi...@gi...:astraw/matplotlib.git mpl.git - cd mpl.git - git config --add remote.origin.fetch +refs/remotes/*:refs/remotes/* - git fetch - git svn init --trunk=trunk/matplotlib --tags=tags https://matplotlib.svn.sourceforge.net/svnroot/matplotlib - - # Now just get the latest svn revisions from the SourceForge SVN repository - git svn fetch -r 6300:HEAD - -.. _matplotlib github mirror: http://github.com/astraw/matplotlib - -To update your git repository with the latest svn updates from SourceForge:: - - git svn rebase - -To list what changes will be committed to svn:: - - git svn dcommit -n - -To commit your changes to svn:: - - git svn dcommit Modified: trunk/matplotlib/doc/faq/installing_faq.rst =================================================================== --- trunk/matplotlib/doc/faq/installing_faq.rst 2008年12月04日 01:58:58 UTC (rev 6487) +++ trunk/matplotlib/doc/faq/installing_faq.rst 2008年12月04日 18:49:16 UTC (rev 6488) @@ -106,8 +106,50 @@ > cd matplotlib > python setup.py install +Install from git +================ +There is an experimental `matplotlib github mirror`_ of the subversion +repository. To make a local clone it the directory ``mpl.git``, enter +the following commands:: + # This will create your copy in the mpl.git directory + git clone git://github.com/astraw/matplotlib.git mpl.git + cd mpl.git + git config --add remote.origin.fetch +refs/remotes/*:refs/remotes/* + git fetch + git svn init --trunk=trunk/matplotlib --tags=tags https://matplotlib.svn.sourceforge.net/svnroot/matplotlib + + # Now just get the latest svn revisions from the SourceForge SVN repository + git svn fetch -r 6300:HEAD + +.. _matplotlib github mirror: http://github.com/astraw/matplotlib + +To update your git repository with the latest svn updates from SourceForge:: + + git svn rebase + +To list what changes will be committed to svn:: + + git svn dcommit -n + +To commit your changes to svn:: + + git svn dcommit + +A note about git write access +----------------------------- + +The matplotlib developers need to figure out if there should be write +access to the git repository. This implies using the personal URL +(``gi...@gi...:astraw/matplotlib.git``) rather than the public URL +(``git://github.com/astraw/matplotlib.git``) for the +repository. However, doing so may make life complicated in the sense +that then there are two writeable matplotlib repositories, which must +be synced to prevent divergence. This is probably not an +insurmountable problem, but it is a problem that the developers should +reach a consensus about. Watch this space... + Backends ======== This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6487 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6487&view=rev Author: astraw Date: 2008年12月04日 01:58:58 +0000 (2008年12月04日) Log Message: ----------- further improvements to github instructions Modified Paths: -------------- trunk/matplotlib/README.git Modified: trunk/matplotlib/README.git =================================================================== --- trunk/matplotlib/README.git 2008年12月04日 01:52:51 UTC (rev 6486) +++ trunk/matplotlib/README.git 2008年12月04日 01:58:58 UTC (rev 6487) @@ -1,7 +1,8 @@ -To clone from the `matplotlib github mirror`_ into the directory -``mpl.git``, enter the following commands. These instructions assume -you already have a github login (-- they use the personal -g...@gi... clone URL instead of the git://github.com clone URL):: +There is an experimental `matplotlib github mirror`_ of the subversion +repository. To make a local clone it the directory ``mpl.git``, enter +the following commands. These instructions assume you already have a +github login (-- they use the personal gi...@gi... clone URL +instead of the git://github.com clone URL):: # This will create your copy in the mpl.git directory git clone gi...@gi...:astraw/matplotlib.git mpl.git @@ -14,3 +15,15 @@ git svn fetch -r 6300:HEAD .. _matplotlib github mirror: http://github.com/astraw/matplotlib + +To update your git repository with the latest svn updates from SourceForge:: + + git svn rebase + +To list what changes will be committed to svn:: + + git svn dcommit -n + +To commit your changes to svn:: + + git svn dcommit This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6486 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6486&view=rev Author: astraw Date: 2008年12月04日 01:52:51 +0000 (2008年12月04日) Log Message: ----------- add github instructions Added Paths: ----------- trunk/matplotlib/README.git Added: trunk/matplotlib/README.git =================================================================== --- trunk/matplotlib/README.git (rev 0) +++ trunk/matplotlib/README.git 2008年12月04日 01:52:51 UTC (rev 6486) @@ -0,0 +1,16 @@ +To clone from the `matplotlib github mirror`_ into the directory +``mpl.git``, enter the following commands. These instructions assume +you already have a github login (-- they use the personal +g...@gi... clone URL instead of the git://github.com clone URL):: + + # This will create your copy in the mpl.git directory + git clone gi...@gi...:astraw/matplotlib.git mpl.git + cd mpl.git + git config --add remote.origin.fetch +refs/remotes/*:refs/remotes/* + git fetch + git svn init --trunk=trunk/matplotlib --tags=tags https://matplotlib.svn.sourceforge.net/svnroot/matplotlib + + # Now just get the latest svn revisions from the SourceForge SVN repository + git svn fetch -r 6300:HEAD + +.. _matplotlib github mirror: http://github.com/astraw/matplotlib This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6485 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6485&view=rev Author: jdh2358 Date: 2008年12月03日 18:50:49 +0000 (2008年12月03日) Log Message: ----------- use standard axes creation func Modified Paths: -------------- trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py Modified: trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py 2008年12月03日 18:38:03 UTC (rev 6484) +++ trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py 2008年12月03日 18:50:49 UTC (rev 6485) @@ -7,9 +7,9 @@ fig1 = plt.figure(1, (4, figheight)) fontsize = 0.3 * fig1.dpi -ax = plt.Axes(fig1, [0, 0, 1, 1], frameon=False, aspect=1.) -fig1.add_axes(ax) +ax = fig1.add_axes([0, 0, 1, 1], frameon=False, aspect=1.) + ax.set_xlim(0, 4) ax.set_ylim(0, figheight) @@ -17,9 +17,7 @@ y = (float(len(styles)) -0.25 - i) # /figheight p = mpatches.Circle((3.2, y), 0.2, fc="w") ax.add_patch(p) - #ax.plot([0.8], [y], "o", mec="b", mfc="w", ms=20, transform=fig1.transFigure) - #ax.scatter([0.8], [y], s=20*20, marker="o", edgecolors=["b"], facecolors=["w"], - # ) + ax.annotate(stylename, (3.2, y), (2., y), #xycoords="figure fraction", textcoords="figure fraction", This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6484 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6484&view=rev Author: jdh2358 Date: 2008年12月03日 18:38:03 +0000 (2008年12月03日) Log Message: ----------- committed Gregor's enter notify update for backend wx Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_wx.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_wx.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_wx.py 2008年12月03日 15:33:53 UTC (rev 6483) +++ trunk/matplotlib/lib/matplotlib/backends/backend_wx.py 2008年12月03日 18:38:03 UTC (rev 6484) @@ -743,6 +743,7 @@ bind(self, wx.EVT_LEFT_UP, self._onLeftButtonUp) bind(self, wx.EVT_MOTION, self._onMotion) bind(self, wx.EVT_LEAVE_WINDOW, self._onLeave) + bind(self, wx.EVT_ENTER_WINDOW, self._onEnter) bind(self, wx.EVT_IDLE, self._onIdle) self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) @@ -1268,7 +1269,11 @@ evt.Skip() FigureCanvasBase.leave_notify_event(self, guiEvent = evt) + def _onEnter(self, evt): + """Mouse has entered the window.""" + FigureCanvasBase.enter_notify_event(self, guiEvent = evt) + ######################################################################## # # The following functions and classes are for pylab compatibility This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6483 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6483&view=rev Author: mdboom Date: 2008年12月03日 15:33:53 +0000 (2008年12月03日) Log Message: ----------- Fix degree display in geographic transforms, also. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/projections/geo.py Modified: trunk/matplotlib/lib/matplotlib/projections/geo.py =================================================================== --- trunk/matplotlib/lib/matplotlib/projections/geo.py 2008年12月03日 09:07:27 UTC (rev 6482) +++ trunk/matplotlib/lib/matplotlib/projections/geo.py 2008年12月03日 15:33:53 UTC (rev 6483) @@ -29,8 +29,10 @@ def __call__(self, x, pos=None): degrees = (x / np.pi) * 180.0 degrees = round(degrees / self._round_to) * self._round_to - # \u00b0 : degree symbol - return u"%d\u00b0" % degrees + if rcParams['text.usetex'] and not rcParams['text.latex.unicode']: + return r"$%0.0f^\circ$" % degrees + else: + return u"%0.0f\u00b0" % degrees RESOLUTION = 75 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6482 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6482&view=rev Author: astraw Date: 2008年12月03日 09:07:27 +0000 (2008年12月03日) Log Message: ----------- docs: add hexbin link in main overview page Modified Paths: -------------- trunk/matplotlib/doc/_templates/index.html Modified: trunk/matplotlib/doc/_templates/index.html =================================================================== --- trunk/matplotlib/doc/_templates/index.html 2008年12月03日 08:27:12 UTC (rev 6481) +++ trunk/matplotlib/doc/_templates/index.html 2008年12月03日 09:07:27 UTC (rev 6482) @@ -490,6 +490,17 @@ </tr> <tr> <th align="left"> + <a href="api/pyplot_api.html#matplotlib.pyplot.hexbin">hexbin</a> + + </th> + + <td align="left"> + make a 2D hexagonal binning plot + </td> + + </tr> + <tr> + <th align="left"> <a href="api/pyplot_api.html#matplotlib.pyplot.hist">hist</a> </th> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6481 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6481&view=rev Author: astraw Date: 2008年12月03日 08:27:12 +0000 (2008年12月03日) Log Message: ----------- add info about how to build HTML documentation Modified Paths: -------------- trunk/matplotlib/doc/README.txt Modified: trunk/matplotlib/doc/README.txt =================================================================== --- trunk/matplotlib/doc/README.txt 2008年12月03日 07:40:09 UTC (rev 6480) +++ trunk/matplotlib/doc/README.txt 2008年12月03日 08:27:12 UTC (rev 6481) @@ -32,3 +32,9 @@ * mpl_examples - a link to the matplotlib examples in case any documentation wants to literal include them + +To build the HTML documentation, install sphinx (0.5 or greater +required), then type "python make.py html" in this directory. Wait +for the initial run (which builds the example gallery) to be done, +then run "python make.py html" again. The top file of the results will +be ./build/html/index.html This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6480 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6480&view=rev Author: leejjoon Date: 2008年12月03日 07:40:09 +0000 (2008年12月03日) Log Message: ----------- reorganization of style classes in patches.py Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/patches.py Added Paths: ----------- trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008年12月02日 22:27:38 UTC (rev 6479) +++ trunk/matplotlib/CHANGELOG 2008年12月03日 07:40:09 UTC (rev 6480) @@ -1,3 +1,7 @@ +2008年12月02日 The transmuter classes in the patches.py are reorganized as + subclasses of the Style classes. A few more box and arrow + styles are added. -JJL + 2008年12月02日 Fixed a bug in the new legend class that didn't allowed a tuple of coordinate vlaues as loc. -JJL Added: trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py 2008年12月03日 07:40:09 UTC (rev 6480) @@ -0,0 +1,43 @@ +import matplotlib.patches as mpatches +import matplotlib.pyplot as plt + +styles = mpatches.ArrowStyle.get_styles() + +figheight = (len(styles)+.5) +fig1 = plt.figure(1, (4, figheight)) +fontsize = 0.3 * fig1.dpi + +ax = plt.Axes(fig1, [0, 0, 1, 1], frameon=False, aspect=1.) +fig1.add_axes(ax) + +ax.set_xlim(0, 4) +ax.set_ylim(0, figheight) + +for i, (stylename, styleclass) in enumerate(sorted(styles.items())): + y = (float(len(styles)) -0.25 - i) # /figheight + p = mpatches.Circle((3.2, y), 0.2, fc="w") + ax.add_patch(p) + #ax.plot([0.8], [y], "o", mec="b", mfc="w", ms=20, transform=fig1.transFigure) + #ax.scatter([0.8], [y], s=20*20, marker="o", edgecolors=["b"], facecolors=["w"], + # ) + ax.annotate(stylename, (3.2, y), + (2., y), + #xycoords="figure fraction", textcoords="figure fraction", + ha="right", va="center", + size=fontsize, + arrowprops=dict(arrowstyle=stylename, + patchB=p, + shrinkA=5, + shrinkB=5, + fc="w", ec="k", + connectionstyle="arc3,rad=-0.05", + ), + bbox=dict(boxstyle="square", fc="w")) + +ax.xaxis.set_visible(False) +ax.yaxis.set_visible(False) + + + +plt.draw() +plt.show() Added: trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py 2008年12月03日 07:40:09 UTC (rev 6480) @@ -0,0 +1,17 @@ +import matplotlib.patches as mpatch +import matplotlib.pyplot as plt + +styles = mpatch.BoxStyle.get_styles() + +figheight = (len(styles)+.5) +fig1 = plt.figure(1, (4, figheight)) +fontsize = 0.4 * fig1.dpi + +for i, (stylename, styleclass) in enumerate(styles.items()): + fig1.text(0.5, (float(len(styles)) - 0.5 - i)/figheight, stylename, + ha="center", + size=fontsize, + transform=fig1.transFigure, + bbox=dict(boxstyle=stylename, fc="w", ec="k")) +plt.draw() +plt.show() Modified: trunk/matplotlib/lib/matplotlib/patches.py =================================================================== --- trunk/matplotlib/lib/matplotlib/patches.py 2008年12月02日 22:27:38 UTC (rev 6479) +++ trunk/matplotlib/lib/matplotlib/patches.py 2008年12月03日 07:40:09 UTC (rev 6480) @@ -289,6 +289,7 @@ rgbFace = (r, g, b) gc.set_alpha(a) + if self._hatch: gc.set_hatch(self._hatch ) @@ -1366,319 +1367,576 @@ r.draw(renderer) -class BboxTransmuterBase(object): + +def _pprint_table(_table, leadingspace=2): """ - :class:`BBoxTransmuterBase` and its derivatives are used to make a - fancy box around a given rectangle. The :meth:`__call__` method - returns the :class:`~matplotlib.path.Path` of the fancy box. This - class is not an artist and actual drawing of the fancy box is done - by the :class:`FancyBboxPatch` class. + Given the list of list of strings, return a string of REST table format. """ + if leadingspace: + pad = ' '*leadingspace + else: + pad = '' - # The derived classes are required to be able to be initialized - # w/o arguments, i.e., all its argument (except self) must have - # the default values. + columns = [[] for cell in _table[0]] - def __init__(self): - super(BboxTransmuterBase, self).__init__() + for row in _table: + for column, cell in zip(columns, row): + column.append(cell) + + + col_len = [max([len(cell) for cell in column]) for column in columns] + lines = [] + table_formatstr = pad + ' '.join([('=' * cl) for cl in col_len]) + lines.append('') + lines.append(table_formatstr) + lines.append(pad + ' '.join([cell.ljust(cl) for cell, cl in zip(_table[0], col_len)])) + lines.append(table_formatstr) + + lines.extend([(pad + ' '.join([cell.ljust(cl) for cell, cl in zip(row, col_len)])) + for row in _table[1:]]) + + lines.append(table_formatstr) + lines.append('') + return "\n".join(lines) - def transmute(self, x0, y0, width, height, mutation_size): + +def _pprint_styles(_styles, leadingspace=2): + """ + A helper function for the _Style class. Given the dictionary of + (stylename : styleclass), return a formatted string listing all the + styles. Used to update the documentation. + """ + if leadingspace: + pad = ' '*leadingspace + else: + pad = '' + + names, attrss, clss = [], [], [] + + import inspect + + _table = [["Class", "Name", "Attrs"]] + + for name, cls in sorted(_styles.items()): + args, varargs, varkw, defaults = inspect.getargspec(cls.__init__) + if defaults: + args = [(argname, argdefault) \ + for argname, argdefault in zip(args[1:], defaults)] + else: + args = [] + + _table.append([cls.__name__, name, + ",".join([("%s=%s" % (an, av)) for an, av in args])]) + + return _pprint_table(_table) + + + +class _Style(object): + """ + A base class for the Styles. It is meant to be a container class, + where actual styles are declared as subclass of it, and it + provides some helper functions. + """ + def __new__(self, stylename, **kw): """ - The transmute method is a very core of the - :class:`BboxTransmuter` class and must be overriden in the - subclasses. It receives the location and size of the - rectangle, and the mutation_size, with which the amount of - padding and etc. will be scaled. It returns a - :class:`~matplotlib.path.Path` instance. + return the instance of the subclass with the given style name. """ - raise NotImplementedError('Derived must override') + # the "class" should have the _style_list attribute, which is + # a dictionary of stylname, style class paie. + + _list = stylename.replace(" ","").split(",") + _name = _list[0].lower() + try: + _cls = self._style_list[_name] + except KeyError: + raise ValueError("Unknown style : %s" % stylename) + try: + _args_pair = [cs.split("=") for cs in _list[1:]] + _args = dict([(k, float(v)) for k, v in _args_pair]) + except ValueError: + raise ValueError("Incorrect style argument : %s" % stylename) + _args.update(kw) - def __call__(self, x0, y0, width, height, mutation_size, - aspect_ratio=1.): + return _cls(**_args) + + + @classmethod + def get_styles(klass): """ - The __call__ method a thin wrapper around the transmute method - and take care of the aspect. + A class method which returns a dictionary of available styles. """ - if aspect_ratio is not None: - # Squeeze the given height by the aspect_ratio - y0, height = y0/aspect_ratio, height/aspect_ratio - # call transmute method with squeezed height. - path = self.transmute(x0, y0, width, height, mutation_size) - vertices, codes = path.vertices, path.codes - # Restore the height - vertices[:,1] = vertices[:,1] * aspect_ratio - return Path(vertices, codes) - else: - return self.transmute(x0, y0, width, height, mutation_size) + return klass._style_list + @classmethod + def pprint_styles(klass): + """ + A class method which returns a string of the available styles. + """ + return _pprint_styles(klass._style_list) -class SquareBoxTransmuter(BboxTransmuterBase): + + +class BoxStyle(_Style): """ - Simple square box. + :class:`BoxStyle` is a container class which defines several + boxstyle classes, which are used for :class:`FancyBoxPatch`. - *pad*: an amount of padding. + A style object can be created as + + BoxStyle.Round(pad=0.2) + + or + + BoxStyle("Round", pad=0.2) + + or + + BoxStyle("Round, pad=0.2") + + Following boxstyle classes are defined. + + %(AvailableBoxstyles)s + + An instance of any boxstyle class is an callable object, + whose call signature is + + __call__(self, x0, y0, width, height, mutation_size, aspect_ratio=1.) + + and returns a :class:`Path` instance. *x0*, *y0*, *width* and + *height* specify the location and size of the box to be + drawn. *mutation_scale* determines the overall size of the + mutation (by which I mean the transformation of the rectangle to + the fancy box). *mutation_aspect* determines the aspect-ratio of + the mutation. + """ + + _style_list = {} - def __init__(self, pad=0.3): - self.pad = pad - super(SquareBoxTransmuter, self).__init__() - def transmute(self, x0, y0, width, height, mutation_size): + class _Base(object): + """ + :class:`BBoxTransmuterBase` and its derivatives are used to make a + fancy box around a given rectangle. The :meth:`__call__` method + returns the :class:`~matplotlib.path.Path` of the fancy box. This + class is not an artist and actual drawing of the fancy box is done + by the :class:`FancyBboxPatch` class. + """ - # padding - pad = mutation_size * self.pad + # The derived classes are required to be able to be initialized + # w/o arguments, i.e., all its argument (except self) must have + # the default values. - # width and height with padding added. - width, height = width + 2.*pad, \ - height + 2.*pad, + def __init__(self): + """ + initializtion. + """ + super(BoxStyle._Base, self).__init__() - # boundary of the padded box - x0, y0 = x0-pad, y0-pad, - x1, y1 = x0+width, y0 + height - cp = [(x0, y0), (x1, y0), (x1, y1), (x0, y1), - (x0, y0), (x0, y0)] - com = [Path.MOVETO, - Path.LINETO, - Path.LINETO, - Path.LINETO, - Path.LINETO, - Path.CLOSEPOLY] - path = Path(cp, com) + def transmute(self, x0, y0, width, height, mutation_size): + """ + The transmute method is a very core of the + :class:`BboxTransmuter` class and must be overriden in the + subclasses. It receives the location and size of the + rectangle, and the mutation_size, with which the amount of + padding and etc. will be scaled. It returns a + :class:`~matplotlib.path.Path` instance. + """ + raise NotImplementedError('Derived must override') - return path -class RoundBoxTransmuter(BboxTransmuterBase): - """ - A box with round corners. - """ + def __call__(self, x0, y0, width, height, mutation_size, + aspect_ratio=1.): + """ + Given the location and size of the box, return the path of + the box around it. - def __init__(self, pad=0.3, rounding_size=None): - self.pad = pad - self.rounding_size = rounding_size - BboxTransmuterBase.__init__(self) + - *x0*, *y0*, *width*, *height* : location and size of the box + - *mutation_size* : a reference scale for the mutation. + - *aspect_ratio* : aspect-ration for the mutation. + """ + # The __call__ method is a thin wrapper around the transmute method + # and take care of the aspect. - def transmute(self, x0, y0, width, height, mutation_size): + if aspect_ratio is not None: + # Squeeze the given height by the aspect_ratio + y0, height = y0/aspect_ratio, height/aspect_ratio + # call transmute method with squeezed height. + path = self.transmute(x0, y0, width, height, mutation_size) + vertices, codes = path.vertices, path.codes + # Restore the height + vertices[:,1] = vertices[:,1] * aspect_ratio + return Path(vertices, codes) + else: + return self.transmute(x0, y0, width, height, mutation_size) - # padding - pad = mutation_size * self.pad - # size of the roudning corner - if self.rounding_size: - dr = mutation_size * self.rounding_size - else: - dr = pad - width, height = width + 2.*pad, \ - height + 2.*pad, + class Square(_Base): + """ + A simple square box. + """ + def __init__(self, pad=0.3): + """ + *pad* + amount of padding + """ + + self.pad = pad + super(BoxStyle.Square, self).__init__() - x0, y0 = x0-pad, y0-pad, - x1, y1 = x0+width, y0 + height + def transmute(self, x0, y0, width, height, mutation_size): - # Round corners are implemented as quadratic bezier. eg. - # [(x0, y0-dr), (x0, y0), (x0+dr, y0)] for lower left corner. - cp = [(x0+dr, y0), - (x1-dr, y0), - (x1, y0), (x1, y0+dr), - (x1, y1-dr), - (x1, y1), (x1-dr, y1), - (x0+dr, y1), - (x0, y1), (x0, y1-dr), - (x0, y0+dr), - (x0, y0), (x0+dr, y0), - (x0+dr, y0)] + # padding + pad = mutation_size * self.pad - com = [Path.MOVETO, - Path.LINETO, - Path.CURVE3, Path.CURVE3, - Path.LINETO, - Path.CURVE3, Path.CURVE3, - Path.LINETO, - Path.CURVE3, Path.CURVE3, - Path.LINETO, - Path.CURVE3, Path.CURVE3, - Path.CLOSEPOLY] + # width and height with padding added. + width, height = width + 2.*pad, \ + height + 2.*pad, - path = Path(cp, com) + # boundary of the padded box + x0, y0 = x0-pad, y0-pad, + x1, y1 = x0+width, y0 + height - return path + cp = [(x0, y0), (x1, y0), (x1, y1), (x0, y1), + (x0, y0), (x0, y0)] + com = [Path.MOVETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.CLOSEPOLY] -class Round4BoxTransmuter(BboxTransmuterBase): - """ - A box with round edges. - """ + path = Path(cp, com) - def __init__(self, pad=0.3, rounding_size=None): - self.pad = pad - self.rounding_size = rounding_size - BboxTransmuterBase.__init__(self) + return path - def transmute(self, x0, y0, width, height, mutation_size): + _style_list["square"] = Square - # padding - pad = mutation_size * self.pad - # roudning size. Use a half of the pad if not set. - if self.rounding_size: - dr = mutation_size * self.rounding_size - else: - dr = pad / 2. + class LArrow(_Base): + """ + (left) Arrow Box + """ - width, height = width + 2.*pad - 2*dr, \ - height + 2.*pad - 2*dr, + def __init__(self, pad=0.3): + self.pad = pad + super(BoxStyle.LArrow, self).__init__() + def transmute(self, x0, y0, width, height, mutation_size): - x0, y0 = x0-pad+dr, y0-pad+dr, - x1, y1 = x0+width, y0 + height + # padding + pad = mutation_size * self.pad + # width and height with padding added. + width, height = width + 2.*pad, \ + height + 2.*pad, - cp = [(x0, y0), - (x0+dr, y0-dr), (x1-dr, y0-dr), (x1, y0), - (x1+dr, y0+dr), (x1+dr, y1-dr), (x1, y1), - (x1-dr, y1+dr), (x0+dr, y1+dr), (x0, y1), - (x0-dr, y1-dr), (x0-dr, y0+dr), (x0, y0), - (x0, y0)] + # boundary of the padded box + x0, y0 = x0-pad, y0-pad, + x1, y1 = x0+width, y0 + height - com = [Path.MOVETO, - Path.CURVE4, Path.CURVE4, Path.CURVE4, - Path.CURVE4, Path.CURVE4, Path.CURVE4, - Path.CURVE4, Path.CURVE4, Path.CURVE4, - Path.CURVE4, Path.CURVE4, Path.CURVE4, - Path.CLOSEPOLY] + dx = (y1-y0)/2. + dxx = dx*.5 + # adjust x0. 1.4 <- sqrt(2) + x0 = x0 + pad / 1.4 + + cp = [(x0+dxx, y0), (x1, y0), (x1, y1), (x0+dxx, y1), + (x0+dxx, y1+dxx), (x0-dx, y0+dx), (x0+dxx, y0-dxx), # arrow + (x0+dxx, y0), (x0+dxx, y0)] - path = Path(cp, com) + com = [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, + Path.LINETO, Path.LINETO, Path.LINETO, + Path.LINETO, Path.CLOSEPOLY] - return path + path = Path(cp, com) + return path + _style_list["larrow"] = LArrow -class SawtoothBoxTransmuter(BboxTransmuterBase): - """ - A sawtooth box. - """ + class RArrow(LArrow): + """ + (right) Arrow Box + """ - def __init__(self, pad=0.3, tooth_size=None): - self.pad = pad - self.tooth_size = tooth_size - BboxTransmuterBase.__init__(self) + def __init__(self, pad=0.3): + self.pad = pad + super(BoxStyle.RArrow, self).__init__() - def _get_sawtooth_vertices(self, x0, y0, width, height, mutation_size): + def transmute(self, x0, y0, width, height, mutation_size): + p = BoxStyle.LArrow.transmute(self, x0, y0, + width, height, mutation_size) - # padding - pad = mutation_size * self.pad + p.vertices[:,0] = 2*x0 + width - p.vertices[:,0] - # size of sawtooth - if self.tooth_size is None: - tooth_size = self.pad * .5 * mutation_size - else: - tooth_size = self.tooth_size * mutation_size + return p - tooth_size2 = tooth_size / 2. - width, height = width + 2.*pad - tooth_size, \ - height + 2.*pad - tooth_size, + + _style_list["rarrow"] = RArrow - # the sizes of the vertical and horizontal sawtooth are - # separately adjusted to fit the given box size. - dsx_n = int(round((width - tooth_size) / (tooth_size * 2))) * 2 - dsx = (width - tooth_size) / dsx_n - dsy_n = int(round((height - tooth_size) / (tooth_size * 2))) * 2 - dsy = (height - tooth_size) / dsy_n + class Round(_Base): + """ + A box with round corners. + """ - x0, y0 = x0-pad+tooth_size2, y0-pad+tooth_size2 - x1, y1 = x0+width, y0 + height + def __init__(self, pad=0.3, rounding_size=None): + """ + *pad* + amount of padding + *rounding_size* + rounding radius of corners. *pad* if None + """ + self.pad = pad + self.rounding_size = rounding_size + super(BoxStyle.Round, self).__init__() - bottom_saw_x = [x0] + \ - [x0 + tooth_size2 + dsx*.5* i for i in range(dsx_n*2)] + \ - [x1 - tooth_size2] - bottom_saw_y = [y0] + \ - [y0 - tooth_size2, y0, y0 + tooth_size2, y0] * dsx_n + \ - [y0 - tooth_size2] + def transmute(self, x0, y0, width, height, mutation_size): - right_saw_x = [x1] + \ - [x1 + tooth_size2, x1, x1 - tooth_size2, x1] * dsx_n + \ - [x1 + tooth_size2] - right_saw_y = [y0] + \ - [y0 + tooth_size2 + dsy*.5* i for i in range(dsy_n*2)] + \ - [y1 - tooth_size2] + # padding + pad = mutation_size * self.pad - top_saw_x = [x1] + \ - [x1 - tooth_size2 - dsx*.5* i for i in range(dsx_n*2)] + \ - [x0 + tooth_size2] - top_saw_y = [y1] + \ - [y1 + tooth_size2, y1, y1 - tooth_size2, y1] * dsx_n + \ - [y1 + tooth_size2] + # size of the roudning corner + if self.rounding_size: + dr = mutation_size * self.rounding_size + else: + dr = pad - left_saw_x = [x0] + \ - [x0 - tooth_size2, x0, x0 + tooth_size2, x0] * dsy_n + \ - [x0 - tooth_size2] - left_saw_y = [y1] + \ - [y1 - tooth_size2 - dsy*.5* i for i in range(dsy_n*2)] + \ - [y0 + tooth_size2] + width, height = width + 2.*pad, \ + height + 2.*pad, - saw_vertices = zip(bottom_saw_x, bottom_saw_y) + \ - zip(right_saw_x, right_saw_y) + \ - zip(top_saw_x, top_saw_y) + \ - zip(left_saw_x, left_saw_y) + \ - [(bottom_saw_x[0], bottom_saw_y[0])] - return saw_vertices + x0, y0 = x0-pad, y0-pad, + x1, y1 = x0+width, y0 + height + # Round corners are implemented as quadratic bezier. eg. + # [(x0, y0-dr), (x0, y0), (x0+dr, y0)] for lower left corner. + cp = [(x0+dr, y0), + (x1-dr, y0), + (x1, y0), (x1, y0+dr), + (x1, y1-dr), + (x1, y1), (x1-dr, y1), + (x0+dr, y1), + (x0, y1), (x0, y1-dr), + (x0, y0+dr), + (x0, y0), (x0+dr, y0), + (x0+dr, y0)] - def transmute(self, x0, y0, width, height, mutation_size): + com = [Path.MOVETO, + Path.LINETO, + Path.CURVE3, Path.CURVE3, + Path.LINETO, + Path.CURVE3, Path.CURVE3, + Path.LINETO, + Path.CURVE3, Path.CURVE3, + Path.LINETO, + Path.CURVE3, Path.CURVE3, + Path.CLOSEPOLY] - saw_vertices = self._get_sawtooth_vertices(x0, y0, width, height, mutation_size) - path = Path(saw_vertices) - return path + path = Path(cp, com) + return path -class RoundtoothBoxTransmuter(SawtoothBoxTransmuter): - """ - A roundtooth(?) box. - """ + _style_list["round"] = Round - def transmute(self, x0, y0, width, height, mutation_size): - saw_vertices = self._get_sawtooth_vertices(x0, y0, width, height, mutation_size) + class Round4(_Base): + """ + Another box with round edges. + """ - cp = [Path.MOVETO] + ([Path.CURVE3, Path.CURVE3] * ((len(saw_vertices)-1)//2)) - path = Path(saw_vertices, cp) + def __init__(self, pad=0.3, rounding_size=None): + """ + *pad* + amount of padding - return path + *rounding_size* + rounding size of edges. *pad* if None + """ + + self.pad = pad + self.rounding_size = rounding_size + super(BoxStyle.Round4, self).__init__() + def transmute(self, x0, y0, width, height, mutation_size): -def _list_available_boxstyles(transmuters): - """ a helper function of the :class:`FancyBboxPatch` to list the available - box styles. It inspects the arguments of the __init__ methods of - each classes and report them - """ - import inspect - s = [] - for name, cls in transmuters.items(): - args, varargs, varkw, defaults = inspect.getargspec(cls.__init__) - args_string = ["%s=%s" % (argname, str(argdefault)) \ - for argname, argdefault in zip(args[1:], defaults)] - s.append(",".join([name]+args_string)) - return s + # padding + pad = mutation_size * self.pad + # roudning size. Use a half of the pad if not set. + if self.rounding_size: + dr = mutation_size * self.rounding_size + else: + dr = pad / 2. + width, height = width + 2.*pad - 2*dr, \ + height + 2.*pad - 2*dr, + x0, y0 = x0-pad+dr, y0-pad+dr, + x1, y1 = x0+width, y0 + height + + cp = [(x0, y0), + (x0+dr, y0-dr), (x1-dr, y0-dr), (x1, y0), + (x1+dr, y0+dr), (x1+dr, y1-dr), (x1, y1), + (x1-dr, y1+dr), (x0+dr, y1+dr), (x0, y1), + (x0-dr, y1-dr), (x0-dr, y0+dr), (x0, y0), + (x0, y0)] + + com = [Path.MOVETO, + Path.CURVE4, Path.CURVE4, Path.CURVE4, + Path.CURVE4, Path.CURVE4, Path.CURVE4, + Path.CURVE4, Path.CURVE4, Path.CURVE4, + Path.CURVE4, Path.CURVE4, Path.CURVE4, + Path.CLOSEPOLY] + + path = Path(cp, com) + + return path + + _style_list["round4"] = Round4 + + + class Sawtooth(_Base): + """ + A sawtooth box. + """ + + def __init__(self, pad=0.3, tooth_size=None): + """ + *pad* + amount of padding + + *tooth_size* + size of the sawtooth. pad* if None + """ + self.pad = pad + self.tooth_size = tooth_size + super(BoxStyle.Sawtooth, self).__init__() + + def _get_sawtooth_vertices(self, x0, y0, width, height, mutation_size): + + + # padding + pad = mutation_size * self.pad + + # size of sawtooth + if self.tooth_size is None: + tooth_size = self.pad * .5 * mutation_size + else: + tooth_size = self.tooth_size * mutation_size + + tooth_size2 = tooth_size / 2. + width, height = width + 2.*pad - tooth_size, \ + height + 2.*pad - tooth_size, + + # the sizes of the vertical and horizontal sawtooth are + # separately adjusted to fit the given box size. + dsx_n = int(round((width - tooth_size) / (tooth_size * 2))) * 2 + dsx = (width - tooth_size) / dsx_n + dsy_n = int(round((height - tooth_size) / (tooth_size * 2))) * 2 + dsy = (height - tooth_size) / dsy_n + + + x0, y0 = x0-pad+tooth_size2, y0-pad+tooth_size2 + x1, y1 = x0+width, y0 + height + + + bottom_saw_x = [x0] + \ + [x0 + tooth_size2 + dsx*.5* i for i in range(dsx_n*2)] + \ + [x1 - tooth_size2] + bottom_saw_y = [y0] + \ + [y0 - tooth_size2, y0, y0 + tooth_size2, y0] * dsx_n + \ + [y0 - tooth_size2] + + right_saw_x = [x1] + \ + [x1 + tooth_size2, x1, x1 - tooth_size2, x1] * dsx_n + \ + [x1 + tooth_size2] + right_saw_y = [y0] + \ + [y0 + tooth_size2 + dsy*.5* i for i in range(dsy_n*2)] + \ + [y1 - tooth_size2] + + top_saw_x = [x1] + \ + [x1 - tooth_size2 - dsx*.5* i for i in range(dsx_n*2)] + \ + [x0 + tooth_size2] + top_saw_y = [y1] + \ + [y1 + tooth_size2, y1, y1 - tooth_size2, y1] * dsx_n + \ + [y1 + tooth_size2] + + left_saw_x = [x0] + \ + [x0 - tooth_size2, x0, x0 + tooth_size2, x0] * dsy_n + \ + [x0 - tooth_size2] + left_saw_y = [y1] + \ + [y1 - tooth_size2 - dsy*.5* i for i in range(dsy_n*2)] + \ + [y0 + tooth_size2] + + saw_vertices = zip(bottom_saw_x, bottom_saw_y) + \ + zip(right_saw_x, right_saw_y) + \ + zip(top_saw_x, top_saw_y) + \ + zip(left_saw_x, left_saw_y) + \ + [(bottom_saw_x[0], bottom_saw_y[0])] + + return saw_vertices + + + def transmute(self, x0, y0, width, height, mutation_size): + + saw_vertices = self._get_sawtooth_vertices(x0, y0, width, height, mutation_size) + path = Path(saw_vertices) + return path + + _style_list["sawtooth"] = Sawtooth + + + class Roundtooth(Sawtooth): + """ + A roundtooth(?) box. + """ + + def __init__(self, pad=0.3, tooth_size=None): + """ + *pad* + amount of padding + + *tooth_size* + size of the sawtooth. pad* if None + """ + super(BoxStyle.Roundtooth, self).__init__(pad, tooth_size) + + + def transmute(self, x0, y0, width, height, mutation_size): + + saw_vertices = self._get_sawtooth_vertices(x0, y0, width, height, mutation_size) + + cp = [Path.MOVETO] + ([Path.CURVE3, Path.CURVE3] * ((len(saw_vertices)-1)//2)) + path = Path(saw_vertices, cp) + + return path + + _style_list["roundtooth"] = Roundtooth + + __doc__ = cbook.dedent(__doc__) % \ + {"AvailableBoxstyles": _pprint_styles(_style_list)} + + class FancyBboxPatch(Patch): """ Draw a fancy box around a rectangle with lower left at *xy*=(*x*, @@ -1689,27 +1947,8 @@ transformation of the rectangle box to the fancy box is delegated to the :class:`BoxTransmuterBase` and its derived classes. - *boxstyle* determines what kind of fancy box will be drawn. In - other words, it selects the :class:`BboxTransmuter` class to use, - and sets optional attributes. - - *bbox_transmuter* can specify a custom :class:`BboxTransmuter` - instance. - - *mutation_scale* determines the overall size of the mutation (by - which I mean the transformation of the rectangle to the fancy - path) - - *mutation_aspect* determines the aspect-ratio of the mutation. """ - _fancy_bbox_transmuters = {"square":SquareBoxTransmuter, - "round":RoundBoxTransmuter, - "round4":Round4BoxTransmuter, - "sawtooth":SawtoothBoxTransmuter, - "roundtooth":RoundtoothBoxTransmuter, - } - def __str__(self): return self.__class__.__name__ \ + "FancyBboxPatch(%g,%g;%gx%g)" % (self._x, self._y, self._width, self._height) @@ -1725,18 +1964,13 @@ *width*, *height* - *boxstyle* describes how the fancy box will be drawn. It - should be one of the available boxstyle names, with optional - comma-separated attributes. These attributes are meant to be - scaled with the *mutation_scale*. Following box styles are - available. + *boxstyle* determines what kind of fancy box will be drawn. It + can be a string of the style name with a comma separated + attribute, or an instance of :class:`BoxStyle`. Following box + styles are available. %(AvailableBoxstyles)s - The *boxstyle* name can be "custom", in which case the - *bbox_transmuter* argument needs to be set, which should be an - instance of :class:`BboxTransmuterBase` (or its derived). - *mutation_scale* : a value with which attributes of boxstyle (e.g., pad) will be scaled. default=1. @@ -1767,17 +2001,12 @@ kwdoc = dict() - kwdoc["AvailableBoxstyles"]="\n".join([" - " + l \ - for l in _list_available_boxstyles(_fancy_bbox_transmuters)]) + kwdoc["AvailableBoxstyles"]=_pprint_styles(BoxStyle._style_list) kwdoc.update(artist.kwdocd) __init__.__doc__ = cbook.dedent(__init__.__doc__) % kwdoc del kwdoc - @classmethod - def list_available_boxstyles(cls): - return _list_available_boxstyles(cls._fancy_bbox_transmuters) - def set_boxstyle(self, boxstyle=None, **kw): """ Set the box style. @@ -1799,29 +2028,20 @@ if boxstyle==None: # print out available boxstyles and return. - print " Following box styles are available." - for l in self.list_available_boxstyles(): - print " - " + l + print "Following box styles are available:" + print BoxStyle.pprint_styles() return - # parse the boxstyle descrption (e.g. "round,pad=0.3") - bs_list = boxstyle.replace(" ","").split(",") - boxstyle_name = bs_list[0] - try: - bbox_transmuter_cls = self._fancy_bbox_transmuters[boxstyle_name] - except KeyError: - raise ValueError("Unknown Boxstyle : %s" % boxstyle_name) - try: - boxstyle_args_pair = [bs.split("=") for bs in bs_list[1:]] - boxstyle_args = dict([(k, float(v)) for k, v in boxstyle_args_pair]) - except ValueError: - raise ValueError("Incorrect Boxstyle argument : %s" % boxstyle) + if isinstance(boxstyle, BoxStyle._Base): + self._bbox_transmuter = boxstyle + elif callable(boxstyle): + self._bbox_transmuter = boxstyle + else: + self._bbox_transmuter = BoxStyle(boxstyle, **kw) + - boxstyle_args.update(kw) - self._bbox_transmuter = bbox_transmuter_cls(**boxstyle_args) kwdoc = dict() - kwdoc["AvailableBoxstyles"]=" | ".join([l \ - for l in _list_available_boxstyles(_fancy_bbox_transmuters)]) + kwdoc["AvailableBoxstyles"]=_pprint_styles(BoxStyle._style_list) kwdoc.update(artist.kwdocd) set_boxstyle.__doc__ = cbook.dedent(set_boxstyle.__doc__) % kwdoc del kwdoc @@ -1854,16 +2074,8 @@ """ return self._mutation_aspect - def set_bbox_transmuter(self, bbox_transmuter): - """ - Set the transmuter object - - ACCEPTS: :class:`BboxTransmuterBase` (or its derivatives) instance - """ - self._bbox_transmuter = bbox_transmuter - - def get_bbox_transmuter(self): - "Return the current transmuter object" + def get_boxstyle(self): + "Return the boxstyle object" return self._bbox_transmuter def get_path(self): @@ -1871,10 +2083,10 @@ Return the mutated path of the rectangle """ - _path = self.get_bbox_transmuter()(self._x, self._y, - self._width, self._height, - self.get_mutation_scale(), - self.get_mutation_aspect()) + _path = self.get_boxstyle()(self._x, self._y, + self._width, self._height, + self.get_mutation_scale(), + self.get_mutation_aspect()) return _path @@ -1954,239 +2166,354 @@ from matplotlib.bezier import split_bezier_intersecting_with_closedpath from matplotlib.bezier import get_intersection, inside_circle, get_parallels from matplotlib.bezier import make_wedged_bezier2 -from matplotlib.bezier import split_path_inout, inside_circle +from matplotlib.bezier import split_path_inout, inside_circle, get_cos_sin -class ConnectorBase(object): - """ The ConnectorClass is used to define a path between a two - points. This class is used in the FancyArrowPatch class. It - creates a path between point A and point B. When optional patch - objects (pathcA & patchB) are provided and if they enclose the - point A or B, the path is clipped to the boundary of the each - patch. Additionally the path can be shirnked by a fixed size - (given in points) with shrinkA and shrinkB. + +class ConnectionStyle(_Style): """ + :class:`ConnectionStyle` is a container class which defines + several connectionstyle classes, which is used to create a path + between two points. These are mainly used with + :class:`FancyArrowPatch`. - class SimpleEvent: - def __init__(self, xy): - self.x, self.y = xy + A connectionstyle object can be either created as - def _clip(self, path, patchA, patchB): - """ Clip the path to the boundary of the patchA and patchB. - The starting point of the path needed to be inside of the - patchA and the end point inside the patch B. The contains - methods of each patch object is utilized to test if the point - is inside the path. + ConnectionStyle.Arc3(rad=0.2) + + or + + ConnectionStyle("Arc3", rad=0.2) + + or + + ConnectionStyle("Arc3, rad=0.2") + + Following classes are defined + + %(AvailableConnectorstyles)s + + + An instance of any connection style class is an callable object, + whose call signature is + + __call__(self, posA, posB, patchA=None, patchB=None, shrinkA=2., shrinkB=2.) + + and it returns a :class:`Path` instance. *posA* and *posB are tuples + of x,y coordinates of the two points to be connected. *patchA* (or + $patchB*) is given, the returned path is clipped so that it start + (or end) from the boundary of the patch. The path is further + shrinked by *shrinkA* (or *shrinkB*) which is given in points. + """ + + _style_list = {} + + + class _Base(object): """ + A base class for connectionstyle classes. The dervided needs + to implement a *connect* methods whose call signature is - if patchA: - def insideA(xy_display): - #xy_display = patchA.get_data_transform().transform_point(xy_data) - xy_event = ConnectorBase.SimpleEvent(xy_display) - return patchA.contains(xy_event)[0] + connect(posA, posB) + + where posA and posB are tuples of x, y coordinates to be + connected. The methods needs to return a path connecting two + points. This base class defines a __call__ method, and few + helper methods. + """ - try: + class SimpleEvent: + def __init__(self, xy): + self.x, self.y = xy + + def _clip(self, path, patchA, patchB): + """ + Clip the path to the boundary of the patchA and patchB. + The starting point of the path needed to be inside of the + patchA and the end point inside the patch B. The *contains* + methods of each patch object is utilized to test if the point + is inside the path. + """ + + if patchA: + def insideA(xy_display): + #xy_display = patchA.get_data_transform().transform_point(xy_data) + xy_event = ConnectionStyle._Base.SimpleEvent(xy_display) + return patchA.contains(xy_event)[0] + + try: + left, right = split_path_inout(path, insideA) + except ValueError: + right = path + + path = right + + if patchB: + def insideB(xy_display): + #xy_display = patchB.get_data_transform().transform_point(xy_data) + xy_event = ConnectionStyle._Base.SimpleEvent(xy_display) + return patchB.contains(xy_event)[0] + + try: + left, right = split_path_inout(path, insideB) + except ValueError: + left = path + + path = left + + return path + + + def _shrink(self, path, shrinkA, shrinkB): + """ + Shrink the path by fixed size (in points) with shrinkA and shrinkB + """ + if shrinkA: + x, y = path.vertices[0] + insideA = inside_circle(x, y, shrinkA) + left, right = split_path_inout(path, insideA) - except ValueError: - right = path + path = right - path = right + if shrinkB: + x, y = path.vertices[-1] + insideB = inside_circle(x, y, shrinkB) - if patchB: - def insideB(xy_display): - #xy_display = patchB.get_data_transform().transform_point(xy_data) - xy_event = ConnectorBase.SimpleEvent(xy_display) - return patchB.contains(xy_event)[0] - - try: left, right = split_path_inout(path, insideB) - except ValueError: - left = path + path = left - path = left + return path - #ppp = patchB.get_patch_transform().transform_path(patchB.get_path()) - #def insideB(xy_data): - # return ppp.contains_point(xy_data) - ##return patchB.contains(ConnectorBase.SimpleEvent(xy))[0] + def __call__(self, posA, posB, + shrinkA=2., shrinkB=2., patchA=None, patchB=None): + """ + Calls the *connect* method to create a path between *posA* + and *posB*. The path is clipped and shrinked. + """ + + path = self.connect(posA, posB) - return path + clipped_path = self._clip(path, patchA, patchB) + shrinked_path = self._shrink(clipped_path, shrinkA, shrinkB) + return shrinked_path - def _shrink(self, path, shrinkA, shrinkB): + + class Arc3(_Base): """ - Shrink the path by fixed size (in points) with shrinkA and shrinkB + Creates a simple quadratic bezier curve between two + points. The curve is created so that the middle contol points + (C1) is located at the same distance from the start (C0) and + end points(C2) and the distance of the C1 to the line + connecting C0-C2 is *rad* times the distance of C0-C2. """ - if shrinkA: - x, y = path.vertices[0] - insideA = inside_circle(x, y, shrinkA) - left, right = split_path_inout(path, insideA) - path = right + def __init__(self, rad=0.): + """ + *rad* + curvature of the curve. + """ + self.rad = rad - if shrinkB: - x, y = path.vertices[-1] - insideB = inside_circle(x, y, shrinkB) + def connect(self, posA, posB): + x1, y1 = posA + x2, y2 = posB + x12, y12 = (x1 + x2)/2., (y1 + y2)/2. + dx, dy = x2 - x1, y2 - y1 - left, right = split_path_inout(path, insideB) - path = left + f = self.rad - return path + cx, cy = x12 + f*dy, y12 - f*dx - def __call__(self, posA, posB, - shrinkA=2., shrinkB=2., patchA=None, patchB=None): + vertices = [(x1, y1), + (cx, cy), + (x2, y2)] + codes = [Path.MOVETO, + Path.CURVE3, + Path.CURVE3] - path = self.connect(posA, posB) + return Path(vertices, codes) - clipped_path = self._clip(path, patchA, patchB) - shrinked_path = self._shrink(clipped_path, shrinkA, shrinkB) + _style_list["arc3"] = Arc3 + - return shrinked_path + class Angle3(_Base): + """ + Creates a simple quadratic bezier curve between two + points. The middle control points is placed at the + intersecting point of two lines which crosses the start (or + end) point and has a angle of angleA (or angleB). + """ -class Arc3Connector(ConnectorBase): - """ Creates a simple quadratic bezier curve between two - points. The curve is created so that the middle contol points (C1) - is located at the same distance from the start (C0) and end - points(C2) and the distance of the C1 to the line connecting C0-C2 - is *rad* times the distance of C0-C2. - """ - def __init__(self, rad=0.): - self.rad = rad + def __init__(self, angleA=90, angleB=0): + """ + *angleA* + starting angle of the path - def connect(self, posA, posB): - x1, y1 = posA - x2, y2 = posB - x12, y12 = (x1 + x2)/2., (y1 + y2)/2. - dx, dy = x2 - x1, y2 - y1 + *angleB* + ending angle of the path + """ - f = self.rad + self.angleA = angleA + self.angleB = angleB - cx, cy = x12 + f*dy, y12 - f*dx - vertices = [(x1, y1), - (cx, cy), - (x2, y2)] - codes = [Path.MOVETO, - Path.CURVE3, - Path.CURVE3] + def connect(self, posA, posB): + x1, y1 = posA + x2, y2 = posB - return Path(vertices, codes) + cosA, sinA = math.cos(self.angleA/180.*math.pi),\ + math.sin(self.angleA/180.*math.pi), + cosB, sinB = math.cos(self.angleB/180.*math.pi),\ + math.sin(self.angleB/180.*math.pi), + cx, cy = get_intersection(x1, y1, cosA, sinA, + x2, y2, cosB, sinB) -class Angle3Connector(ConnectorBase): - """ Creates a simple quadratic bezier curve between two - points. The middle control points is placed at the intersecting - point of two lines which crosses the start (or end) point - and has a angle of angleA (or angleB). - """ - def __init__(self, angleA=90, angleB=0): - self.angleA = angleA - self.angleB = angleB + vertices = [(x1, y1), (cx, cy), (x2, y2)] + codes = [Path.MOVETO, Path.CURVE3, Path.CURVE3] - def connect(self, posA, posB): - x1, y1 = posA - x2, y2 = posB + return Path(vertices, codes) - cosA, sinA = math.cos(self.angleA/180.*math.pi),\ - math.sin(self.angleA/180.*math.pi), - cosB, sinB = math.cos(self.angleB/180.*math.pi),\ - math.sin(self.angleB/180.*math.pi), + _style_list["angle3"] = Angle3 - cx, cy = get_intersection(x1, y1, cosA, sinA, - x2, y2, cosB, sinB) - vertices = [(x1, y1), (cx, cy), (x2, y2)] - codes = [Path.MOVETO, Path.CURVE3, Path.CURVE3] + class Angle(_Base): + """ + Creates a picewise continuous quadratic bezier path between + two points. The path has a one passing-through point placed at + the intersecting point of two lines which crosses the start + (or end) point and has a angle of angleA (or angleB). The + connecting edges are rounded with *rad*. + """ - return Path(vertices, codes) + def __init__(self, angleA=90, angleB=0, rad=0.): + """ + *angleA* + starting angle of the path + *angleB* + ending angle of the path -class AngleConnector(ConnectorBase): - """ Creates a picewise continuous quadratic bezier path between - two points. The path has a one passing-through point placed at the - intersecting point of two lines which crosses the start (or end) - point and has a angle of angleA (or angleB). The connecting edges are - rounded with *rad*. - """ + *rad* + rounding radius of the edge + """ - def __init__(self, angleA=90, angleB=0, rad=0.): - self.angleA = angleA - self.angleB = angleB + self.angleA = angleA + self.angleB = angleB - self.rad = rad + self.rad = rad - def connect(self, posA, posB): - x1, y1 = posA - x2, y2 = posB + def connect(self, posA, posB): + x1, y1 = posA + x2, y2 = posB - cosA, sinA = math.cos(self.angleA/180.*math.pi),\ - math.sin(self.angleA/180.*math.pi), - cosB, sinB = math.cos(self.angleB/180.*math.pi),\ - -math.sin(self.angleB/180.*math.pi), + cosA, sinA = math.cos(self.angleA/180.*math.pi),\ + math.sin(self.angleA/180.*math.pi), + cosB, sinB = math.cos(self.angleB/180.*math.pi),\ + -math.sin(self.angleB/180.*math.pi), - cx, cy = get_intersection(x1, y1, cosA, sinA, - x2, y2, cosB, sinB) + cx, cy = get_intersection(x1, y1, cosA, sinA, + x2, y2, cosB, sinB) - vertices = [(x1, y1)] - codes = [Path.MOVETO] + vertices = [(x1, y1)] + codes = [Path.MOVETO] - if self.rad == 0.: - vertices.append((cx, cy)) + if self.rad == 0.: + vertices.append((cx, cy)) + codes.append(Path.LINETO) + else: + vertices.extend([(cx - self.rad * cosA, cy - self.rad * sinA), + (cx, cy), + (cx + self.rad * cosB, cy + self.rad * sinB)]) + codes.extend([Path.LINETO, Path.CURVE3, Path.CURVE3]) + + vertices.append((x2, y2)) codes.append(Path.LINETO) - else: - vertices.extend([(cx - self.rad * cosA, cy - self.rad * sinA), - (cx, cy), - (cx + self.rad * cosB, cy + self.rad * sinB)]) - codes.extend([Path.LINETO, Path.CURVE3, Path.CURVE3]) - vertices.append((x2, y2)) - codes.append(Path.LINETO) + return Path(vertices, codes) - return Path(vertices, codes) + _style_list["angle"] = Angle + class Arc(_Base): + """ + Creates a picewise continuous quadratic bezier path between + two points. The path can have two passing-through points, a + point placed at the distance of armA and angle of angleA from + point A, another point with respect to point B. The edges are + rounded with *rad*. + """ -class ArcConnector(ConnectorBase): - """ Creates a picewise continuous quadratic bezier path between - two points. The path can have two passing-through points, a point - placed at the distance of armA and angle of angleA from point A, - another point with respect to point B. The edges are rounded with - *rad*. - """ + def __init__(self, angleA=0, angleB=0, armA=None, armB=None, rad=0.): + """ + *angleA* : + starting angle of the path - def __init__(self, angleA=0, angleB=0, armA=None, armB=None, rad=0.): - self.angleA = angleA - self.angleB = angleB - self.armA = armA - self.armB = armB + *angleB* : + ending angle of the path - self.rad = rad + *armA* : + length of the starting arm - def connect(self, posA, posB): - x1, y1 = posA - x2, y2 = posB + *armB* : + length of the ending arm - vertices = [(x1, y1)] - rounded = [] - codes = [Path.MOVETO] + *rad* : + rounding radius of the edges + """ - if self.armA: - cosA = math.cos(self.angleA/180.*math.pi) - sinA = math.sin(self.angleA/180.*math.pi) - #x_armA, y_armB - d = self.armA - self.rad - rounded.append((x1 + d*cosA, y1 + d*sinA)) - d = self.armA - rounded.append((x1 + d*cosA, y1 + d*sinA)) + self.angleA = angleA + self.angleB = angleB + self.armA = armA + self.armB = armB - if self.armB: - cosB = math.cos(self.angleB/180.*math.pi) - sinB = math.sin(self.angleB/180.*math.pi) - x_armB, y_armB = x2 + self.armB*cosB, y2 + self.armB*sinB + self.rad = rad + def connect(self, posA, posB): + x1, y1 = posA + x2, y2 = posB + + vertices = [(x1, y1)] + rounded = [] + codes = [Path.MOVETO] + + if self.armA: + cosA = math.cos(self.angleA/180.*math.pi) + sinA = math.sin(self.angleA/180.*math.pi) + #x_armA, y_armB + d = self.armA - self.rad + rounded.append((x1 + d*cosA, y1 + d*sinA)) + d = self.armA + rounded.append((x1 + d*cosA, y1 + d*sinA)) + + if self.armB: + cosB = math.cos(self.angleB/180.*math.pi) + sinB = math.sin(self.angleB/180.*math.pi) + x_armB, y_armB = x2 + self.armB*cosB, y2 + self.armB*sinB + + if rounded: + xp, yp = rounded[-1] + dx, dy = x_armB - xp, y_armB - yp + dd = (dx*dx + dy*dy)**.5 + + rounded.append((xp + self.rad*dx/dd, yp + self.rad*dy/dd)) + vertices.extend(rounded) + codes.extend([Path.LINETO, + Path.CURVE3, + Path.CURVE3]) + else: + xp, yp = vertices[-1] + dx, dy = x_armB - xp, y_armB - yp + dd = (dx*dx + dy*dy)**.5 + + d = dd - self.rad + rounded = [(xp + d*dx/dd, yp + d*dy/dd), + (x_armB, y_armB)] + if rounded: xp, yp = rounded[-1] - dx, dy = x_armB - xp, y_armB - yp + dx, dy = x2 - xp, y2 - yp dd = (dx*dx + dy*dy)**.5 rounded.append((xp + self.rad*dx/dd, yp + self.rad*dy/dd)) @@ -2194,528 +2521,677 @@ codes.extend([Path.LINETO, Path.CURVE3, Path.CURVE3]) - else: - xp, yp = vertices[-1] - dx, dy = x_armB - xp, y_armB - yp - dd = (dx*dx + dy*dy)**.5 - d = dd - self.rad - rounded = [(xp + d*dx/dd, yp + d*dy/dd), - (x_armB, y_armB)] + vertices.append((x2, y2)) + codes.append(Path.LINETO) - if rounded: - xp, yp = rounded[-1] - dx, dy = x2 - xp, y2 - yp - dd = (dx*dx + dy*dy)**.5 + return Path(vertices, codes) - rounded.append((xp + self.rad*dx/dd, yp + self.rad*dy/dd)) - vertices.extend(rounded) - codes.extend([Path.LINETO, - Path.CURVE3, - Path.CURVE3]) + _style_list["arc"] = Arc - vertices.append((x2, y2)) - codes.append(Path.LINETO) + __doc__ = cbook.dedent(__doc__) % \ + {"AvailableConnectorstyles": _pprint_styles(_style_list)} + - return Path(vertices, codes) +class ArrowStyle(_Style): + """ + :class:`ArrowStyle` is a container class which defines several + arrowstyle classes, which is used to create an arrow path along a + given path. These are mainly used with :class:`FancyArrowPatch`. + A arrowstyle object can be either created as + ArrowStyle.Fancy(head_length=.4, head_width=.4, tail_width=.4) + or -class ArrowTransmuterBase(object): - """ - Arrow Transmuter Base class + ArrowStyle("Fancy", head_length=.4, head_width=.4, tail_width=.4) - ArrowTransmuterBase and its derivatives are used to make a fancy - arrow around a given path. The __call__ method returns a path - (which will be used to create a PathPatch instance) and a boolean - value indicating the path is open therefore is not fillable. This - class is not an artist and actual drawing of the fancy arrow is - done by the FancyArrowPatch class. + or + + ArrowStyle("Fancy, head_length=.4, head_width=.4, tail_width=.4") + Following classes are defined + + %(AvailableArrowstyles)s + + + An instance of any arrow style class is an callable object, + whose call signature is + + __call__(self, path, mutation_size, linewidth, aspect_ratio=1.) + + and it returns a tuple of a :class:`Path` instance and a boolean + value. *path* is a :class:`Path` instance along witch the arrow + will be drawn. *mutation_size* and *aspect_ratio* has a same + meaning as in :class:`BoxStyle`. *linewidth* is a line width to be + stroked. This is meant to be used to correct the location of the + head so that it does not overshoot the destination point, but not all + classes support it. """ - # The derived classes are required to be able to be initialized - # w/o arguments, i.e., all its argument (except self) must have - # the default values. - def __init__(self): - super(ArrowTransmuterBase, self).__init__() + _style_list = {} - @staticmethod - def ensure_quadratic_bezier(path): - """ Some ArrowTransmuter class only wokrs with a simple - quaratic bezier curve (created with Arc3Connetion or - Angle3Connector). This static method is to check if the - provided path is a simple quadratic bezier curve and returns - its control points if true. + class _Base(object): """ - segments = list(path.iter_segments()) - assert len(segments) == 2 + Arrow Transmuter Base class - assert segments[0][1] == Path.MOVETO - assert segments[1][1] == Path.CURVE3 + ArrowTransmuterBase and its derivatives are used to make a fancy + arrow around a given path. The __call__ method returns a path + (which will be used to create a PathPatch instance) and a boolean + value indicating the path is open therefore is not fillable. This + class is not an artist and actual drawing of the fancy arrow is + done by the FancyArrowPatch class. - return list(segments[0][0]) + list(segments[1][0]) + """ + # The derived classes are required to be able to be initialized + # w/o arguments, i.e., all its argument (except self) must have + # the default values. - def transmute(self, path, mutation_size, linewidth): + def __init__(self): + super(ArrowStyle.... [truncated message content]