You can subscribe to this list here.
| 2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(115) |
Aug
(120) |
Sep
(137) |
Oct
(170) |
Nov
(461) |
Dec
(263) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2008 |
Jan
(120) |
Feb
(74) |
Mar
(35) |
Apr
(74) |
May
(245) |
Jun
(356) |
Jul
(240) |
Aug
(115) |
Sep
(78) |
Oct
(225) |
Nov
(98) |
Dec
(271) |
| 2009 |
Jan
(132) |
Feb
(84) |
Mar
(74) |
Apr
(56) |
May
(90) |
Jun
(79) |
Jul
(83) |
Aug
(296) |
Sep
(214) |
Oct
(76) |
Nov
(82) |
Dec
(66) |
| 2010 |
Jan
(46) |
Feb
(58) |
Mar
(51) |
Apr
(77) |
May
(58) |
Jun
(126) |
Jul
(128) |
Aug
(64) |
Sep
(50) |
Oct
(44) |
Nov
(48) |
Dec
(54) |
| 2011 |
Jan
(68) |
Feb
(52) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
| 2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
1
(7) |
2
(14) |
3
(6) |
4
(8) |
5
(6) |
6
(3) |
|
7
(2) |
8
(22) |
9
(9) |
10
(23) |
11
(14) |
12
(22) |
13
(7) |
|
14
(3) |
15
(22) |
16
(13) |
17
(18) |
18
(21) |
19
(9) |
20
|
|
21
(3) |
22
(6) |
23
(5) |
24
|
25
|
26
(3) |
27
|
|
28
(1) |
29
(11) |
30
(1) |
31
(12) |
|
|
|
|
From: <js...@us...> - 2008-12-31 20:19:20
|
Revision: 6729
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6729&view=rev
Author: jswhit
Date: 2008-12-31 20:19:16 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
fix small bug in land-sea mask lat/lon definitions
Modified Paths:
--------------
trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py
Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py
===================================================================
--- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008-12-31 19:56:55 UTC (rev 6728)
+++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008-12-31 20:19:16 UTC (rev 6729)
@@ -3110,9 +3110,16 @@
lsmaskf = open(os.path.join(basemap_datadir,'5minmask.bin'),'rb')
nlons = 4320; nlats = nlons/2
delta = 360./float(nlons)
- lsmask_lons = np.arange(-180+0.5*delta,180.,delta)
- lsmask_lats = np.arange(-90.+0.5*delta,90.,delta)
lsmask = np.reshape(np.fromstring(lsmaskf.read(),np.uint8),(nlats,nlons))
+ lsmask_lons = np.arange(-180,180.,delta)
+ lsmask_lats = np.arange(-90.,90+0.5*delta,delta)
+ # add cyclic point in longitude
+ lsmask, lsmask_lons = addcyclic(lsmask, lsmask_lons)
+ nlons = nlons + 1; nlats = nlats + 1
+ # add North Pole point (assumed water)
+ tmparr = np.zeros((nlats,nlons),lsmask.dtype)
+ tmparr[0:nlats-1,0:nlons] = lsmask
+ lsmask = tmparr
lsmaskf.close()
# instance variable lsmask is set on first invocation,
# it contains the land-sea mask interpolated to the native
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jo...@us...> - 2008-12-31 19:57:00
|
Revision: 6728
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6728&view=rev
Author: jouni
Date: 2008-12-31 19:56:55 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
Don't crash with Microsoft fonts such as Tahoma
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-31 19:42:44 UTC (rev 6727)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-31 19:56:55 UTC (rev 6728)
@@ -333,7 +333,7 @@
self.file.write(compressed)
self.compressobj = None
-class PdfFile:
+class PdfFile(object):
"""PDF file with one page."""
def __init__(self, width, height, dpi, filename):
@@ -900,7 +900,14 @@
# Beginning of main embedTTF function...
# You are lost in a maze of TrueType tables, all different...
- ps_name = Name(font.get_sfnt()[(1,0,0,6)])
+ sfnt = font.get_sfnt()
+ try:
+ ps_name = sfnt[(1,0,0,6)] # Macintosh scheme
+ except KeyError:
+ # Microsoft scheme:
+ ps_name = sfnt[(3,1,0x0409,6)].decode('utf-16be').encode('ascii','replace')
+ # (see freetype/ttnameid.h)
+ ps_name = Name(ps_name)
pclt = font.get_sfnt_table('pclt') \
or { 'capHeight': 0, 'xHeight': 0 }
post = font.get_sfnt_table('post') \
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jo...@us...> - 2008-12-31 19:42:48
|
Revision: 6727
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6727&view=rev
Author: jouni
Date: 2008-12-31 19:42:44 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
Modernize a little since we can assume Python 2.4
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-31 19:01:41 UTC (rev 6726)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-31 19:42:44 UTC (rev 6727)
@@ -185,7 +185,7 @@
"Don't know a PDF representation for %s objects." \
% type(obj)
-class Reference:
+class Reference(object):
"""PDF reference object.
Use PdfFile.reserveObject() to create References.
"""
@@ -205,8 +205,9 @@
write(pdfRepr(contents))
write("\nendobj\n")
-class Name:
+class Name(object):
"""PDF name object."""
+ __slots__ = ('name',)
_regex = re.compile(r'[^!-~]')
def __init__(self, name):
@@ -218,15 +219,16 @@
def __repr__(self):
return "<Name %s>" % self.name
+ @staticmethod
def hexify(match):
return '#%02x' % ord(match.group())
- hexify = staticmethod(hexify)
def pdfRepr(self):
return '/' + self.name
-class Operator:
+class Operator(object):
"""PDF operator object."""
+ __slots__ = ('op',)
def __init__(self, op):
self.op = op
@@ -257,12 +259,13 @@
Op = Bunch(**dict([(name, Operator(value))
for name, value in _pdfops.items()]))
-class Stream:
+class Stream(object):
"""PDF stream object.
This has no pdfRepr method. Instead, call begin(), then output the
contents of the stream by calling write(), and finally call end().
"""
+ __slots__ = ('id', 'len', 'pdfFile', 'file', 'compressobj', 'extra', 'pos')
def __init__(self, id, len, file, extra=None):
"""id: object id of stream; len: an unused Reference object for the
@@ -1107,7 +1110,7 @@
self.output(Op.stroke)
self.endStream()
- #@staticmethod
+ @staticmethod
def pathOperations(path, transform, simplify=None):
tpath = transform.transform_path(path)
@@ -1131,7 +1134,6 @@
cmds.append(Op.closepath)
last_points = points
return cmds
- pathOperations = staticmethod(pathOperations)
def writePath(self, path, transform):
cmds = self.pathOperations(
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-31 19:01:44
|
Revision: 6726
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6726&view=rev
Author: jswhit
Date: 2008-12-31 19:01:41 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
add comment
Modified Paths:
--------------
trunk/toolkits/basemap/examples/garp.py
Modified: trunk/toolkits/basemap/examples/garp.py
===================================================================
--- trunk/toolkits/basemap/examples/garp.py 2008-12-31 19:00:19 UTC (rev 6725)
+++ trunk/toolkits/basemap/examples/garp.py 2008-12-31 19:01:41 UTC (rev 6726)
@@ -16,6 +16,8 @@
lat_0 = float(raw_input('input reference lat (degrees):'))
location = raw_input('name of location:')
+# no width/height or lat/lon corners specified, so whole world
+# is plotted in a circle.
m = Basemap(resolution='c',projection='aeqd',lat_0=lat_0,lon_0=lon_0)
# draw coastlines and fill continents.
@@ -27,8 +29,8 @@
#m.drawmapboundary(fill_color='white')
#m.drawcoastlines(linewidth=0.5)
#m.fillcontinents(color='black',lake_color='white')
-#m.drawparallels(np.arange(-80,81,20))
-#m.drawmeridians(np.arange(-180,180,20))
+#m.drawparallels(np.arange(-80,81,20),color='0.7')
+#m.drawmeridians(np.arange(-180,180,20),color='0.7')
# draw lsmask instead of drawing continents (slower, but more robust).
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-31 19:00:24
|
Revision: 6725
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6725&view=rev
Author: jswhit
Date: 2008-12-31 19:00:19 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
make graticule gray show the lines show up over continents.
Modified Paths:
--------------
trunk/toolkits/basemap/examples/garp.py
Modified: trunk/toolkits/basemap/examples/garp.py
===================================================================
--- trunk/toolkits/basemap/examples/garp.py 2008-12-31 18:49:07 UTC (rev 6724)
+++ trunk/toolkits/basemap/examples/garp.py 2008-12-31 19:00:19 UTC (rev 6725)
@@ -33,8 +33,8 @@
# draw lsmask instead of drawing continents (slower, but more robust).
m.drawlsmask(land_color='black',ocean_color='white',lakes=True)
-m.drawparallels(np.arange(-80,81,20))
-m.drawmeridians(np.arange(-180,180,20))
+m.drawparallels(np.arange(-80,81,20),color='0.7')
+m.drawmeridians(np.arange(-180,180,20),color='0.7')
m.drawmapboundary()
# blue marble background (pretty, but slow).
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-31 18:49:12
|
Revision: 6724
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6724&view=rev
Author: jswhit
Date: 2008-12-31 18:49:07 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
fix bluemarble for full-disk aeqd, update garp.py example.
Modified Paths:
--------------
trunk/toolkits/basemap/examples/garp.py
trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py
Modified: trunk/toolkits/basemap/examples/garp.py
===================================================================
--- trunk/toolkits/basemap/examples/garp.py 2008-12-31 17:10:51 UTC (rev 6723)
+++ trunk/toolkits/basemap/examples/garp.py 2008-12-31 18:49:07 UTC (rev 6724)
@@ -17,17 +17,38 @@
location = raw_input('name of location:')
m = Basemap(resolution='c',projection='aeqd',lat_0=lat_0,lon_0=lon_0)
-# fill background.
-m.drawmapboundary(fill_color='aqua')
-# draw coasts and fill continents.
-m.drawcoastlines(linewidth=0.5)
-m.fillcontinents(color='coral',lake_color='aqua')
-# 20 degree graticule.
+
+# draw coastlines and fill continents.
+# **it's easy to make this fail with global aeqd plots.
+# For example, if the center point is at the North Pole,
+# the continent filling routines get confused and fills
+# the outside of Antartica instead of the inside**
+
+#m.drawmapboundary(fill_color='white')
+#m.drawcoastlines(linewidth=0.5)
+#m.fillcontinents(color='black',lake_color='white')
+#m.drawparallels(np.arange(-80,81,20))
+#m.drawmeridians(np.arange(-180,180,20))
+
+# draw lsmask instead of drawing continents (slower, but more robust).
+
+m.drawlsmask(land_color='black',ocean_color='white',lakes=True)
m.drawparallels(np.arange(-80,81,20))
m.drawmeridians(np.arange(-180,180,20))
-# draw a black dot at the center.
+m.drawmapboundary()
+
+# blue marble background (pretty, but slow).
+
+#m.bluemarble(scale=0.5)
+#m.drawparallels(np.arange(-80,81,20),color='0.5')
+#m.drawmeridians(np.arange(-180,180,20),color='0.5')
+#m.drawmapboundary(color='0.5')
+
+# draw a red dot at the center.
xpt, ypt = m(lon_0, lat_0)
-m.plot([xpt],[ypt],'ko')
+m.plot([xpt],[ypt],'ro')
+
# draw the title.
plt.title('The World According to Garp in '+location)
+
plt.show()
Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py
===================================================================
--- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008-12-31 17:10:51 UTC (rev 6723)
+++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008-12-31 18:49:07 UTC (rev 6724)
@@ -3317,7 +3317,8 @@
self.transform_scalar(self._bm_rgba[:,:,k],\
self._bm_lons,self._bm_lats,nx,ny,returnxy=True)
# for ortho,geos mask pixels outside projection limb.
- if self.projection in ['geos','ortho']:
+ if self.projection in ['geos','ortho'] or \
+ (self.projection == 'aeqd' and self._fulldisk):
lonsr,latsr = self(x,y,inverse=True)
mask = ma.zeros((ny,nx,4),np.int8)
mask[:,:,0] = np.logical_or(lonsr>1.e20,latsr>1.e30)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-31 17:10:56
|
Revision: 6723
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6723&view=rev
Author: jswhit
Date: 2008-12-31 17:10:51 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
more comments added to document proj4 bug
Modified Paths:
--------------
trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
===================================================================
--- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-31 17:00:34 UTC (rev 6722)
+++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-31 17:10:51 UTC (rev 6723)
@@ -99,7 +99,11 @@
# raise an exception for ellipsoids - there appears to be a bug
# in proj4 that causes the inverse transform to fail for points
# more than 90 degrees of arc away from center point for ellipsoids
- # (works fine for spheres)
+ # (works fine for spheres) - below is an example
+ #from pyproj import Proj
+ #p1 = Proj(proj='aeqd',a=6378137.00,b=6356752.3142,lat_0=0,lon_0=0)
+ #x,y= p1(91,0)
+ #lon,lat = p1(x,y,inverse=True) # lon is 89 instead of 91
if self.ellipsoid:
msg = dedent("""
full disk (whole world) Azimuthal Equidistant projection can
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-31 17:00:46
|
Revision: 6722
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6722&view=rev
Author: jswhit
Date: 2008-12-31 17:00:34 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
add some comments
Modified Paths:
--------------
trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
===================================================================
--- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-31 16:29:37 UTC (rev 6721)
+++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-31 17:00:34 UTC (rev 6722)
@@ -96,13 +96,17 @@
urcrnrlat == 90):
self._fulldisk = True
self._proj4 = pyproj.Proj(projparams)
+ # raise an exception for ellipsoids - there appears to be a bug
+ # in proj4 that causes the inverse transform to fail for points
+ # more than 90 degrees of arc away from center point for ellipsoids
+ # (works fine for spheres)
if self.ellipsoid:
msg = dedent("""
full disk (whole world) Azimuthal Equidistant projection can
only be drawn for a perfect sphere""")
raise ValueError(msg)
- llcrnrx = -np.pi*self.rminor
- llcrnry = -np.pi*self.rminor
+ llcrnrx = -np.pi*self.rmajor
+ llcrnry = -np.pi*self.rmajor
self._width = -llcrnrx
self._height = -llcrnry
urcrnrx = -llcrnrx
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-31 16:29:42
|
Revision: 6721
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6721&view=rev
Author: jswhit
Date: 2008-12-31 16:29:37 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
fix typo
Modified Paths:
--------------
trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
===================================================================
--- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-31 14:41:54 UTC (rev 6720)
+++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-31 16:29:37 UTC (rev 6721)
@@ -101,8 +101,8 @@
full disk (whole world) Azimuthal Equidistant projection can
only be drawn for a perfect sphere""")
raise ValueError(msg)
- llcrnrx = -0.5*(self.rmajor+self.rminor)
- llcrnry = -0.5*(self.rmajor+self.rminor)
+ llcrnrx = -np.pi*self.rminor
+ llcrnry = -np.pi*self.rminor
self._width = -llcrnrx
self._height = -llcrnry
urcrnrx = -llcrnrx
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-31 14:42:07
|
Revision: 6720
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6720&view=rev
Author: jswhit
Date: 2008-12-31 14:41:54 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
fix bug in fulldisk aeqd, change garp.py example to plot whole disk
Modified Paths:
--------------
trunk/toolkits/basemap/examples/garp.py
Modified: trunk/toolkits/basemap/examples/garp.py
===================================================================
--- trunk/toolkits/basemap/examples/garp.py 2008-12-31 14:37:44 UTC (rev 6719)
+++ trunk/toolkits/basemap/examples/garp.py 2008-12-31 14:41:54 UTC (rev 6720)
@@ -11,20 +11,12 @@
# it will be to reach that destination.
# The specified point shows up as a red dot in the center of the map.
-# This example shows how to use the width and height keywords
-# to specify the map projection region (instead of specifying
-# the lat/lon of the upper right and lower left corners).
-
# user enters the lon/lat of the point, and it's name
lon_0 = float(raw_input('input reference lon (degrees):'))
lat_0 = float(raw_input('input reference lat (degrees):'))
location = raw_input('name of location:')
-# use these values to setup Basemap instance.
-width = 28000000
-m = Basemap(width=width,height=width,\
- resolution='c',projection='aeqd',\
- lat_0=lat_0,lon_0=lon_0)
+m = Basemap(resolution='c',projection='aeqd',lat_0=lat_0,lon_0=lon_0)
# fill background.
m.drawmapboundary(fill_color='aqua')
# draw coasts and fill continents.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-31 14:37:48
|
Revision: 6719
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6719&view=rev
Author: jswhit
Date: 2008-12-31 14:37:44 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
whole world aeqd added
Modified Paths:
--------------
trunk/toolkits/basemap/Changelog
trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py
trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
Modified: trunk/toolkits/basemap/Changelog
===================================================================
--- trunk/toolkits/basemap/Changelog 2008-12-31 13:20:50 UTC (rev 6718)
+++ trunk/toolkits/basemap/Changelog 2008-12-31 14:37:44 UTC (rev 6719)
@@ -1,4 +1,7 @@
version 0.99.3 (not yet released)
+ * if upper right/lower left corners nor width/height given for
+ azimuthal equidistant ('aeqd') the whole world is drawn in
+ a circle (only works for perfect spheres, not ellipsoids).
* have setup.py check for already installed pyshapelib (just
like it does for httplib2 and pydap).
* Basemap will now look for it's data in BASEMAPDATA.
Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py
===================================================================
--- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008-12-31 13:20:50 UTC (rev 6718)
+++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008-12-31 14:37:44 UTC (rev 6719)
@@ -625,10 +625,17 @@
raise ValueError, 'must specify lat_0 and lon_0 for Azimuthal Equidistant basemap'
if not using_corners:
if width is None or height is None:
- raise ValueError, 'must either specify lat/lon values of corners (llcrnrlon,llcrnrlat,ucrnrlon,urcrnrlat) in degrees or width and height in meters'
+ self._fulldisk = True
+ llcrnrlon = -180.
+ llcrnrlat = -90.
+ urcrnrlon = 180
+ urcrnrlat = 90.
+ else:
+ self._fulldisk = False
if lon_0 is None or lat_0 is None:
raise ValueError, 'must specify lon_0 and lat_0 when using width, height to specify projection region'
- llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat = _choosecorners(width,height,**projparams)
+ if not self._fulldisk:
+ llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat = _choosecorners(width,height,**projparams)
self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat
self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat
elif projection in _cylproj:
@@ -1046,12 +1053,8 @@
if self.projection in ['ortho','geos']:
# circular region.
thetas = np.linspace(0.,2.*np.pi,2*nx*ny)[:-1]
- if self.projection == 'ortho':
- rminor = self.rmajor
- rmajor = self.rmajor
- else:
- rminor = self._height
- rmajor = self._width
+ rminor = self._height
+ rmajor = self._width
x = rmajor*np.cos(thetas) + rmajor
y = rminor*np.sin(thetas) + rminor
b = np.empty((len(x),2),np.float64)
@@ -1075,6 +1078,16 @@
projparms['x_0']=-llcrnrx
projparms['y_0']=-llcrnry
maptran = pyproj.Proj(projparms)
+ elif self.projection == 'aeqd' and self._fulldisk:
+ # circular region.
+ thetas = np.linspace(0.,2.*np.pi,2*nx*ny)[:-1]
+ rminor = self._height
+ rmajor = self._width
+ x = rmajor*np.cos(thetas) + rmajor
+ y = rminor*np.sin(thetas) + rminor
+ b = np.empty((len(x),2),np.float64)
+ b[:,0]=x; b[:,1]=y
+ boundaryxy = _geoslib.Polygon(b)
elif self.projection in _pseudocyl:
# quasi-elliptical region.
lon_0 = self.projparams['lon_0']
@@ -1188,11 +1201,10 @@
elif ax is None and self.ax is not None:
ax = self.ax
limb = None
- if self.projection == 'ortho':
- limb = Circle((self.rmajor,self.rmajor),self.rmajor)
- elif self.projection == 'geos':
+ if self.projection in ['ortho','geos'] or (self.projection=='aeqd' and\
+ self._fulldisk):
limb = Ellipse((self._width,self._height),2.*self._width,2.*self._height)
- if self.projection in ['ortho','geos'] and self._fulldisk:
+ if self.projection in ['ortho','geos','aeqd'] and self._fulldisk:
# elliptical region.
ax.add_patch(limb)
if fill_color is None:
@@ -1822,7 +1834,7 @@
linecolls[circ] = (lines,[])
# draw labels for parallels
# parallels not labelled for fulldisk orthographic or geostationary
- if self.projection in ['ortho','geos','vandg'] and max(labels):
+ if self.projection in ['ortho','geos','vandg','aeqd'] and max(labels):
if self.projection == 'vandg' or self._fulldisk:
print 'Warning: Cannot label parallels on %s basemap' % _projnames[self.projection]
labels = [0,0,0,0]
@@ -2068,9 +2080,12 @@
if self.projection in ['sinu','moll','vandg'] and max(labels):
print 'Warning: Cannot label meridians on %s basemap' % _projnames[self.projection]
labels = [0,0,0,0]
- if self.projection in ['ortho','geos'] and max(labels):
+ if self.projection in ['ortho','geos','aeqd'] and max(labels):
if self._fulldisk:
- print 'Warning: Cannot label meridians on full-disk Geostationary or Orthographic basemap'
+ print dedent(
+ """'Warning: Cannot label meridians on full-disk
+ Geostationary, Orthographic or Azimuthal equidistant basemap
+ """)
labels = [0,0,0,0]
# search along edges of map to see if parallels intersect.
# if so, find x,y location of intersection and draw a label there.
@@ -2535,7 +2550,7 @@
# turn off axes frame for non-rectangular projections.
if self.projection in _pseudocyl:
ax.set_frame_on(False)
- if self.projection in ['ortho','geos'] and self._fulldisk:
+ if self.projection in ['ortho','geos','aeqd'] and self._fulldisk:
ax.set_frame_on(False)
# make sure aspect ratio of map preserved.
# plot is re-centered in bounding rectangle.
Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
===================================================================
--- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-31 13:20:50 UTC (rev 6718)
+++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-31 14:37:44 UTC (rev 6719)
@@ -1,6 +1,7 @@
import numpy as np
import pyproj
import math
+from matplotlib.cbook import dedent
__version__ = '1.2.2'
_dg2rad = math.radians(1.)
@@ -70,19 +71,18 @@
self.esq = (self.rmajor**2 - self.rminor**2)/self.rmajor**2
self.llcrnrlon = llcrnrlon
self.llcrnrlat = llcrnrlat
- if self.projection not in ['ortho','geos','cyl'] + _pseudocyl:
- self._proj4 = pyproj.Proj(projparams)
- llcrnrx, llcrnry = self(llcrnrlon,llcrnrlat)
- elif self.projection == 'cyl':
+ if self.projection == 'cyl':
llcrnrx = llcrnrlon
llcrnry = llcrnrlat
- elif self.projection == 'ortho':
+ elif self.projection in 'ortho':
if (llcrnrlon == -180 and llcrnrlat == -90 and
urcrnrlon == 180 and urcrnrlat == 90):
self._fulldisk = True
self._proj4 = pyproj.Proj(projparams)
llcrnrx = -self.rmajor
llcrnry = -self.rmajor
+ self._width = 0.5*(self.rmajor+self.rminor)
+ self._height = 0.5*(self.rmajor+self.rminor)
urcrnrx = -llcrnrx
urcrnry = -llcrnry
else:
@@ -91,6 +91,22 @@
llcrnrx, llcrnry = self(llcrnrlon,llcrnrlat)
if llcrnrx > 1.e20 or llcrnry > 1.e20:
raise ValueError(_lower_left_out_of_bounds)
+ elif self.projection == 'aeqd' and\
+ (llcrnrlon == -180 and llcrnrlat == -90 and urcrnrlon == 180 and\
+ urcrnrlat == 90):
+ self._fulldisk = True
+ self._proj4 = pyproj.Proj(projparams)
+ if self.ellipsoid:
+ msg = dedent("""
+ full disk (whole world) Azimuthal Equidistant projection can
+ only be drawn for a perfect sphere""")
+ raise ValueError(msg)
+ llcrnrx = -0.5*(self.rmajor+self.rminor)
+ llcrnry = -0.5*(self.rmajor+self.rminor)
+ self._width = -llcrnrx
+ self._height = -llcrnry
+ urcrnrx = -llcrnrx
+ urcrnry = -llcrnry
elif self.projection == 'geos':
self._proj4 = pyproj.Proj(projparams)
# find major and minor axes of ellipse defining map proj region.
@@ -129,6 +145,10 @@
urcrnrx,xtmp = self(projparams['lon_0']+180.,0)
llcrnrx = -urcrnrx
llcrnry = -urcrnry
+ else:
+ self._proj4 = pyproj.Proj(projparams)
+ llcrnrx, llcrnry = self(llcrnrlon,llcrnrlat)
+ if self.projection == 'aeqd': self._fulldisk=False
# compute x_0, y_0 so ll corner of domain is x=0,y=0.
# note that for 'cyl' x,y == lon,lat
self.projparams['x_0']=-llcrnrx
@@ -144,18 +164,10 @@
if urcrnrislatlon:
self.urcrnrlon = urcrnrlon
self.urcrnrlat = urcrnrlat
- if self.projection not in ['ortho','geos'] + _pseudocyl:
+ if self.projection not in ['ortho','geos','aeqd'] + _pseudocyl:
urcrnrx,urcrnry = self(urcrnrlon,urcrnrlat)
- elif self.projection == 'ortho':
+ elif self.projection in ['ortho','geos','aeqd']:
if self._fulldisk:
- urcrnrx = 2.*self.rmajor
- urcrnry = 2.*self.rmajor
- else:
- urcrnrx,urcrnry = self(urcrnrlon,urcrnrlat)
- if urcrnrx > 1.e20 or urcrnry > 1.e20:
- raise ValueError(_upper_right_out_of_bounds)
- elif self.projection == 'geos':
- if self._fulldisk:
urcrnrx = 2.*self._width
urcrnry = 2.*self._height
else:
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 collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-30 16:07:06
|
Revision: 6717
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6717&view=rev
Author: jdh2358
Date: 2008-12-30 16:06:59 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
added rcparams import to path
Modified Paths:
--------------
branches/v0_98_5_maint/lib/matplotlib/path.py
Modified: branches/v0_98_5_maint/lib/matplotlib/path.py
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/path.py 2008-12-29 15:34:30 UTC (rev 6716)
+++ branches/v0_98_5_maint/lib/matplotlib/path.py 2008-12-30 16:06:59 UTC (rev 6717)
@@ -12,6 +12,7 @@
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 import rcParams
class Path(object):
"""
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: <md...@us...> - 2008-12-29 15:33:24
|
Revision: 6715
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6715&view=rev
Author: mdboom
Date: 2008-12-29 15:33:18 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Handle path.simplify rcParam in all backends.
Modified Paths:
--------------
branches/v0_98_5_maint/lib/matplotlib/path.py
Modified: branches/v0_98_5_maint/lib/matplotlib/path.py
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/path.py 2008-12-29 15:29:52 UTC (rev 6714)
+++ branches/v0_98_5_maint/lib/matplotlib/path.py 2008-12-29 15:33:18 UTC (rev 6715)
@@ -109,7 +109,7 @@
assert vertices.ndim == 2
assert vertices.shape[1] == 2
- self.should_simplify = (rcParam['path.simplify'] and
+ self.should_simplify = (rcParams['path.simplify'] and
(len(vertices) >= 128 and
(codes is None or np.all(codes <= Path.LINETO))))
self.has_nonfinite = not np.isfinite(vertices).all()
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:29:56
|
Revision: 6714
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6714&view=rev
Author: mdboom
Date: 2008-12-29 15:29:52 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Handle path.simplify rcParam in all backends.
Modified Paths:
--------------
branches/v0_98_5_maint/lib/matplotlib/path.py
Modified: branches/v0_98_5_maint/lib/matplotlib/path.py
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/path.py 2008-12-29 14:52:30 UTC (rev 6713)
+++ branches/v0_98_5_maint/lib/matplotlib/path.py 2008-12-29 15:29:52 UTC (rev 6714)
@@ -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
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jo...@us...> - 2008-12-29 14:52:33
|
Revision: 6713
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6713&view=rev
Author: jouni
Date: 2008-12-29 14:52:30 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Fix buglet in path.py
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/path.py
Modified: trunk/matplotlib/lib/matplotlib/path.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 14:42:20 UTC (rev 6712)
+++ trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 14:52:30 UTC (rev 6713)
@@ -12,6 +12,7 @@
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, maxdict
+from matplotlib import rcParams
class Path(object):
"""
@@ -109,7 +110,7 @@
assert vertices.ndim == 2
assert vertices.shape[1] == 2
- self.should_simplify = (rcParam['path.simplify'] and
+ self.should_simplify = (rcParams['path.simplify'] and
(len(vertices) >= 128 and
(codes is None or np.all(codes <= Path.LINETO))))
self.has_nonfinite = not np.isfinite(vertices).all()
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 14:25:57
|
Revision: 6711
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6711&view=rev
Author: mdboom
Date: 2008-12-29 14:25:47 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Oops in last commit
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/patches.py
Modified: trunk/matplotlib/lib/matplotlib/patches.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/patches.py 2008-12-29 14:23:24 UTC (rev 6710)
+++ trunk/matplotlib/lib/matplotlib/patches.py 2008-12-29 14:25:47 UTC (rev 6711)
@@ -252,7 +252,7 @@
ACCEPTS: [ '/' | '\\' | '|' | '-' | '#' | 'x' ] (ps & pdf backend only)
"""
- self._hatch = h
+ self._hatch = hatch
def get_hatch(self):
'Return the current hatching pattern'
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:10:31
|
Revision: 6709
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6709&view=rev
Author: mdboom
Date: 2008-12-29 14:10:22 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Oops in hatch_demo.py
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/hatch_demo.py
Modified: trunk/matplotlib/examples/pylab_examples/hatch_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-29 14:08:13 UTC (rev 6708)
+++ trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-29 14:10:22 UTC (rev 6709)
@@ -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', edgecolor='red', hatch="/")
+ax1.bar(range(1,5), range(1,5), color='gray', edgecolor='black', hatch="/")
ax2 = fig.add_subplot(122)
@@ -23,5 +23,3 @@
bar.set_hatch(pattern)
plt.show()
-plt.savefig("test.pdf")
-plt.savefig("test.ps")
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: <jo...@us...> - 2008-12-29 13:58:28
|
Revision: 6707
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6707&view=rev
Author: jouni
Date: 2008-12-29 13:58:18 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Fix bug in earlier bugfix
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-29 13:48:51 UTC (rev 6706)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-29 13:58:18 UTC (rev 6707)
@@ -528,7 +528,8 @@
# TODO: font effects such as SlantFont
matplotlib.verbose.report(
'Embedding Type 1 font ' + fontinfo.fontfile +
- ' with encoding ' + fontinfo.encodingfile, 'debug')
+ ' with encoding ' + (fontinfo.encodingfile or '(none)'),
+ 'debug')
# Use FT2Font to get several font properties
font = FT2Font(fontinfo.fontfile)
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: <js...@us...> - 2008-12-28 16:07:13
|
Revision: 6705
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6705&view=rev
Author: jswhit
Date: 2008-12-28 16:07:10 +0000 (Sun, 28 Dec 2008)
Log Message:
-----------
simplify calculation of geostationary limb
Modified Paths:
--------------
trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
Modified: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py
===================================================================
--- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-26 23:20:56 UTC (rev 6704)
+++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/proj.py 2008-12-28 16:07:10 UTC (rev 6705)
@@ -94,20 +94,21 @@
elif self.projection == 'geos':
self._proj4 = pyproj.Proj(projparams)
# find major and minor axes of ellipse defining map proj region.
- delta = 0.01
- lats = np.arange(0,90,delta)
- lon_0 = projparams['lon_0']
- lons = lon_0*np.ones(len(lats),'d')
- x, y = self._proj4(lons, lats)
- yi = (y > 1.e20).tolist()
- ny = yi.index(1)-1
- height = y[ny]
- lons = np.arange(lon_0,lon_0+90,delta)
- lats = np.zeros(len(lons),'d')
- x, y = self(lons, lats)
- xi = (x > 1.e20).tolist()
- nx = xi.index(1)-1
- width = x[nx]
+ # h is measured from surface of earth at equator.
+ h = projparams['h'] + self.rmajor
+ # latitude of horizon on central meridian
+ lonmax = 90.-(180./np.pi)*np.arcsin(self.rmajor/h)
+ # longitude of horizon on equator
+ latmax = 90.-(180./np.pi)*np.arcsin(self.rminor/h)
+ # truncate to nearest hundredth of a degree (to make sure
+ # they aren't slightly over the horizon)
+ latmax = int(100*latmax)/100.
+ lonmax = int(100*lonmax)/100.
+ # width and height of visible projection
+ P = pyproj.Proj(proj='geos',a=self.rmajor,\
+ b=self.rminor,lat_0=0,lon_0=0,h=projparams['h'])
+ x1,y1 = P(0.,latmax); x2,y2 = P(lonmax,0.)
+ width = x2; height = y1
self._height = height
self._width = width
if (llcrnrlon == -180 and llcrnrlat == -90 and
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|