SourceForge logo
SourceForge logo
Menu

matplotlib-checkins — Commit notification. DO NOT POST to this list, just subscribe to it.

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)



Showing results of 271

<< < 1 .. 9 10 11 (Page 11 of 11)
From: <lee...@us...> - 2008年12月02日 22:27:43
Revision: 6479
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6479&view=rev
Author: leejjoon
Date: 2008年12月02日 22:27:38 +0000 (2008年12月02日)
Log Message:
-----------
Fixed a bug in the new legend class that didn't allowed a tuple of coordinate vlaues as loc
Modified Paths:
--------------
 trunk/matplotlib/CHANGELOG
 trunk/matplotlib/lib/matplotlib/legend.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG	2008年12月02日 22:04:41 UTC (rev 6478)
+++ trunk/matplotlib/CHANGELOG	2008年12月02日 22:27:38 UTC (rev 6479)
@@ -1,3 +1,6 @@
+2008年12月02日 Fixed a bug in the new legend class that didn't allowed 
+ a tuple of coordinate vlaues as loc. -JJL
+
 2008年12月02日 Improve checks for external dependencies, using subprocess 
 (instead of deprecated popen*) and distutils (for version
 checking) - DSD
Modified: trunk/matplotlib/lib/matplotlib/legend.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/legend.py	2008年12月02日 22:04:41 UTC (rev 6478)
+++ trunk/matplotlib/lib/matplotlib/legend.py	2008年12月02日 22:27:38 UTC (rev 6479)
@@ -61,6 +61,9 @@
 'upper center' : 9,
 'center' : 10,
 
+ loc can be a tuple of the noramilzed coordinate values with
+ respect its parent.
+ 
 Return value is a sequence of text, line instances that make
 up the legend
 """
@@ -100,7 +103,7 @@
 axespad = None, # deprecated; use borderaxespad
 
 # spacing & pad defined as a fractionof the font-size 
- borderpad = None, # the fractional whitespace inside the legend border
+ borderpad = None, # the 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
@@ -119,11 +122,11 @@
 
 Optional keyword arguments:
 
- ================ =========================================
+ ================ =================================================
 Keyword Description
- ================ =========================================
+ ================ =================================================
 
- loc a location code
+ loc a location code or a tuple of coordinates
 numpoints the number of points in the legend line
 prop the font property
 markerscale the relative size of legend markers vs. original
@@ -284,14 +287,22 @@
 a.set_transform(self.get_transform())
 
 def _findoffset_best(self, width, height, xdescent, ydescent):
- "Heper function to locate the legend"
+ "Heper function to locate the legend at its best position"
 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)
+ "Heper function to locate the legend using the location code"
+
+ if iterable(self._loc) and len(self._loc)==2:
+ # when loc is a tuple of axes(or figure) coordinates.
+ fx, fy = self._loc
+ bbox = self.parent.bbox
+ x, y = bbox.x0 + bbox.width * fx, bbox.y0 + bbox.height * fy
+ else:
+ 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):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6478
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6478&view=rev
Author: dsdale
Date: 2008年12月02日 22:04:41 +0000 (2008年12月02日)
Log Message:
-----------
removed lingering print statement
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py	2008年12月02日 20:09:44 UTC (rev 6477)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py	2008年12月02日 22:04:41 UTC (rev 6478)
@@ -110,7 +110,6 @@
 FigureCanvasBase.enter_notify_event(self, event)
 
 def leaveEvent(self, event):
- print event
 FigureCanvasBase.leave_notify_event(self, event)
 
 def mousePressEvent( self, event ):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6477
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6477&view=rev
Author: mdboom
Date: 2008年12月02日 20:09:44 +0000 (2008年12月02日)
Log Message:
-----------
Round theta ticks to the nearest degree, rather than truncating.
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/projections/polar.py
Modified: trunk/matplotlib/lib/matplotlib/projections/polar.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/projections/polar.py	2008年12月02日 20:08:53 UTC (rev 6476)
+++ trunk/matplotlib/lib/matplotlib/projections/polar.py	2008年12月02日 20:09:44 UTC (rev 6477)
@@ -137,14 +137,14 @@
 def __call__(self, x, pos=None):
 # \u00b0 : degree symbol
 if rcParams['text.usetex'] and not rcParams['text.latex.unicode']:
- return r"$%d^\circ$" % ((x / npy.pi) * 180.0)
+ return r"$%0.0f^\circ$" % ((x / npy.pi) * 180.0)
 else:
 # we use unicode, rather than mathtext with \circ, so
 # that it will work correctly with any arbitrary font
 # (assuming it has a degree sign), whereas 5ドル\circ$
 # will only work correctly with one of the supported
 # math fonts (Computer Modern and STIX)
- return u"%d\u00b0" % ((x / npy.pi) * 180.0)
+ return u"%0.0f\u00b0" % ((x / npy.pi) * 180.0)
 
 class RadialLocator(Locator):
 """
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2008年12月02日 20:08:57
Revision: 6476
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6476&view=rev
Author: mdboom
Date: 2008年12月02日 20:08:53 +0000 (2008年12月02日)
Log Message:
-----------
Replace axes when current one is of the wrong projection type. This lets "subplot(111); polar()" work.
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/figure.py
Modified: trunk/matplotlib/lib/matplotlib/figure.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/figure.py	2008年12月02日 19:51:10 UTC (rev 6475)
+++ trunk/matplotlib/lib/matplotlib/figure.py	2008年12月02日 20:08:53 UTC (rev 6476)
@@ -656,13 +656,8 @@
 %(Axes)s
 """
 
- key = self._make_key(*args, **kwargs)
- if key in self._seen:
- ax = self._seen[key]
- self.sca(ax)
- return ax
+ kwargs = kwargs.copy()
 
-
 if not len(args): return
 
 if isinstance(args[0], SubplotBase):
@@ -680,8 +675,18 @@
 projection = 'polar'
 
 projection_class = get_projection_class(projection)
- a = subplot_class_factory(projection_class)(self, *args, **kwargs)
 
+ key = self._make_key(*args, **kwargs)
+ if key in self._seen:
+ ax = self._seen[key]
+ if isinstance(ax, projection_class):
+ self.sca(ax)
+ return ax
+ else:
+ self.axes.remove(ax)
+ self._axstack.remove(ax)
+
+ a = subplot_class_factory(projection_class)(self, *args, **kwargs)
 self.axes.append(a)
 self._axstack.push(a)
 self.sca(a)
@@ -891,7 +896,20 @@
 %(Axes)s
 """
 ax = self._axstack()
- if ax is not None: return ax
+ if ax is not None:
+ ispolar = kwargs.get('polar', False)
+ projection = kwargs.get('projection', None)
+ if ispolar:
+ if projection is not None and projection != 'polar':
+ raise ValueError(
+ "polar=True, yet projection='%s'. " +
+ "Only one of these arguments should be supplied." %
+ projection)
+ projection = 'polar'
+
+ projection_class = get_projection_class(projection)
+ if isinstance(ax, projection_class):
+ return ax
 return self.add_subplot(111, **kwargs)
 gca.__doc__ = dedent(gca.__doc__) % artist.kwdocd
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2008年12月02日 19:51:12
Revision: 6475
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6475&view=rev
Author: mdboom
Date: 2008年12月02日 19:51:10 +0000 (2008年12月02日)
Log Message:
-----------
suppress gcc-4.3 warnings
Modified Paths:
--------------
 trunk/matplotlib/src/_backend_agg.cpp
 trunk/matplotlib/src/_image.cpp
Modified: trunk/matplotlib/src/_backend_agg.cpp
===================================================================
--- trunk/matplotlib/src/_backend_agg.cpp	2008年12月02日 17:55:15 UTC (rev 6474)
+++ trunk/matplotlib/src/_backend_agg.cpp	2008年12月02日 19:51:10 UTC (rev 6475)
@@ -1216,8 +1216,8 @@
 
 private:
 inline unsigned vertex(unsigned idx, double* x, double* y) {
- size_t m = m_m + ((idx & 0x2) >> 1);
- size_t n = m_n + ((idx+1 & 0x2) >> 1);
+ size_t m = m_m + ((idx & 0x2) >> 1);
+ size_t n = m_n + (((idx+1) & 0x2) >> 1);
 double* pair = (double*)PyArray_GETPTR2(m_coordinates, n, m);
 *x = *pair++;
 *y = *pair;
@@ -1336,11 +1336,15 @@
 throw Py::RuntimeError(e);
 }
 } catch (...) {
- if (free_edgecolors) Py_XDECREF(edgecolors_obj.ptr());
+ if (free_edgecolors) {
+ Py_XDECREF(edgecolors_obj.ptr());
+ }
 throw;
 }
 
- if (free_edgecolors) Py_XDECREF(edgecolors_obj.ptr());
+ if (free_edgecolors) {
+ Py_XDECREF(edgecolors_obj.ptr());
+ }
 
 return Py::Object();
 }
Modified: trunk/matplotlib/src/_image.cpp
===================================================================
--- trunk/matplotlib/src/_image.cpp	2008年12月02日 17:55:15 UTC (rev 6474)
+++ trunk/matplotlib/src/_image.cpp	2008年12月02日 19:51:10 UTC (rev 6475)
@@ -1327,20 +1327,27 @@
 void _pcolor_cleanup(PyArrayObject* x, PyArrayObject* y, PyArrayObject *d,
 unsigned int * rowstarts ,unsigned int*colstarts ,
 float *acols , float *arows) {
- if (x)
+ if (x) {
 Py_XDECREF(x);
- if (y)
+ }
+ if (y) {
 Py_XDECREF(y);
- if(d)
+ }
+ if(d) {
 Py_XDECREF(d);
- if(rowstarts)
+ }
+ if(rowstarts) {
 PyMem_Free(rowstarts);
- if(colstarts)
+ }
+ if(colstarts) {
 PyMem_Free(colstarts);
- if(acols)
+ }
+ if(acols) {
 PyMem_Free(acols);
- if(arows)
+ }
+ if(arows) {
 PyMem_Free(arows);
+ }
 return;
 }
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <ry...@us...> - 2008年12月02日 17:55:17
Revision: 6474
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6474&view=rev
Author: ryanmay
Date: 2008年12月02日 17:55:15 +0000 (2008年12月02日)
Log Message:
-----------
Begin and end docstrings on newlines.
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/quiver.py
Modified: trunk/matplotlib/lib/matplotlib/quiver.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/quiver.py	2008年12月02日 17:54:44 UTC (rev 6473)
+++ trunk/matplotlib/lib/matplotlib/quiver.py	2008年12月02日 17:55:15 UTC (rev 6474)
@@ -745,7 +745,8 @@
 %s""" % _barbs_doc
 
 def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50):
- '''Find how many of each of the tail pieces is necessary. Flag
+ '''
+ Find how many of each of the tail pieces is necessary. Flag
 specifies the increment for a flag, barb for a full barb, and half for
 half a barb. Mag should be the magnitude of a vector (ie. >= 0).
 
@@ -777,7 +778,8 @@
 
 def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length,
 pivot, sizes, fill_empty, flip):
- '''This function actually creates the wind barbs. *u* and *v*
+ '''
+ This function actually creates the wind barbs. *u* and *v*
 are components of the vector in the *x* and *y* directions,
 respectively.
 
@@ -817,7 +819,8 @@
 
 This function returns list of arrays of vertices, defining a polygon for
 each of the wind barbs. These polygons have been rotated to properly
- align with the vector direction.'''
+ align with the vector direction.
+ '''
 
 #These control the spacing and size of barb elements relative to the
 #length of the shaft
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2008年12月02日 17:54:50
Revision: 6473
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6473&view=rev
Author: mdboom
Date: 2008年12月02日 17:54:44 +0000 (2008年12月02日)
Log Message:
-----------
Fix axhline etc. with non-linear scales.
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/transforms.py
Modified: trunk/matplotlib/lib/matplotlib/transforms.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/transforms.py	2008年12月02日 17:53:45 UTC (rev 6472)
+++ trunk/matplotlib/lib/matplotlib/transforms.py	2008年12月02日 17:54:44 UTC (rev 6473)
@@ -1237,6 +1237,7 @@
 of the same dimensions.
 """
 pass_through = True
+ is_affine = False
 
 def __init__(self, child):
 """
@@ -1288,10 +1289,6 @@
 self.invalidate()
 self._invalid = 0
 
- def _get_is_affine(self):
- return self._child.is_affine
- is_affine = property(_get_is_affine)
-
 def _get_is_separable(self):
 return self._child.is_separable
 is_separable = property(_get_is_separable)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <ry...@us...> - 2008年12月02日 17:53:48
Revision: 6472
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6472&view=rev
Author: ryanmay
Date: 2008年12月02日 17:53:45 +0000 (2008年12月02日)
Log Message:
-----------
Add information to docstring for pyplot.subplot()
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/pyplot.py
Modified: trunk/matplotlib/lib/matplotlib/pyplot.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/pyplot.py	2008年12月02日 17:11:07 UTC (rev 6471)
+++ trunk/matplotlib/lib/matplotlib/pyplot.py	2008年12月02日 17:53:45 UTC (rev 6472)
@@ -588,11 +588,6 @@
 
 ``subplot(111)`` is the default axis.
 
- The background color of the subplot can be specified via keyword
- argument *axisbg*, which takes a color string as value, as in::
-
- subplot(211, axisbg='y')
-
 New subplots that overlap old will delete the old axes. If you do
 not want this behavior, use
 :meth:`matplotlib.figure.Figure.add_subplot` or the
@@ -602,11 +597,35 @@
 plot([1,2,3]) # implicitly creates subplot(111)
 subplot(211) # overlaps, subplot(111) is killed
 plot(rand(12), rand(12))
+ subplot(212, axisbg='y') # creates 2nd subplot with yellow background
 
+ Keyword arguments:
+
+ *axisbg*:
+ The background color of the subplot, which can be any valid
+ color specifier. See :module:`matplotlib.colors` for more
+ information.
+
+ *polar*:
+ A boolean flag indicating whether the subplot plot should be
+ a polar projection. Defaults to False.
+
+ *projection*:
+ A string giving the name of a custom projection to be used
+ for the subplot. This projection must have been previously
+ registered. See :func:`matplotlib.projections.register_projection`
+
 .. seealso::
 :func:`~matplotlib.pyplot.axes`:
 For additional information on :func:`axes` and
 :func:`subplot` keyword arguments.
+
+ :file:`examples/pylab_examples/polar_scatter.py`
+
+ **Example:**
+
+ .. plot:: mpl_examples/pylab_examples/subplot_demo.py
+
 """
 
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <ds...@us...> - 2008年12月02日 17:12:17
Revision: 6471
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6471&view=rev
Author: dsdale
Date: 2008年12月02日 17:11:07 +0000 (2008年12月02日)
Log Message:
-----------
improved checks for external dependencies
Modified Paths:
--------------
 trunk/matplotlib/CHANGELOG
 trunk/matplotlib/lib/matplotlib/__init__.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG	2008年12月02日 17:07:57 UTC (rev 6470)
+++ trunk/matplotlib/CHANGELOG	2008年12月02日 17:11:07 UTC (rev 6471)
@@ -1,3 +1,7 @@
+2008年12月02日 Improve checks for external dependencies, using subprocess 
+ (instead of deprecated popen*) and distutils (for version
+ checking) - DSD
+
 2008年11月30日 Reimplementaion of the legend which supports baseline alignement,
 	 multi-column, and expand mode. - JJL
 
Modified: trunk/matplotlib/lib/matplotlib/__init__.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/__init__.py	2008年12月02日 17:07:57 UTC (rev 6470)
+++ trunk/matplotlib/lib/matplotlib/__init__.py	2008年12月02日 17:11:07 UTC (rev 6471)
@@ -93,8 +93,9 @@
 __revision__ = '$Revision$'
 __date__ = '$Date$'
 
-import os, re, shutil, sys, warnings
+import os, re, shutil, subprocess, sys, warnings
 import distutils.sysconfig
+import distutils.version
 
 
 NEWCONFIG = False
@@ -256,10 +257,10 @@
 
 def checkdep_dvipng():
 try:
- stdin, stdout = os.popen4('dvipng -version')
- line = stdout.readlines()[1]
+ s = subprocess.Popen(['dvipng','-version'], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ line = s.stdout.readlines()[1]
 v = line.split()[-1]
- float(v)
 return v
 except (IndexError, ValueError):
 return None
@@ -267,47 +268,45 @@
 def checkdep_ghostscript():
 try:
 if sys.platform == 'win32':
- command = 'gswin32c --version'
+ command_args = ['gswin32c', '--version']
 else:
- command = 'gs --version'
- stdin, stdout = os.popen4(command)
- v = stdout.read()[:-1]
- vtest = '.'.join(v.split('.')[:2]) # deal with version numbers like '7.07.1'
- float(vtest)
- return vtest
+ command_args = ['gs', '--version']
+ s = subprocess.Popen(command_args, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ v = s.stdout.read()[:-1]
+ return v
 except (IndexError, ValueError):
 return None
 
 def checkdep_tex():
 try:
- stdin, stdout = os.popen4('tex -version')
- line = stdout.readlines()[0]
+ s = subprocess.Popen(['tex','-version'], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ line = s.stdout.readlines()[0]
 pattern = '3\.1\d+'
 match = re.search(pattern, line)
 v = match.group(0)
- float(v)
 return v
 except (IndexError, ValueError, AttributeError):
 return None
 
 def checkdep_pdftops():
 try:
- stdin, stdout = os.popen4('pdftops -v')
- for line in stdout.readlines():
+ s = subprocess.Popen(['pdftops','-v'], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ for line in s.stderr:
 if 'version' in line:
 v = line.split()[-1]
- float(v)
 return v
 except (IndexError, ValueError, UnboundLocalError):
 return None
 
 def compare_versions(a, b):
- "return True if a is greater than b"
+ "return True if a is greater than or equal to b"
 if a:
- a = [int(i) for i in a.split('.')]
- b = [int(i) for i in b.split('.')]
- if a[0]>b[0]: return True
- elif (a[0]==b[0]) and (a[1]>=b[1]): return True
+ a = distutils.version.LooseVersion(a)
+ b = distutils.version.LooseVersion(b)
+ if a>=b: return True
 else: return False
 else: return False
 
@@ -330,8 +329,13 @@
 
 if s == 'xpdf':
 pdftops_req = '3.0'
+ pdftops_req_alt = '0.9' # poppler version numbers, ugh
 pdftops_v = checkdep_pdftops()
- if compare_versions(pdftops_v, pdftops_req): pass
+ if compare_versions(pdftops_v, pdftops_req):
+ pass
+ elif compare_versions(pdftops_v, pdftops_req_alt) and not \
+ compare_versions(pdftops_v, '1.0'):
+ pass
 else:
 flag = False
 warnings.warn(('matplotlibrc ps.usedistiller can not be set to '
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <ds...@us...> - 2008年12月02日 17:09:35
Revision: 6470
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6470&view=rev
Author: dsdale
Date: 2008年12月02日 17:07:57 +0000 (2008年12月02日)
Log Message:
-----------
Pass qt* enter and leave events to FigureCanvasBase
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/backends/backend_qt.py
 trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_qt.py	2008年12月02日 15:52:39 UTC (rev 6469)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_qt.py	2008年12月02日 17:07:57 UTC (rev 6470)
@@ -102,6 +102,12 @@
 w,h = self.get_width_height()
 self.resize( w, h )
 
+ def enterEvent(self, event):
+ FigureCanvasBase.enter_notify_event(self, event)
+
+ def leaveEvent(self, event):
+ FigureCanvasBase.leave_notify_event(self, event)
+
 def mousePressEvent( self, event ):
 x = event.pos().x()
 # flipy so y=0 is bottom of canvas
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py	2008年12月02日 15:52:39 UTC (rev 6469)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py	2008年12月02日 17:07:57 UTC (rev 6470)
@@ -105,8 +105,12 @@
 def __timerEvent(self, event):
 # hide until we can test and fix
 self.mpl_idle_event(event)
- 
+
+ def enterEvent(self, event):
+ FigureCanvasBase.enter_notify_event(self, event)
+
 def leaveEvent(self, event):
+ print event
 FigureCanvasBase.leave_notify_event(self, event)
 
 def mousePressEvent( self, event ):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2008年12月02日 15:52:42
Revision: 6469
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6469&view=rev
Author: mdboom
Date: 2008年12月02日 15:52:39 +0000 (2008年12月02日)
Log Message:
-----------
Minor formatting changes.
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/transforms.py
Modified: trunk/matplotlib/lib/matplotlib/transforms.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/transforms.py	2008年12月02日 15:40:44 UTC (rev 6468)
+++ trunk/matplotlib/lib/matplotlib/transforms.py	2008年12月02日 15:52:39 UTC (rev 6469)
@@ -313,7 +313,8 @@
 return [min(self.get_points()[:, 0]),
 min(self.get_points()[:, 1])]
 min = property(_get_min, None, None, """
- (property) :attr:`min` is the bottom-left corner of the bounding box.""")
+ (property) :attr:`min` is the bottom-left corner of the bounding
+ box.""")
 
 def _get_max(self):
 return [max(self.get_points()[:, 0]),
@@ -324,41 +325,44 @@
 def _get_intervalx(self):
 return self.get_points()[:, 0]
 intervalx = property(_get_intervalx, None, None, """
- (property) :attr:`intervalx` is the pair of *x* coordinates that define the
- bounding box. It is not guaranteed to be sorted from left to right.""")
+ (property) :attr:`intervalx` is the pair of *x* coordinates that define
+ the bounding box. It is not guaranteed to be sorted from left to
+ right.""")
 
 def _get_intervaly(self):
 return self.get_points()[:, 1]
 intervaly = property(_get_intervaly, None, None, """
- (property) :attr:`intervaly` is the pair of *y* coordinates that define the
- bounding box. It is not guaranteed to be sorted from bottom to top.""")
+ (property) :attr:`intervaly` is the pair of *y* coordinates that define
+ the bounding box. It is not guaranteed to be sorted from bottom to
+ top.""")
 
 def _get_width(self):
 points = self.get_points()
 return points[1, 0] - points[0, 0]
 width = property(_get_width, None, None, """
- (property) The width of the bounding box. It may be negative if :attr:`x1` <
- :attr:`x0`.""")
+ (property) The width of the bounding box. It may be negative if
+ :attr:`x1` < :attr:`x0`.""")
 
 def _get_height(self):
 points = self.get_points()
 return points[1, 1] - points[0, 1]
 height = property(_get_height, None, None, """
- (property) The height of the bounding box. It may be negative if :attr:`y1` <
- :attr:`y0`.""")
+ (property) The height of the bounding box. It may be negative if
+ :attr:`y1` < :attr:`y0`.""")
 
 def _get_size(self):
 points = self.get_points()
 return points[1] - points[0]
 size = property(_get_size, None, None, """
- (property) The width and height of the bounding box. May be negative, in the same
- way as :attr:`width` and :attr:`height`.""")
+ (property) The width and height of the bounding box. May be negative,
+ in the same way as :attr:`width` and :attr:`height`.""")
 
 def _get_bounds(self):
 x0, y0, x1, y1 = self.get_points().flatten()
 return (x0, y0, x1 - x0, y1 - y0)
 bounds = property(_get_bounds, None, None, """
- (property) Returns (:attr:`x0`, :attr:`y0`, :attr:`width`, :attr:`height`).""")
+ (property) Returns (:attr:`x0`, :attr:`y0`, :attr:`width`,
+ :attr:`height`).""")
 
 def _get_extents(self):
 return self.get_points().flatten().copy()
@@ -788,7 +792,8 @@
 - when False, include the existing bounds of the :class:`Bbox`.
 - when None, use the last value passed to :meth:`ignore`.
 """
- warnings.warn("update_from_data requires a memory copy -- please replace with update_from_data_xy")
+ warnings.warn(
+ "update_from_data requires a memory copy -- please replace with update_from_data_xy")
 xy = np.hstack((x.reshape((len(x), 1)), y.reshape((len(y), 1))))
 return self.update_from_data_xy(xy, ignore)
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <jd...@us...> - 2008年12月02日 15:40:49
Revision: 6468
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6468&view=rev
Author: jdh2358
Date: 2008年12月02日 15:40:44 +0000 (2008年12月02日)
Log Message:
-----------
added gregor's wx enter/leave patch - fixed figure_enter problem
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/backend_bases.py
 trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
 trunk/matplotlib/lib/matplotlib/backends/backend_wx.py
Modified: trunk/matplotlib/lib/matplotlib/backend_bases.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backend_bases.py	2008年12月02日 15:32:07 UTC (rev 6467)
+++ trunk/matplotlib/lib/matplotlib/backend_bases.py	2008年12月02日 15:40:44 UTC (rev 6468)
@@ -791,9 +791,6 @@
 'process the figure/axes enter leave events'
 if LocationEvent.lastevent is not None:
 last = LocationEvent.lastevent
- if last.canvas!=self.canvas:
- # process figure enter/leave event
- self.canvas.callbacks.process('figure_enter_event', self)
 if last.inaxes!=self.inaxes:
 # process axes enter/leave events
 if last.inaxes is not None:
@@ -803,8 +800,6 @@
 
 else:
 # process a figure enter event
- self.canvas.callbacks.process('figure_enter_event', self)
- # process an axes enter event if we are over an axes
 if self.inaxes is not None:
 self.canvas.callbacks.process('axes_enter_event', self)
 
@@ -952,8 +947,6 @@
 'pick_event',
 'idle_event',
 'figure_enter_event',
- # todo: we only process this when a mouse enters a different
- # figure -- we need to connect to the GUI leavel event
 'figure_leave_event',
 'axes_enter_event',
 'axes_leave_event'
@@ -1216,7 +1209,18 @@
 self.callbacks.process('figure_leave_event', LocationEvent.lastevent)
 LocationEvent.lastevent = None
 
+ def enter_notify_event(self, guiEvent=None):
+ """
+ Backend derived classes should call this function when entering
+ canvas
 
+ *guiEvent*
+ the native UI event that generated the mpl event
+
+ """
+ event = Event('figure_enter_event', self, guiEvent)
+ self.callbacks.process('figure_enter_event', event)
+
 def idle_event(self, guiEvent=None):
 'call when GUI is idle'
 s = 'idle_event'
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py	2008年12月02日 15:32:07 UTC (rev 6467)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py	2008年12月02日 15:40:44 UTC (rev 6468)
@@ -147,6 +147,7 @@
 gdk.EXPOSURE_MASK |
 gdk.KEY_PRESS_MASK |
 gdk.KEY_RELEASE_MASK |
+ gdk.ENTER_NOTIFY_MASK |
 gdk.LEAVE_NOTIFY_MASK |
 gdk.POINTER_MOTION_MASK |
 gdk.POINTER_MOTION_HINT_MASK)
@@ -171,6 +172,7 @@
 self.connect('key_release_event', self.key_release_event)
 self.connect('motion_notify_event', self.motion_notify_event)
 self.connect('leave_notify_event', self.leave_notify_event)
+ self.connect('enter_notify_event', self.enter_notify_event)
 
 self.set_events(self.__class__.event_mask)
 
@@ -243,6 +245,9 @@
 def leave_notify_event(self, widget, event):
 FigureCanvasBase.leave_notify_event(self, event)
 
+ def enter_notify_event(self, widget, event):
+ FigureCanvasBase.enter_notify_event(self, event)
+
 def _get_key(self, event):
 if event.keyval in self.keyvald:
 key = self.keyvald[event.keyval]
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_wx.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_wx.py	2008年12月02日 15:32:07 UTC (rev 6467)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_wx.py	2008年12月02日 15:40:44 UTC (rev 6468)
@@ -1263,10 +1263,10 @@
 FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=evt)
 
 def _onLeave(self, evt):
- """Mouse has left the window; fake a motion event."""
+ """Mouse has left the window."""
 
 evt.Skip()
- FigureCanvasBase.motion_notify_event(self, -1, -1, guiEvent=evt)
+ FigureCanvasBase.leave_notify_event(self, guiEvent = evt)
 
 
 ########################################################################
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 6467
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6467&view=rev
Author: mdboom
Date: 2008年12月02日 15:32:07 +0000 (2008年12月02日)
Log Message:
-----------
Be more conservative about chunking large paths -- filled paths shouldn't be chunked -- or at least would require a more complex algorithm.
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py	2008年12月02日 15:27:23 UTC (rev 6466)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py	2008年12月02日 15:32:07 UTC (rev 6467)
@@ -79,7 +79,7 @@
 def draw_path(self, gc, path, transform, rgbFace=None):
 nmax = rcParams['agg.path.chunksize'] # here at least for testing
 npts = path.vertices.shape[0]
- if nmax > 100 and npts > nmax and path.should_simplify:
+ if nmax > 100 and npts > nmax and path.should_simplify and rgbFace is None:
 nch = npy.ceil(npts/float(nmax))
 chsize = int(npy.ceil(npts/nch))
 i0 = npy.arange(0, npts, chsize)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2008年12月02日 15:27:28
Revision: 6466
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6466&view=rev
Author: mdboom
Date: 2008年12月02日 15:27:23 +0000 (2008年12月02日)
Log Message:
-----------
Remove one-pixel offset in clipbox code.
Modified Paths:
--------------
 trunk/matplotlib/src/_backend_agg.cpp
Modified: trunk/matplotlib/src/_backend_agg.cpp
===================================================================
--- trunk/matplotlib/src/_backend_agg.cpp	2008年12月01日 19:35:39 UTC (rev 6465)
+++ trunk/matplotlib/src/_backend_agg.cpp	2008年12月02日 15:27:23 UTC (rev 6466)
@@ -312,8 +312,8 @@
 
 double l, b, r, t;
 if (py_convert_bbox(cliprect.ptr(), l, b, r, t)) {
- rasterizer.clip_box(int(mpl_round(l)) + 1, height - int(mpl_round(b)),
- int(mpl_round(r)), height - int(mpl_round(t)));
+ rasterizer.clip_box(int(mpl_round(l)), height - int(mpl_round(b)),
+ int(mpl_round(r)), height - int(mpl_round(t)));
 }
 
 _VERBOSE("RendererAgg::set_clipbox done");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2008年12月01日 19:35:43
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.
From: <ry...@us...> - 2008年12月01日 19:07:12
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.
From: <md...@us...> - 2008年12月01日 15:23:52
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.
From: <jd...@us...> - 2008年12月01日 14:51:40
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.
From: <mme...@us...> - 2008年12月01日 14:07:05
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.
From: <mme...@us...> - 2008年12月01日 10:10:46
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.

Showing results of 271

<< < 1 .. 9 10 11 (Page 11 of 11)
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.
Thanks for helping keep SourceForge clean.
X





Briefly describe the problem (required):
Upload screenshot of ad (required):
Select a file, or drag & drop file here.
Screenshot instructions:

Click URL instructions:
Right-click on the ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)

More information about our ad policies

Ad destination/click URL:

AltStyle によって変換されたページ (->オリジナル) /