|
From: <jd...@us...> - 2008-12-18 19:40:36
|
Revision: 6677
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6677&view=rev
Author: jdh2358
Date: 2008-12-18 19:40:26 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
Merged revisions 6675-6676 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6675 | jdh2358 | 2008-12-18 11:19:26 -0800 (Thu, 18 Dec 2008) | 1 line
fixed a small_docs bug when no args present
........
r6676 | jdh2358 | 2008-12-18 11:28:46 -0800 (Thu, 18 Dec 2008) | 1 line
pushed out new 98.5.2 tarball with smalldocs fix
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/doc/make.py
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6673
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6676
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-18 19:28:46 UTC (rev 6676)
+++ trunk/matplotlib/CHANGELOG 2008-12-18 19:40:26 UTC (rev 6677)
@@ -1,7 +1,8 @@
2008-12-18 add new arrow style, a line + filled triangles. -JJL
==================================================================
-2008-12-18 Released 0.98.5.2 from v0_98_5_maint at r6667
+2008-12-18 Re-Released 0.98.5.2 from v0_98_5_maint at r6675
+ Released 0.98.5.2 from v0_98_5_maint at r6667
2008-12-18 Removed configobj, experimental traits and doc/mpl_data link - JDH
Modified: trunk/matplotlib/doc/make.py
===================================================================
--- trunk/matplotlib/doc/make.py 2008-12-18 19:28:46 UTC (rev 6676)
+++ trunk/matplotlib/doc/make.py 2008-12-18 19:40:26 UTC (rev 6677)
@@ -105,4 +105,5 @@
arg, funcd.keys()))
func()
else:
+ small_docs = False
all()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-19 12:40:16
|
Revision: 6682
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6682&view=rev
Author: jdh2358
Date: 2008-12-19 12:40:09 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
Merged revisions 6679-6680 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6679 | jdh2358 | 2008-12-19 06:29:49 -0600 (Fri, 19 Dec 2008) | 1 line
added macosx.m to manifest
........
r6680 | jdh2358 | 2008-12-19 06:30:33 -0600 (Fri, 19 Dec 2008) | 1 line
added macosx.m to manifest; released 98.5.2 tarball
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/MANIFEST.in
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6676
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6681
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-19 12:38:33 UTC (rev 6681)
+++ trunk/matplotlib/CHANGELOG 2008-12-19 12:40:09 UTC (rev 6682)
@@ -1,7 +1,7 @@
2008-12-18 add new arrow style, a line + filled triangles. -JJL
==================================================================
-2008-12-18 Re-Released 0.98.5.2 from v0_98_5_maint at r6675
+2008-12-18 Re-Released 0.98.5.2 from v0_98_5_maint at r6679
Released 0.98.5.2 from v0_98_5_maint at r6667
2008-12-18 Removed configobj, experimental traits and doc/mpl_data link - JDH
Modified: trunk/matplotlib/MANIFEST.in
===================================================================
--- trunk/matplotlib/MANIFEST.in 2008-12-19 12:38:33 UTC (rev 6681)
+++ trunk/matplotlib/MANIFEST.in 2008-12-19 12:40:09 UTC (rev 6682)
@@ -16,7 +16,7 @@
recursive-include license LICENSE*
recursive-include examples *
recursive-include doc *
-recursive-include src *.cpp *.c *.h
+recursive-include src *.cpp *.c *.h *.m
recursive-include CXX *.cxx *.hxx *.c *.h
recursive-include agg24 *
recursive-include lib *
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <lee...@us...> - 2008-12-19 22:03:12
|
Revision: 6686
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6686&view=rev
Author: leejjoon
Date: 2008-12-19 21:41:11 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
Merged revisions 6685 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6685 | leejjoon | 2008-12-19 16:24:32 -0500 (Fri, 19 Dec 2008) | 1 line
update legend-related document
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/doc/api/api_changes.rst
trunk/matplotlib/lib/matplotlib/__init__.py
trunk/matplotlib/lib/matplotlib/axes.py
trunk/matplotlib/lib/matplotlib/legend.py
trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template
trunk/matplotlib/lib/matplotlib/rcsetup.py
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6681
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6685
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/CHANGELOG 2008-12-19 21:41:11 UTC (rev 6686)
@@ -1,3 +1,7 @@
+2008-12-19 Update Axes.legend documnetation. /api/api_changes.rst is also
+ updated to describe chages in keyword parameters.
+ Issue a warning if old keyword parameters are used. - JJL
+
2008-12-18 add new arrow style, a line + filled triangles. -JJL
==================================================================
Modified: trunk/matplotlib/doc/api/api_changes.rst
===================================================================
--- trunk/matplotlib/doc/api/api_changes.rst 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/doc/api/api_changes.rst 2008-12-19 21:41:11 UTC (rev 6686)
@@ -15,6 +15,22 @@
Changes for 0.98.x
==================
+* Following keyword parameters for :class:`matplotlib.label.Label` are now
+ deprecated and new set of parameters are introduced. The new parameters
+ are given as a fraction of the font-size. Also, *scatteryoffsets*,
+ *fancybox* and *columnspacing* are added as keyword parameters.
+
+ ================ ================
+ Deprecated New
+ ================ ================
+ pad borderpad
+ labelsep labelspacing
+ handlelen handlelength
+ handlestextsep handletextpad
+ axespad borderaxespad
+ ================ ================
+
+
* Removed the configobj and experiemtnal traits rc support
* Modified :func:`matplotlib.mlab.psd`, :func:`matplotlib.mlab.csd`,
Modified: trunk/matplotlib/lib/matplotlib/__init__.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/__init__.py 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/__init__.py 2008-12-19 21:41:11 UTC (rev 6686)
@@ -582,7 +582,15 @@
'tick.size' : 'tick.major.size',
}
+_deprecated_ignore_map = {
+ 'legend.pad' : 'legend.borderpad',
+ 'legend.labelsep' : 'legend.labelspacing',
+ 'legend.handlelen' : 'legend.handlelength',
+ 'legend.handletextsep' : 'legend.handletextpad',
+ 'legend.axespad' : 'legend.borderaxespad',
+ }
+
class RcParams(dict):
"""
@@ -602,6 +610,10 @@
warnings.warn('%s is deprecated in matplotlibrc. Use %s \
instead.'% (key, alt))
key = alt
+ elif key in _deprecated_ignore_map:
+ alt = _deprecated_ignore_map[key]
+ warnings.warn('%s is deprecated. Use %s instead.'% (key, alt))
+ return
cval = self.validate[key](val)
dict.__setitem__(self, key, cval)
except KeyError:
@@ -665,6 +677,9 @@
except Exception, msg:
warnings.warn('Bad val "%s" on line #%d\n\t"%s"\n\tin file \
"%s"\n\t%s' % (val, cnt, line, fname, msg))
+ elif key in _deprecated_ignore_map:
+ warnings.warn('%s is deprecated. Update your matplotlibrc to use %s instead.'% (key, _deprecated_ignore_map[key]))
+
else:
print >> sys.stderr, """
Bad key "%s" on line %d in
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2008-12-19 21:41:11 UTC (rev 6686)
@@ -3740,10 +3740,6 @@
A :class:`matplotlib.font_manager.FontProperties`
instance, or *None* to use rc settings.
- *pad*: [ None | scalar ]
- The fractional whitespace inside the legend border, between 0 and 1.
- If *None*, use rc settings.
-
*markerscale*: [ None | scalar ]
The relative size of legend markers vs. original. If *None*, use rc
settings.
@@ -3751,21 +3747,21 @@
*shadow*: [ None | False | True ]
If *True*, draw a shadow behind legend. If *None*, use rc settings.
- *labelsep*: [ None | scalar ]
- The vertical space between the legend entries. If *None*, use rc
- settings.
+ Padding and spacing between various elements use following keywords
+ parameters. The dimensions of these values are given as a fraction
+ of the fontsize. Values from rcParams will be used if None.
- *handlelen*: [ None | scalar ]
- The length of the legend lines. If *None*, use rc settings.
+ ================ ==================================================================
+ Keyword Description
+ ================ ==================================================================
+ 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
+ ================ ==================================================================
- *handletextsep*: [ None | scalar ]
- The space between the legend line and legend text. If *None*, use rc
- settings.
-
- *axespad*: [ None | scalar ]
- The border between the axes and legend edge. If *None*, use rc
- settings.
-
**Example:**
.. plot:: mpl_examples/api/legend_demo.py
Modified: trunk/matplotlib/lib/matplotlib/legend.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/legend.py 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/legend.py 2008-12-19 21:41:11 UTC (rev 6686)
@@ -98,7 +98,7 @@
handletextsep = None, # deprecated; use handletextpad
axespad = None, # deprecated; use borderaxespad
- # spacing & pad defined as a fractionof the font-size
+ # spacing & pad defined as a fraction of the font-size
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
Modified: trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template
===================================================================
--- trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template 2008-12-19 21:41:11 UTC (rev 6686)
@@ -233,19 +233,11 @@
origin = 'upper'
[legend]
- # a float
- axespad = 0.02
# a float or 'xx-small' or 'x-small' or 'small' or 'medium' or 'large' or
# 'x-large' or 'xx-large'
fontsize = 'medium'
- # a float
- handlelen = 0.050000000000000003
- # a float
- handletextsep = 0.02
# a boolean
isaxes = True
- # a float
- labelsep = 0.01
# 'best' or 'upper right' or 'upper left' or 'lower left' or 'lower right'
# or 'right' or 'center left' or 'center right' or 'lower center' or
# 'upper center' or 'center'
@@ -254,11 +246,22 @@
markerscale = 1.0
# an integer
numpoints = 3
- # a float
- pad = 0.20000000000000001
# a boolean
shadow = False
+ # float
+ borderpad = 0.4
+ # float
+ labelspacing = 0.5
+ # float
+ handlelength = 2.
+ # float
+ handletextpad = 0.8
+ # float
+ borderaxespad = 0.5
+ # float
+ columnspacing = 2.
+
[lines]
# a boolean
antialiased = True
Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-12-19 21:41:11 UTC (rev 6686)
@@ -432,18 +432,12 @@
'legend.isaxes' : [True,validate_bool], # this option is internally ignored - it never served any useful purpose
'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.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
- '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.02, validate_float], # the border between the axes and legend edge
'legend.shadow' : [False, validate_bool],
+ # the following dimensions are in fraction of the font size
+ 'legend.borderpad' : [0.4, validate_float], # units are fontsize
'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
@@ -453,11 +447,6 @@
'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],
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <lee...@us...> - 2008-12-19 22:48:15
|
Revision: 6687
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6687&view=rev
Author: leejjoon
Date: 2008-12-19 22:48:11 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
axes_locator in the Axes class
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/axes.py
Added Paths:
-----------
trunk/matplotlib/examples/pylab_examples/axes_divider.py
trunk/matplotlib/examples/pylab_examples/axes_grid.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-19 21:41:11 UTC (rev 6686)
+++ trunk/matplotlib/CHANGELOG 2008-12-19 22:48:11 UTC (rev 6687)
@@ -1,3 +1,6 @@
+2008-12-19 Add axes_locator attribute in Axes. Two examples are added.
+ - JJL
+
2008-12-19 Update Axes.legend documnetation. /api/api_changes.rst is also
updated to describe chages in keyword parameters.
Issue a warning if old keyword parameters are used. - JJL
Added: trunk/matplotlib/examples/pylab_examples/axes_divider.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/axes_divider.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/axes_divider.py 2008-12-19 22:48:11 UTC (rev 6687)
@@ -0,0 +1,638 @@
+
+import matplotlib.axes as maxes
+import matplotlib.transforms as mtransforms
+
+import matplotlib.cbook as cbook
+
+import new
+
+
+class Size(object):
+
+ @classmethod
+ def from_any(self, size, fraction_ref=None):
+ if cbook.is_numlike(size):
+ return Size.Fixed(size)
+ elif cbook.is_string_like(size):
+ if size[-1] == "%":
+ return Size.Fraction(fraction_ref, float(size[:-1])/100.)
+
+ raise ValueError("")
+
+
+
+ class _Base(object):
+ pass
+
+ class Fixed(_Base):
+ def __init__(self, fixed_size):
+ self._fixed_size = fixed_size
+
+ def get_size(self, renderer):
+ rel_size = 0.
+ abs_size = self._fixed_size
+ return rel_size, abs_size
+
+ class Scalable(_Base):
+ def __init__(self, scalable_size):
+ self._scalable_size = scalable_size
+
+ def get_size(self, renderer):
+ rel_size = self._scalable_size
+ abs_size = 0.
+ return rel_size, abs_size
+
+
+ class AxesX(_Base):
+ def __init__(self, axes, aspect=1.):
+ self._axes = axes
+ self._aspect = aspect
+
+ def get_size(self, renderer):
+ l1, l2 = self._axes.get_xlim()
+ rel_size = abs(l2-l1)*self._aspect
+ abs_size = 0.
+ return rel_size, abs_size
+
+ class AxesY(_Base):
+ def __init__(self, axes, aspect=1.):
+ self._axes = axes
+ self._aspect = aspect
+
+ def get_size(self, renderer):
+ l1, l2 = self._axes.get_ylim()
+ rel_size = abs(l2-l1)*self._aspect
+ abs_size = 0.
+ return rel_size, abs_size
+
+
+ class MaxExtent(_Base):
+ def __init__(self, artist_list, w_or_h):
+ self._artist_list = artist_list
+
+ if w_or_h not in ["width", "height"]:
+ raise ValueError()
+
+ self._w_or_h = w_or_h
+
+ def add_artist(self, a):
+ self._artist_list.append(a)
+
+ def get_size(self, renderer):
+ rel_size = 0.
+ w_list, h_list = [], []
+ for a in self._artist_list:
+ bb = a.get_window_extent(renderer)
+ w_list.append(bb.width)
+ h_list.append(bb.height)
+ dpi = a.get_figure().get_dpi()
+ if self._w_or_h == "width":
+ abs_size = max(w_list)/dpi
+ elif self._w_or_h == "height":
+ abs_size = max(h_list)/dpi
+
+ return rel_size, abs_size
+
+ class Fraction(_Base):
+ def __init__(self, size, fraction):
+ self._size = size
+ self._fraction = fraction
+
+ def get_size(self, renderer):
+ r, a = self._size.get_size(renderer)
+ rel_size = r*self._fraction
+ abs_size = a*self._fraction
+ return rel_size, abs_size
+
+ class Padded(_Base):
+ def __init__(self, size, pad):
+ self._size = size
+ self._pad = pad
+
+ def get_size(self, renderer):
+ r, a = self._size.get_size(renderer)
+ rel_size = r
+ abs_size = a + self._pad
+ return rel_size, abs_size
+
+
+
+class AxesLocator(object):
+ def __init__(self, axes_divider, nx, ny, nx1=None, ny1=None):
+
+ self._axes_divider = axes_divider
+
+ _xrefindex = axes_divider._xrefindex
+ _yrefindex = axes_divider._yrefindex
+
+ self._nx, self._ny = nx - _xrefindex, ny - _yrefindex
+
+ if nx1 is None:
+ nx1 = nx+1
+ if ny1 is None:
+ ny1 = ny+1
+
+ self._nx1 = nx1 - _xrefindex
+ self._ny1 = ny1 - _yrefindex
+
+
+ def __call__(self, axes, renderer):
+
+ _xrefindex = self._axes_divider._xrefindex
+ _yrefindex = self._axes_divider._yrefindex
+
+ return self._axes_divider.locate(self._nx + _xrefindex, self._ny + _yrefindex,
+ self._nx1 + _xrefindex, self._ny1 + _yrefindex,
+ renderer)
+
+
+class Divider(object):
+
+ def __init__(self, fig, pos, horizontal, vertical, aspect=None, anchor="C"):
+ self._fig = fig
+ self._pos = pos
+ self._horizontal = horizontal
+ self._vertical = vertical
+ self._anchor = anchor
+ self._aspect = aspect
+ self._xrefindex = 0
+ self._yrefindex = 0
+
+
+ @staticmethod
+ def _calc_k(l, total_size, renderer):
+
+ rs_sum, as_sum = 0., 0.
+
+ for s in l:
+ rs, as = s.get_size(renderer)
+ rs_sum += rs
+ as_sum += as
+
+ k = (total_size - as_sum) / rs_sum
+ return k
+
+
+ @staticmethod
+ def _calc_offsets(l, k, renderer):
+
+ offsets = [0.]
+
+ for s in l:
+ rs, as = s.get_size(renderer)
+ offsets.append(offsets[-1] + rs*k + as)
+
+ return offsets
+
+
+ def set_position(self, pos):
+ self._pos = pos
+
+ def get_position(self):
+ return self._pos
+
+ def set_anchor(self, anchor):
+ """
+ *anchor*
+
+ ===== ============
+ value description
+ ===== ============
+ 'C' Center
+ 'SW' bottom left
+ 'S' bottom
+ 'SE' bottom right
+ 'E' right
+ 'NE' top right
+ 'N' top
+ 'NW' top left
+ 'W' left
+ ===== ============
+
+ """
+ if anchor in mtransforms.Bbox.coefs.keys() or len(anchor) == 2:
+ self._anchor = anchor
+ else:
+ raise ValueError('argument must be among %s' %
+ ', '.join(mtransforms.BBox.coefs.keys()))
+
+
+ def set_horizontal(self, h):
+ self._horizontal = h
+
+ def get_horizontal(self):
+ return self._horizontal
+
+ def set_vertical(self, v):
+ self._vertical = v
+
+ def get_vertical(self):
+ return self._vertical
+
+
+ def get_anchor(self):
+ return self._anchor
+
+
+ def set_aspect(self, aspect=False):
+ """
+ *aspect* : True or False
+ """
+ self._aspect = aspect
+
+ def get_aspect(self):
+ return self._aspect
+
+
+ def locate(self, nx, ny, nx1=None, ny1=None, renderer=None):
+
+
+ figW,figH = self._fig.get_size_inches()
+ x, y, w, h = self.get_position()
+
+ k_h = self._calc_k(self._horizontal, figW*w, renderer)
+ k_v = self._calc_k(self._vertical, figH*h, renderer)
+
+ if self.get_aspect():
+ k = min(k_h, k_v)
+ ox = self._calc_offsets(self._horizontal, k, renderer)
+ oy = self._calc_offsets(self._vertical, k, renderer)
+ else:
+ ox = self._calc_offsets(self._horizontal, k_h, renderer)
+ oy = self._calc_offsets(self._vertical, k_v, renderer)
+
+
+ ww = (ox[-1] - ox[0])/figW
+ hh = (oy[-1] - oy[0])/figH
+ pb = mtransforms.Bbox.from_bounds(x, y, w, h)
+ pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh)
+ pb1_anchored = pb1.anchored(self.get_anchor(), pb)
+
+ if nx1 is None:
+ nx1=nx+1
+ if ny1 is None:
+ ny1=ny+1
+
+ x0, y0 = pb1_anchored.x0, pb1_anchored.y0
+ x1, w1 = x0 + ox[nx]/figW, (ox[nx1] - ox[nx])/figW
+ y1, h1 = y0 + oy[ny]/figH, (oy[ny1] - oy[ny])/figH
+
+ return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
+
+
+ def new_locator(self, nx, ny, nx1=None, ny1=None):
+ return AxesLocator(self, nx, ny, nx1, ny1)
+
+
+class SubplotDivider(Divider):
+
+ def __init__(self, fig, *args, **kwargs):
+ """
+ *fig* is a :class:`matplotlib.figure.Figure` instance.
+
+ *args* is the tuple (*numRows*, *numCols*, *plotNum*), where
+ the array of subplots in the figure has dimensions *numRows*,
+ *numCols*, and where *plotNum* is the number of the subplot
+ being created. *plotNum* starts at 1 in the upper left
+ corner and increases to the right.
+
+ If *numRows* <= *numCols* <= *plotNum* < 10, *args* can be the
+ decimal integer *numRows* * 100 + *numCols* * 10 + *plotNum*.
+ """
+
+ self.figure = fig
+
+ if len(args)==1:
+ s = str(args[0])
+ if len(s) != 3:
+ raise ValueError('Argument to subplot must be a 3 digits long')
+ rows, cols, num = map(int, s)
+ elif len(args)==3:
+ rows, cols, num = args
+ else:
+ raise ValueError( 'Illegal argument to subplot')
+
+
+ total = rows*cols
+ num -= 1 # convert from matlab to python indexing
+ # ie num in range(0,total)
+ if num >= total:
+ raise ValueError( 'Subplot number exceeds total subplots')
+ self._rows = rows
+ self._cols = cols
+ self._num = num
+
+ self.update_params()
+
+ pos = self.figbox.bounds
+ horizontal = kwargs.pop("horizontal", [])
+ vertical = kwargs.pop("vertical", [])
+ aspect = kwargs.pop("aspect", None)
+ anchor = kwargs.pop("anchor", "C")
+
+ if kwargs:
+ raise Exception("")
+
+ Divider.__init__(self, fig, pos, horizontal, vertical,
+ aspect=aspect, anchor=anchor)
+
+
+ def get_position(self):
+ self.update_params()
+ return self.figbox.bounds
+
+
+ def update_params(self):
+ 'update the subplot position from fig.subplotpars'
+
+ rows = self._rows
+ cols = self._cols
+ num = self._num
+
+ pars = self.figure.subplotpars
+ left = pars.left
+ right = pars.right
+ bottom = pars.bottom
+ top = pars.top
+ wspace = pars.wspace
+ hspace = pars.hspace
+ totWidth = right-left
+ totHeight = top-bottom
+
+ figH = totHeight/(rows + hspace*(rows-1))
+ sepH = hspace*figH
+
+ figW = totWidth/(cols + wspace*(cols-1))
+ sepW = wspace*figW
+
+ rowNum, colNum = divmod(num, cols)
+
+ figBottom = top - (rowNum+1)*figH - rowNum*sepH
+ figLeft = left + colNum*(figW + sepW)
+
+ self.figbox = mtransforms.Bbox.from_bounds(figLeft, figBottom,
+ figW, figH)
+
+class AxesDivider(Divider):
+
+
+ def __init__(self, axes):
+ self._axes = axes
+ self._xref = Size.AxesX(axes)
+ self._yref = Size.AxesY(axes)
+ Divider.__init__(self, fig=axes.get_figure(), pos=None,
+ horizontal=[self._xref], vertical=[self._yref],
+ aspect=None, anchor="C")
+
+ def new_horizontal(self, size, pad=None, pack_start=False):
+
+ if pad:
+ if not isinstance(pad, Size._Base):
+ pad = Size.from_any(pad,
+ fraction_ref=self._xref)
+ if pack_start:
+ self._horizontal.insert(0, pad)
+ self._xrefindex += 1
+ else:
+ self._horizontal.append(pad)
+
+ if not isinstance(size, Size._Base):
+ size = Size.from_any(size,
+ fraction_ref=self._xref)
+
+ if pack_start:
+ self._horizontal.insert(0, pad)
+ self._xrefindex += 1
+ locator = self.new_locator(nx=0, ny=0)
+ else:
+ self._horizontal.append(size)
+ locator = self.new_locator(nx=len(self._horizontal)-1, ny=0)
+
+ ax = LocatableAxes(self._axes.get_figure(),
+ self._axes.get_position(original=True))
+ locator = self.new_locator(nx=len(self._horizontal)-1, ny=0)
+ ax.set_axes_locator(locator)
+
+ return ax
+
+ def new_vertical(self, size, pad=None, pack_start=False):
+
+ if pad:
+ if not isinstance(pad, Size._Base):
+ pad = Size.from_any(pad,
+ fraction_ref=self._yref)
+ if pack_start:
+ self._vertical.insert(0, pad)
+ self._yrefindex += 1
+ else:
+ self._vertical.append(pad)
+
+ if not isinstance(size, Size._Base):
+ size = Size.from_any(size,
+ fraction_ref=self._yref)
+
+ if pack_start:
+ self._vertical.insert(0, pad)
+ self._yrefindex += 1
+ locator = self.new_locator(nx=0, ny=0)
+ else:
+ self._vertical.append(size)
+ locator = self.new_locator(nx=0, ny=len(self._vertical)-1)
+
+ ax = LocatableAxes(self._axes.get_figure(),
+ self._axes.get_position(original=True))
+ ax.set_axes_locator(locator)
+
+ return ax
+
+
+ def get_aspect(self):
+ if self._aspect is None:
+ aspect = self._axes.get_aspect()
+ if aspect == "auto":
+ return False
+ else:
+ return True
+ else:
+ return self._aspect
+
+ def get_position(self):
+ if self._pos is None:
+ bbox = self._axes.get_position(original=True)
+ return bbox.bounds
+ else:
+ return self._pos
+
+ def get_anchor(self):
+ if self._anchor is None:
+ return self._axes.get_anchor()
+ else:
+ return self._anchor
+
+
+
+class LocatableAxesBase:
+ def __init__(self, *kl, **kw):
+
+ self._axes_class.__init__(self, *kl, **kw)
+
+ self._locator = None
+ self._locator_renderer = None
+
+ def set_axes_locator(self, locator):
+ self._locator = locator
+
+ def get_axes_locator(self):
+ return self._locator
+
+ def apply_aspect(self, position=None):
+
+ if self.get_axes_locator() is None:
+ self._axes_class.apply_apsect(self, position)
+ else:
+ pos = self.get_axes_locator()(self, self._locator_renderer)
+ self._axes_class.apply_aspect(self, position=pos)
+
+
+ def draw(self, renderer=None, inframe=False):
+
+ self._locator_renderer = renderer
+
+ self._axes_class.draw(self, renderer, inframe)
+
+
+
+_locatableaxes_classes = {}
+def locatable_axes_factory(axes_class):
+
+ new_class = _locatableaxes_classes.get(axes_class)
+ if new_class is None:
+ new_class = new.classobj("Locatable%s" % (axes_class.__name__),
+ (LocatableAxesBase, axes_class),
+ {'_axes_class': axes_class})
+ _locatableaxes_classes[axes_class] = new_class
+
+ return new_class
+
+if hasattr(maxes.Axes, "get_axes_locator"):
+ LocatableAxes = maxes.Axes
+else:
+ LocatableAxes = locatable_axes_factory(maxes.Axes)
+
+
+def make_axes_locatable(axes):
+ if not hasattr(axes, "set_axes_locator"):
+ new_class = locatable_axes_factory(type(axes))
+ axes.__class__ = new_class
+
+ divider = AxesDivider(axes)
+ locator = divider.new_locator(nx=0, ny=0)
+ axes.set_axes_locator(locator)
+
+ return divider
+
+
+def get_demo_image():
+ # prepare image
+ delta = 0.5
+
+ extent = (-3,4,-4,3)
+ import numpy as np
+ x = np.arange(-3.0, 4.001, delta)
+ y = np.arange(-4.0, 3.001, delta)
+ X, Y = np.meshgrid(x, y)
+ import matplotlib.mlab as mlab
+ Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
+ Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
+ Z = (Z1 - Z2) * 10
+
+ return Z, extent
+
+def demo_locatable_axes():
+ import matplotlib.pyplot as plt
+
+ fig1 = plt.figure(1, (6, 6))
+ fig1.clf()
+
+ ## PLOT 1
+ # simple image & colorbar
+ ax = fig1.add_subplot(2, 2, 1)
+
+ Z, extent = get_demo_image()
+
+ im = ax.imshow(Z, extent=extent, interpolation="nearest")
+ cb = plt.colorbar(im)
+ plt.setp(cb.ax.get_yticklabels(), visible=False)
+
+
+ ## PLOT 2
+ # image and colorbar whose location is adjusted in the drawing time.
+ # a hard way
+
+ divider = SubplotDivider(fig1, 2, 2, 2, aspect=True)
+
+ # axes for image
+ ax = LocatableAxes(fig1, divider.get_position())
+
+ # axes for coloarbar
+ ax_cb = LocatableAxes(fig1, divider.get_position())
+
+ h = [Size.AxesX(ax), # main axes
+ Size.Fixed(0.05), # padding, 0.1 inch
+ Size.Fixed(0.2), # colorbar, 0.3 inch
+ ]
+
+ v = [Size.AxesY(ax)]
+
+ divider.set_horizontal(h)
+ divider.set_vertical(v)
+
+ ax.set_axes_locator(divider.new_locator(nx=0, ny=0))
+ ax_cb.set_axes_locator(divider.new_locator(nx=2, ny=0))
+
+ fig1.add_axes(ax)
+ fig1.add_axes(ax_cb)
+
+ ax_cb.yaxis.set_ticks_position("right")
+
+ Z, extent = get_demo_image()
+
+ im = ax.imshow(Z, extent=extent, interpolation="nearest")
+ plt.colorbar(im, cax=ax_cb)
+ plt.setp(ax_cb.get_yticklabels(), visible=False)
+
+ plt.draw()
+ #plt.colorbar(im, cax=ax_cb)
+
+
+ ## PLOT 3
+ # image and colorbar whose location is adjusted in the drawing time.
+ # a easy way
+
+ ax = fig1.add_subplot(2, 2, 3)
+ divider = make_axes_locatable(ax)
+
+ ax_cb = divider.new_horizontal(size="5%", pad=0.05)
+ fig1.add_axes(ax_cb)
+
+ im = ax.imshow(Z, extent=extent, interpolation="nearest")
+ plt.colorbar(im, cax=ax_cb)
+ plt.setp(ax_cb.get_yticklabels(), visible=False)
+
+
+ ## PLOT 4
+ # two images side by sied with fixed padding.
+
+ ax = fig1.add_subplot(2, 2, 4)
+ divider = make_axes_locatable(ax)
+
+ ax2 = divider.new_horizontal(size="100%", pad=0.05)
+ fig1.add_axes(ax2)
+
+ ax.imshow(Z, extent=extent, interpolation="nearest")
+ ax2.imshow(Z, extent=extent, interpolation="nearest")
+ plt.setp(ax2.get_yticklabels(), visible=False)
+ plt.draw()
+
+if __name__ == "__main__":
+ demo_locatable_axes()
Added: trunk/matplotlib/examples/pylab_examples/axes_grid.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/axes_grid.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/axes_grid.py 2008-12-19 22:48:11 UTC (rev 6687)
@@ -0,0 +1,343 @@
+import matplotlib.cbook as cbook
+
+import matplotlib.pyplot as plt
+
+from axes_divider import Size, SubplotDivider, LocatableAxes, Divider, get_demo_image
+
+class AxesGrid(object):
+
+ def __init__(self, fig, rect,
+ nrows_ncols,
+ ngrids = None,
+ direction="row",
+ axes_pad = 0.02,
+ axes_class=None,
+ add_all=True,
+ share_all=False,
+ aspect=True,
+ label_mode="L",
+ colorbar_mode=None,
+ colorbar_location="right",
+ colorbar_pad=None,
+ colorbar_size="5%",
+ ):
+
+ self._nrows, self._ncols = nrows_ncols
+
+ if ngrids is None:
+ ngrids = self._nrows * self._ncols
+ else:
+ if (ngrids > self._nrows * self._ncols) or (ngrids <= 0):
+ raise Exception("")
+
+ self.ngrids = ngrids
+
+ self._axes_pad = axes_pad
+
+ self._colorbar_mode = colorbar_mode
+ self._colorbar_location = colorbar_location
+ if colorbar_pad is None:
+ self._colorbar_pad = axes_pad
+ else:
+ self._colorbar_pad = colorbar_pad
+
+ self._colorbar_size = colorbar_size
+
+ if direction not in ["column", "row"]:
+ raise Exception("")
+
+ self._direction = direction
+
+
+ if axes_class is None:
+ axes_class = LocatableAxes
+
+
+ self.axes_all = []
+ self.axes_column = [[] for i in range(self._ncols)]
+ self.axes_row = [[] for i in range(self._nrows)]
+
+ self.cbar_axes = []
+
+ h = []
+ v = []
+ if cbook.is_string_like(rect) or cbook.is_numlike(rect):
+ self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v,
+ aspect=aspect)
+ elif len(rect) == 3:
+ kw = dict(horizontal=h, vertical=v, aspect=aspect)
+ self._divider = SubplotDivider(fig, *rect, **kw)
+ elif len(rect) == 4:
+ self._divider = Divider(fig, rect, horizontal=h, vertical=v,
+ aspect=aspect)
+ else:
+ raise Exception("")
+
+
+ rect = self._divider.get_position()
+
+ # reference axes
+ self._column_refax = [None for i in range(self._ncols)]
+ self._row_refax = [None for i in range(self._nrows)]
+ self._refax = None
+
+ for i in range(self.ngrids):
+
+ col, row = self.get_col_row(i)
+
+ if share_all:
+ sharex = self._refax
+ sharey = self._refax
+ else:
+ sharex = self._column_refax[col]
+ sharey = self._row_refax[row]
+
+ ax = axes_class(fig, rect, sharex=sharex, sharey=sharey)
+
+ if share_all:
+ if self._refax is None:
+ self._refax = ax
+ else:
+ if sharex is None:
+ self._column_refax[col] = ax
+ if sharey is None:
+ self._row_refax[row] = ax
+
+ self.axes_all.append(ax)
+ self.axes_column[col].append(ax)
+ self.axes_row[row].append(ax)
+
+ cax = axes_class(fig, rect)
+ self.cbar_axes.append(cax)
+
+ self.axes_llc = self.axes_column[0][-1]
+
+ self._update_locators()
+
+ if add_all:
+ for ax in self.axes_all+self.cbar_axes:
+ fig.add_axes(ax)
+
+ self.set_label_mode(label_mode)
+
+
+ def _update_locators(self):
+
+ h = []
+
+ h_ax_pos = []
+ h_cb_pos = []
+ for ax in self._column_refax:
+ if h: h.append(Size.Fixed(self._axes_pad))
+
+ h_ax_pos.append(len(h))
+
+ if ax:
+ sz = Size.AxesX(ax)
+ else:
+ sz = Size.AxesX(self.axes_llc)
+ h.append(sz)
+
+ if self._colorbar_mode == "each" and self._colorbar_location == "right":
+ h.append(Size.from_any(self._colorbar_pad, sz))
+ h_cb_pos.append(len(h))
+ h.append(Size.from_any(self._colorbar_size, sz))
+
+
+ v = []
+
+ v_ax_pos = []
+ v_cb_pos = []
+ for ax in self._row_refax[::-1]:
+ if v: v.append(Size.Fixed(self._axes_pad))
+ v_ax_pos.append(len(v))
+ if ax:
+ sz = Size.AxesY(ax)
+ else:
+ sz = Size.AxesY(self.axes_llc)
+ v.append(sz)
+
+
+ if self._colorbar_mode == "each" and self._colorbar_location == "top":
+ v.append(Size.from_any(self._colorbar_pad, sz))
+ v_cb_pos.append(len(v))
+ v.append(Size.from_any(self._colorbar_size, sz))
+
+
+ for i in range(self.ngrids):
+ col, row = self.get_col_row(i)
+ #locator = self._divider.new_locator(nx=4*col, ny=2*(self._nrows - row - 1))
+ locator = self._divider.new_locator(nx=h_ax_pos[col],
+ ny=v_ax_pos[self._nrows -1 - row])
+ self.axes_all[i].set_axes_locator(locator)
+
+ if self._colorbar_mode == "each":
+ if self._colorbar_location == "right":
+ locator = self._divider.new_locator(nx=h_cb_pos[col],
+ ny=v_ax_pos[self._nrows -1 - row])
+ elif self._colorbar_location == "top":
+ locator = self._divider.new_locator(nx=h_ax_pos[col],
+ ny=v_cb_pos[self._nrows -1 - row])
+ self.cbar_axes[i].set_axes_locator(locator)
+
+
+ if self._colorbar_mode == "single":
+ if self._colorbar_location == "right":
+ sz = Size.Fraction(Size.AxesX(self.axes_llc), self._nrows)
+ h.append(Size.from_any(self._colorbar_pad, sz))
+ h.append(Size.from_any(self._colorbar_size, sz))
+ locator = self._divider.new_locator(nx=-2, ny=0, ny1=-1)
+ elif self._colorbar_location == "top":
+ sz = Size.Fraction(Size.AxesY(self.axes_llc), self._ncols)
+ v.append(Size.from_any(self._colorbar_pad, sz))
+ v.append(Size.from_any(self._colorbar_size, sz))
+ locator = self._divider.new_locator(nx=0, nx1=-1, ny=-2)
+ for i in range(self.ngrids):
+ self.cbar_axes[i].set_visible(False)
+ self.cbar_axes[0].set_axes_locator(locator)
+ self.cbar_axes[0].set_visible(True)
+ elif self._colorbar_mode == "each":
+ for i in range(self.ngrids):
+ self.cbar_axes[i].set_visible(True)
+ else:
+ for i in range(self.ngrids):
+ self.cbar_axes[i].set_visible(False)
+
+ self._divider.set_horizontal(h)
+ self._divider.set_vertical(v)
+
+
+
+ def get_col_row(self, n):
+ if self._direction == "column":
+ col, row = divmod(n, self._nrows)
+ else:
+ row, col = divmod(n, self._ncols)
+
+ return col, row
+
+
+ def __getitem__(self, i):
+ return self.axes_all[i]
+
+
+ def get_geometry(self):
+ return self._nrows, self._ncols
+
+ def set_axes_pad(self, axes_pad):
+ self._axes_pad = axes_pad
+
+ def get_axes_pad(self):
+ return self._axes_pad
+
+ def set_aspect(self, aspect):
+ self._divider.set_aspect(aspect)
+
+ def get_aspect(self):
+ return self._divider.get_aspect()
+
+ def set_label_mode(self, mode):
+ if mode == "all":
+ for ax in self.axes_all:
+ [l.set_visible(True) for l in ax.get_xticklabels()]
+ [l.set_visible(True) for l in ax.get_yticklabels()]
+ elif mode == "L":
+ for ax in self.axes_column[0][:-1]:
+ [l.set_visible(False) for l in ax.get_xticklabels()]
+ [l.set_visible(True) for l in ax.get_yticklabels()]
+ ax = self.axes_column[0][-1]
+ [l.set_visible(True) for l in ax.get_xticklabels()]
+ [l.set_visible(True) for l in ax.get_yticklabels()]
+ for col in self.axes_column[1:]:
+ for ax in col[:-1]:
+ [l.set_visible(False) for l in ax.get_xticklabels()]
+ [l.set_visible(False) for l in ax.get_yticklabels()]
+ ax = col[-1]
+ [l.set_visible(True) for l in ax.get_xticklabels()]
+ [l.set_visible(False) for l in ax.get_yticklabels()]
+ elif mode == "1":
+ for ax in self.axes_all:
+ [l.set_visible(False) for l in ax.get_xticklabels()]
+ [l.set_visible(False) for l in ax.get_yticklabels()]
+ ax = self.axes_llc
+ [l.set_visible(True) for l in ax.get_xticklabels()]
+ [l.set_visible(True) for l in ax.get_yticklabels()]
+
+
+
+if __name__ == "__main__":
+ F = plt.figure(1, (9, 3.5))
+ F.clf()
+
+ F.subplots_adjust(left=0.05, right=0.98)
+
+ grid = AxesGrid(F, 131, # similar to subplot(111)
+ nrows_ncols = (2, 2),
+ direction="row",
+ axes_pad = 0.05,
+ add_all=True,
+ label_mode = "1",
+ )
+
+ Z, extent = get_demo_image()
+ plt.ioff()
+ for i in range(4):
+ im = grid[i].imshow(Z, extent=extent, interpolation="nearest")
+
+ # This only affects axes in first column and second row as share_all = False.
+ grid.axes_llc.set_xticks([-2, 0, 2])
+ grid.axes_llc.set_yticks([-2, 0, 2])
+ plt.ion()
+
+
+ grid = AxesGrid(F, 132, # similar to subplot(111)
+ nrows_ncols = (2, 2),
+ direction="row",
+ axes_pad = 0.0,
+ add_all=True,
+ share_all=True,
+ label_mode = "1",
+ colorbar_mode="single",
+ )
+
+ Z, extent = get_demo_image()
+ plt.ioff()
+ for i in range(4):
+ im = grid[i].imshow(Z, extent=extent, interpolation="nearest")
+ plt.colorbar(im, cax = grid.cbar_axes[0])
+ plt.setp(grid.cbar_axes[0].get_yticklabels(), visible=False)
+
+ # This affects all axes as share_all = True.
+ grid.axes_llc.set_xticks([-2, 0, 2])
+ grid.axes_llc.set_yticks([-2, 0, 2])
+
+ p...
[truncated message content] |
|
From: <lee...@us...> - 2008-12-21 04:14:24
|
Revision: 6690
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6690&view=rev
Author: leejjoon
Date: 2008-12-21 04:14:20 +0000 (Sun, 21 Dec 2008)
Log Message:
-----------
Merged revisions 6688-6689 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6688 | leejjoon | 2008-12-20 22:46:05 -0500 (Sat, 20 Dec 2008) | 1 line
fix hatch bug in pdf backend
........
r6689 | leejjoon | 2008-12-20 23:07:26 -0500 (Sat, 20 Dec 2008) | 1 line
fix dpi dependent offset of Shadow
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/examples/pylab_examples/hatch_demo.py
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
trunk/matplotlib/lib/matplotlib/patches.py
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6685
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6689
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-21 04:07:26 UTC (rev 6689)
+++ trunk/matplotlib/CHANGELOG 2008-12-21 04:14:20 UTC (rev 6690)
@@ -1,8 +1,13 @@
+2008-12-20 fix the dpi-dependent offset of Shadow. - JJL
+
+2008-12-20 fix the hatch bug in the pdf backend. minor update
+ in docs and example - JJL
+
2008-12-19 Add axes_locator attribute in Axes. Two examples are added.
- JJL
-2008-12-19 Update Axes.legend documnetation. /api/api_changes.rst is also
- updated to describe chages in keyword parameters.
+2008-12-19 Update Axes.legend documnetation. /api/api_changes.rst is also
+ updated to describe chages in keyword parameters.
Issue a warning if old keyword parameters are used. - JJL
2008-12-18 add new arrow style, a line + filled triangles. -JJL
Modified: trunk/matplotlib/examples/pylab_examples/hatch_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-21 04:07:26 UTC (rev 6689)
+++ trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-21 04:14:20 UTC (rev 6690)
@@ -1,18 +1,25 @@
"""
-Hatching (pattern filled polygons) is supported currently on PS
+Hatching (pattern filled polygons) is supported currently on PS and PDF
backend only. See the set_patch method in
http://matplotlib.sf.net/matplotlib.patches.html#Patch
for details
"""
-import matplotlib
-matplotlib.use('PS')
-from pylab import figure
+import matplotlib.pyplot as plt
-fig = figure()
-ax = fig.add_subplot(111)
-bars = ax.bar(range(1,5), range(1,5), color='gray', ecolor='black')
+fig = plt.figure()
+ax1 = fig.add_subplot(121)
+ax1.annotate("Hatch is only supported in the PS and PDF backend", (1, 1),
+ xytext=(0, 5),
+ xycoords="axes fraction", textcoords="offset points", ha="center"
+ )
+ax1.bar(range(1,5), range(1,5), color='gray', ecolor='black', hatch="/")
+
+ax2 = fig.add_subplot(122)
+bars = ax2.bar(range(1,5), range(1,5), color='gray', ecolor='black')
+
patterns = ('/', '+', 'x', '\\')
for bar, pattern in zip(bars, patterns):
bar.set_hatch(pattern)
-fig.savefig('hatch4.ps')
+
+plt.show()
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-21 04:07:26 UTC (rev 6689)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-21 04:14:20 UTC (rev 6690)
@@ -942,7 +942,7 @@
def hatchPattern(self, lst):
pattern = self.hatchPatterns.get(lst, None)
if pattern is not None:
- return pattern[0]
+ return pattern
name = Name('H%d' % self.nextHatch)
self.nextHatch += 1
@@ -1233,7 +1233,7 @@
def get_image_magnification(self):
return self.image_dpi/72.0
-
+
def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None):
# MGDTODO: Support clippath here
gc = self.new_gc()
Modified: trunk/matplotlib/lib/matplotlib/patches.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/patches.py 2008-12-21 04:07:26 UTC (rev 6689)
+++ trunk/matplotlib/lib/matplotlib/patches.py 2008-12-21 04:14:20 UTC (rev 6690)
@@ -247,12 +247,12 @@
CURRENT LIMITATIONS:
- 1. Hatching is supported in the PostScript backend only.
+ 1. Hatching is supported in the PostScript and the PDF backend only.
2. Hatching is done with solid black lines of width 0.
- ACCEPTS: [ '/' | '\\' | '|' | '-' | '#' | 'x' ]
+ ACCEPTS: [ '/' | '\\' | '|' | '-' | '#' | 'x' ] (ps & pdf backend only)
"""
self._hatch = h
@@ -373,7 +373,7 @@
self.patch = patch
self.props = props
self._ox, self._oy = ox, oy
- self._update_transform()
+ self._shadow_transform = transforms.Affine2D()
self._update()
__init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
@@ -391,20 +391,20 @@
self.set_facecolor((r,g,b,0.5))
self.set_edgecolor((r,g,b,0.5))
- def _update_transform(self):
- self._shadow_transform = transforms.Affine2D().translate(self._ox, self._oy)
+ def _update_transform(self, renderer):
+ ox = renderer.points_to_pixels(self._ox)
+ oy = renderer.points_to_pixels(self._oy)
+ self._shadow_transform.clear().translate(ox, oy)
def _get_ox(self):
return self._ox
def _set_ox(self, ox):
self._ox = ox
- self._update_transform()
def _get_oy(self):
return self._oy
def _set_oy(self, oy):
self._oy = oy
- self._update_transform()
def get_path(self):
return self.patch.get_path()
@@ -412,6 +412,10 @@
def get_patch_transform(self):
return self.patch.get_patch_transform() + self._shadow_transform
+ def draw(self, renderer):
+ self._update_transform(renderer)
+ Patch.draw(self, renderer)
+
class Rectangle(Patch):
"""
Draw a rectangle with lower left at *xy* = (*x*, *y*) with
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-23 19:49:18
|
Revision: 6699
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6699&view=rev
Author: jdh2358
Date: 2008-12-23 19:49:08 +0000 (Tue, 23 Dec 2008)
Log Message:
-----------
added support for mincnt to hexbin
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/axes.py
trunk/matplotlib/release/osx/Makefile
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2008-12-23 16:06:15 UTC (rev 6698)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2008-12-23 19:49:08 UTC (rev 6699)
@@ -5212,7 +5212,7 @@
xscale = 'linear', yscale = 'linear',
cmap=None, norm=None, vmin=None, vmax=None,
alpha=1.0, linewidths=None, edgecolors='none',
- reduce_C_function = np.mean,
+ reduce_C_function = np.mean, mincnt=None,
**kwargs):
"""
call signature::
@@ -5221,7 +5221,7 @@
xscale = 'linear', yscale = 'linear',
cmap=None, norm=None, vmin=None, vmax=None,
alpha=1.0, linewidths=None, edgecolors='none'
- reduce_C_function = np.mean,
+ reduce_C_function = np.mean, mincnt=None,
**kwargs)
Make a hexagonal binning plot of *x* versus *y*, where *x*,
@@ -5269,6 +5269,10 @@
*scale*: [ 'linear' | 'log' ]
Use a linear or log10 scale on the vertical axis.
+ *mincnt*: None | a positive integer
+ If not None, only display cells with at least *mincnt*
+ number of points in the cell
+
Other keyword arguments controlling color mapping and normalization
arguments:
@@ -5369,6 +5373,8 @@
d1 = (x-ix1)**2 + 3.0 * (y-iy1)**2
d2 = (x-ix2-0.5)**2 + 3.0 * (y-iy2-0.5)**2
bdist = (d1<d2)
+ if mincnt is None:
+ mincnt = 0
if C is None:
accum = np.zeros(n)
@@ -5400,10 +5406,11 @@
else:
lattice2[ix2[i], iy2[i]].append( C[i] )
+
for i in xrange(nx1):
for j in xrange(ny1):
vals = lattice1[i,j]
- if len(vals):
+ if len(vals)>mincnt:
lattice1[i,j] = reduce_C_function( vals )
else:
lattice1[i,j] = np.nan
Modified: trunk/matplotlib/release/osx/Makefile
===================================================================
--- trunk/matplotlib/release/osx/Makefile 2008-12-23 16:06:15 UTC (rev 6698)
+++ trunk/matplotlib/release/osx/Makefile 2008-12-23 19:49:08 UTC (rev 6699)
@@ -95,7 +95,7 @@
rm -rf upload &&\
mkdir upload &&\
cp matplotlib-${MPLVERSION}.tar.gz upload/ &&\
- cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}_r0-py2.5-macosx-10.3-fat.egg upload/matplotlib-${MPLVERSION}-py2.5.egg &&\
+ cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}_r0-py2.5-macosx-10.3-fat.egg upload/matplotlib-${MPLVERSION}-macosx-py2.5.egg &&\
cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}-py2.5-macosx10.5.zip upload/matplotlib-${MPLVERSION}-py2.5-mpkg.zip&&\
scp upload/* jd...@fr...:uploads/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-26 16:28:07
|
Revision: 6702
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6702&view=rev
Author: mdboom
Date: 2008-12-26 16:28:04 +0000 (Fri, 26 Dec 2008)
Log Message:
-----------
Merge branch 'mathdefault'
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/config/mplconfig.py
trunk/matplotlib/lib/matplotlib/config/rcsetup.py
trunk/matplotlib/lib/matplotlib/mathtext.py
trunk/matplotlib/lib/matplotlib/rcsetup.py
trunk/matplotlib/matplotlibrc.template
Modified: trunk/matplotlib/lib/matplotlib/config/mplconfig.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2008-12-23 21:55:45 UTC (rev 6701)
+++ trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2008-12-26 16:28:04 UTC (rev 6702)
@@ -168,6 +168,7 @@
bf = T.Trait('serif:bold' , mplT.FontconfigPatternHandler())
sf = T.Trait('sans' , mplT.FontconfigPatternHandler())
fontset = T.Trait('cm', 'cm', 'stix', 'stixsans', 'custom')
+ default = T.Trait(*("rm cal it tt sf bf default bb frak circled scr regular".split()))
fallback_to_cm = T.true
class axes(TConfig):
Modified: trunk/matplotlib/lib/matplotlib/config/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2008-12-23 21:55:45 UTC (rev 6701)
+++ trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2008-12-26 16:28:04 UTC (rev 6702)
@@ -209,6 +209,9 @@
validate_fontset = ValidateInStrings('fontset', ['cm', 'stix', 'stixsans', 'custom'])
+validate_mathtext_default = ValidateInStrings(
+ 'default', "rm cal it tt sf bf default bb frak circled scr regular".split())
+
validate_verbose = ValidateInStrings('verbose',[
'silent', 'helpful', 'debug', 'debug-annoying',
])
@@ -371,6 +374,7 @@
'mathtext.bf' : ['serif:bold', validate_font_properties],
'mathtext.sf' : ['sans\-serif', validate_font_properties],
'mathtext.fontset' : ['cm', validate_fontset],
+ 'mathtext.default' : ['it', validate_mathtext_default],
'mathtext.fallback_to_cm' : [True, validate_bool],
'image.aspect' : ['equal', validate_aspect], # equal, auto, a number
Modified: trunk/matplotlib/lib/matplotlib/mathtext.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/mathtext.py 2008-12-23 21:55:45 UTC (rev 6701)
+++ trunk/matplotlib/lib/matplotlib/mathtext.py 2008-12-26 16:28:04 UTC (rev 6702)
@@ -403,7 +403,7 @@
*fontX*: one of the TeX font names::
- tt, it, rm, cal, sf, bf or default (non-math)
+ tt, it, rm, cal, sf, bf or default/regular (non-math)
*fontclassX*: TODO
@@ -419,7 +419,7 @@
"""
*font*: one of the TeX font names::
- tt, it, rm, cal, sf, bf or default (non-math)
+ tt, it, rm, cal, sf, bf or default/regular (non-math)
*font_class*: TODO
@@ -543,6 +543,7 @@
filename = findfont(default_font_prop)
default_font = self.CachedFont(FT2Font(str(filename)))
self._fonts['default'] = default_font
+ self._fonts['regular'] = default_font
def destroy(self):
self.glyphd = None
@@ -616,7 +617,7 @@
pclt = cached_font.font.get_sfnt_table('pclt')
if pclt is None:
# Some fonts don't store the xHeight, so we do a poor man's xHeight
- metrics = self.get_metrics(font, 'it', 'x', fontsize, dpi)
+ metrics = self.get_metrics(font, rcParams['mathtext.default'], 'x', fontsize, dpi)
return metrics.iceberg
xHeight = (pclt['xHeight'] / 64.0) * (fontsize / 12.0) * (dpi / 100.0)
return xHeight
@@ -936,7 +937,7 @@
elif not doing_sans_conversion:
# This will generate a dummy character
uniindex = 0x1
- fontname = 'it'
+ fontname = rcParams['mathtext.default']
# Handle private use area glyphs
if (fontname in ('it', 'rm', 'bf') and
@@ -1007,6 +1008,7 @@
default_font.fname = filename
self.fonts['default'] = default_font
+ self.fonts['regular'] = default_font
self.pswriter = StringIO()
def _get_font(self, font):
@@ -2064,7 +2066,7 @@
_dropsub_symbols = set(r'''\int \oint'''.split())
- _fontnames = set("rm cal it tt sf bf default bb frak circled scr".split())
+ _fontnames = set("rm cal it tt sf bf default bb frak circled scr regular".split())
_function_names = set("""
arccos csc ker min arcsin deg lg Pr arctan det lim sec arg dim
@@ -2294,7 +2296,7 @@
def _get_font(self):
return self._font
def _set_font(self, name):
- if name in ('it', 'rm', 'bf'):
+ if name in Parser._fontnames:
self.font_class = name
self._font = name
font = property(_get_font, _set_font)
@@ -2336,7 +2338,7 @@
hlist = Hlist(symbols)
# We're going into math now, so set font to 'it'
self.push_state()
- self.get_state().font = 'it'
+ self.get_state().font = rcParams['mathtext.default']
return [hlist]
def _make_space(self, percentage):
@@ -2346,7 +2348,7 @@
width = self._em_width_cache.get(key)
if width is None:
metrics = state.font_output.get_metrics(
- state.font, 'it', 'm', state.fontsize, state.dpi)
+ state.font, rcParams['mathtext.default'], 'm', state.fontsize, state.dpi)
width = metrics.advance
self._em_width_cache[key] = width
return Kern(width * percentage)
@@ -2665,7 +2667,7 @@
# Shift so the fraction line sits in the middle of the
# equals sign
metrics = state.font_output.get_metrics(
- state.font, 'it', '=', state.fontsize, state.dpi)
+ state.font, rcParams['mathtext.default'], '=', state.fontsize, state.dpi)
shift = (cden.height -
((metrics.ymax + metrics.ymin) / 2 -
thickness * 3.0))
Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-12-23 21:55:45 UTC (rev 6701)
+++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-12-26 16:28:04 UTC (rev 6702)
@@ -233,6 +233,9 @@
validate_fontset = ValidateInStrings('fontset', ['cm', 'stix', 'stixsans', 'custom'])
+validate_mathtext_default = ValidateInStrings(
+ 'default', "rm cal it tt sf bf default bb frak circled scr regular".split())
+
validate_verbose = ValidateInStrings('verbose',[
'silent', 'helpful', 'debug', 'debug-annoying',
])
@@ -397,6 +400,7 @@
'mathtext.bf' : ['serif:bold', validate_font_properties],
'mathtext.sf' : ['sans\-serif', validate_font_properties],
'mathtext.fontset' : ['cm', validate_fontset],
+ 'mathtext.default' : ['it', validate_mathtext_default],
'mathtext.fallback_to_cm' : [True, validate_bool],
'image.aspect' : ['equal', validate_aspect], # equal, auto, a number
Modified: trunk/matplotlib/matplotlibrc.template
===================================================================
--- trunk/matplotlib/matplotlibrc.template 2008-12-23 21:55:45 UTC (rev 6701)
+++ trunk/matplotlib/matplotlibrc.template 2008-12-26 16:28:04 UTC (rev 6702)
@@ -185,6 +185,11 @@
# fonts when a symbol can not be found in one of
# the custom math fonts.
+#mathtext.default : it # The default font to use for math.
+ # Can be any of the LaTeX font names, including
+ # the special name "regular" for the same font
+ # used in regular text.
+
### AXES
# default face and edge color, default tick sizes,
# default fontsizes for ticklabels, and so on. See
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jo...@us...> - 2008-12-29 13:49:02
|
Revision: 6706
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6706&view=rev
Author: jouni
Date: 2008-12-29 13:48:51 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Fix a bug in pdf usetex support
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-28 16:07:10 UTC (rev 6705)
+++ trunk/matplotlib/CHANGELOG 2008-12-29 13:48:51 UTC (rev 6706)
@@ -1,3 +1,7 @@
+2008-12-29 Fix a bug in pdf usetex support, which occurred if the same
+ Type-1 font was used with different encodings, e.g. with
+ Minion Pro and MnSymbol. - JKS
+
2008-12-20 fix the dpi-dependent offset of Shadow. - JJL
2008-12-20 fix the hatch bug in the pdf backend. minor update
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-28 16:07:10 UTC (rev 6705)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-29 13:48:51 UTC (rev 6706)
@@ -394,10 +394,11 @@
'Contents': contentObject }
self.writeObject(thePageObject, thePage)
- # self.fontNames maps filenames to internal font names
- self.fontNames = {}
+ self.fontNames = {} # maps filenames to internal font names
self.nextFont = 1 # next free internal font name
- self.fontInfo = {} # information on fonts: metrics, encoding
+ self.dviFontInfo = {} # information on dvi fonts
+ self.type1Descriptors = {} # differently encoded Type-1 fonts may
+ # share the same descriptor
self.alphaStates = {} # maps alpha values to graphics state objects
self.nextAlphaState = 1
@@ -474,7 +475,7 @@
"""
Select a font based on fontprop and return a name suitable for
Op.selectfont. If fontprop is a string, it will be interpreted
- as the filename of the font.
+ as the filename (or dvi name) of the font.
"""
if is_string_like(fontprop):
@@ -496,17 +497,18 @@
fonts = {}
for filename, Fx in self.fontNames.items():
if filename.endswith('.afm'):
+ # from pdf.use14corefonts
fontdictObject = self._write_afm_font(filename)
- elif filename.endswith('.pfb') or filename.endswith('.pfa'):
- # a Type 1 font; limited support for now
- fontdictObject = self.embedType1(filename, self.fontInfo[Fx])
+ elif self.dviFontInfo.has_key(filename):
+ # a Type 1 font from a dvi file
+ fontdictObject = self.embedType1(filename, self.dviFontInfo[filename])
else:
+ # a normal TrueType font
realpath, stat_key = get_realpath_and_stat(filename)
chars = self.used_characters.get(stat_key)
if chars is not None and len(chars[1]):
fontdictObject = self.embedTTF(realpath, chars[1])
fonts[Fx] = fontdictObject
- #print >>sys.stderr, filename
self.writeObject(self.fontObject, fonts)
def _write_afm_font(self, filename):
@@ -522,36 +524,40 @@
self.writeObject(fontdictObject, fontdict)
return fontdictObject
- def embedType1(self, filename, fontinfo):
+ def embedType1(self, texname, fontinfo):
# TODO: font effects such as SlantFont
- fh = open(filename, 'rb')
matplotlib.verbose.report(
- 'Embedding Type 1 font ' + filename, 'debug')
- try:
- fontdata = fh.read()
- finally:
- fh.close()
+ 'Embedding Type 1 font ' + fontinfo.fontfile +
+ ' with encoding ' + fontinfo.encodingfile, 'debug')
- font = FT2Font(filename)
+ # Use FT2Font to get several font properties
+ font = FT2Font(fontinfo.fontfile)
- widthsObject, fontdescObject, fontdictObject, fontfileObject = \
- [ self.reserveObject(n) for n in
- ('font widths', 'font descriptor',
- 'font dictionary', 'font file') ]
+ # Font descriptors may be shared between differently encoded
+ # Type-1 fonts, so only create a new descriptor if there is no
+ # existing descriptor for this font.
+ fontdesc = self.type1Descriptors.get(fontinfo.fontfile)
+ if fontdesc is None:
+ fontdesc = self.createType1Descriptor(font, fontinfo.fontfile)
+ self.type1Descriptors[fontinfo.fontfile] = fontdesc
- firstchar = 0
- lastchar = len(fontinfo.widths) - 1
+ # Widths
+ widthsObject = self.reserveObject('font widths')
+ self.writeObject(widthsObject, fontinfo.widths)
+ # Font dictionary
+ fontdictObject = self.reserveObject('font dictionary')
fontdict = {
'Type': Name('Font'),
'Subtype': Name('Type1'),
'BaseFont': Name(font.postscript_name),
'FirstChar': 0,
- 'LastChar': lastchar,
+ 'LastChar': len(fontinfo.widths) - 1,
'Widths': widthsObject,
- 'FontDescriptor': fontdescObject,
+ 'FontDescriptor': fontdesc,
}
+ # Encoding (if needed)
if fontinfo.encodingfile is not None:
enc = dviread.Encoding(fontinfo.encodingfile)
differencesArray = [ Name(ch) for ch in enc ]
@@ -561,6 +567,15 @@
'Differences': differencesArray },
})
+ self.writeObject(fontdictObject, fontdict)
+ return fontdictObject
+
+ def createType1Descriptor(self, font, fontfile):
+ # Create and write the font descriptor and the font file
+ # of a Type-1 font
+ fontdescObject = self.reserveObject('font descriptor')
+ fontfileObject = self.reserveObject('font file')
+
_, _, fullname, familyname, weight, italic_angle, fixed_pitch, \
ul_position, ul_thickness = font.get_ps_font_info()
@@ -591,11 +606,9 @@
#'FontWeight': a number where 400 = Regular, 700 = Bold
}
- self.writeObject(fontdictObject, fontdict)
- self.writeObject(widthsObject, fontinfo.widths)
self.writeObject(fontdescObject, descriptor)
- t1font = type1font.Type1Font(filename)
+ t1font = type1font.Type1Font(fontfile)
self.beginStream(fontfileObject.id, None,
{ 'Length1': len(t1font.parts[0]),
'Length2': len(t1font.parts[1]),
@@ -604,7 +617,7 @@
self.currentstream.write(t1font.parts[1])
self.endStream()
- return fontdictObject
+ return fontdescObject
def _get_xobject_symbol_name(self, filename, symbol_name):
return "%s-%s" % (
@@ -1362,13 +1375,15 @@
oldfont, seq = None, []
for x1, y1, dvifont, glyph, width in page.text:
if dvifont != oldfont:
- psfont = self.tex_font_mapping(dvifont.texname)
- pdfname = self.file.fontName(psfont.filename)
- if self.file.fontInfo.get(pdfname, None) is None:
- self.file.fontInfo[pdfname] = Bunch(
+ pdfname = self.file.fontName(dvifont.texname)
+ if not self.file.dviFontInfo.has_key(dvifont.texname):
+ psfont = self.tex_font_mapping(dvifont.texname)
+ self.file.dviFontInfo[dvifont.texname] = Bunch(
+ fontfile=psfont.filename,
encodingfile=psfont.encoding,
widths=dvifont.widths,
dvifont=dvifont)
+ # TODO: font effects
seq += [['font', pdfname, dvifont.size]]
oldfont = dvifont
seq += [['text', x1, y1, [chr(glyph)], x1+width]]
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-29 14:08:16
|
Revision: 6708
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6708&view=rev
Author: mdboom
Date: 2008-12-29 14:08:13 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Merge branch 'hatching'
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/hatch_demo.py
trunk/matplotlib/lib/matplotlib/backend_bases.py
trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
trunk/matplotlib/lib/matplotlib/path.py
trunk/matplotlib/src/_backend_agg.cpp
trunk/matplotlib/src/_backend_agg.h
Modified: trunk/matplotlib/examples/pylab_examples/hatch_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-29 14:08:13 UTC (rev 6708)
@@ -12,7 +12,7 @@
xytext=(0, 5),
xycoords="axes fraction", textcoords="offset points", ha="center"
)
-ax1.bar(range(1,5), range(1,5), color='gray', ecolor='black', hatch="/")
+ax1.bar(range(1,5), range(1,5), color='gray', edgecolor='red', hatch="/")
ax2 = fig.add_subplot(122)
@@ -23,3 +23,5 @@
bar.set_hatch(pattern)
plt.show()
+plt.savefig("test.pdf")
+plt.savefig("test.ps")
Modified: trunk/matplotlib/lib/matplotlib/backend_bases.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backend_bases.py 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backend_bases.py 2008-12-29 14:08:13 UTC (rev 6708)
@@ -30,6 +30,7 @@
import matplotlib.colors as colors
import matplotlib.transforms as transforms
import matplotlib.widgets as widgets
+import matplotlib.path as path
from matplotlib import rcParams
class RendererBase:
@@ -679,6 +680,14 @@
"""
return self._hatch
+ def get_hatch_path(self, density=6.0):
+ """
+ Returns a Path for the current hatch.
+ """
+ if self._hatch is None:
+ return None
+ return path.Path.hatch(self._hatch, density)
+
class Event:
"""
A matplotlib event. Attach additional attributes as defined in
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2008-12-29 14:08:13 UTC (rev 6708)
@@ -73,9 +73,13 @@
'debug-annoying')
def draw_path(self, gc, path, transform, rgbFace=None):
+ """
+ Draw the path
+ """
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 and rgbFace is None:
+ if (nmax > 100 and npts > nmax and path.should_simplify and
+ rgbFace is None and gc.get_hatch() is None):
nch = npy.ceil(npts/float(nmax))
chsize = int(npy.ceil(npts/nch))
i0 = npy.arange(0, npts, chsize)
@@ -93,7 +97,6 @@
else:
self._renderer.draw_path(gc, path, transform, rgbFace)
-
def draw_mathtext(self, gc, x, y, s, prop, angle):
"""
Draw the math text using matplotlib.mathtext
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-29 14:08:13 UTC (rev 6708)
@@ -953,21 +953,20 @@
'CA': alpha, 'ca': alpha })
return name
- def hatchPattern(self, lst):
- pattern = self.hatchPatterns.get(lst, None)
+ def hatchPattern(self, hatch_style):
+ pattern = self.hatchPatterns.get(hatch_style, None)
if pattern is not None:
return pattern
name = Name('H%d' % self.nextHatch)
self.nextHatch += 1
- self.hatchPatterns[lst] = name
+ self.hatchPatterns[hatch_style] = name
return name
def writeHatches(self):
hatchDict = dict()
- sidelen = 144.0
- density = 24.0
- for lst, name in self.hatchPatterns.items():
+ sidelen = 72.0
+ for hatch_style, name in self.hatchPatterns.items():
ob = self.reserveObject('hatch pattern')
hatchDict[name] = ob
res = { 'Procsets':
@@ -983,33 +982,21 @@
# lst is a tuple of stroke color, fill color,
# number of - lines, number of / lines,
# number of | lines, number of \ lines
- rgb = lst[0]
+ rgb = hatch_style[0]
self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_stroke)
- if lst[1] is not None:
- rgb = lst[1]
+ if hatch_style[1] is not None:
+ rgb = hatch_style[1]
self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_nonstroke,
0, 0, sidelen, sidelen, Op.rectangle,
Op.fill)
- if lst[2]: # -
- for j in npy.arange(0.0, sidelen, density/lst[2]):
- self.output(0, j, Op.moveto,
- sidelen, j, Op.lineto)
- if lst[3]: # /
- for j in npy.arange(0.0, sidelen, density/lst[3]):
- self.output(0, j, Op.moveto,
- sidelen-j, sidelen, Op.lineto,
- sidelen-j, 0, Op.moveto,
- sidelen, j, Op.lineto)
- if lst[4]: # |
- for j in npy.arange(0.0, sidelen, density/lst[4]):
- self.output(j, 0, Op.moveto,
- j, sidelen, Op.lineto)
- if lst[5]: # \
- for j in npy.arange(sidelen, 0.0, -density/lst[5]):
- self.output(sidelen, j, Op.moveto,
- j, sidelen, Op.lineto,
- j, 0, Op.moveto,
- 0, j, Op.lineto)
+
+ self.output(0.1, Op.setlinewidth)
+
+ # TODO: We could make this dpi-dependent, but that would be
+ # an API change
+ self.output(*self.pathOperations(
+ Path.hatch(hatch_style[2]),
+ Affine2D().scale(sidelen)))
self.output(Op.stroke)
self.endStream()
@@ -1735,13 +1722,8 @@
return [Name('DeviceRGB'), Op.setcolorspace_nonstroke]
else:
hatch = hatch.lower()
- lst = ( self._rgb,
- self._fillcolor,
- hatch.count('-') + hatch.count('+'),
- hatch.count('/') + hatch.count('x'),
- hatch.count('|') + hatch.count('+'),
- hatch.count('\\') + hatch.count('x') )
- name = self.file.hatchPattern(lst)
+ hatch_style = (self._rgb, self._fillcolor, hatch)
+ name = self.file.hatchPattern(hatch_style)
return [Name('Pattern'), Op.setcolorspace_nonstroke,
name, Op.setcolor_nonstroke]
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2008-12-29 14:08:13 UTC (rev 6708)
@@ -31,7 +31,7 @@
from matplotlib._mathtext_data import uni2type1
from matplotlib.text import Text
from matplotlib.path import Path
-from matplotlib.transforms import IdentityTransform
+from matplotlib.transforms import Affine2D
import numpy as npy
import binascii
@@ -163,7 +163,7 @@
self.linedash = None
self.fontname = None
self.fontsize = None
- self.hatch = None
+ self._hatches = {}
self.image_magnification = imagedpi/72.0
self._clip_paths = {}
self._path_collection_id = 0
@@ -231,58 +231,36 @@
if store: self.fontname = fontname
if store: self.fontsize = fontsize
- def set_hatch(self, hatch):
- """
- hatch can be one of:
- / - diagonal hatching
- \ - back diagonal
- | - vertical
- - - horizontal
- + - crossed
- X - crossed diagonal
+ def create_hatch(self, hatch):
+ sidelen = 72
+ if self._hatches.has_key(hatch):
+ return self._hatches[hatch]
+ name = 'H%d' % len(self._hatches)
+ self._pswriter.write("""\
+ << /PatternType 1
+ /PaintType 2
+ /TilingType 2
+ /BBox[0 0 %(sidelen)d %(sidelen)d]
+ /XStep %(sidelen)d
+ /YStep %(sidelen)d
- letters can be combined, in which case all the specified
- hatchings are done
+ /PaintProc {
+ pop
+ 0 setlinewidth
+""" % locals())
+ self._pswriter.write(
+ self._convert_path(Path.hatch(hatch), Affine2D().scale(72.0)))
+ self._pswriter.write("""\
+ stroke
+ } bind
+ >>
+ matrix
+ makepattern
+ /%(name)s exch def
+""" % locals())
+ self._hatches[hatch] = name
+ return name
- if same letter repeats, it increases the density of hatching
- in that direction
- """
- hatches = {'horiz':0, 'vert':0, 'diag1':0, 'diag2':0}
-
- for letter in hatch:
- if (letter == '/'): hatches['diag2'] += 1
- elif (letter == '\\'): hatches['diag1'] += 1
- elif (letter == '|'): hatches['vert'] += 1
- elif (letter == '-'): hatches['horiz'] += 1
- elif (letter == '+'):
- hatches['horiz'] += 1
- hatches['vert'] += 1
- elif (letter.lower() == 'x'):
- hatches['diag1'] += 1
- hatches['diag2'] += 1
-
- def do_hatch(angle, density):
- if (density == 0): return ""
- return """\
- gsave
- eoclip %s rotate 0.0 0.0 0.0 0.0 setrgbcolor 0 setlinewidth
- /hatchgap %d def
- pathbbox /hatchb exch def /hatchr exch def /hatcht exch def /hatchl exch def
- hatchl cvi hatchgap idiv hatchgap mul
- hatchgap
- hatchr cvi hatchgap idiv hatchgap mul
- {hatcht m 0 hatchb hatcht sub r }
- for
- stroke
- grestore
- """ % (angle, 12/density)
- self._pswriter.write("gsave\n")
- self._pswriter.write(do_hatch(90, hatches['horiz']))
- self._pswriter.write(do_hatch(0, hatches['vert']))
- self._pswriter.write(do_hatch(45, hatches['diag1']))
- self._pswriter.write(do_hatch(-45, hatches['diag2']))
- self._pswriter.write("grestore\n")
-
def get_canvas_width_height(self):
'return the canvas width and height in display coords'
return self.width, self.height
@@ -816,15 +794,17 @@
if fill:
if stroke:
write("gsave\n")
- self.set_color(store=0, *rgbFace[:3])
- write("fill\ngrestore\n")
- else:
- self.set_color(store=0, *rgbFace[:3])
- write("fill\n")
+ self.set_color(store=0, *rgbFace[:3])
+ write("fill\n")
+ if stroke:
+ write("grestore\n")
hatch = gc.get_hatch()
if hatch:
- self.set_hatch(hatch)
+ hatch_name = self.create_hatch(hatch)
+ write("gsave\n")
+ write("[/Pattern [/DeviceRGB]] setcolorspace %f %f %f " % gc.get_rgb()[:3])
+ write("%s setcolor fill grestore\n" % hatch_name)
if stroke:
write("stroke\n")
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008-12-29 14:08:13 UTC (rev 6708)
@@ -57,6 +57,7 @@
self._markers = {}
self._path_collection_id = 0
self._imaged = {}
+ self._hatchd = {}
self.mathtext_parser = MathTextParser('SVG')
svgwriter.write(svgProlog%(width,height,width,height))
@@ -90,15 +91,38 @@
font.set_size(size, 72.0)
return font
+ def _get_hatch(self, gc, rgbFace):
+ """
+ Create a new hatch pattern
+ """
+ HATCH_SIZE = 144
+ dictkey = (gc.get_hatch().lower(), rgbFace, gc.get_rgb())
+ id = self._hatchd.get(dictkey)
+ if id is None:
+ id = 'h%s' % md5(str(dictkey)).hexdigest()
+ self._svgwriter.write('<defs>\n <pattern id="%s" ' % id)
+ self._svgwriter.write('patternUnits="userSpaceOnUse" x="0" y="0" ')
+ self._svgwriter.write(' width="%d" height="%d" >\n' % (HATCH_SIZE, HATCH_SIZE))
+ path_data = self._convert_path(gc.get_hatch_path(), Affine2D().scale(144))
+ path = '<path d="%s" fill="%s" stroke="%s" stroke-width="1.0"/>' % (
+ path_data, rgb2hex(rgbFace[:3]), rgb2hex(gc.get_rgb()[:3]))
+ self._svgwriter.write(path)
+ self._svgwriter.write('\n </pattern>\n</defs>')
+ self._hatchd[dictkey] = id
+ return id
+
def _get_style(self, gc, rgbFace):
"""
return the style string.
style is generated from the GraphicsContext, rgbFace and clippath
"""
- if rgbFace is None:
- fill = 'none'
+ if gc.get_hatch() is not None:
+ fill = "url(#%s)" % self._get_hatch(gc, rgbFace)
else:
- fill = rgb2hex(rgbFace[:3])
+ if rgbFace is None:
+ fill = 'none'
+ else:
+ fill = rgb2hex(rgbFace[:3])
offset, seq = gc.get_dashes()
if seq is None:
@@ -150,7 +174,7 @@
def open_group(self, s, gid=None):
"""
Open a grouping element with label *s*. If *gid* is given, use
- *gid* as the id of the group.
+ *gid* as the id of the group.
"""
if gid:
self._svgwriter.write('<g id="%s">\n' % (gid))
Modified: trunk/matplotlib/lib/matplotlib/path.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 14:08:13 UTC (rev 6708)
@@ -11,7 +11,7 @@
from matplotlib._path import point_in_path, get_path_extents, \
point_in_path_collection, get_path_collection_extents, \
path_in_path, path_intersects_path, convert_path_to_polygons
-from matplotlib.cbook import simple_linear_interpolation
+from matplotlib.cbook import simple_linear_interpolation, maxdict
class Path(object):
"""
@@ -115,8 +115,8 @@
self.codes = codes
self.vertices = vertices
- #@staticmethod
- def make_compound_path(*args):
+ #@classmethod
+ def make_compound_path(cls, *args):
"""
(staticmethod) Make a compound path from a list of Path
objects. Only polygons (not curves) are supported.
@@ -130,14 +130,14 @@
vertices = np.vstack([x.vertices for x in args])
vertices.reshape((total_length, 2))
- codes = Path.LINETO * np.ones(total_length)
+ codes = cls.LINETO * np.ones(total_length)
i = 0
for length in lengths:
- codes[i] = Path.MOVETO
+ codes[i] = cls.MOVETO
i += length
- return Path(vertices, codes)
- make_compound_path = staticmethod(make_compound_path)
+ return cls(vertices, codes)
+ make_compound_path = classmethod(make_compound_path)
def __repr__(self):
return "Path(%s, %s)" % (self.vertices, self.codes)
@@ -343,7 +343,7 @@
"""
if cls._unit_rectangle is None:
cls._unit_rectangle = \
- Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]])
+ cls([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]])
return cls._unit_rectangle
unit_rectangle = classmethod(unit_rectangle)
@@ -366,7 +366,7 @@
# "points-up"
theta += np.pi / 2.0
verts = np.concatenate((np.cos(theta), np.sin(theta)), 1)
- path = Path(verts)
+ path = cls(verts)
cls._unit_regular_polygons[numVertices] = path
return path
unit_regular_polygon = classmethod(unit_regular_polygon)
@@ -392,7 +392,7 @@
r = np.ones(ns2 + 1)
r[1::2] = innerCircle
verts = np.vstack((r*np.cos(theta), r*np.sin(theta))).transpose()
- path = Path(verts)
+ path = cls(verts)
cls._unit_regular_polygons[(numVertices, innerCircle)] = path
return path
unit_regular_star = classmethod(unit_regular_star)
@@ -466,7 +466,7 @@
codes[0] = cls.MOVETO
codes[-1] = cls.CLOSEPOLY
- cls._unit_circle = Path(vertices, codes)
+ cls._unit_circle = cls(vertices, codes)
return cls._unit_circle
unit_circle = classmethod(unit_circle)
@@ -523,19 +523,19 @@
if is_wedge:
length = n * 3 + 4
- vertices = np.zeros((length, 2), np.float_)
- codes = Path.CURVE4 * np.ones((length, ), Path.code_type)
+ vertices = np.empty((length, 2), np.float_)
+ codes = cls.CURVE4 * np.ones((length, ), cls.code_type)
vertices[1] = [xA[0], yA[0]]
- codes[0:2] = [Path.MOVETO, Path.LINETO]
- codes[-2:] = [Path.LINETO, Path.CLOSEPOLY]
+ codes[0:2] = [cls.MOVETO, cls.LINETO]
+ codes[-2:] = [cls.LINETO, cls.CLOSEPOLY]
vertex_offset = 2
end = length - 2
else:
length = n * 3 + 1
- vertices = np.zeros((length, 2), np.float_)
- codes = Path.CURVE4 * np.ones((length, ), Path.code_type)
+ vertices = np.empty((length, 2), np.float_)
+ codes = cls.CURVE4 * np.ones((length, ), cls.code_type)
vertices[0] = [xA[0], yA[0]]
- codes[0] = Path.MOVETO
+ codes[0] = cls.MOVETO
vertex_offset = 1
end = length
@@ -546,7 +546,7 @@
vertices[vertex_offset+2:end:3, 0] = xB
vertices[vertex_offset+2:end:3, 1] = yB
- return Path(vertices, codes)
+ return cls(vertices, codes)
arc = classmethod(arc)
#@classmethod
@@ -562,6 +562,94 @@
return cls.arc(theta1, theta2, n, True)
wedge = classmethod(wedge)
+ _hatch_dict = maxdict(8)
+ #@classmethod
+ def hatch(cls, hatchpattern, density=6):
+ """
+ Given a hatch specifier, *hatchpattern*, generates a Path that
+ can be used in a repeated hatching pattern. *density* is the
+ number of lines per unit square.
+ """
+ if hatchpattern is None:
+ return None
+
+ hatch = hatchpattern.lower()
+ hatch_path = cls._hatch_dict.get((hatch, density))
+ if hatch_path is not None:
+ return hatch_path
+
+ size = 1.0
+ density = int(density)
+ counts = [
+ hatch.count('-') + hatch.count('+'),
+ hatch.count('/') + hatch.count('x'),
+ hatch.count('|') + hatch.count('+'),
+ hatch.count('\\') + hatch.count('x')
+ ]
+
+ if sum(counts) == 0:
+ return cls([])
+
+ counts = [x * density for x in counts]
+
+ num_vertices = (counts[0] * 2 + counts[1] * 4 +
+ counts[2] * 2 + counts[3] * 4)
+ vertices = np.empty((num_vertices, 2))
+ codes = np.empty((num_vertices,), cls.code_type)
+ codes[0::2] = cls.MOVETO
+ codes[1::2] = cls.LINETO
+
+ cursor = 0
+
+ if counts[0]:
+ vertices_chunk = vertices[cursor:cursor + counts[0] * 2]
+ cursor += counts[0] * 2
+ steps = np.linspace(0.0, 1.0, counts[0], False)
+ vertices_chunk[0::2, 0] = 0.0
+ vertices_chunk[0::2, 1] = steps
+ vertices_chunk[1::2, 0] = size
+ vertices_chunk[1::2, 1] = steps
+
+ if counts[1]:
+ vertices_chunk = vertices[cursor:cursor + counts[1] * 4]
+ cursor += counts[1] * 4
+ steps = np.linspace(0.0, 1.0, counts[1], False)
+ vertices_chunk[0::4, 0] = 0.0
+ vertices_chunk[0::4, 1] = steps
+ vertices_chunk[1::4, 0] = size - steps
+ vertices_chunk[1::4, 1] = size
+ vertices_chunk[2::4, 0] = size - steps
+ vertices_chunk[2::4, 1] = 0.0
+ vertices_chunk[3::4, 0] = size
+ vertices_chunk[3::4, 1] = steps
+
+ if counts[2]:
+ vertices_chunk = vertices[cursor:cursor + counts[2] * 2]
+ cursor += counts[2] * 2
+ steps = np.linspace(0.0, 1.0, counts[2], False)
+ vertices_chunk[0::2, 0] = steps
+ vertices_chunk[0::2, 1] = 0.0
+ vertices_chunk[1::2, 0] = steps
+ vertices_chunk[1::2, 1] = size
+
+ if counts[3]:
+ vertices_chunk = vertices[cursor:cursor + counts[3] * 4]
+ cursor += counts[3] * 4
+ steps = np.linspace(0.0, 1.0, counts[3], False)
+ vertices_chunk[0::4, 0] = size
+ vertices_chunk[0::4, 1] = steps
+ vertices_chunk[1::4, 0] = steps
+ vertices_chunk[1::4, 1] = size
+ vertices_chunk[2::4, 0] = steps
+ vertices_chunk[2::4, 1] = 0.0
+ vertices_chunk[3::4, 0] = 0.0
+ vertices_chunk[3::4, 1] = steps
+
+ hatch_path = cls(vertices, codes)
+ cls._hatch_dict[(hatch, density)] = hatch_path
+ return hatch_path
+ hatch = classmethod(hatch)
+
_get_path_collection_extents = get_path_collection_extents
def get_path_collection_extents(*args):
"""
Modified: trunk/matplotlib/src/_backend_agg.cpp
===================================================================
--- trunk/matplotlib/src/_backend_agg.cpp 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/src/_backend_agg.cpp 2008-12-29 14:08:13 UTC (rev 6708)
@@ -30,6 +30,7 @@
#include "agg_span_image_filter_gray.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_span_interpolator_linear.h"
+#include "agg_span_pattern_rgba.h"
#include "agg_conv_shorten_path.h"
#include "util/agg_color_conv_rgb8.h"
@@ -149,6 +150,7 @@
_set_clip_rectangle(gc);
_set_clip_path(gc);
_set_snap(gc);
+ _set_hatch_path(gc);
}
GCAgg::GCAgg(double dpi) :
@@ -273,6 +275,15 @@
}
}
+void
+GCAgg::_set_hatch_path( const Py::Object& gc) {
+ _VERBOSE("GCAgg::_set_hatch_path");
+
+ Py::Object method_obj = gc.getAttr("get_hatch_path");
+ Py::Callable method(method_obj);
+ hatchpath = method.apply(Py::Tuple());
+}
+
const size_t
RendererAgg::PIXELS_PER_INCH(96);
@@ -310,6 +321,7 @@
rendererBase.clear(agg::rgba(1, 1, 1, 0));
rendererAA.attach(rendererBase);
rendererBin.attach(rendererBase);
+ hatchRenderingBuffer.attach(hatchBuffer, HATCH_SIZE, HATCH_SIZE, HATCH_SIZE*4);
}
void RendererAgg::create_alpha_buffers() {
@@ -879,6 +891,55 @@
}
}
+ // Render hatch
+ if (!gc.hatchpath.isNone()) {
+ // Reset any clipping that may be in effect, since we'll be
+ // drawing the hatch in a scratch buffer at origin (0, 0)
+ theRasterizer.reset_clipping();
+ rendererBase.reset_clipping(true);
+
+ // Create and transform the path
+ typedef agg::conv_transform<PathIterator> hatch_path_trans_t;
+ typedef SimplifyPath<hatch_path_trans_t> hatch_path_simplify_t;
+ typedef agg::conv_stroke<hatch_path_simplify_t> hatch_path_stroke_t;
+
+ PathIterator hatch_path(gc.hatchpath);
+ agg::trans_affine hatch_trans;
+ hatch_trans *= agg::trans_affine_scaling(HATCH_SIZE, HATCH_SIZE);
+ hatch_path_trans_t hatch_path_trans(hatch_path, hatch_trans);
+ hatch_path_simplify_t hatch_path_simplify
+ (hatch_path_trans, true, false, HATCH_SIZE, HATCH_SIZE);
+ hatch_path_stroke_t hatch_path_stroke(hatch_path_simplify);
+ hatch_path_stroke.width(1.0);
+ hatch_path_stroke.line_cap(agg::square_cap);
+ theRasterizer.add_path(hatch_path_stroke);
+
+ // Render the path into the hatch buffer
+ pixfmt hatch_img_pixf(hatchRenderingBuffer);
+ renderer_base rb(hatch_img_pixf);
+ renderer_aa rs(rb);
+ rb.clear(agg::rgba(0.0, 0.0, 0.0, 0.0));
+ rs.color(gc.color);
+ agg::render_scanlines(theRasterizer, slineP8, rs);
+
+ // Put clipping back on, if originally set on entry to this
+ // function
+ set_clipbox(gc.cliprect, theRasterizer);
+ if (has_clippath)
+ render_clippath(gc.clippath, gc.clippath_trans);
+
+ // Transfer the hatch to the main image buffer
+ typedef agg::image_accessor_wrap<pixfmt,
+ agg::wrap_mode_repeat_auto_pow2,
+ agg::wrap_mode_repeat_auto_pow2> img_source_type;
+ typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
+ agg::span_allocator<agg::rgba8> sa;
+ img_source_type img_src(hatch_img_pixf);
+ span_gen_type sg(img_src, 0, 0);
+ theRasterizer.add_path(path);
+ agg::render_scanlines_aa(theRasterizer, slineP8, rendererBase, sa, sg);
+ }
+
// Render stroke
if (gc.linewidth != 0.0) {
double linewidth = gc.linewidth;
Modified: trunk/matplotlib/src/_backend_agg.h
===================================================================
--- trunk/matplotlib/src/_backend_agg.h 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/src/_backend_agg.h 2008-12-29 14:08:13 UTC (rev 6708)
@@ -60,7 +60,6 @@
typedef agg::scanline_bin scanline_bin;
typedef agg::amask_no_clip_gray8 alpha_mask_type;
-
typedef agg::renderer_base<agg::pixfmt_gray8> renderer_base_alpha_mask_type;
typedef agg::renderer_scanline_aa_solid<renderer_base_alpha_mask_type> renderer_alpha_mask_type;
@@ -129,6 +128,8 @@
SNAP_TRUE
} snap;
+ Py::Object hatchpath;
+
protected:
agg::rgba get_color(const Py::Object& gc);
double points_to_pixels( const Py::Object& points);
@@ -139,6 +140,7 @@
void _set_clip_path( const Py::Object& gc);
void _set_antialiased( const Py::Object& gc);
void _set_snap( const Py::Object& gc);
+ void _set_hatch_path( const Py::Object& gc);
};
@@ -206,6 +208,12 @@
Py::Object lastclippath;
agg::trans_affine lastclippath_transform;
+ // HATCH_SIZE should be a power of 2, to take advantage of Agg's
+ // fast pattern rendering
+ static const size_t HATCH_SIZE = 128;
+ agg::int8u hatchBuffer[HATCH_SIZE * HATCH_SIZE * 4];
+ agg::rendering_buffer hatchRenderingBuffer;
+
const int debug;
protected:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-29 14:23:28
|
Revision: 6710
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6710&view=rev
Author: mdboom
Date: 2008-12-29 14:23:24 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Update hatch documentation.
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/hatch_demo.py
trunk/matplotlib/lib/matplotlib/patches.py
Modified: trunk/matplotlib/examples/pylab_examples/hatch_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-29 14:10:22 UTC (rev 6709)
+++ trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-29 14:23:24 UTC (rev 6710)
@@ -1,8 +1,6 @@
"""
-Hatching (pattern filled polygons) is supported currently on PS and PDF
-backend only. See the set_patch method in
-http://matplotlib.sf.net/matplotlib.patches.html#Patch
-for details
+Hatching (pattern filled polygons) is supported currently in the PS,
+PDF, SVG and Agg backends only.
"""
import matplotlib.pyplot as plt
Modified: trunk/matplotlib/lib/matplotlib/patches.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/patches.py 2008-12-29 14:10:22 UTC (rev 6709)
+++ trunk/matplotlib/lib/matplotlib/patches.py 2008-12-29 14:23:24 UTC (rev 6710)
@@ -228,11 +228,11 @@
'return whether fill is set'
return self.fill
- def set_hatch(self, h):
+ def set_hatch(self, hatch):
"""
Set the hatching pattern
- hatch can be one of::
+ *hatch* can be one of::
/ - diagonal hatching
\ - back diagonal
@@ -247,11 +247,9 @@
CURRENT LIMITATIONS:
- 1. Hatching is supported in the PostScript and the PDF backend only.
+ 1. Hatching is supported in the PostScript, PDF, SVG and Agg
+ backends only.
- 2. Hatching is done with solid black lines of width 0.
-
-
ACCEPTS: [ '/' | '\\' | '|' | '-' | '#' | 'x' ] (ps & pdf backend only)
"""
self._hatch = h
@@ -2655,7 +2653,7 @@
"""
path = make_path_regular(path)
-
+
if aspect_ratio is not None:
# Squeeze the given height by the aspect_ratio
@@ -2808,27 +2806,27 @@
[(x3+ddxB, y3+ddyB)]]),
path.codes)]
_fillable = [False]
-
+
if self.beginarrow:
if self.fillbegin:
p = np.concatenate([verticesA, [verticesA[0], verticesA[0]], ])
- c = np.concatenate([codesA, [Path.LINETO, Path.CLOSEPOLY]])
+ c = np.concatenate([codesA, [Path.LINETO, Path.CLOSEPOLY]])
_path.append(Path(p, c))
_fillable.append(True)
else:
_path.append(Path(verticesA, codesA))
_fillable.append(False)
-
+
if self.endarrow:
if self.fillend:
_fillable.append(True)
p = np.concatenate([verticesB, [verticesB[0], verticesB[0]], ])
- c = np.concatenate([codesB, [Path.LINETO, Path.CLOSEPOLY]])
+ c = np.concatenate([codesB, [Path.LINETO, Path.CLOSEPOLY]])
_path.append(Path(p, c))
else:
_fillable.append(False)
_path.append(Path(verticesB, codesB))
-
+
return _path, _fillable
@@ -2926,7 +2924,7 @@
super(ArrowStyle.CurveFilledA, self).__init__( \
beginarrow=True, endarrow=False,
- fillbegin=True, fillend=False,
+ fillbegin=True, fillend=False,
head_length=head_length, head_width=head_width )
_style_list["<|-"] = CurveFilledA
@@ -2948,7 +2946,7 @@
super(ArrowStyle.CurveFilledB, self).__init__( \
beginarrow=False, endarrow=True,
- fillbegin=False, fillend=True,
+ fillbegin=False, fillend=True,
head_length=head_length, head_width=head_width )
_style_list["-|>"] = CurveFilledB
@@ -2970,7 +2968,7 @@
super(ArrowStyle.CurveFilledAB, self).__init__( \
beginarrow=True, endarrow=True,
- fillbegin=True, fillend=True,
+ fillbegin=True, fillend=True,
head_length=head_length, head_width=head_width )
_style_list["<|-|>"] = CurveFilledAB
@@ -3532,7 +3530,7 @@
if cbook.iterable(fillable):
_path = concatenate_paths(_path)
-
+
return self.get_transform().inverted().transform_path(_path)
@@ -3604,8 +3602,8 @@
if not cbook.iterable(fillable):
path = [path]
fillable = [fillable]
-
+
affine = transforms.IdentityTransform()
renderer.open_group('patch', self.get_gid())
@@ -3615,6 +3613,6 @@
renderer.draw_path(gc, p, affine, rgbFace)
else:
renderer.draw_path(gc, p, affine, None)
-
+
renderer.close_group('patch')
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-29 14:42:23
|
Revision: 6712
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6712&view=rev
Author: mdboom
Date: 2008-12-29 14:42:20 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Fix path simplification by a) making it more conservative about when it will simplify based on segment length, and b) honoring path.simplify rcParam in Agg backend.
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/config/rcsetup.py
trunk/matplotlib/lib/matplotlib/path.py
trunk/matplotlib/lib/matplotlib/rcsetup.py
trunk/matplotlib/src/agg_py_path_iterator.h
Modified: trunk/matplotlib/lib/matplotlib/config/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2008-12-29 14:25:47 UTC (rev 6711)
+++ trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2008-12-29 14:42:20 UTC (rev 6712)
@@ -479,7 +479,7 @@
'svg.embed_char_paths' : [True, validate_bool], # True to save all characters as paths in the SVG
'plugins.directory' : ['.matplotlib_plugins', str], # where plugin directory is locate
- 'path.simplify' : [False, validate_bool]
+ 'path.simplify' : [True, validate_bool]
}
if __name__ == '__main__':
Modified: trunk/matplotlib/lib/matplotlib/path.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 14:25:47 UTC (rev 6711)
+++ trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 14:42:20 UTC (rev 6712)
@@ -109,8 +109,9 @@
assert vertices.ndim == 2
assert vertices.shape[1] == 2
- self.should_simplify = (len(vertices) >= 128 and
- (codes is None or np.all(codes <= Path.LINETO)))
+ self.should_simplify = (rcParam['path.simplify'] and
+ (len(vertices) >= 128 and
+ (codes is None or np.all(codes <= Path.LINETO))))
self.has_nonfinite = not np.isfinite(vertices).all()
self.codes = codes
self.vertices = vertices
Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-12-29 14:25:47 UTC (rev 6711)
+++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-12-29 14:42:20 UTC (rev 6712)
@@ -518,7 +518,7 @@
'docstring.hardcopy' : [False, validate_bool], # set this when you want to generate hardcopy docstring
'plugins.directory' : ['.matplotlib_plugins', str], # where plugin directory is locate
- 'path.simplify' : [False, validate_bool],
+ 'path.simplify' : [True, validate_bool],
'agg.path.chunksize' : [0, validate_int] # 0 to disable chunking;
# recommend about 20000 to
# enable. Experimental.
Modified: trunk/matplotlib/src/agg_py_path_iterator.h
===================================================================
--- trunk/matplotlib/src/agg_py_path_iterator.h 2008-12-29 14:25:47 UTC (rev 6711)
+++ trunk/matplotlib/src/agg_py_path_iterator.h 2008-12-29 14:42:20 UTC (rev 6712)
@@ -353,7 +353,7 @@
//if the perp vector is less than some number of (squared)
//pixels in size, then merge the current vector
- if (perpdNorm2 < 0.25)
+ if (perpdNorm2 < (1.0 / 9.0))
{
//check if the current vector is parallel or
//anti-parallel to the orig vector. If it is parallel, test
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-29 15:34:33
|
Revision: 6716
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6716&view=rev
Author: mdboom
Date: 2008-12-29 15:34:30 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Merged revisions 6714-6715 via svnmerge from
https://matplotlib.svn.sf.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6714 | mdboom | 2008-12-29 10:29:52 -0500 (Mon, 29 Dec 2008) | 2 lines
Handle path.simplify rcParam in all backends.
........
r6715 | mdboom | 2008-12-29 10:33:18 -0500 (Mon, 29 Dec 2008) | 2 lines
Handle path.simplify rcParam in all backends.
........
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/path.py
Property Changed:
----------------
trunk/matplotlib/
trunk/matplotlib/doc/pyplots/README
trunk/matplotlib/doc/sphinxext/gen_gallery.py
trunk/matplotlib/doc/sphinxext/gen_rst.py
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6689
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6715
Modified: svn:mergeinfo
- /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673
+ /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715
Property changes on: trunk/matplotlib/doc/pyplots/README
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673
+ /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715
Property changes on: trunk/matplotlib/doc/sphinxext/gen_gallery.py
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673
+ /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715
Property changes on: trunk/matplotlib/doc/sphinxext/gen_rst.py
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771
+ /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715
Modified: trunk/matplotlib/lib/matplotlib/path.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 15:33:18 UTC (rev 6715)
+++ trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 15:34:30 UTC (rev 6716)
@@ -112,7 +112,7 @@
self.should_simplify = (rcParams['path.simplify'] and
(len(vertices) >= 128 and
- (codes is None or np.all(codes <= Path.LINETO))))
+ (codes is None or np.all(codes <= Path.LINETO))))
self.has_nonfinite = not np.isfinite(vertices).all()
self.codes = codes
self.vertices = vertices
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jo...@us...> - 2008-12-31 13:20:56
|
Revision: 6718
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6718&view=rev
Author: jouni
Date: 2008-12-31 13:20:50 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
Improve pdf usetex by adding support for font effects
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/doc/api/index_backend_api.rst
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
trunk/matplotlib/lib/matplotlib/dviread.py
trunk/matplotlib/lib/matplotlib/type1font.py
Added Paths:
-----------
trunk/matplotlib/doc/api/dviread.rst
trunk/matplotlib/doc/api/type1font.rst
trunk/matplotlib/examples/pylab_examples/usetex_fonteffects.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-30 16:06:59 UTC (rev 6717)
+++ trunk/matplotlib/CHANGELOG 2008-12-31 13:20:50 UTC (rev 6718)
@@ -1,3 +1,6 @@
+2008-12-31 Improve pdf usetex by adding support for font effects
+ (slanting and extending). - JKS
+
2008-12-29 Fix a bug in pdf usetex support, which occurred if the same
Type-1 font was used with different encodings, e.g. with
Minion Pro and MnSymbol. - JKS
Added: trunk/matplotlib/doc/api/dviread.rst
===================================================================
--- trunk/matplotlib/doc/api/dviread.rst (rev 0)
+++ trunk/matplotlib/doc/api/dviread.rst 2008-12-31 13:20:50 UTC (rev 6718)
@@ -0,0 +1,8 @@
+
+:mod:`matplotlib.dviread`
+=========================
+
+.. automodule:: matplotlib.dviread
+ :members:
+ :undoc-members:
+ :show-inheritance:
Modified: trunk/matplotlib/doc/api/index_backend_api.rst
===================================================================
--- trunk/matplotlib/doc/api/index_backend_api.rst 2008-12-30 16:06:59 UTC (rev 6717)
+++ trunk/matplotlib/doc/api/index_backend_api.rst 2008-12-31 13:20:50 UTC (rev 6718)
@@ -8,3 +8,5 @@
backend_gtkagg_api.rst
backend_qt4agg_api.rst
backend_wxagg_api.rst
+ dviread.rst
+ type1font.rst
Added: trunk/matplotlib/doc/api/type1font.rst
===================================================================
--- trunk/matplotlib/doc/api/type1font.rst (rev 0)
+++ trunk/matplotlib/doc/api/type1font.rst 2008-12-31 13:20:50 UTC (rev 6718)
@@ -0,0 +1,8 @@
+
+:mod:`matplotlib.type1font`
+===========================
+
+.. automodule:: matplotlib.type1font
+ :members:
+ :undoc-members:
+ :show-inheritance:
Added: trunk/matplotlib/examples/pylab_examples/usetex_fonteffects.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/usetex_fonteffects.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/usetex_fonteffects.py 2008-12-31 13:20:50 UTC (rev 6718)
@@ -0,0 +1,22 @@
+# This script demonstrates that font effects specified in your pdftex.map
+# are now supported in pdf usetex.
+
+import matplotlib
+matplotlib.rc('text', usetex=True)
+import pylab
+
+def setfont(font):
+ return r'\font\a %s at 14pt\a ' % font
+
+for y, font, text in zip(range(5),
+ ['ptmr8r', 'ptmri8r', 'ptmro8r', 'ptmr8rn', 'ptmrr8re'],
+ ['Nimbus Roman No9 L ' + x for x in
+ ['', 'Italics (real italics for comparison)',
+ '(slanted)', '(condensed)', '(extended)']]):
+ pylab.text(0, y, setfont(font) + text)
+
+pylab.ylim(-1, 5)
+pylab.xlim(-0.2, 0.6)
+pylab.setp(pylab.gca(), frame_on=False, xticks=(), yticks=())
+pylab.title('Usetex font effects')
+pylab.savefig('usetex_fonteffects.pdf')
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-30 16:06:59 UTC (rev 6717)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-31 13:20:50 UTC (rev 6718)
@@ -500,7 +500,7 @@
# from pdf.use14corefonts
fontdictObject = self._write_afm_font(filename)
elif self.dviFontInfo.has_key(filename):
- # a Type 1 font from a dvi file
+ # a Type 1 font from a dvi file; the filename is really the TeX name
fontdictObject = self.embedType1(filename, self.dviFontInfo[filename])
else:
# a normal TrueType font
@@ -525,22 +525,25 @@
return fontdictObject
def embedType1(self, texname, fontinfo):
- # TODO: font effects such as SlantFont
matplotlib.verbose.report(
- 'Embedding Type 1 font ' + fontinfo.fontfile +
- ' with encoding ' + (fontinfo.encodingfile or '(none)'),
+ 'Embedding ' + texname +
+ ' which is the Type 1 font ' + fontinfo.fontfile +
+ ' with encoding ' + (fontinfo.encodingfile or '(none)') +
+ ' and effects ' + `fontinfo.effects`,
'debug')
- # Use FT2Font to get several font properties
- font = FT2Font(fontinfo.fontfile)
+ t1font = type1font.Type1Font(fontinfo.fontfile)
+ if fontinfo.effects:
+ t1font = t1font.transform(fontinfo.effects)
# Font descriptors may be shared between differently encoded
# Type-1 fonts, so only create a new descriptor if there is no
# existing descriptor for this font.
- fontdesc = self.type1Descriptors.get(fontinfo.fontfile)
+ effects = (fontinfo.effects.get('slant', 0.0), fontinfo.effects.get('extend', 1.0))
+ fontdesc = self.type1Descriptors.get((fontinfo.fontfile, effects))
if fontdesc is None:
- fontdesc = self.createType1Descriptor(font, fontinfo.fontfile)
- self.type1Descriptors[fontinfo.fontfile] = fontdesc
+ fontdesc = self.createType1Descriptor(t1font, fontinfo.fontfile)
+ self.type1Descriptors[(fontinfo.fontfile, effects)] = fontdesc
# Widths
widthsObject = self.reserveObject('font widths')
@@ -551,7 +554,7 @@
fontdict = {
'Type': Name('Font'),
'Subtype': Name('Type1'),
- 'BaseFont': Name(font.postscript_name),
+ 'BaseFont': Name(t1font.prop['FontName']),
'FirstChar': 0,
'LastChar': len(fontinfo.widths) - 1,
'Widths': widthsObject,
@@ -571,14 +574,14 @@
self.writeObject(fontdictObject, fontdict)
return fontdictObject
- def createType1Descriptor(self, font, fontfile):
+ def createType1Descriptor(self, t1font, fontfile):
# Create and write the font descriptor and the font file
# of a Type-1 font
fontdescObject = self.reserveObject('font descriptor')
fontfileObject = self.reserveObject('font file')
- _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \
- ul_position, ul_thickness = font.get_ps_font_info()
+ italic_angle = t1font.prop['ItalicAngle']
+ fixed_pitch = t1font.prop['isFixedPitch']
flags = 0
if fixed_pitch: flags |= 1 << 0 # fixed width
@@ -590,18 +593,20 @@
if 0: flags |= 1 << 17 # TODO: small caps
if 0: flags |= 1 << 18 # TODO: force bold
+ ft2font = FT2Font(fontfile)
+
descriptor = {
'Type': Name('FontDescriptor'),
- 'FontName': Name(font.postscript_name),
+ 'FontName': Name(t1font.prop['FontName']),
'Flags': flags,
- 'FontBBox': font.bbox,
+ 'FontBBox': ft2font.bbox,
'ItalicAngle': italic_angle,
- 'Ascent': font.ascender,
- 'Descent': font.descender,
+ 'Ascent': ft2font.ascender,
+ 'Descent': ft2font.descender,
'CapHeight': 1000, # TODO: find this out
'XHeight': 500, # TODO: this one too
'FontFile': fontfileObject,
- 'FontFamily': familyname,
+ 'FontFamily': t1font.prop['FamilyName'],
'StemV': 50, # TODO
# (see also revision 3874; but not all TeX distros have AFM files!)
#'FontWeight': a number where 400 = Regular, 700 = Bold
@@ -609,7 +614,6 @@
self.writeObject(fontdescObject, descriptor)
- t1font = type1font.Type1Font(fontfile)
self.beginStream(fontfileObject.id, None,
{ 'Length1': len(t1font.parts[0]),
'Length2': len(t1font.parts[1]),
@@ -1369,14 +1373,14 @@
self.file.dviFontInfo[dvifont.texname] = Bunch(
fontfile=psfont.filename,
encodingfile=psfont.encoding,
+ effects=psfont.effects,
widths=dvifont.widths,
dvifont=dvifont)
- # TODO: font effects
seq += [['font', pdfname, dvifont.size]]
oldfont = dvifont
seq += [['text', x1, y1, [chr(glyph)], x1+width]]
- # Find consecutive text strings with constant x coordinate and
+ # Find consecutive text strings with constant y coordinate and
# combine into a sequence of strings and kerns, or just one
# string (if any kerns would be less than 0.1 points).
i, curx = 0, 0
Modified: trunk/matplotlib/lib/matplotlib/dviread.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/dviread.py 2008-12-30 16:06:59 UTC (rev 6717)
+++ trunk/matplotlib/lib/matplotlib/dviread.py 2008-12-31 13:20:50 UTC (rev 6718)
@@ -1,12 +1,14 @@
"""
An experimental module for reading dvi files output by TeX. Several
limitations make this not (currently) useful as a general-purpose dvi
-preprocessor.
+preprocessor, but it is currently used by the pdf backend for
+processing usetex text.
Interface::
dvi = Dvi(filename, 72)
- for page in dvi: # iterate over pages
+ # iterate over pages (but only one page is supported for now):
+ for page in dvi:
w, h, d = page.width, page.height, page.descent
for x,y,font,glyph,width in page.text:
fontname = font.texname
@@ -49,7 +51,7 @@
"""
Iterate through the pages of the file.
- Returns (text, pages) pairs, where:
+ Returns (text, boxes) pairs, where:
text is a list of (x, y, fontnum, glyphnum, width) tuples
boxes is a list of (x, y, height, width) tuples
@@ -131,8 +133,8 @@
def _arg(self, nbytes, signed=False):
"""
- Read and return an integer argument "nbytes" long.
- Signedness is determined by the "signed" keyword.
+ Read and return an integer argument *nbytes* long.
+ Signedness is determined by the *signed* keyword.
"""
str = self.file.read(nbytes)
value = ord(str[0])
@@ -144,7 +146,7 @@
def _dispatch(self, byte):
"""
- Based on the opcode "byte", read the correct kinds of
+ Based on the opcode *byte*, read the correct kinds of
arguments from the dvi file and call the method implementing
that opcode with those arguments.
"""
@@ -385,9 +387,27 @@
Object that holds a font's texname and size, supports comparison,
and knows the widths of glyphs in the same units as the AFM file.
There are also internal attributes (for use by dviread.py) that
- are _not_ used for comparison.
+ are *not* used for comparison.
The size is in Adobe points (converted from TeX points).
+
+ .. attribute:: texname
+
+ Name of the font as used internally by TeX and friends. This
+ is usually very different from any external font names, and
+ :class:`dviread.PsfontsMap` can be used to find the external
+ name of the font.
+
+ .. attribute:: size
+
+ Size of the font in Adobe points, converted from the slightly
+ smaller TeX points.
+
+ .. attribute:: widths
+
+ Widths of glyphs in glyph-space units, typically 1/1000ths of
+ the point size.
+
"""
__slots__ = ('texname', 'size', 'widths', '_scale', '_vf', '_tfm')
@@ -532,17 +552,27 @@
A TeX Font Metric file. This implementation covers only the bare
minimum needed by the Dvi class.
- Attributes:
+ .. attribute:: checksum
- checksum: for verifying against dvi file
+ Used for verifying against the dvi file.
- design_size: design size of the font (in what units?)
+ .. attribute:: design_size
- width[i]: width of character \#i, needs to be scaled
- by the factor specified in the dvi file
- (this is a dict because indexing may not start from 0)
+ Design size of the font (in what units?)
- height[i], depth[i]: height and depth of character \#i
+ .. attribute:: width
+
+ Width of each character, needs to be scaled by the factor
+ specified in the dvi file. This is a dict because indexing may
+ not start from 0.
+
+ .. attribute:: height
+
+ Height of each character.
+
+ .. attribute:: depth
+
+ Depth of each character.
"""
__slots__ = ('checksum', 'design_size', 'width', 'height', 'depth')
@@ -581,8 +611,20 @@
class PsfontsMap(object):
"""
A psfonts.map formatted file, mapping TeX fonts to PS fonts.
- Usage: map = PsfontsMap('.../psfonts.map'); map['cmr10']
+ Usage::
+ >>> map = PsfontsMap(find_tex_file('pdftex.map'))
+ >>> entry = map['ptmbo8r']
+ >>> entry.texname
+ 'ptmbo8r'
+ >>> entry.psname
+ 'Times-Bold'
+ >>> entry.encoding
+ '/usr/local/texlive/2008/texmf-dist/fonts/enc/dvips/base/8r.enc'
+ >>> entry.effects
+ {'slant': 0.16700000000000001}
+ >>> entry.filename
+
For historical reasons, TeX knows many Type-1 fonts by different
names than the outside world. (For one thing, the names have to
fit in eight characters.) Also, TeX's native fonts are not Type-1
@@ -594,11 +636,12 @@
file names.
A texmf tree typically includes mapping files called e.g.
- psfonts.map, pdftex.map, dvipdfm.map. psfonts.map is used by
+ psfonts.map, pdftex.map, dvipdfm.map. psfonts.map is used by
dvips, pdftex.map by pdfTeX, and dvipdfm.map by dvipdfm.
- psfonts.map might avoid embedding the 35 PostScript fonts, while
- the pdf-related files perhaps only avoid the "Base 14" pdf fonts.
- But the user may have configured these files differently.
+ psfonts.map might avoid embedding the 35 PostScript fonts (i.e.,
+ have no filename for them, as in the Times-Bold example above),
+ while the pdf-related files perhaps only avoid the "Base 14" pdf
+ fonts. But the user may have configured these files differently.
"""
__slots__ = ('_font',)
@@ -655,10 +698,10 @@
subsetting, but I have no example of << in my TeX installation.
"""
texname, psname = words[:2]
- effects, encoding, filename = [], None, None
+ effects, encoding, filename = '', None, None
for word in words[2:]:
if not word.startswith('<'):
- effects.append(word)
+ effects = word
else:
word = word.lstrip('<')
if word.startswith('['):
@@ -670,6 +713,18 @@
else:
assert filename is None
filename = word
+
+ eff = effects.split()
+ effects = {}
+ try:
+ effects['slant'] = float(eff[eff.index('SlantFont')-1])
+ except ValueError:
+ pass
+ try:
+ effects['extend'] = float(eff[eff.index('ExtendFont')-1])
+ except ValueError:
+ pass
+
self._font[texname] = mpl_cbook.Bunch(
texname=texname, psname=psname, effects=effects,
encoding=encoding, filename=filename)
@@ -733,13 +788,18 @@
def find_tex_file(filename, format=None):
"""
- Call kpsewhich to find a file in the texmf tree.
- If format is not None, it is used as the value for the --format option.
- See the kpathsea documentation for more information.
+ Call :program:`kpsewhich` to find a file in the texmf tree. If
+ *format* is not None, it is used as the value for the
+ :option:`--format` option.
Apparently most existing TeX distributions on Unix-like systems
use kpathsea. I hear MikTeX (a popular distribution on Windows)
doesn't use kpathsea, so what do we do? (TODO)
+
+ .. seealso::
+
+ `Kpathsea documentation <http://www.tug.org/kpathsea/>`_
+ The library that :program:`kpsewhich` is part of.
"""
cmd = ['kpsewhich']
Modified: trunk/matplotlib/lib/matplotlib/type1font.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/type1font.py 2008-12-30 16:06:59 UTC (rev 6717)
+++ trunk/matplotlib/lib/matplotlib/type1font.py 2008-12-31 13:20:50 UTC (rev 6718)
@@ -1,37 +1,70 @@
"""
-A class representing a Type 1 font.
+This module contains a class representing a Type 1 font.
-This version merely reads pfa and pfb files and splits them for
-embedding in pdf files. There is no support yet for subsetting or
-anything like that.
+This version reads pfa and pfb files and splits them for embedding in
+pdf files. It also supports SlantFont and ExtendFont transformations,
+similarly to pdfTeX and friends. There is no support yet for
+subsetting.
-Usage (subject to change):
+Usage::
- font = Type1Font(filename)
- clear_part, encrypted_part, finale = font.parts
+ >>> font = Type1Font(filename)
+ >>> clear_part, encrypted_part, finale = font.parts
+ >>> slanted_font = font.transform({'slant': 0.167})
+ >>> extended_font = font.transform({'extend': 1.2})
-Source: Adobe Technical Note #5040, Supporting Downloadable PostScript
-Language Fonts.
+Sources:
-If extending this class, see also: Adobe Type 1 Font Format, Adobe
-Systems Incorporated, third printing, v1.1, 1993. ISBN 0-201-57044-0.
+* Adobe Technical Note #5040, Supporting Downloadable PostScript
+ Language Fonts.
+
+* Adobe Type 1 Font Format, Adobe Systems Incorporated, third printing,
+ v1.1, 1993. ISBN 0-201-57044-0.
"""
+import matplotlib.cbook as cbook
+import cStringIO
+import itertools
+import numpy as np
import re
import struct
class Type1Font(object):
+ """
+ A class representing a Type-1 font, for use by backends.
- def __init__(self, filename):
- file = open(filename, 'rb')
- try:
- data = self._read(file)
- finally:
- file.close()
- self.parts = self._split(data)
- #self._parse()
+ .. attribute:: parts
+ A 3-tuple of the cleartext part, the encrypted part, and the
+ finale of zeros.
+
+ .. attribute:: prop
+
+ A dictionary of font properties.
+ """
+ __slots__ = ('parts', 'prop')
+
+ def __init__(self, input):
+ """
+ Initialize a Type-1 font. *input* can be either the file name of
+ a pfb file or a 3-tuple of already-decoded Type-1 font parts.
+ """
+ if isinstance(input, tuple) and len(input) == 3:
+ self.parts = input
+ else:
+ file = open(input, 'rb')
+ try:
+ data = self._read(file)
+ finally:
+ file.close()
+ self.parts = self._split(data)
+
+ self._parse()
+
def _read(self, file):
+ """
+ Read the font from a file, decoding into usable parts.
+ """
rawdata = file.read()
if not rawdata.startswith(chr(128)):
return rawdata
@@ -100,85 +133,177 @@
return data[:len1], binary, data[idx:]
_whitespace = re.compile(r'[\0\t\r\014\n ]+')
- _delim = re.compile(r'[()<>[]{}/%]')
_token = re.compile(r'/{0,2}[^]\0\t\r\v\n ()<>{}/%[]+')
_comment = re.compile(r'%[^\r\n\v]*')
_instring = re.compile(r'[()\\]')
- def _parse(self):
+ @classmethod
+ def _tokens(cls, text):
"""
- A very limited kind of parsing to find the Encoding of the
- font.
+ A PostScript tokenizer. Yield (token, value) pairs such as
+ ('whitespace', ' ') or ('name', '/Foobar').
"""
- def tokens(text):
- """
- Yield pairs (position, token), ignoring comments and
- whitespace. Numbers count as tokens.
- """
- pos = 0
- while pos < len(text):
- match = self._comment.match(text[pos:]) or self._whitespace.match(text[pos:])
+ pos = 0
+ while pos < len(text):
+ match = cls._comment.match(text[pos:]) or cls._whitespace.match(text[pos:])
+ if match:
+ yield ('whitespace', match.group())
+ pos += match.end()
+ elif text[pos] == '(':
+ start = pos
+ pos += 1
+ depth = 1
+ while depth:
+ match = cls._instring.search(text[pos:])
+ if match is None: return
+ pos += match.end()
+ if match.group() == '(':
+ depth += 1
+ elif match.group() == ')':
+ depth -= 1
+ else: # a backslash - skip the next character
+ pos += 1
+ yield ('string', text[start:pos])
+ elif text[pos:pos+2] in ('<<', '>>'):
+ yield ('delimiter', text[pos:pos+2])
+ pos += 2
+ elif text[pos] == '<':
+ start = pos
+ pos += text[pos:].index('>')
+ yield ('string', text[start:pos])
+ else:
+ match = cls._token.match(text[pos:])
if match:
+ try:
+ float(match.group())
+ yield ('number', match.group())
+ except ValueError:
+ yield ('name', match.group())
pos += match.end()
- elif text[pos] == '(':
- start = pos
+ else:
+ yield ('delimiter', text[pos])
pos += 1
- depth = 1
- while depth:
- match = self._instring.search(text[pos:])
- if match is None: return
- if match.group() == '(':
- depth += 1
- pos += 1
- elif match.group() == ')':
- depth -= 1
- pos += 1
- else:
- pos += 2
- yield (start, text[start:pos])
- elif text[pos:pos+2] in ('<<', '>>'):
- yield (pos, text[pos:pos+2])
- pos += 2
- elif text[pos] == '<':
- start = pos
- pos += text[pos:].index('>')
- yield (start, text[start:pos])
- else:
- match = self._token.match(text[pos:])
- if match:
- yield (pos, match.group())
- pos += match.end()
+
+ def _parse(self):
+ """
+ Find the values of various font properties. This limited kind
+ of parsing is described in Chapter 10 "Adobe Type Manager
+ Compatibility" of the Type-1 spec.
+ """
+ # Start with reasonable defaults
+ prop = { 'weight': 'Regular', 'ItalicAngle': 0.0, 'isFixedPitch': False,
+ 'UnderlinePosition': -100, 'UnderlineThickness': 50 }
+ tokenizer = self._tokens(self.parts[0])
+ filtered = itertools.ifilter(lambda x: x[0] != 'whitespace', tokenizer)
+ for token, value in filtered:
+ if token == 'name' and value.startswith('/'):
+ key = value[1:]
+ token, value = filtered.next()
+ if token == 'name':
+ if value in ('true', 'false'):
+ value = value == 'true'
else:
- yield (pos, text[pos])
- pos += 1
+ value = value.lstrip('/')
+ elif token == 'string':
+ value = value.lstrip('(').rstrip(')')
+ elif token == 'number':
+ if '.' in value: value = float(value)
+ else: value = int(value)
+ else: # more complicated value such as an array
+ value = None
+ if key != 'FontInfo' and value is not None:
+ prop[key] = value
- enc_starts, enc_ends = None, None
- state = 0
- # State transitions:
- # 0 -> /Encoding -> 1
- # 1 -> StandardEncoding -> 2 -> def -> (ends)
- # 1 -> dup -> 4 -> put -> 5
- # 5 -> dup -> 4 -> put -> 5
- # 5 -> def -> (ends)
- for pos,token in tokens(self.parts[0]):
- if state == 0 and token == '/Encoding':
- enc_starts = pos
- state = 1
- elif state == 1 and token == 'StandardEncoding':
- state = 2
- elif state in (2,5) and token == 'def':
- enc_ends = pos+3
- break
- elif state in (1,5) and token == 'dup':
- state = 4
- elif state == 4 and token == 'put':
- state = 5
- self.enc_starts, self.enc_ends = enc_starts, enc_ends
+ # Fill in the various *Name properties
+ if not prop.has_key('FontName'):
+ prop['FontName'] = prop.get('FullName') or prop.get('FamilyName') or 'Unknown'
+ if not prop.has_key('FullName'):
+ prop['FullName'] = prop['FontName']
+ if not prop.has_key('FamilyName'):
+ extras = r'(?i)([ -](regular|plain|italic|oblique|(semi)?bold|(ultra)?light|extra|condensed))+$'
+ prop['FamilyName'] = re.sub(extras, '', prop['FullName'])
+ self.prop = prop
+
+ @classmethod
+ def _transformer(cls, tokens, slant, extend):
+ def fontname(name):
+ result = name
+ if slant: result += '_Slant_' + str(int(1000*slant))
+ if extend != 1.0: result += '_Extend_' + str(int(1000*extend))
+ return result
+
+ def italicangle(angle):
+ return str(float(angle) - np.arctan(slant)/np.pi*180)
+
+ def fontmatrix(array):
+ array = array.lstrip('[').rstrip(']').strip().split()
+ array = [ float(x) for x in array ]
+ oldmatrix = np.eye(3,3)
+ oldmatrix[0:3,0] = array[::2]
+ oldmatrix[0:3,1] = array[1::2]
+ modifier = np.array([[extend, 0, 0],
+ [slant, 1, 0],
+ [0, 0, 1]])
+ newmatrix = np.dot(modifier, oldmatrix)
+ array[::2] = newmatrix[0:3,0]
+ array[1::2] = newmatrix[0:3,1]
+ return '[' + ' '.join(str(x) for x in array) + ']'
+
+ def replace(fun):
+ def replacer(tokens):
+ token, value = tokens.next() # name, e.g. /FontMatrix
+ yield value
+ token, value = tokens.next() # possible whitespace
+ while token == 'whitespace':
+ yield value
+ token, value = tokens.next()
+ if value != '[': # name/number/etc.
+ yield fun(value)
+ else: # array, e.g. [1 2 3]
+ array = []
+ while value != ']':
+ array += value
+ token, value = tokens.next()
+ array += value
+ yield fun(''.join(array))
+ return replacer
+
+ def suppress(tokens):
+ for x in itertools.takewhile(lambda x: x[1] != 'def', tokens):
+ pass
+ yield ''
+
+ table = { '/FontName': replace(fontname),
+ '/ItalicAngle': replace(italicangle),
+ '/FontMatrix': replace(fontmatrix),
+ '/UniqueID': suppress }
+
+ while True:
+ token, value = tokens.next()
+ if token == 'name' and value in table:
+ for value in table[value](itertools.chain([(token, value)], tokens)):
+ yield value
+ else:
+ yield value
+
+ def transform(self, effects):
+ """
+ Transform the font by slanting or extending. *effects* should
+ be a dict where ``effects['slant']`` is the tangent of the
+ angle that the font is to be slanted to the right (so negative
+ values slant to the left) and ``effects['extend']`` is the
+ multiplier by which the font is to be extended (so values less
+ than 1.0 condense). Returns a new :class:`Type1Font` object.
+ """
+
+ buffer = cStringIO.StringIO()
+ tokenizer = self._tokens(self.parts[0])
+ for value in self._transformer(tokenizer,
+ slant=effects.get('slant', 0.0),
+ extend=effects.get('extend', 1.0)):
+ buffer.write(value)
+ result = buffer.getvalue()
+ buffer.close()
+
+ return Type1Font((result, self.parts[1], self.parts[2]))
-if __name__ == '__main__':
- import sys
- font = Type1Font(sys.argv[1])
- parts = font.parts
- print len(parts[0]), len(parts[1]), len(parts[2])
- #print parts[0][font.enc_starts:font.enc_ends]
-
This was sent by the SourceForge.net coll...
[truncated message content] |
|
From: <jo...@us...> - 2009-01-01 22:24:03
|
Revision: 6730
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6730&view=rev
Author: jouni
Date: 2009-01-01 22:23:57 +0000 (Thu, 01 Jan 2009)
Log Message:
-----------
Allow multipage pdf files
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
Added Paths:
-----------
trunk/matplotlib/examples/pylab_examples/multipage_pdf.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-31 20:19:16 UTC (rev 6729)
+++ trunk/matplotlib/CHANGELOG 2009-01-01 22:23:57 UTC (rev 6730)
@@ -1,3 +1,5 @@
+2009-01-02 Allow multipage pdf files. - JKS
+
2008-12-31 Improve pdf usetex by adding support for font effects
(slanting and extending). - JKS
Added: trunk/matplotlib/examples/pylab_examples/multipage_pdf.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/multipage_pdf.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/multipage_pdf.py 2009-01-01 22:23:57 UTC (rev 6730)
@@ -0,0 +1,29 @@
+import numpy as np
+import matplotlib
+from matplotlib.backends.backend_pdf import PdfFile
+from pylab import *
+
+pdf = PdfFile('multipage_pdf.pdf')
+
+figure(figsize=(3,3))
+plot(range(7), [3,1,4,1,5,9,2], 'r-o')
+title('Page One')
+savefig(pdf, format='pdf')
+close()
+
+rc('text', usetex=True)
+figure(figsize=(8,6))
+x = np.arange(0,5,0.1)
+plot(x, np.sin(x), 'b-')
+title('Page Two')
+savefig(pdf, format='pdf')
+close()
+
+rc('text', usetex=False)
+figure(figsize=(4,5))
+plot(x, x*x, 'ko')
+title('Page Three')
+savefig(pdf, format='pdf')
+close()
+
+pdf.close()
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-31 20:19:16 UTC (rev 6729)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-01 22:23:57 UTC (rev 6730)
@@ -219,6 +219,9 @@
def __repr__(self):
return "<Name %s>" % self.name
+ def __str__(self):
+ return '/' + self.name
+
@staticmethod
def hexify(match):
return '#%02x' % ord(match.group())
@@ -336,13 +339,7 @@
class PdfFile(object):
"""PDF file with one page."""
- def __init__(self, width, height, dpi, filename):
- self.width, self.height = width, height
- self.dpi = dpi
- if rcParams['path.simplify']:
- self.simplify = (width * dpi, height * dpi)
- else:
- self.simplify = None
+ def __init__(self, filename):
self.nextObject = 1 # next free object id
self.xrefTable = [ [0, 65535, 'the zero object'] ]
self.passed_in_file_object = False
@@ -364,17 +361,16 @@
self.rootObject = self.reserveObject('root')
self.infoObject = self.reserveObject('info')
- pagesObject = self.reserveObject('pages')
- thePageObject = self.reserveObject('page 0')
- contentObject = self.reserveObject('contents of page 0')
+ self.pagesObject = self.reserveObject('pages')
+ self.pageList = []
self.fontObject = self.reserveObject('fonts')
self.alphaStateObject = self.reserveObject('extended graphics states')
self.hatchObject = self.reserveObject('tiling patterns')
self.XObjectObject = self.reserveObject('external objects')
- resourceObject = self.reserveObject('resources')
+ self.resourceObject = self.reserveObject('resources')
root = { 'Type': Name('Catalog'),
- 'Pages': pagesObject }
+ 'Pages': self.pagesObject }
self.writeObject(self.rootObject, root)
info = { 'Creator': 'matplotlib ' + __version__ \
@@ -385,23 +381,12 @@
# Possible TODO: Title, Author, Subject, Keywords
self.writeObject(self.infoObject, info)
- pages = { 'Type': Name('Pages'),
- 'Kids': [ thePageObject ],
- 'Count': 1 }
- self.writeObject(pagesObject, pages)
-
- thePage = { 'Type': Name('Page'),
- 'Parent': pagesObject,
- 'Resources': resourceObject,
- 'MediaBox': [ 0, 0, dpi*width, dpi*height ],
- 'Contents': contentObject }
- self.writeObject(thePageObject, thePage)
-
self.fontNames = {} # maps filenames to internal font names
self.nextFont = 1 # next free internal font name
self.dviFontInfo = {} # information on dvi fonts
self.type1Descriptors = {} # differently encoded Type-1 fonts may
# share the same descriptor
+ self.used_characters = {}
self.alphaStates = {} # maps alpha values to graphics state objects
self.nextAlphaState = 1
@@ -426,16 +411,32 @@
'ExtGState': self.alphaStateObject,
'Pattern': self.hatchObject,
'ProcSet': procsets }
- self.writeObject(resourceObject, resources)
+ self.writeObject(self.resourceObject, resources)
- # Start the content stream of the page
+ def newPage(self, width, height):
+ self.endStream()
+
+ self.width, self.height = width, height
+ if rcParams['path.simplify']:
+ self.simplify = (width * 72, height * 72)
+ else:
+ self.simplify = None
+ contentObject = self.reserveObject('page contents')
+ thePage = { 'Type': Name('Page'),
+ 'Parent': self.pagesObject,
+ 'Resources': self.resourceObject,
+ 'MediaBox': [ 0, 0, 72*width, 72*height ],
+ 'Contents': contentObject }
+ pageObject = self.reserveObject('page')
+ self.writeObject(pageObject, thePage)
+ self.pageList.append(pageObject)
+
self.beginStream(contentObject.id,
self.reserveObject('length of content stream'))
def close(self):
- # End the content stream and write out the various deferred
- # objects
self.endStream()
+ # Write out the various deferred objects
self.writeFonts()
self.writeObject(self.alphaStateObject,
dict([(val[0], val[1])
@@ -449,6 +450,12 @@
self.writeObject(self.XObjectObject, xobjects)
self.writeImages()
self.writeMarkers()
+ self.writeObject(self.pagesObject,
+ { 'Type': Name('Pages'),
+ 'Kids': self.pageList,
+ 'Count': len(self.pageList) })
+
+ # Finalize the file
self.writeXref()
self.writeTrailer()
if self.passed_in_file_object:
@@ -471,8 +478,9 @@
self.currentstream = Stream(id, len, self, extra)
def endStream(self):
- self.currentstream.end()
- self.currentstream = None
+ if self.currentstream is not None:
+ self.currentstream.end()
+ self.currentstream = None
def fontName(self, fontprop):
"""
@@ -493,20 +501,27 @@
Fx = Name('F%d' % self.nextFont)
self.fontNames[filename] = Fx
self.nextFont += 1
+ matplotlib.verbose.report(
+ 'Assigning font %s = %s' % (Fx, filename),
+ 'debug')
return Fx
def writeFonts(self):
fonts = {}
for filename, Fx in self.fontNames.items():
+ matplotlib.verbose.report('Embedding font %s' % filename, 'debug')
if filename.endswith('.afm'):
# from pdf.use14corefonts
+ matplotlib.verbose.report('Writing AFM font', 'debug')
fontdictObject = self._write_afm_font(filename)
elif self.dviFontInfo.has_key(filename):
# a Type 1 font from a dvi file; the filename is really the TeX name
+ matplotlib.verbose.report('Writing Type-1 font', 'debug')
fontdictObject = self.embedType1(filename, self.dviFontInfo[filename])
else:
# a normal TrueType font
+ matplotlib.verbose.report('Writing TrueType font', 'debug')
realpath, stat_key = get_realpath_and_stat(filename)
chars = self.used_characters.get(stat_key)
if chars is not None and len(chars[1]):
@@ -1143,8 +1158,7 @@
return cmds
def writePath(self, path, transform):
- cmds = self.pathOperations(
- path, transform, self.simplify)
+ cmds = self.pathOperations(path, transform, self.simplify)
self.output(*cmds)
def reserveObject(self, name=''):
@@ -1198,13 +1212,11 @@
truetype_font_cache = maxdict(50)
afm_font_cache = maxdict(50)
- def __init__(self, file, dpi, image_dpi):
+ def __init__(self, file, image_dpi):
RendererBase.__init__(self)
self.file = file
self.gc = self.new_gc()
- self.file.used_characters = self.used_characters = {}
self.mathtext_parser = MathTextParser("Pdf")
- self.dpi = dpi
self.image_dpi = image_dpi
self.tex_font_map = None
@@ -1235,13 +1247,13 @@
else:
fname = font.fname
realpath, stat_key = get_realpath_and_stat(fname)
- used_characters = self.used_characters.setdefault(
+ used_characters = self.file.used_characters.setdefault(
stat_key, (realpath, set()))
used_characters[1].update([ord(x) for x in s])
def merge_used_characters(self, other):
for stat_key, (realpath, charset) in other.items():
- used_characters = self.used_characters.setdefault(
+ used_characters = self.file.used_characters.setdefault(
stat_key, (realpath, set()))
used_characters[1].update(charset)
@@ -1299,7 +1311,7 @@
def draw_mathtext(self, gc, x, y, s, prop, angle):
# TODO: fix positioning and encoding
width, height, descent, glyphs, rects, used_characters = \
- self.mathtext_parser.parse(s, self.dpi, prop)
+ self.mathtext_parser.parse(s, 72, prop)
self.merge_used_characters(used_characters)
# When using Type 3 fonts, we can't use character codes higher
@@ -1327,7 +1339,6 @@
self._setup_textpos(ox, oy, 0, 0, oldx, oldy)
oldx, oldy = ox, oy
if (fontname, fontsize) != prev_font:
- fontsize *= self.dpi/72.0
self.file.output(self.file.fontName(fontname), fontsize,
Op.selectfont)
prev_font = fontname, fontsize
@@ -1338,7 +1349,6 @@
# as XObjects using the 'Do' command.
if global_fonttype == 3:
for ox, oy, fontname, fontsize, num, symbol_name in glyphs:
- fontsize *= self.dpi/72.0
if is_opentype_cff_font(fontname):
fonttype = 42
else:
@@ -1367,7 +1377,7 @@
texmanager = self.get_texmanager()
fontsize = prop.get_size_in_points()
dvifile = texmanager.make_dvi(s, fontsize)
- dvi = dviread.Dvi(dvifile, self.dpi)
+ dvi = dviread.Dvi(dvifile, 72)
page = iter(dvi).next()
dvi.close()
@@ -1463,7 +1473,7 @@
self.check_gc(gc, gc._rgb)
if ismath: return self.draw_mathtext(gc, x, y, s, prop, angle)
- fontsize = prop.get_size_in_points() * self.dpi/72.0
+ fontsize = prop.get_size_in_points()
if rcParams['pdf.use14corefonts']:
font = self._get_font_afm(prop)
@@ -1593,14 +1603,14 @@
texmanager = self.get_texmanager()
fontsize = prop.get_size_in_points()
dvifile = texmanager.make_dvi(s, fontsize)
- dvi = dviread.Dvi(dvifile, self.dpi)
+ dvi = dviread.Dvi(dvifile, 72)
page = iter(dvi).next()
dvi.close()
# A total height (including the descent) needs to be returned.
return page.width, page.height+page.descent, page.descent
if ismath:
w, h, d, glyphs, rects, used_characters = \
- self.mathtext_parser.parse(s, self.dpi, prop)
+ self.mathtext_parser.parse(s, 72, prop)
elif rcParams['pdf.use14corefonts']:
font = self._get_font_afm(prop)
@@ -1645,14 +1655,14 @@
self.truetype_font_cache[filename] = font
self.truetype_font_cache[key] = font
font.clear()
- font.set_size(prop.get_size_in_points(), self.dpi)
+ font.set_size(prop.get_size_in_points(), 72)
return font
def flipy(self):
return False
def get_canvas_width_height(self):
- return self.file.width / self.dpi, self.file.height / self.dpi
+ return self.file.width / 72.0, self.file.height / 72.0
def new_gc(self):
return GraphicsContextPdf(self.file)
@@ -1887,16 +1897,22 @@
return 'pdf'
def print_pdf(self, filename, **kwargs):
- ppi = 72 # Postscript points in an inch
image_dpi = kwargs.get('dpi', 72) # dpi to use for images
- self.figure.set_dpi(ppi)
+ self.figure.set_dpi(72) # there are 72 pdf points to an inch
width, height = self.figure.get_size_inches()
- file = PdfFile(width, height, ppi, filename)
+ if isinstance(filename, PdfFile):
+ file = filename
+ else:
+ file = PdfFile(filename)
+ file.newPage(width, height)
renderer = MixedModeRenderer(
- width, height, ppi, RendererPdf(file, ppi, image_dpi))
+ width, height, 72, RendererPdf(file, image_dpi))
self.figure.draw(renderer)
renderer.finalize()
- file.close()
+ if file != filename: # we opened the file
+ file.close()
+ else: # multipage file; just finish off the page
+ file.endStream()
class FigureManagerPdf(FigureManagerBase):
pass
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2009-01-02 17:56:26
|
Revision: 6733
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6733&view=rev
Author: mdboom
Date: 2009-01-02 17:56:15 +0000 (Fri, 02 Jan 2009)
Log Message:
-----------
Merged revisions 6717,6732 via svnmerge from
https://matplotlib.svn.sf.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6717 | jdh2358 | 2008-12-30 11:06:59 -0500 (Tue, 30 Dec 2008) | 1 line
added rcparams import to path
........
r6732 | efiring | 2009-01-02 12:13:37 -0500 (Fri, 02 Jan 2009) | 2 lines
Backport r6731 polar fixes from trunk.
........
Property Changed:
----------------
trunk/matplotlib/
trunk/matplotlib/doc/pyplots/README
trunk/matplotlib/doc/sphinxext/gen_gallery.py
trunk/matplotlib/doc/sphinxext/gen_rst.py
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6715
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6732
Modified: svn:mergeinfo
- /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715
+ /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732
Property changes on: trunk/matplotlib/doc/pyplots/README
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715
+ /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732
Property changes on: trunk/matplotlib/doc/sphinxext/gen_gallery.py
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715
+ /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732
Property changes on: trunk/matplotlib/doc/sphinxext/gen_rst.py
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715
+ /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <lee...@us...> - 2009-01-05 05:29:01
|
Revision: 6734
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6734&view=rev
Author: leejjoon
Date: 2009-01-05 05:28:57 +0000 (Mon, 05 Jan 2009)
Log Message:
-----------
optional use of preview.sty in usetex mode
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template
trunk/matplotlib/lib/matplotlib/rcsetup.py
trunk/matplotlib/lib/matplotlib/texmanager.py
Added Paths:
-----------
trunk/matplotlib/examples/pylab_examples/usetex_baseline_test.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-02 17:56:15 UTC (rev 6733)
+++ trunk/matplotlib/CHANGELOG 2009-01-05 05:28:57 UTC (rev 6734)
@@ -1,3 +1,5 @@
+2009-01-05 optional use of preview.sty in usetex mode. - JJL
+
2009-01-02 Allow multipage pdf files. - JKS
2008-12-31 Improve pdf usetex by adding support for font effects
Added: trunk/matplotlib/examples/pylab_examples/usetex_baseline_test.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/usetex_baseline_test.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/usetex_baseline_test.py 2009-01-05 05:28:57 UTC (rev 6734)
@@ -0,0 +1,76 @@
+
+import matplotlib
+import matplotlib.pyplot as plt
+import matplotlib.axes as maxes
+
+class Axes(maxes.Axes):
+ """
+ A hackish way to simultaneously draw texts w/ usetex=True and
+ usetex=False in the same figure. It does not work in the ps backend.
+ """
+ def __init__(self, *kl, **kw):
+ self.usetex = kw.pop("usetex", "False")
+ self.preview = kw.pop("preview", "False")
+
+ maxes.Axes.__init__(self, *kl, **kw)
+
+ def draw(self, renderer):
+ usetex = plt.rcParams["text.usetex"]
+ preview = plt.rcParams["text.latex.preview"]
+ plt.rcParams["text.usetex"] = self.usetex
+ plt.rcParams["text.latex.preview"] = self.preview
+
+ maxes.Axes.draw(self, renderer)
+
+ plt.rcParams["text.usetex"] = usetex
+ plt.rcParams["text.latex.preview"] = preview
+
+Subplot = maxes.subplot_class_factory(Axes)
+
+
+def test_window_extent(ax, usetex, preview):
+
+ va = "baseline"
+ ax.xaxis.set_visible(False)
+ ax.yaxis.set_visible(False)
+
+
+ #t = ax.text(0., 0., r"mlp", va="baseline", size=150)
+ text_kw = dict(va=va,
+ size=50,
+ bbox=dict(pad=0., ec="k", fc="none"))
+
+
+ test_strings = ["lg", r"$\frac{1}{2}\pi$",
+ r"$p^{3^A}$", r"$p_{3_2}$"]
+
+ ax.axvline(0, color="r")
+
+ for i, s in enumerate(test_strings):
+
+ ax.axhline(i, color="r")
+ ax.text(0., 3-i, s, **text_kw)
+
+ ax.set_xlim(-0.1,1.1)
+ ax.set_ylim(-.8,3.9)
+
+
+ ax.set_title("usetex=%s\npreview=%s" % (str(usetex), str(preview)))
+
+
+
+F = plt.figure(figsize=(2.*3,6.5))
+
+for i, usetex, preview in [[0, False, False],
+ [1, True, False],
+ [2, True, True]]:
+ ax = Subplot(F, 1, 3, i+1, usetex=usetex, preview=preview)
+ F.add_subplot(ax)
+ F.subplots_adjust(top=0.85)
+
+ test_window_extent(ax, usetex=usetex, preview=preview)
+
+
+plt.draw()
+plt.show()
+
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2009-01-02 17:56:15 UTC (rev 6733)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2009-01-05 05:28:57 UTC (rev 6734)
@@ -146,10 +146,10 @@
# todo: handle props
size = prop.get_size_in_points()
texmanager = self.get_texmanager()
- Z = texmanager.get_grey(s, size, self.dpi)
- m,n = Z.shape
- # TODO: descent of TeX text (I am imitating backend_ps here -JKS)
- return n, m, 0
+ fontsize = prop.get_size_in_points()
+ w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
+ renderer=self)
+ return w, h, d
if ismath:
ox, oy, width, height, descent, fonts, used_characters = \
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-02 17:56:15 UTC (rev 6733)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-05 05:28:57 UTC (rev 6734)
@@ -612,7 +612,7 @@
if 0: flags |= 1 << 18 # TODO: force bold
ft2font = FT2Font(fontfile)
-
+
descriptor = {
'Type': Name('FontDescriptor'),
'FontName': Name(t1font.prop['FontName']),
@@ -1602,12 +1602,10 @@
if rcParams['text.usetex']:
texmanager = self.get_texmanager()
fontsize = prop.get_size_in_points()
- dvifile = texmanager.make_dvi(s, fontsize)
- dvi = dviread.Dvi(dvifile, 72)
- page = iter(dvi).next()
- dvi.close()
- # A total height (including the descent) needs to be returned.
- return page.width, page.height+page.descent, page.descent
+ w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
+ renderer=self)
+ return w, h, d
+
if ismath:
w, h, d, glyphs, rects, used_characters = \
self.mathtext_parser.parse(s, 72, prop)
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2009-01-02 17:56:15 UTC (rev 6733)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2009-01-05 05:28:57 UTC (rev 6734)
@@ -274,12 +274,9 @@
if rcParams['text.usetex']:
texmanager = self.get_texmanager()
fontsize = prop.get_size_in_points()
- l,b,r,t = texmanager.get_ps_bbox(s, fontsize)
- w = (r-l)
- h = (t-b)
- # TODO: We need a way to get a good baseline from
- # text.usetex
- return w, h, 0
+ w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
+ renderer=self)
+ return w, h, d
if ismath:
width, height, descent, pswriter, used_characters = \
Modified: trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template
===================================================================
--- trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template 2009-01-02 17:56:15 UTC (rev 6733)
+++ trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template 2009-01-05 05:28:57 UTC (rev 6734)
@@ -357,6 +357,8 @@
preamble = []
# a boolean
unicode = False
+ # a boolean
+ preview = False
[verbose]
# a file name or 'sys.stdout'
Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/rcsetup.py 2009-01-02 17:56:15 UTC (rev 6733)
+++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2009-01-05 05:28:57 UTC (rev 6734)
@@ -386,6 +386,7 @@
'text.usetex' : [False, validate_bool],
'text.latex.unicode' : [False, validate_bool],
'text.latex.preamble' : [[''], validate_stringlist],
+ 'text.latex.preview' : [False, validate_bool],
'text.dvipnghack' : [None, validate_bool_maybe_none],
'text.fontstyle' : ['normal', str],
'text.fontangle' : ['normal', str],
Modified: trunk/matplotlib/lib/matplotlib/texmanager.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/texmanager.py 2009-01-02 17:56:15 UTC (rev 6733)
+++ trunk/matplotlib/lib/matplotlib/texmanager.py 2009-01-05 05:28:57 UTC (rev 6734)
@@ -45,6 +45,8 @@
import matplotlib as mpl
from matplotlib import rcParams
from matplotlib._png import read_png
+import matplotlib.dviread as dviread
+import re
DEBUG = False
@@ -262,12 +264,83 @@
return texfile
+
+ _re_vbox = re.compile(r"MatplotlibBox:\(([\d.]+)pt\+([\d.]+)pt\)x([\d.]+)pt")
+
+ def make_tex_preview(self, tex, fontsize):
+ """
+ Generate a tex file to render the tex string at a specific
+ font size. It uses the preview.sty to determin the dimension
+ (width, height, descent) of the output.
+
+ returns the file name
+ """
+ basefile = self.get_basefile(tex, fontsize)
+ texfile = '%s.tex'%basefile
+ fh = file(texfile, 'w')
+ custom_preamble = self.get_custom_preamble()
+ fontcmd = {'sans-serif' : r'{\sffamily %s}',
+ 'monospace' : r'{\ttfamily %s}'}.get(self.font_family,
+ r'{\rmfamily %s}')
+ tex = fontcmd % tex
+
+ if rcParams['text.latex.unicode']:
+ unicode_preamble = """\usepackage{ucs}
+\usepackage[utf8x]{inputenc}"""
+ else:
+ unicode_preamble = ''
+
+
+
+ # newbox, setbox, immediate, etc. are used to find the box
+ # extent of the rendered text.
+
+
+ s = r"""\documentclass{article}
+%s
+%s
+%s
+\usepackage[active,showbox,tightpage]{preview}
+%%\usepackage[papersize={72in,72in}, body={70in,70in}, margin={1in,1in}]{geometry}
+
+%% we override the default showbox as it is treated as an error and makes
+%% the exit status not zero
+\def\showbox#1{\immediate\write16{MatplotlibBox:(\the\ht#1+\the\dp#1)x\the\wd#1}}
+
+\begin{document}
+\begin{preview}
+{\fontsize{%f}{%f}%s}
+\end{preview}
+\end{document}
+""" % (self._font_preamble, unicode_preamble, custom_preamble,
+ fontsize, fontsize*1.25, tex)
+ if rcParams['text.latex.unicode']:
+ fh.write(s.encode('utf8'))
+ else:
+ try:
+ fh.write(s)
+ except UnicodeEncodeError, err:
+ mpl.verbose.report("You are using unicode and latex, but have "
+ "not enabled the matplotlib 'text.latex.unicode' "
+ "rcParam.", 'helpful')
+ raise
+
+ fh.close()
+
+ return texfile
+
+
def make_dvi(self, tex, fontsize):
"""
generates a dvi file containing latex's layout of tex string
returns the file name
"""
+
+
+ if rcParams['text.latex.preview']:
+ return self.make_dvi_preview(tex, fontsize)
+
basefile = self.get_basefile(tex, fontsize)
dvifile = '%s.dvi'% basefile
@@ -298,6 +371,55 @@
return dvifile
+
+ def make_dvi_preview(self, tex, fontsize):
+ """
+ generates a dvi file containing latex's layout of tex
+ string. It calls make_tex_preview() method and store the size
+ information (width, height, descent) in a separte file.
+
+ returns the file name
+ """
+ basefile = self.get_basefile(tex, fontsize)
+ dvifile = '%s.dvi'% basefile
+ baselinefile = '%s.baseline'% basefile
+
+ if DEBUG or not os.path.exists(dvifile) or \
+ not os.path.exists(baselinefile):
+ texfile = self.make_tex_preview(tex, fontsize)
+ outfile = basefile+'.output'
+ command = self._get_shell_cmd('cd "%s"'% self.texcache,
+ 'latex -interaction=nonstopmode %s > "%s"'\
+ %(os.path.split(texfile)[-1], outfile))
+ mpl.verbose.report(command, 'debug')
+ exit_status = os.system(command)
+ try:
+ fh = file(outfile)
+ report = fh.read()
+ fh.close()
+
+ except IOError:
+ report = 'No latex error report available.'
+ if exit_status:
+ raise RuntimeError(('LaTeX was not able to process the following \
+string:\n%s\nHere is the full report generated by LaTeX: \n\n'% repr(tex)) + report)
+ else: mpl.verbose.report(report, 'debug')
+
+ # find the box extent information in the latex output
+ # file and store them in ".baseline" file
+ m = TexManager._re_vbox.search(report)
+ open(basefile+'.baseline',"w").write(" ".join(m.groups()))
+
+ for fname in glob.glob(basefile+'*'):
+ if fname.endswith('dvi'): pass
+ elif fname.endswith('tex'): pass
+ elif fname.endswith('baseline'): pass
+ else:
+ try: os.remove(fname)
+ except OSError: pass
+
+ return dvifile
+
def make_png(self, tex, fontsize, dpi):
"""
generates a png file containing latex's rendering of tex string
@@ -441,3 +563,37 @@
self.rgba_arrayd[key] = Z
return Z
+
+
+ def get_text_width_height_descent(self, tex, fontsize, renderer=None):
+ """
+ return width, heigth and descent of the text.
+ """
+
+ if renderer:
+ dpi_fraction = renderer.points_to_pixels(1.)
+ else:
+ dpi_fraction = 1.
+
+ if rcParams['text.latex.preview']:
+ # use preview.sty
+ basefile = self.get_basefile(tex, fontsize)
+ baselinefile = '%s.baseline'% basefile
+
+
+ if DEBUG or not os.path.exists(baselinefile):
+ dvifile = self.make_dvi_preview(tex, fontsize)
+
+ l = open(baselinefile).read().split()
+ height, depth, width = [float(l1)*dpi_fraction for l1 in l]
+ return width, height+depth, depth
+
+ else:
+ # use dviread. It sometimes returns a wrong descent.
+ dvifile = self.make_dvi(tex, fontsize)
+ dvi = dviread.Dvi(dvifile, 72*dpi_fraction)
+ page = iter(dvi).next()
+ dvi.close()
+ # A total height (including the descent) needs to be returned.
+ return page.width, page.height+page.descent, page.descent
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jo...@us...> - 2009-01-05 17:48:05
|
Revision: 6737
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6737&view=rev
Author: jouni
Date: 2009-01-05 17:48:01 +0000 (Mon, 05 Jan 2009)
Log Message:
-----------
Fix a bug in pdf usetex: allow using non-embedded fonts
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-05 14:47:08 UTC (rev 6736)
+++ trunk/matplotlib/CHANGELOG 2009-01-05 17:48:01 UTC (rev 6737)
@@ -1,3 +1,5 @@
+2009-01-05 Fix a bug in pdf usetex: allow using non-embedded fonts. - JKS
+
2009-01-05 optional use of preview.sty in usetex mode. - JJL
2009-01-02 Allow multipage pdf files. - JKS
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-05 14:47:08 UTC (rev 6736)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-05 17:48:01 UTC (rev 6737)
@@ -88,11 +88,9 @@
# * the alpha channel of images
# * image compression could be improved (PDF supports png-like compression)
# * encoding of fonts, including mathtext fonts and unicode support
-# * Type 1 font support (i.e., "pdf.use_afm")
# * TTF support has lots of small TODOs, e.g. how do you know if a font
# is serif/sans-serif, or symbolic/non-symbolic?
# * draw_markers, draw_line_collection, etc.
-# * use_tex
def fill(strings, linelen=75):
"""Make one string from sequence of strings, with whitespace
@@ -518,7 +516,7 @@
elif self.dviFontInfo.has_key(filename):
# a Type 1 font from a dvi file; the filename is really the TeX name
matplotlib.verbose.report('Writing Type-1 font', 'debug')
- fontdictObject = self.embedType1(filename, self.dviFontInfo[filename])
+ fontdictObject = self.embedTeXFont(filename, self.dviFontInfo[filename])
else:
# a normal TrueType font
matplotlib.verbose.report('Writing TrueType font', 'debug')
@@ -542,53 +540,62 @@
self.writeObject(fontdictObject, fontdict)
return fontdictObject
- def embedType1(self, texname, fontinfo):
+ def embedTeXFont(self, texname, fontinfo):
matplotlib.verbose.report(
- 'Embedding ' + texname +
- ' which is the Type 1 font ' + (fontinfo.fontfile or '(none)') +
- ' with encoding ' + (fontinfo.encodingfile or '(none)') +
- ' and effects ' + `fontinfo.effects`,
+ 'Embedding TeX font ' + texname + ' - fontinfo=' + `fontinfo.__dict__`,
'debug')
- t1font = type1font.Type1Font(fontinfo.fontfile)
- if fontinfo.effects:
- t1font = t1font.transform(fontinfo.effects)
-
- # Font descriptors may be shared between differently encoded
- # Type-1 fonts, so only create a new descriptor if there is no
- # existing descriptor for this font.
- effects = (fontinfo.effects.get('slant', 0.0), fontinfo.effects.get('extend', 1.0))
- fontdesc = self.type1Descriptors.get((fontinfo.fontfile, effects))
- if fontdesc is None:
- fontdesc = self.createType1Descriptor(t1font, fontinfo.fontfile)
- self.type1Descriptors[(fontinfo.fontfile, effects)] = fontdesc
-
# Widths
widthsObject = self.reserveObject('font widths')
- self.writeObject(widthsObject, fontinfo.widths)
+ self.writeObject(widthsObject, fontinfo.dvifont.widths)
# Font dictionary
fontdictObject = self.reserveObject('font dictionary')
fontdict = {
- 'Type': Name('Font'),
- 'Subtype': Name('Type1'),
- 'BaseFont': Name(t1font.prop['FontName']),
- 'FirstChar': 0,
- 'LastChar': len(fontinfo.widths) - 1,
- 'Widths': widthsObject,
- 'FontDescriptor': fontdesc,
- }
+ 'Type': Name('Font'),
+ 'Subtype': Name('Type1'),
+ 'FirstChar': 0,
+ 'LastChar': len(fontinfo.dvifont.widths) - 1,
+ 'Widths': widthsObject,
+ }
# Encoding (if needed)
if fontinfo.encodingfile is not None:
enc = dviread.Encoding(fontinfo.encodingfile)
differencesArray = [ Name(ch) for ch in enc ]
differencesArray = [ 0 ] + differencesArray
- fontdict.update({
- 'Encoding': { 'Type': Name('Encoding'),
- 'Differences': differencesArray },
- })
+ fontdict['Encoding'] = \
+ { 'Type': Name('Encoding'),
+ 'Differences': differencesArray }
+ # If no file is specified, stop short
+ if fontinfo.fontfile is None:
+ warnings.warn(
+ 'Because of TeX configuration (pdftex.map, see updmap ' +
+ 'option pdftexDownloadBase14) the font %s ' % fontinfo.basefont +
+ 'is not embedded. This is deprecated as of PDF 1.5 ' +
+ 'and it may cause the consumer application to show something ' +
+ 'that was not intended.')
+ fontdict['BaseFont'] = Name(fontinfo.basefont)
+ self.writeObject(fontdictObject, fontdict)
+ return fontdictObject
+
+ # We have a font file to embed - read it in and apply any effects
+ t1font = type1font.Type1Font(fontinfo.fontfile)
+ if fontinfo.effects:
+ t1font = t1font.transform(fontinfo.effects)
+ fontdict['BaseFont'] = Name(t1font.prop['FontName'])
+
+ # Font descriptors may be shared between differently encoded
+ # Type-1 fonts, so only create a new descriptor if there is no
+ # existing descriptor for this font.
+ effects = (fontinfo.effects.get('slant', 0.0), fontinfo.effects.get('extend', 1.0))
+ fontdesc = self.type1Descriptors.get((fontinfo.fontfile, effects))
+ if fontdesc is None:
+ fontdesc = self.createType1Descriptor(t1font, fontinfo.fontfile)
+ self.type1Descriptors[(fontinfo.fontfile, effects)] = fontdesc
+ fontdict['FontDescriptor'] = fontdesc
+
self.writeObject(fontdictObject, fontdict)
return fontdictObject
@@ -1389,11 +1396,12 @@
pdfname = self.file.fontName(dvifont.texname)
if not self.file.dviFontInfo.has_key(dvifont.texname):
psfont = self.tex_font_mapping(dvifont.texname)
+ fontfile = psfont.filename
self.file.dviFontInfo[dvifont.texname] = Bunch(
fontfile=psfont.filename,
+ basefont=psfont.psname,
encodingfile=psfont.encoding,
effects=psfont.effects,
- widths=dvifont.widths,
dvifont=dvifont)
seq += [['font', pdfname, dvifont.size]]
oldfont = dvifont
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jo...@us...> - 2009-01-06 08:07:20
|
Revision: 6739
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6739&view=rev
Author: jouni
Date: 2009-01-06 08:07:18 +0000 (Tue, 06 Jan 2009)
Log Message:
-----------
Create a PdfFile wrapper named PdfPages to act as the target of savefig
to avoid saving figures in png format onto the file-like PdfPages object.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/doc/api/api_changes.rst
trunk/matplotlib/examples/pylab_examples/multipage_pdf.py
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-05 18:11:47 UTC (rev 6738)
+++ trunk/matplotlib/CHANGELOG 2009-01-06 08:07:18 UTC (rev 6739)
@@ -1,3 +1,6 @@
+2009-01-06 Change user-visible multipage pdf object to PdfPages to
+ avoid accidents with the file-like PdfFile. - JKS
+
2009-01-05 Fix a bug in pdf usetex: allow using non-embedded fonts. - JKS
2009-01-05 optional use of preview.sty in usetex mode. - JJL
Modified: trunk/matplotlib/doc/api/api_changes.rst
===================================================================
--- trunk/matplotlib/doc/api/api_changes.rst 2009-01-05 18:11:47 UTC (rev 6738)
+++ trunk/matplotlib/doc/api/api_changes.rst 2009-01-06 08:07:18 UTC (rev 6739)
@@ -6,6 +6,10 @@
outward-facing API. If updating matplotlib breaks your scripts, this
list may help describe what changes may be necessary in your code.
+* You can now print several figures to one pdf file. See the docstrings
+ of the class :class:`matplotlib.backends.backend_pdf.PdfPages` for
+ more information.
+
* Removed configobj_ and `enthought.traits`_ packages, which are only
required by the experimental traited config and are somewhat out of
date. If needed, install them independently.
Modified: trunk/matplotlib/examples/pylab_examples/multipage_pdf.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/multipage_pdf.py 2009-01-05 18:11:47 UTC (rev 6738)
+++ trunk/matplotlib/examples/pylab_examples/multipage_pdf.py 2009-01-06 08:07:18 UTC (rev 6739)
@@ -1,14 +1,17 @@
+# This is a demo of creating a pdf file with several pages.
+
import numpy as np
import matplotlib
-from matplotlib.backends.backend_pdf import PdfFile
+from matplotlib.backends.backend_pdf import PdfPages
from pylab import *
-pdf = PdfFile('multipage_pdf.pdf')
+# Create the PdfPages object to which we will save the pages:
+pdf = PdfPages('multipage_pdf.pdf')
figure(figsize=(3,3))
plot(range(7), [3,1,4,1,5,9,2], 'r-o')
title('Page One')
-savefig(pdf, format='pdf')
+savefig(pdf, format='pdf') # note the format='pdf' argument!
close()
rc('text', usetex=True)
@@ -16,14 +19,15 @@
x = np.arange(0,5,0.1)
plot(x, np.sin(x), 'b-')
title('Page Two')
-savefig(pdf, format='pdf')
+pdf.savefig() # here's another way - or you could do pdf.savefig(1)
close()
rc('text', usetex=False)
-figure(figsize=(4,5))
+fig=figure(figsize=(4,5))
plot(x, x*x, 'ko')
title('Page Three')
-savefig(pdf, format='pdf')
+pdf.savefig(fig) # or you can pass a Figure object to pdf.savefig
close()
+# Remember to close the object - otherwise the file will not be usable
pdf.close()
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-05 18:11:47 UTC (rev 6738)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-06 08:07:18 UTC (rev 6739)
@@ -1882,7 +1882,64 @@
manager = FigureManagerPdf(canvas, num)
return manager
+class PdfPages(object):
+ """
+ A multi-page PDF file.
+ Use like this:
+
+ # Initialize:
+ pdf_pages = PdfPages('foo.pdf')
+
+ # As many times as you like, create a figure fig, then either:
+ fig.savefig(pdf_pages, format='pdf') # note the format argument!
+ # or:
+ pdf_pages.savefig(fig)
+
+ # Once you are done, remember to close the object:
+ pdf_pages.close()
+
+ (In reality PdfPages is a thin wrapper around PdfFile, in order to
+ avoid confusion when using savefig and forgetting the format
+ argument.)
+ """
+ __slots__ = ('_file',)
+
+ def __init__(self, filename):
+ """
+ Create a new PdfPages object that will be written to the file
+ named *filename*. The file is opened at once and any older
+ file with the same name is overwritten.
+ """
+ self._file = PdfFile(filename)
+
+ def close(self):
+ """
+ Finalize this object, making the underlying file a complete
+ PDF file.
+ """
+ self._file.close()
+ self._file = None
+
+ def savefig(self, figure=None, **kwargs):
+ """
+ Save the Figure instance *figure* to this file as a new page.
+ If *figure* is a number, the figure instance is looked up by
+ number, and if *figure* is None, the active figure is saved.
+ Any other keyword arguments are passed to Figure.savefig.
+ """
+ if isinstance(figure, Figure):
+ figure.savefig(self, format='pdf', **kwargs)
+ else:
+ if figure is None:
+ figureManager = Gcf.get_active()
+ else:
+ figureManager = Gcf.get_fig_manager(figure)
+ if figureManager is None:
+ raise ValueError, "No such figure: " + `figure`
+ else:
+ figureManager.canvas.figure.savefig(self, format='pdf')
+
class FigureCanvasPdf(FigureCanvasBase):
"""
The canvas the figure renders into. Calls the draw and print fig
@@ -1905,8 +1962,8 @@
image_dpi = kwargs.get('dpi', 72) # dpi to use for images
self.figure.set_dpi(72) # there are 72 pdf points to an inch
width, height = self.figure.get_size_inches()
- if isinstance(filename, PdfFile):
- file = filename
+ if isinstance(filename, PdfPages):
+ file = filename._file
else:
file = PdfFile(filename)
file.newPage(width, height)
@@ -1914,10 +1971,10 @@
width, height, 72, RendererPdf(file, image_dpi))
self.figure.draw(renderer)
renderer.finalize()
- if file != filename: # we opened the file
+ if isinstance(filename, PdfPages): # finish off this page
+ file.endStream()
+ else: # we opened the file above; now finish it off
file.close()
- else: # multipage file; just finish off the page
- file.endStream()
class FigureManagerPdf(FigureManagerBase):
pass
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2009-01-06 17:06:08
|
Revision: 6743
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6743&view=rev
Author: jdh2358
Date: 2009-01-06 17:06:06 +0000 (Tue, 06 Jan 2009)
Log Message:
-----------
added marginal density option to hexbin
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/boilerplate.py
trunk/matplotlib/examples/pylab_examples/hexbin_demo2.py
trunk/matplotlib/lib/matplotlib/axes.py
trunk/matplotlib/setupext.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-06 16:53:09 UTC (rev 6742)
+++ trunk/matplotlib/CHANGELOG 2009-01-06 17:06:06 UTC (rev 6743)
@@ -1,3 +1,6 @@
+2009-01-06 Added marginals kwarg to hexbin to plot marginal densities
+ JDH
+
2009-01-06 Change user-visible multipage pdf object to PdfPages to
avoid accidents with the file-like PdfFile. - JKS
Modified: trunk/matplotlib/boilerplate.py
===================================================================
--- trunk/matplotlib/boilerplate.py 2009-01-06 16:53:09 UTC (rev 6742)
+++ trunk/matplotlib/boilerplate.py 2009-01-06 17:06:06 UTC (rev 6743)
@@ -102,7 +102,7 @@
cmappable = {
'contour' : 'if ret._A is not None: gci._current = ret',
'contourf': 'if ret._A is not None: gci._current = ret',
- 'hexbin' : 'gci._current = ret',
+ 'hexbin' : 'gci._current = ret[0]',
'scatter' : 'gci._current = ret',
'pcolor' : 'gci._current = ret',
'pcolormesh' : 'gci._current = ret',
Modified: trunk/matplotlib/examples/pylab_examples/hexbin_demo2.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/hexbin_demo2.py 2009-01-06 16:53:09 UTC (rev 6742)
+++ trunk/matplotlib/examples/pylab_examples/hexbin_demo2.py 2009-01-06 17:06:06 UTC (rev 6743)
@@ -39,13 +39,14 @@
gridsize=30
plt.subplot(211)
-plt.hexbin(x,y, C=z, gridsize=gridsize )
+plt.hexbin(x,y, C=z, gridsize=gridsize, marginals=True)
plt.axis([xmin, xmax, ymin, ymax])
cb = plt.colorbar()
cb.set_label('mean value')
+
plt.subplot(212)
-plt.hexbin(x,y, gridsize=gridsize )
+plt.hexbin(x,y, gridsize=gridsize)
plt.axis([xmin, xmax, ymin, ymax])
cb = plt.colorbar()
cb.set_label('N observations')
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2009-01-06 16:53:09 UTC (rev 6742)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2009-01-06 17:06:06 UTC (rev 6743)
@@ -5212,7 +5212,7 @@
xscale = 'linear', yscale = 'linear',
cmap=None, norm=None, vmin=None, vmax=None,
alpha=1.0, linewidths=None, edgecolors='none',
- reduce_C_function = np.mean, mincnt=None,
+ reduce_C_function = np.mean, mincnt=None, marginals=True,
**kwargs):
"""
call signature::
@@ -5221,7 +5221,7 @@
xscale = 'linear', yscale = 'linear',
cmap=None, norm=None, vmin=None, vmax=None,
alpha=1.0, linewidths=None, edgecolors='none'
- reduce_C_function = np.mean, mincnt=None,
+ reduce_C_function = np.mean, mincnt=None, marginals=True
**kwargs)
Make a hexagonal binning plot of *x* versus *y*, where *x*,
@@ -5273,6 +5273,11 @@
If not None, only display cells with more than *mincnt*
number of points in the cell
+ *marginals*: True|False
+ if marginals is True, plot the marginal density as
+ colormapped rectagles along the bottom of the x-axis and
+ left of the y-axis
+
Other keyword arguments controlling color mapping and normalization
arguments:
@@ -5320,8 +5325,11 @@
:class:`~matplotlib.collections.PolyCollection` instance; use
:meth:`~matplotlib.collection.PolyCollection.get_array` on
this :class:`~matplotlib.collections.PolyCollection` to get
- the counts in each hexagon.
+ the counts in each hexagon.. If marginals is True, horizontal
+ bar and vertical bar (both PolyCollections) will be attached
+ to the return collection as attributes *hbar* and *vbar*
+
**Example:**
.. plot:: mpl_examples/pylab_examples/hexbin_demo.py
@@ -5331,8 +5339,10 @@
self._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
+
x, y, C = cbook.delete_masked_points(x, y, C)
+
# Set the size of the hexagon grid
if iterable(gridsize):
nx, ny = gridsize
@@ -5357,6 +5367,11 @@
xmax += padding
sx = (xmax-xmin) / nx
sy = (ymax-ymin) / ny
+
+ if marginals:
+ xorig = x.copy()
+ yorig = y.copy()
+
x = (x-xmin)/sx
y = (y-ymin)/sy
ix1 = np.round(x).astype(int)
@@ -5496,6 +5511,93 @@
# add the collection last
self.add_collection(collection)
+ if not marginals:
+ return collection
+
+
+ if C is None:
+ C = np.ones(len(x))
+
+ def coarse_bin(x, y, coarse):
+ ind = coarse.searchsorted(x).clip(0, len(coarse)-1)
+ mus = np.zeros(len(coarse))
+ for i in range(len(coarse)):
+ mu = reduce_C_function(y[ind==i])
+ mus[i] = mu
+ return mus
+
+ coarse = np.linspace(xmin, xmax, gridsize)
+
+ xcoarse = coarse_bin(xorig, C, coarse)
+ valid = ~np.isnan(xcoarse)
+ verts, values = [], []
+ for i,val in enumerate(xcoarse):
+ thismin = coarse[i]
+ if i<len(coarse)-1:
+ thismax = coarse[i+1]
+ else:
+ thismax = thismin + np.diff(coarse)[-1]
+
+ if not valid[i]: continue
+
+ verts.append([(thismin, 0), (thismin, 0.05), (thismax, 0.05), (thismax, 0)])
+ values.append(val)
+
+ values = np.array(values)
+ trans = mtransforms.blended_transform_factory(
+ self.transData, self.transAxes)
+
+
+ hbar = mcoll.PolyCollection(verts, transform=trans, edgecolors='face')
+
+ hbar.set_array(values)
+ hbar.set_cmap(cmap)
+ hbar.set_norm(norm)
+ hbar.set_alpha(alpha)
+ hbar.update(kwargs)
+ self.add_collection(hbar)
+
+ coarse = np.linspace(ymin, ymax, gridsize)
+ ycoarse = coarse_bin(yorig, C, coarse)
+ valid = ~np.isnan(ycoarse)
+ verts, values = [], []
+ for i,val in enumerate(ycoarse):
+ thismin = coarse[i]
+ if i<len(coarse)-1:
+ thismax = coarse[i+1]
+ else:
+ thismax = thismin + np.diff(coarse)[-1]
+ if not valid[i]: continue
+ verts.append([(0, thismin), (0.0, thismax), (0.05, thismax), (0.05, thismin)])
+ values.append(val)
+
+ values = np.array(values)
+
+
+ trans = mtransforms.blended_transform_factory(
+ self.transAxes, self.transData)
+
+ vbar = mcoll.PolyCollection(verts, transform=trans, edgecolors='face')
+ vbar.set_array(values)
+ vbar.set_cmap(cmap)
+ vbar.set_norm(norm)
+ vbar.set_alpha(alpha)
+ vbar.update(kwargs)
+ self.add_collection(vbar)
+
+
+
+ collection.hbar = hbar
+ collection.vbar = vbar
+
+ def on_changed(collection):
+ hbar.set_cmap(collection.get_cmap())
+ hbar.set_clim(collection.get_clim())
+ vbar.set_cmap(collection.get_cmap())
+ vbar.set_clim(collection.get_clim())
+
+ collection.callbacksSM.connect('changed', on_changed)
+
return collection
hexbin.__doc__ = cbook.dedent(hexbin.__doc__) % martist.kwdocd
Modified: trunk/matplotlib/setupext.py
===================================================================
--- trunk/matplotlib/setupext.py 2009-01-06 16:53:09 UTC (rev 6742)
+++ trunk/matplotlib/setupext.py 2009-01-06 17:06:06 UTC (rev 6743)
@@ -1066,8 +1066,7 @@
global BUILT_WINDOWING
if BUILT_WINDOWING: return # only build it if you you haven't already
module = Extension('matplotlib._windowing',
- ['src/_windowing.cpp',
- ],
+ ['src/_windowing.cpp'],
)
add_windowing_flags(module)
ext_modules.append(module)
@@ -1341,7 +1340,7 @@
temp_copy('src/_backend_gdk.c', 'src/backend_gdk.c')
module = Extension(
'matplotlib.backends._backend_gdk',
- ['src/backend_gdk.c', ],
+ ['src/backend_gdk.c'],
libraries = [],
include_dirs=numpy_inc_dirs,
)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2009-01-06 17:24:35
|
Revision: 6744
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6744&view=rev
Author: mdboom
Date: 2009-01-06 17:24:32 +0000 (Tue, 06 Jan 2009)
Log Message:
-----------
Add more hatch styles. Improve consistency across backends.
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/hatch_demo.py
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
trunk/matplotlib/lib/matplotlib/patches.py
trunk/matplotlib/lib/matplotlib/path.py
trunk/matplotlib/src/_backend_agg.cpp
trunk/matplotlib/src/_backend_agg.h
Added Paths:
-----------
trunk/matplotlib/lib/matplotlib/hatch.py
Modified: trunk/matplotlib/examples/pylab_examples/hatch_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2009-01-06 17:06:06 UTC (rev 6743)
+++ trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2009-01-06 17:24:32 UTC (rev 6744)
@@ -6,17 +6,18 @@
fig = plt.figure()
ax1 = fig.add_subplot(121)
-ax1.annotate("Hatch is only supported in the PS and PDF backend", (1, 1),
+ax1.annotate("Hatch is only supported in the PS, PDF, SVG and Agg backends", (1, 1),
xytext=(0, 5),
xycoords="axes fraction", textcoords="offset points", ha="center"
)
-ax1.bar(range(1,5), range(1,5), color='gray', edgecolor='black', hatch="/")
+ax1.bar(range(1,5), range(1,5), color='red', edgecolor='black', hatch="/")
+ax1.bar(range(1,5), [6] * 4, bottom=range(1,5), color='blue', edgecolor='black', hatch='//')
-
ax2 = fig.add_subplot(122)
-bars = ax2.bar(range(1,5), range(1,5), color='gray', ecolor='black')
+bars = ax2.bar(range(1,5), range(1,5), color='yellow', ecolor='black') + \
+ ax2.bar(range(1, 5), [6] * 4, bottom=range(1,5), color='green', ecolor='black')
-patterns = ('/', '+', 'x', '\\')
+patterns = ('-', '+', 'x', '\\', '*', 'o', 'O', '.')
for bar, pattern in zip(bars, patterns):
bar.set_hatch(pattern)
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-06 17:06:06 UTC (rev 6743)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-01-06 17:24:32 UTC (rev 6744)
@@ -557,7 +557,7 @@
'FirstChar': 0,
'LastChar': len(fontinfo.dvifont.widths) - 1,
'Widths': widthsObject,
- }
+ }
# Encoding (if needed)
if fontinfo.encodingfile is not None:
@@ -595,7 +595,7 @@
fontdesc = self.createType1Descriptor(t1font, fontinfo.fontfile)
self.type1Descriptors[(fontinfo.fontfile, effects)] = fontdesc
fontdict['FontDescriptor'] = fontdesc
-
+
self.writeObject(fontdictObject, fontdict)
return fontdictObject
@@ -1749,7 +1749,6 @@
else:
return [Name('DeviceRGB'), Op.setcolorspace_nonstroke]
else:
- hatch = hatch.lower()
hatch_style = (self._rgb, self._fillcolor, hatch)
name = self.file.hatchPattern(hatch_style)
return [Name('Pattern'), Op.setcolorspace_nonstroke,
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2009-01-06 17:06:06 UTC (rev 6743)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2009-01-06 17:24:32 UTC (rev 6744)
@@ -95,17 +95,22 @@
"""
Create a new hatch pattern
"""
- HATCH_SIZE = 144
- dictkey = (gc.get_hatch().lower(), rgbFace, gc.get_rgb())
+ HATCH_SIZE = 72
+ dictkey = (gc.get_hatch(), rgbFace, gc.get_rgb())
id = self._hatchd.get(dictkey)
if id is None:
id = 'h%s' % md5(str(dictkey)).hexdigest()
self._svgwriter.write('<defs>\n <pattern id="%s" ' % id)
self._svgwriter.write('patternUnits="userSpaceOnUse" x="0" y="0" ')
self._svgwriter.write(' width="%d" height="%d" >\n' % (HATCH_SIZE, HATCH_SIZE))
- path_data = self._convert_path(gc.get_hatch_path(), Affine2D().scale(144))
+ path_data = self._convert_path(
+ gc.get_hatch_path(),
+ Affine2D().scale(HATCH_SIZE).scale(1.0, -1.0).translate(0, HATCH_SIZE))
+ self._svgwriter.write(
+ '<rect x="0" y="0" width="%d" height="%d" fill="%s"/>' %
+ (HATCH_SIZE+1, HATCH_SIZE+1, rgb2hex(rgbFace)))
path = '<path d="%s" fill="%s" stroke="%s" stroke-width="1.0"/>' % (
- path_data, rgb2hex(rgbFace[:3]), rgb2hex(gc.get_rgb()[:3]))
+ path_data, rgb2hex(gc.get_rgb()[:3]), rgb2hex(gc.get_rgb()[:3]))
self._svgwriter.write(path)
self._svgwriter.write('\n </pattern>\n</defs>')
self._hatchd[dictkey] = id
Added: trunk/matplotlib/lib/matplotlib/hatch.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/hatch.py (rev 0)
+++ trunk/matplotlib/lib/matplotlib/hatch.py 2009-01-06 17:24:32 UTC (rev 6744)
@@ -0,0 +1,194 @@
+"""
+Contains a classes for generating hatch patterns.
+"""
+
+import numpy as np
+from matplotlib.path import Path
+
+class HatchPatternBase:
+ """
+ The base class for a hatch pattern.
+ """
+ pass
+
+class HorizontalHatch(HatchPatternBase):
+ def __init__(self, hatch, density):
+ self.num_lines = (hatch.count('-') + hatch.count('+')) * density
+ self.num_vertices = self.num_lines * 2
+
+ def set_vertices_and_codes(self, vertices, codes):
+ steps = np.linspace(0.0, 1.0, self.num_lines, False)
+ vertices[0::2, 0] = 0.0
+ vertices[0::2, 1] = steps
+ vertices[1::2, 0] = 1.0
+ vertices[1::2, 1] = steps
+ codes[0::2] = Path.MOVETO
+ codes[1::2] = Path.LINETO
+
+class VerticalHatch(HatchPatternBase):
+ def __init__(self, hatch, density):
+ self.num_lines = (hatch.count('|') + hatch.count('+')) * density
+ self.num_vertices = self.num_lines * 2
+
+ def set_vertices_and_codes(self, vertices, codes):
+ steps = np.linspace(0.0, 1.0, self.num_lines, False)
+ vertices[0::2, 0] = steps
+ vertices[0::2, 1] = 0.0
+ vertices[1::2, 0] = steps
+ vertices[1::2, 1] = 1.0
+ codes[0::2] = Path.MOVETO
+ codes[1::2] = Path.LINETO
+
+class NorthEastHatch(HatchPatternBase):
+ def __init__(self, hatch, density):
+ self.num_lines = (hatch.count('/') + hatch.count('x') + hatch.count('X')) * density
+ self.num_vertices = self.num_lines * 4
+
+ def set_vertices_and_codes(self, vertices, codes):
+ steps = np.linspace(0.0, 1.0, self.num_lines, False)
+ rev_steps = 1.0 - steps
+ vertices[0::4, 0] = 0.0
+ vertices[0::4, 1] = steps
+ vertices[1::4, 0] = rev_steps
+ vertices[1::4, 1] = 1.0
+ vertices[2::4, 0] = rev_steps
+ vertices[2::4, 1] = 0.0
+ vertices[3::4, 0] = 1.0
+ vertices[3::4, 1] = steps
+ codes[0::2] = Path.MOVETO
+ codes[1::2] = Path.LINETO
+
+class SouthEastHatch(HatchPatternBase):
+ def __init__(self, hatch, density):
+ self.num_lines = (hatch.count('\\') + hatch.count('x') + hatch.count('X')) * density
+ self.num_vertices = self.num_lines * 4
+
+ def set_vertices_and_codes(self, vertices, codes):
+ steps = np.linspace(0.0, 1.0, self.num_lines, False)
+ vertices[0::4, 0] = 1.0
+ vertices[0::4, 1] = steps
+ vertices[1::4, 0] = steps
+ vertices[1::4, 1] = 1.0
+ vertices[2::4, 0] = steps
+ vertices[2::4, 1] = 0.0
+ vertices[3::4, 0] = 0.0
+ vertices[3::4, 1] = steps
+ codes[0::2] = Path.MOVETO
+ codes[1::2] = Path.LINETO
+
+class Shapes(HatchPatternBase):
+ filled = False
+ def __init__(self, hatch, density):
+ if self.num_rows == 0:
+ self.num_shapes = 0
+ self.num_vertices = 0
+ else:
+ self.num_shapes = ((self.num_rows / 2 + 1) * (self.num_rows + 1) +
+ (self.num_rows / 2) * (self.num_rows))
+ self.num_vertices = (self.num_shapes *
+ len(self.shape_vertices) *
+ (self.filled and 1 or 2))
+
+ def set_vertices_and_codes(self, vertices, codes):
+ offset = 1.0 / self.num_rows
+ shape_vertices = self.shape_vertices * offset * self.size
+ if not self.filled:
+ inner_vertices = shape_vertices[::-1] * 0.9
+ shape_codes = self.shape_codes
+ shape_size = len(shape_vertices)
+
+ cursor = 0
+ for row in xrange(self.num_rows + 1):
+ if row % 2 == 0:
+ cols = np.linspace(0.0, 1.0, self.num_rows + 1, True)
+ else:
+ cols = np.linspace(offset / 2.0, 1.0 - offset / 2.0, self.num_rows, True)
+ row_pos = row * offset
+ for col_pos in cols:
+ vertices[cursor:cursor+shape_size] = shape_vertices + (col_pos, row_pos)
+ codes[cursor:cursor+shape_size] = shape_codes
+ cursor += shape_size
+ if not self.filled:
+ vertices[cursor:cursor+shape_size] = inner_vertices + (col_pos, row_pos)
+ codes[cursor:cursor+shape_size] = shape_codes
+ cursor += shape_size
+
+class Circles(Shapes):
+ def __init__(self, hatch, density):
+ path = Path.unit_circle()
+ self.shape_vertices = path.vertices
+ self.shape_codes = path.codes
+ Shapes.__init__(self, hatch, density)
+
+class SmallCircles(Circles):
+ size = 0.2
+
+ def __init__(self, hatch, density):
+ self.num_rows = (hatch.count('o')) * density
+ Circles.__init__(self, hatch, density)
+
+class LargeCircles(Circles):
+ size = 0.35
+
+ def __init__(self, hatch, density):
+ self.num_rows = (hatch.count('O')) * density
+ Circles.__init__(self, hatch, density)
+
+class SmallFilledCircles(SmallCircles):
+ size = 0.1
+ filled = True
+
+ def __init__(self, hatch, density):
+ self.num_rows = (hatch.count('.')) * density
+ Circles.__init__(self, hatch, density)
+
+class Stars(Shapes):
+ size = 1.0 / 3.0
+ filled = True
+
+ def __init__(self, hatch, density):
+ self.num_rows = (hatch.count('*')) * density
+ path = Path.unit_regular_star(5)
+ self.shape_vertices = path.vertices
+ self.shape_codes = np.ones(len(self.shape_vertices)) * Path.LINETO
+ self.shape_codes[0] = Path.MOVETO
+ Shapes.__init__(self, hatch, density)
+
+_hatch_types = [
+ HorizontalHatch,
+ VerticalHatch,
+ NorthEastHatch,
+ SouthEastHatch,
+ SmallCircles,
+ LargeCircles,
+ SmallFilledCircles,
+ Stars
+ ]
+
+def get_path(hatchpattern, density=6):
+ """
+ Given a hatch specifier, *hatchpattern*, generates Path to render
+ the hatch in a unit square. *density* is the number of lines per
+ unit square.
+ """
+ size = 1.0
+ density = int(density)
+
+ patterns = [hatch_type(hatchpattern, density) for hatch_type in _hatch_types]
+ num_vertices = sum([pattern.num_vertices for pattern in patterns])
+
+ if num_vertices == 0:
+ return Path(np.empty((0, 2)))
+
+ vertices = np.empty((num_vertices, 2))
+ codes = np.empty((num_vertices,), np.uint8)
+
+ cursor = 0
+ for pattern in patterns:
+ if pattern.num_vertices != 0:
+ vertices_chunk = vertices[cursor:cursor + pattern.num_vertices]
+ codes_chunk = codes[cursor:cursor + pattern.num_vertices]
+ pattern.set_vertices_and_codes(vertices_chunk, codes_chunk)
+ cursor += pattern.num_vertices
+
+ return Path(vertices, codes)
Modified: trunk/matplotlib/lib/matplotlib/patches.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/patches.py 2009-01-06 17:06:06 UTC (rev 6743)
+++ trunk/matplotlib/lib/matplotlib/patches.py 2009-01-06 17:24:32 UTC (rev 6744)
@@ -238,19 +238,23 @@
\ - back diagonal
| - vertical
- - horizontal
- # - crossed
+ + - crossed
x - crossed diagonal
+ o - small circle
+ O - large circle
+ . - dots
+ * - stars
Letters can be combined, in which case all the specified
hatchings are done. If same letter repeats, it increases the
- density of hatching in that direction.
+ density of hatching of that pattern.
CURRENT LIMITATIONS:
1. Hatching is supported in the PostScript, PDF, SVG and Agg
backends only.
- ACCEPTS: [ '/' | '\\' | '|' | '-' | '#' | 'x' ] (ps & pdf backend only)
+ ACCEPTS: [ '/' | '\\' | '|' | '-' | '+' | 'x' | 'o' | 'O' | '.' | ' *' ]
"""
self._hatch = hatch
Modified: trunk/matplotlib/lib/matplotlib/path.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/path.py 2009-01-06 17:06:06 UTC (rev 6743)
+++ trunk/matplotlib/lib/matplotlib/path.py 2009-01-06 17:24:32 UTC (rev 6744)
@@ -572,87 +572,17 @@
can be used in a repeated hatching pattern. *density* is the
number of lines per unit square.
"""
+ from matplotlib.hatch import get_path
+
if hatchpattern is None:
return None
- hatch = hatchpattern.lower()
- hatch_path = cls._hatch_dict.get((hatch, density))
+ hatch_path = cls._hatch_dict.get((hatchpattern, density))
if hatch_path is not None:
return hatch_path
- size = 1.0
- density = int(density)
- counts = [
- hatch.count('-') + hatch.count('+'),
- hatch.count('/') + hatch.count('x'),
- hatch.count('|') + hatch.count('+'),
- hatch.count('\\') + hatch.count('x')
- ]
-
- if sum(counts) == 0:
- return cls([])
-
- counts = [x * density for x in counts]
-
- num_vertices = (counts[0] * 2 + counts[1] * 4 +
- counts[2] * 2 + counts[3] * 4)
- vertices = np.empty((num_vertices, 2))
- codes = np.empty((num_vertices,), cls.code_type)
- codes[0::2] = cls.MOVETO
- codes[1::2] = cls.LINETO
-
- cursor = 0
-
- # - horizontal
- if counts[0]:
- vertices_chunk = vertices[cursor:cursor + counts[0] * 2]
- cursor += counts[0] * 2
- steps = np.linspace(0.0, 1.0, counts[0], False)
- vertices_chunk[0::2, 0] = 0.0
- vertices_chunk[0::2, 1] = steps
- vertices_chunk[1::2, 0] = size
- vertices_chunk[1::2, 1] = steps
-
- # / ne
- if counts[1]:
- vertices_chunk = vertices[cursor:cursor + counts[1] * 4]
- cursor += counts[1] * 4
- steps = np.linspace(0.0, 1.0, counts[1], False)
- vertices_chunk[0::4, 0] = 0.0
- vertices_chunk[0::4, 1] = steps
- vertices_chunk[1::4, 0] = size - steps
- vertices_chunk[1::4, 1] = size
- vertices_chunk[2::4, 0] = size - steps
- vertices_chunk[2::4, 1] = 0.0
- vertices_chunk[3::4, 0] = size
- vertices_chunk[3::4, 1] = steps
-
- # | vertical
- if counts[2]:
- vertices_chunk = vertices[cursor:cursor + counts[2] * 2]
- cursor += counts[2] * 2
- steps = np.linspace(0.0, 1.0, counts[2], False)
- vertices_chunk[0::2, 0] = steps
- vertices_chunk[0::2, 1] = 0.0
- vertices_chunk[1::2, 0] = steps
- vertices_chunk[1::2, 1] = size
-
- # \ se
- if counts[3]:
- vertices_chunk = vertices[cursor:cursor + counts[3] * 4]
- cursor += counts[3] * 4
- steps = np.linspace(0.0, 1.0, counts[3], False)
- vertices_chunk[0::4, 0] = size
- vertices_chunk[0::4, 1] = steps
- vertices_chunk[1::4, 0] = steps
- vertices_chunk[1::4, 1] = size
- vertices_chunk[2::4, 0] = steps
- vertices_chunk[2::4, 1] = 0.0
- vertices_chunk[3::4, 0] = 0.0
- vertices_chunk[3::4, 1] = steps
-
- hatch_path = cls(vertices, codes)
- cls._hatch_dict[(hatch, density)] = hatch_path
+ hatch_path = get_path(hatchpattern, density)
+ cls._hatch_dict[(hatchpattern, density)] = hatch_path
return hatch_path
hatch = classmethod(hatch)
Modified: trunk/matplotlib/src/_backend_agg.cpp
===================================================================
--- trunk/matplotlib/src/_backend_agg.cpp 2009-01-06 17:06:06 UTC (rev 6743)
+++ trunk/matplotlib/src/_backend_agg.cpp 2009-01-06 17:24:32 UTC (rev 6744)
@@ -901,18 +901,20 @@
// Create and transform the path
typedef agg::conv_transform<PathIterator> hatch_path_trans_t;
typedef SimplifyPath<hatch_path_trans_t> hatch_path_simplify_t;
- typedef agg::conv_stroke<hatch_path_simplify_t> hatch_path_stroke_t;
+ typedef agg::conv_curve<hatch_path_simplify_t> hatch_path_curve_t;
+ typedef agg::conv_stroke<hatch_path_curve_t> hatch_path_stroke_t;
PathIterator hatch_path(gc.hatchpath);
agg::trans_affine hatch_trans;
+ hatch_trans *= agg::trans_affine_scaling(1.0, -1.0);
+ hatch_trans *= agg::trans_affine_translation(0.0, 1.0);
hatch_trans *= agg::trans_affine_scaling(HATCH_SIZE, HATCH_SIZE);
hatch_path_trans_t hatch_path_trans(hatch_path, hatch_trans);
- hatch_path_simplify_t hatch_path_simplify
- (hatch_path_trans, true, false, HATCH_SIZE, HATCH_SIZE);
- hatch_path_stroke_t hatch_path_stroke(hatch_path_simplify);
+ hatch_path_simplify_t hatch_path_simplify(hatch_path_trans, false, false, HATCH_SIZE, HATCH_SIZE);
+ hatch_path_curve_t hatch_path_curve(hatch_path_simplify);
+ hatch_path_stroke_t hatch_path_stroke(hatch_path_curve);
hatch_path_stroke.width(1.0);
hatch_path_stroke.line_cap(agg::square_cap);
- theRasterizer.add_path(hatch_path_stroke);
// Render the path into the hatch buffer
pixfmt hatch_img_pixf(hatchRenderingBuffer);
@@ -920,7 +922,11 @@
renderer_aa rs(rb);
rb.clear(agg::rgba(0.0, 0.0, 0.0, 0.0));
rs.color(gc.color);
+
+ theRasterizer.add_path(hatch_path_curve);
agg::render_scanlines(theRasterizer, slineP8, rs);
+ theRasterizer.add_path(hatch_path_stroke);
+ agg::render_scanlines(theRasterizer, slineP8, rs);
// Put clipping back on, if originally set on entry to this
// function
Modified: trunk/matplotlib/src/_backend_agg.h
===================================================================
--- trunk/matplotlib/src/_backend_agg.h 2009-01-06 17:06:06 UTC (rev 6743)
+++ trunk/matplotlib/src/_backend_agg.h 2009-01-06 17:24:32 UTC (rev 6744)
@@ -208,9 +208,7 @@
Py::Object lastclippath;
agg::trans_affine lastclippath_transform;
- // HATCH_SIZE should be a power of 2, to take advantage of Agg's
- // fast pattern rendering
- static const size_t HATCH_SIZE = 128;
+ static const size_t HATCH_SIZE = 72;
agg::int8u hatchBuffer[HATCH_SIZE * HATCH_SIZE * 4];
agg::rendering_buffer hatchRenderingBuffer;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mme...@us...> - 2009-01-06 18:59:34
|
Revision: 6745
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6745&view=rev
Author: mmetz_bn
Date: 2009-01-06 18:59:31 +0000 (Tue, 06 Jan 2009)
Log Message:
-----------
Fault tolerant handling of linestyles when too many
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/contour.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-06 17:24:32 UTC (rev 6744)
+++ trunk/matplotlib/CHANGELOG 2009-01-06 18:59:31 UTC (rev 6745)
@@ -1,3 +1,5 @@
+2009-01-06 Be fault tolerant when len(linestyles)>NLev in contour. - MM
+
2009-01-06 Added marginals kwarg to hexbin to plot marginal densities
JDH
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2009-01-06 17:24:32 UTC (rev 6744)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2009-01-06 18:59:31 UTC (rev 6745)
@@ -860,8 +860,10 @@
else:
if cbook.is_string_like(linestyles):
tlinestyles = [linestyles] * Nlev
- elif cbook.iterable(linestyles) and len(linestyles) <= Nlev:
+ elif cbook.iterable(linestyles) and len(linestyles) < Nlev:
tlinestyles = list(linestyles) * int(np.ceil(Nlev/len(linestyles)))
+ elif cbook.iterable(linestyles): # len(linestyles) >= Nlev
+ tlinestyles = list(linestyles)[:Nlev]
return tlinestyles
def get_alpha(self):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ef...@us...> - 2009-01-06 19:22:10
|
Revision: 6746
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6746&view=rev
Author: efiring
Date: 2009-01-06 19:22:09 +0000 (Tue, 06 Jan 2009)
Log Message:
-----------
Fix bug in setting of negative contour linestyles.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/contour.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-06 18:59:31 UTC (rev 6745)
+++ trunk/matplotlib/CHANGELOG 2009-01-06 19:22:09 UTC (rev 6746)
@@ -1,6 +1,8 @@
+2009-01-06 Fix bug in setting of dashed negative contours. - EF
+
2009-01-06 Be fault tolerant when len(linestyles)>NLev in contour. - MM
-2009-01-06 Added marginals kwarg to hexbin to plot marginal densities
+2009-01-06 Added marginals kwarg to hexbin to plot marginal densities
JDH
2009-01-06 Change user-visible multipage pdf object to PdfPages to
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2009-01-06 18:59:31 UTC (rev 6745)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2009-01-06 19:22:09 UTC (rev 6746)
@@ -535,7 +535,7 @@
self.levels = kwargs.get('levels', None)
self.filled = kwargs.get('filled', False)
self.linewidths = kwargs.get('linewidths', None)
- self.linestyles = kwargs.get('linestyles', 'solid')
+ self.linestyles = kwargs.get('linestyles', None)
self.alpha = kwargs.get('alpha', 1.0)
self.origin = kwargs.get('origin', None)
@@ -613,9 +613,6 @@
linestyle = lstyle,
alpha=self.alpha)
- if level < 0.0 and self.monochrome:
- ls = mpl.rcParams['contour.negative_linestyle']
- col.set_linestyle(ls)
col.set_label('_nolegend_')
self.ax.add_collection(col, False)
self.collections.append(col)
@@ -857,6 +854,11 @@
Nlev = len(self.levels)
if linestyles is None:
tlinestyles = ['solid'] * Nlev
+ if self.monochrome:
+ neg_ls = mpl.rcParams['contour.negative_linestyle']
+ for i, lev in enumerate(self.levels):
+ if lev < 0.0:
+ tlinestyles[i] = neg_ls
else:
if cbook.is_string_like(linestyles):
tlinestyles = [linestyles] * Nlev
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2009-01-06 20:57:30
|
Revision: 6755
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6755&view=rev
Author: mdboom
Date: 2009-01-06 20:57:28 +0000 (Tue, 06 Jan 2009)
Log Message:
-----------
Merged revisions 6752,6754 via svnmerge from
https://matplotlib.svn.sf.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6752 | efiring | 2009-01-06 14:56:03 -0500 (Tue, 06 Jan 2009) | 2 lines
Backport 6745, 6746 from trunk
........
r6754 | mdboom | 2009-01-06 15:51:53 -0500 (Tue, 06 Jan 2009) | 1 line
Update git instructions with information about working on branches.
........
Modified Paths:
--------------
trunk/matplotlib/doc/devel/coding_guide.rst
trunk/matplotlib/lib/matplotlib/contour.py
Property Changed:
----------------
trunk/matplotlib/
trunk/matplotlib/doc/pyplots/README
trunk/matplotlib/doc/sphinxext/gen_gallery.py
trunk/matplotlib/doc/sphinxext/gen_rst.py
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6732
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6754
Modified: svn:mergeinfo
- /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732
+ /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754
Modified: trunk/matplotlib/doc/devel/coding_guide.rst
===================================================================
--- trunk/matplotlib/doc/devel/coding_guide.rst 2009-01-06 20:51:53 UTC (rev 6754)
+++ trunk/matplotlib/doc/devel/coding_guide.rst 2009-01-06 20:57:28 UTC (rev 6755)
@@ -174,7 +174,7 @@
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
+ git svn init --branches=branches --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
@@ -224,6 +224,37 @@
git checkout whizbang-branch
git rebase master
+Working on a maintenance branch from git
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The matplotlib maintenance branches are also available through git.
+(Note that the ``git svn init`` line in the instructions above was
+updated to make this possible. If you created your git mirror without
+a ``--branches`` option, you will need to perform all of the steps
+again in a new directory).
+
+You can see which branches are available with::
+
+ git branch -a
+
+To switch your working copy to the 0.98.5 maintenance branch::
+
+ git checkout v0_98_5_maint
+
+Then you probably want to (as above) create a new local branch based
+on that branch::
+
+ git checkout -b whizbang-branch
+
+When you ``git svn dcommit`` from a maintenance branch, it will commit
+to that branch, not to the trunk.
+
+While it should theoretically be possible to perform merges from a git
+maintenance branch to a git trunk and then commit those changes back
+to the SVN trunk, I have yet to find the magic incantation to make
+that work. However, svnmerge as described `above <svn-merge>`_ can be
+used and in fact works quite well.
+
A note about git write access
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Property changes on: trunk/matplotlib/doc/pyplots/README
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732
+ /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754
Property changes on: trunk/matplotlib/doc/sphinxext/gen_gallery.py
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732
+ /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732,6752-6754
Property changes on: trunk/matplotlib/doc/sphinxext/gen_rst.py
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732
+ /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732,6752-6754
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2009-01-06 20:51:53 UTC (rev 6754)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2009-01-06 20:57:28 UTC (rev 6755)
@@ -875,6 +875,8 @@
tlinestyles = tlinestyles[:Nlev]
else:
raise ValueError("Unrecognized type for linestyles kwarg")
+ elif cbook.iterable(linestyles): # len(linestyles) >= Nlev
+ tlinestyles = list(linestyles)[:Nlev]
return tlinestyles
def get_alpha(self):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2009-01-10 20:04:03
|
Revision: 6771
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6771&view=rev
Author: jdh2358
Date: 2009-01-10 20:03:59 +0000 (Sat, 10 Jan 2009)
Log Message:
-----------
applied michiel's hatch patch for macosx sf id 2497785
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/examples/pylab_examples/hatch_demo.py
trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py
trunk/matplotlib/src/_macosx.m
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-08 22:11:09 UTC (rev 6770)
+++ trunk/matplotlib/CHANGELOG 2009-01-10 20:03:59 UTC (rev 6771)
@@ -1,3 +1,6 @@
+2009-01-10 Applied Michiel's hatch patch for macosx backend. Closes
+ sf patch 2497785 - JDH
+
2009-01-06 Fix bug in setting of dashed negative contours. - EF
2009-01-06 Be fault tolerant when len(linestyles)>NLev in contour. - MM
Modified: trunk/matplotlib/examples/pylab_examples/hatch_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2009-01-08 22:11:09 UTC (rev 6770)
+++ trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2009-01-10 20:03:59 UTC (rev 6771)
@@ -6,10 +6,6 @@
fig = plt.figure()
ax1 = fig.add_subplot(121)
-ax1.annotate("Hatch is only supported in the PS, PDF, SVG and Agg backends", (1, 1),
- xytext=(0, 5),
- xycoords="axes fraction", textcoords="offset points", ha="center"
- )
ax1.bar(range(1,5), range(1,5), color='red', edgecolor='black', hatch="/")
ax1.bar(range(1,5), [6] * 4, bottom=range(1,5), color='blue', edgecolor='black', hatch='//')
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py 2009-01-08 22:11:09 UTC (rev 6770)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py 2009-01-10 20:03:59 UTC (rev 6771)
@@ -77,6 +77,7 @@
def new_gc(self):
self.gc.reset()
+ self.gc.set_hatch(None)
return self.gc
def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None):
@@ -166,10 +167,14 @@
_macosx.GraphicsContext.__init__(self)
def set_foreground(self, fg, isRGB=False):
- if not isRGB:
- fg = colorConverter.to_rgb(fg)
- _macosx.GraphicsContext.set_foreground(self, fg)
+ GraphicsContextBase.set_foreground(self, fg, isRGB)
+ rgb = self.get_rgb()
+ _macosx.GraphicsContext.set_foreground(self, rgb[:3])
+ def set_graylevel(self, fg):
+ GraphicsContextBase.set_graylevel(self, fg)
+ _macosx.GraphicsContext.set_graylevel(self, fg)
+
def set_clip_rectangle(self, box):
GraphicsContextBase.set_clip_rectangle(self, box)
if not box: return
Modified: trunk/matplotlib/src/_macosx.m
===================================================================
--- trunk/matplotlib/src/_macosx.m 2009-01-08 22:11:09 UTC (rev 6770)
+++ trunk/matplotlib/src/_macosx.m 2009-01-10 20:03:59 UTC (rev 6771)
@@ -31,6 +31,10 @@
#define CURVE3 3
#define CURVE4 4
#define CLOSEPOLY 5
+
+/* Hatching */
+#define HATCH_SIZE 72
+
/* -------------------------- Helper function ---------------------------- */
static void stdin_ready(CFReadStreamRef readStream, CFStreamEventType eventType, void* context)
@@ -203,6 +207,269 @@
PyErr_WarnEx(PyExc_RuntimeWarning, "ATSUDisposeTextLayout failed", 1);
}
+static int
+_draw_path(CGContextRef cr, PyObject* path, CGAffineTransform affine)
+{
+ CGPoint point;
+
+ PyObject* vertices = PyObject_GetAttrString(path, "vertices");
+ if (vertices==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "path has no vertices");
+ return -1;
+ }
+ Py_DECREF(vertices); /* Don't keep a reference here */
+
+ PyObject* codes = PyObject_GetAttrString(path, "codes");
+ if (codes==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "path has no codes");
+ return -1;
+ }
+ Py_DECREF(codes); /* Don't keep a reference here */
+
+ PyArrayObject* coordinates;
+ coordinates = (PyArrayObject*)PyArray_FromObject(vertices,
+ NPY_DOUBLE, 2, 2);
+ if (!coordinates)
+ {
+ PyErr_SetString(PyExc_ValueError, "failed to convert vertices array");
+ return -1;
+ }
+
+ if (PyArray_NDIM(coordinates) != 2 || PyArray_DIM(coordinates, 1) != 2)
+ {
+ Py_DECREF(coordinates);
+ PyErr_SetString(PyExc_ValueError, "invalid vertices array");
+ return -1;
+ }
+
+ npy_intp n = PyArray_DIM(coordinates, 0);
+
+ if (n==0) /* Nothing to do here */
+ {
+ Py_DECREF(coordinates);
+ return 0;
+ }
+
+ PyArrayObject* codelist = NULL;
+ if (codes != Py_None)
+ {
+ codelist = (PyArrayObject*)PyArray_FromObject(codes,
+ NPY_UINT8, 1, 1);
+ if (!codelist)
+ {
+ Py_DECREF(coordinates);
+ PyErr_SetString(PyExc_ValueError, "invalid codes array");
+ return -1;
+ }
+ }
+
+ if (codelist==NULL)
+ {
+ npy_intp i;
+ npy_uint8 code = MOVETO;
+ for (i = 0; i < n; i++)
+ {
+ point.x = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ point.y = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ if (isnan(point.x) || isnan(point.y))
+ {
+ code = MOVETO;
+ }
+ else
+ {
+ point = CGPointApplyAffineTransform(point, affine);
+ switch (code)
+ {
+ case MOVETO:
+ CGContextMoveToPoint(cr, point.x, point.y);
+ break;
+ case LINETO:
+ CGContextAddLineToPoint(cr, point.x, point.y);
+ break;
+ }
+ code = LINETO;
+ }
+ }
+ }
+ else
+ {
+ npy_intp i = 0;
+ BOOL was_nan = false;
+ npy_uint8 code;
+ CGFloat x1, y1, x2, y2, x3, y3;
+ while (i < n)
+ {
+ code = *(npy_uint8*)PyArray_GETPTR1(codelist, i);
+ if (code == CLOSEPOLY)
+ {
+ CGContextClosePath(cr);
+ i++;
+ }
+ else if (code == STOP)
+ {
+ break;
+ }
+ else if (was_nan)
+ {
+ if (code==CURVE3) i++;
+ else if (code==CURVE4) i+=2;
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ CGContextMoveToPoint(cr, point.x, point.y);
+ was_nan = false;
+ }
+ }
+ else if (code==MOVETO)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ CGContextMoveToPoint(cr, point.x, point.y);
+ was_nan = false;
+ }
+ }
+ else if (code==LINETO)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ CGContextAddLineToPoint(cr, point.x, point.y);
+ was_nan = false;
+ }
+ }
+ else if (code==CURVE3)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ x1 = point.x;
+ y1 = point.y;
+ point.x = x2;
+ point.y = y2;
+ point = CGPointApplyAffineTransform(point, affine);
+ x2 = point.x;
+ y2 = point.y;
+ CGContextAddQuadCurveToPoint(cr, x1, y1, x2, y2);
+ was_nan = false;
+ }
+ }
+ else if (code==CURVE4)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2) || isnan(x3) || isnan(y3))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ x1 = point.x;
+ y1 = point.y;
+ point.x = x2;
+ point.y = y2;
+ point = CGPointApplyAffineTransform(point, affine);
+ x2 = point.x;
+ y2 = point.y;
+ point.x = x3;
+ point.y = y3;
+ point = CGPointApplyAffineTransform(point, affine);
+ x3 = point.x;
+ y3 = point.y;
+ CGContextAddCurveToPoint(cr, x1, y1, x2, y2, x3, y3);
+ was_nan = false;
+ }
+ }
+ }
+ }
+
+ Py_DECREF(coordinates);
+ Py_XDECREF(codelist);
+ return n;
+}
+
+static void _draw_hatch (void *info, CGContextRef cr)
+{
+ PyObject* hatchpath = (PyObject*)info;
+ CGAffineTransform affine = CGAffineTransformMakeScale(HATCH_SIZE, HATCH_SIZE);
+
+ int n = _draw_path(cr, hatchpath, affine);
+ if (n < 0)
+ {
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyErr_Print();
+ PyGILState_Release(gstate);
+ return;
+ }
+ else if (n==0)
+ {
+ return;
+ }
+ else
+ {
+ CGContextSetLineWidth(cr, 1.0);
+ CGContextSetLineCap(cr, kCGLineCapSquare);
+ CGContextDrawPath(cr, kCGPathFillStroke);
+ }
+}
+
+static void _release_hatch(void* info)
+{
+ PyObject* hatchpath = (PyObject*)info;
+ Py_DECREF(hatchpath);
+}
+
/* ---------------------------- Cocoa classes ---------------------------- */
@@ -274,7 +541,6 @@
typedef struct {
PyObject_HEAD
CGContextRef cr;
- CGPatternRef pattern; /* For drawing hatches */
} GraphicsContext;
static PyObject*
@@ -283,7 +549,6 @@
GraphicsContext* self = (GraphicsContext*)type->tp_alloc(type, 0);
if (!self) return NULL;
self->cr = NULL;
- self->pattern = NULL;
if (ngc==0)
{
@@ -301,8 +566,6 @@
static void
GraphicsContext_dealloc(GraphicsContext *self)
{
- CGPatternRelease(self->pattern);
-
ngc--;
if (ngc==0) _dealloc_atsui();
@@ -325,12 +588,6 @@
return NULL;
}
- if (self->pattern)
- {
- CGPatternRelease(self->pattern);
- self->pattern = NULL;
- }
-
CGContextRestoreGState(cr);
CGContextSaveGState(cr);
Py_INCREF(Py_None);
@@ -431,10 +688,6 @@
PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
return NULL;
}
-#ifdef BUH
- CGContextRestoreGState(cr); /* FIXME */
- CGContextSaveGState(cr); /* FIXME */
-#endif
PyObject* path;
@@ -759,116 +1012,7 @@
return Py_None;
}
-static void _draw_hatch (void *info, CGContextRef cr)
-{
- int i;
-
- PyObject* string = (PyObject*)info;
- char* hatches = PyString_AS_STRING(string);
-
- int frequency[4] = {0, 0, 0, 0};
- float position, distance;
-
- const float size = 12.0;
- const int n = strlen(hatches);
-
- for (i = 0; i < n; i++)
- {
- switch(hatches[i])
- {
- case '/': frequency[3]++; break;
- case '\\': frequency[2]++; break;
- case '|': frequency[1]++; break;
- case '-': frequency[0]++; break;
- case '+': frequency[0]++; frequency[1]++; break;
- case 'x': frequency[2]++; frequency[3]++; break;
- }
- }
-
- distance = size / frequency[0];
- position = distance / 2.0;
- for (i = 0; i < frequency[0]; i++, position += distance)
- {
- CGContextMoveToPoint(cr, 0.0, position);
- CGContextAddLineToPoint(cr, size, position);
- }
- distance = size / frequency[1];
- position = distance / 2.0;
- for (i = 0; i < frequency[1]; i++, position += distance)
- {
- CGContextMoveToPoint(cr, position, 0.0);
- CGContextAddLineToPoint(cr, position, size);
- }
- distance = size / frequency[2];
- position = distance / 2.0;
- for (i = 0; i < frequency[2]; i++, position += distance)
- {
- CGContextMoveToPoint(cr, position, 0.0);
- CGContextAddLineToPoint(cr, 0.0, position);
- CGContextMoveToPoint(cr, position, size);
- CGContextAddLineToPoint(cr, size, position);
- }
- distance = size / frequency[3];
- position = distance / 2.0;
- for (i = 0; i < frequency[3]; i++, position += distance)
- {
- CGContextMoveToPoint(cr, position, 0.0);
- CGContextAddLineToPoint(cr, size, size-position);
- CGContextMoveToPoint(cr, position, size);
- CGContextAddLineToPoint(cr, 0.0, size-position);
- }
- CGContextSetLineWidth(cr, 2.0);
- CGContextSetLineCap(cr, kCGLineCapSquare);
- CGContextStrokePath(cr);
-
- Py_DECREF(string);
-}
-
-static void _release_hatch(void* info)
-{
- PyObject* hatches = info;
- Py_DECREF(hatches);
-}
-
static PyObject*
-GraphicsContext_set_hatch(GraphicsContext* self, PyObject* args)
-{ PyObject* hatches;
-
- const float size = 12.0;
- static const CGPatternCallbacks callbacks = {0,
- &_draw_hatch,
- &_release_hatch};
-
- CGContextRef cr = self->cr;
- if (!cr)
- {
- PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
- return NULL;
- }
-
- if(!PyArg_ParseTuple(args, "O", &hatches)) return NULL;
- if(!PyString_Check(hatches)) return NULL;
-
- Py_INCREF(hatches);
-
- CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
- CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(baseSpace);
- CGColorSpaceRelease(baseSpace);
- CGContextSetFillColorSpace(cr, patternSpace);
- CGColorSpaceRelease(patternSpace);
-
- self->pattern = CGPatternCreate((void*)hatches,
- CGRectMake(0, 0, size, size),
- CGAffineTransformIdentity, size, size,
- kCGPatternTilingNoDistortion,
- false,
- &callbacks);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject*
GraphicsContext_set_linewidth (GraphicsContext* self, PyObject* args)
{
float width;
@@ -965,238 +1109,6 @@
return 1;
}
-static int
-_draw_path(CGContextRef cr, PyObject* path, CGAffineTransform affine)
-{
- CGPoint point;
-
- PyObject* vertices = PyObject_GetAttrString(path, "vertices");
- if (vertices==NULL)
- {
- PyErr_SetString(PyExc_AttributeError, "path has no vertices");
- return -1;
- }
- Py_DECREF(vertices); /* Don't keep a reference here */
-
- PyObject* codes = PyObject_GetAttrString(path, "codes");
- if (codes==NULL)
- {
- PyErr_SetString(PyExc_AttributeError, "path has no codes");
- return -1;
- }
- Py_DECREF(codes); /* Don't keep a reference here */
-
- PyArrayObject* coordinates;
- coordinates = (PyArrayObject*)PyArray_FromObject(vertices,
- NPY_DOUBLE, 2, 2);
- if (!coordinates)
- {
- PyErr_SetString(PyExc_ValueError, "failed to convert vertices array");
- return -1;
- }
-
- if (PyArray_NDIM(coordinates) != 2 || PyArray_DIM(coordinates, 1) != 2)
- {
- Py_DECREF(coordinates);
- PyErr_SetString(PyExc_ValueError, "invalid vertices array");
- return -1;
- }
-
- npy_intp n = PyArray_DIM(coordinates, 0);
-
- if (n==0) /* Nothing to do here */
- {
- Py_DECREF(coordinates);
- return 0;
- }
-
- PyArrayObject* codelist = NULL;
- if (codes != Py_None)
- {
- codelist = (PyArrayObject*)PyArray_FromObject(codes,
- NPY_UINT8, 1, 1);
- if (!codelist)
- {
- Py_DECREF(coordinates);
- PyErr_SetString(PyExc_ValueError, "invalid codes array");
- return -1;
- }
- }
-
- if (codelist==NULL)
- {
- npy_intp i;
- npy_uint8 code = MOVETO;
- for (i = 0; i < n; i++)
- {
- point.x = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 0));
- point.y = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 1));
- if (isnan(point.x) || isnan(point.y))
- {
- code = MOVETO;
- }
- else
- {
- point = CGPointApplyAffineTransform(point, affine);
- switch (code)
- {
- case MOVETO:
- CGContextMoveToPoint(cr, point.x, point.y);
- break;
- case LINETO:
- CGContextAddLineToPoint(cr, point.x, point.y);
- break;
- }
- code = LINETO;
- }
- }
- }
- else
- {
- npy_intp i = 0;
- BOOL was_nan = false;
- npy_uint8 code;
- CGFloat x1, y1, x2, y2, x3, y3;
- while (i < n)
- {
- code = *(npy_uint8*)PyArray_GETPTR1(codelist, i);
- if (code == CLOSEPOLY)
- {
- CGContextClosePath(cr);
- i++;
- }
- else if (code == STOP)
- {
- break;
- }
- else if (was_nan)
- {
- if (code==CURVE3) i++;
- else if (code==CURVE4) i+=2;
- x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
- y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
- i++;
- if (isnan(x1) || isnan(y1))
- {
- was_nan = true;
- }
- else
- {
- point.x = x1;
- point.y = y1;
- point = CGPointApplyAffineTransform(point, affine);
- CGContextMoveToPoint(cr, point.x, point.y);
- was_nan = false;
- }
- }
- else if (code==MOVETO)
- {
- x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
- y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
- i++;
- if (isnan(x1) || isnan(y1))
- {
- was_nan = true;
- }
- else
- {
- point.x = x1;
- point.y = y1;
- point = CGPointApplyAffineTransform(point, affine);
- CGContextMoveToPoint(cr, point.x, point.y);
- was_nan = false;
- }
- }
- else if (code==LINETO)
- {
- x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
- y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
- i++;
- if (isnan(x1) || isnan(y1))
- {
- was_nan = true;
- }
- else
- {
- point.x = x1;
- point.y = y1;
- point = CGPointApplyAffineTransform(point, affine);
- CGContextAddLineToPoint(cr, point.x, point.y);
- was_nan = false;
- }
- }
- else if (code==CURVE3)
- {
- x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
- y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
- i++;
- x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
- y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
- i++;
- if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2))
- {
- was_nan = true;
- }
- else
- {
- point.x = x1;
- point.y = y1;
- point = CGPointApplyAffineTransform(point, affine);
- x1 = point.x;
- y1 = point.y;
- point.x = x2;
- point.y = y2;
- point = CGPointApplyAffineTransform(point, affine);
- x2 = point.x;
- y2 = point.y;
- CGContextAddQuadCurveToPoint(cr, x1, y1, x2, y2);
- was_nan = false;
- }
- }
- else if (code==CURVE4)
- {
- x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
- y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
- i++;
- x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
- y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
- i++;
- x3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
- y3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
- i++;
- if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2) || isnan(x3) || isnan(y3))
- {
- was_nan = true;
- }
- else
- {
- point.x = x1;
- point.y = y1;
- point = CGPointApplyAffineTransform(point, affine);
- x1 = point.x;
- y1 = point.y;
- point.x = x2;
- point.y = y2;
- point = CGPointApplyAffineTransform(point, affine);
- x2 = point.x;
- y2 = point.y;
- point.x = x3;
- point.y = y3;
- point = CGPointApplyAffineTransform(point, affine);
- x3 = point.x;
- y3 = point.y;
- CGContextAddCurveToPoint(cr, x1, y1, x2, y2, x3, y3);
- was_nan = false;
- }
- }
- }
- }
-
- Py_DECREF(coordinates);
- Py_XDECREF(codelist);
- return n;
-}
-
static PyObject*
GraphicsContext_draw_path (GraphicsContext* self, PyObject* args)
{
@@ -1230,6 +1142,7 @@
if (n > 0)
{
+ PyObject* hatchpath;
if(rgbFace)
{
float r, g, b;
@@ -1239,22 +1152,60 @@
return NULL;
}
CGContextSaveGState(cr);
- if(self->pattern)
- {
- float components[4];
- components[0] = r;
- components[1] = g;
- components[2] = b;
- components[3] = 1.0;
- CGContextSetFillPattern(cr, self->pattern, components);
- CGPatternRelease(self->pattern);
- self->pattern = nil;
- }
- else CGContextSetRGBFillColor(cr, r, g, b, 1.0);
+ CGContextSetRGBFillColor(cr, r, g, b, 1.0);
CGContextDrawPath(cr, kCGPathFillStroke);
CGContextRestoreGState(cr);
}
else CGContextStrokePath(cr);
+
+ hatchpath = PyObject_CallMethod((PyObject*)self, "get_hatch_path", "");
+ if (!hatchpath)
+ {
+ return NULL;
+ }
+ else if (hatchpath==Py_None)
+ {
+ Py_DECREF(hatchpath);
+ }
+ else
+ {
+ float color[4] = {0, 0, 0, 1};
+ CGPatternRef pattern;
+ static const CGPatternCallbacks callbacks = {0,
+ &_draw_hatch,
+ &_release_hatch};
+ PyObject* rgb = PyObject_CallMethod((PyObject*)self, "get_rgb", "");
+ if (!rgb)
+ {
+ Py_DECREF(hatchpath);
+ return NULL;
+ }
+ ok = PyArg_ParseTuple(rgb, "ffff", &color[0], &color[1], &color[2], &color[3]);
+ Py_DECREF(rgb);
+ if (!ok)
+ {
+ Py_DECREF(hatchpath);
+ return NULL;
+ }
+
+ CGColorSpaceRef baseSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(baseSpace);
+ CGColorSpaceRelease(baseSpace);
+ CGContextSetFillColorSpace(cr, patternSpace);
+ CGColorSpaceRelease(patternSpace);
+
+ pattern = CGPatternCreate((void*)hatchpath,
+ CGRectMake(0, 0, HATCH_SIZE, HATCH_SIZE),
+ CGAffineTransformIdentity,
+ HATCH_SIZE, HATCH_SIZE,
+ kCGPatternTilingNoDistortion,
+ false,
+ &callbacks);
+ CGContextSetFillPattern(cr, pattern, color);
+ CGPatternRelease(pattern);
+ _draw_path(cr, path, affine);
+ CGContextFillPath(cr);
+ }
}
Py_INCREF(Py_None);
@@ -1297,18 +1248,7 @@
{
return NULL;
}
- if(self->pattern)
- {
- float components[4];
- components[0] = r;
- components[1] = g;
- components[2] = b;
- components[3] = 1.0;
- CGContextSetFillPattern(cr, self->pattern, components);
- CGPatternRelease(self->pattern);
- self->pattern = nil;
- }
- else CGContextSetRGBFillColor(cr, r, g, b, 1.0);
+ CGContextSetRGBFillColor(cr, r, g, b, 1.0);
}
CGAffineTransform affine;
@@ -2516,7 +2456,7 @@
const size_t nComponents = 4; /* red, green, blue, alpha */
const size_t bitsPerPixel = bitsPerComponent * nComponents;
const size_t bytesPerRow = nComponents * bytesPerComponent * ncols;
- CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
+ CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
Py_INCREF(image);
n = PyString_GET_SIZE(image);
@@ -2627,22 +2567,6 @@
METH_VARARGS,
"Sets the current stroke and fill color to a value in the DeviceGray color space."
},
- {"set_hatch",
- (PyCFunction)GraphicsContext_set_hatch,
- METH_VARARGS,
- "\n"
- " hatch can be one of:\n"
- " / - diagonal hatching\n"
- " \\ - back diagonal\n"
- " | - vertical\n"
- " - - horizontal\n"
- " # - crossed\n"
- " X - crossed diagonal\n"
- " letters can be combined, in which case all the specified\n"
- " hatchings are done\n"
- " if same letter repeats, it increases the density of hatching\n"
- " in that direction\n"
- },
{"set_linewidth",
(PyCFunction)GraphicsContext_set_linewidth,
METH_VARARGS,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2009-01-10 20:05:26
|
Revision: 6772
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6772&view=rev
Author: jdh2358
Date: 2009-01-10 20:05:24 +0000 (Sat, 10 Jan 2009)
Log Message:
-----------
michiel's backend qt draw idle patch - sf id 2468809
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-10 20:03:59 UTC (rev 6771)
+++ trunk/matplotlib/CHANGELOG 2009-01-10 20:05:24 UTC (rev 6772)
@@ -1,5 +1,6 @@
-2009-01-10 Applied Michiel's hatch patch for macosx backend. Closes
- sf patch 2497785 - JDH
+2009-01-10 Applied Michiel's hatch patch for macosx backend and
+ draw_idle patch for qt. Closes sf patched 2497785 and
+ 2468809 - JDH
2009-01-06 Fix bug in setting of dashed negative contours. - EF
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2009-01-10 20:03:59 UTC (rev 6771)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2009-01-10 20:05:24 UTC (rev 6772)
@@ -37,7 +37,7 @@
if matplotlib.is_interactive():
figManager = Gcf.get_active()
if figManager != None:
- figManager.canvas.draw()
+ figManager.canvas.draw_idle()
def _create_qApp():
"""
@@ -97,6 +97,7 @@
FigureCanvasBase.__init__( self, figure )
self.figure = figure
self.setMouseTracking( True )
+ self._idle = True
# hide until we can test and fix
#self.startTimer(backend_IdleEvent.milliseconds)
w,h = self.get_width_height()
@@ -198,6 +199,15 @@
FigureCanvasBase.stop_event_loop_default(self)
stop_event_loop.__doc__=FigureCanvasBase.stop_event_loop_default.__doc__
+ def draw_idle(self):
+ 'update drawing area only if idle'
+ d = self._idle
+ self._idle = False
+ def idle_draw(*args):
+ self.draw()
+ self._idle = True
+ if d: QtCore.QTimer.singleShot(0, idle_draw)
+
class FigureManagerQT( FigureManagerBase ):
"""
Public attributes
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|