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
|
2
(2) |
3
(4) |
4
(4) |
5
(2) |
6
(2) |
7
(6) |
8
(4) |
9
(1) |
10
(1) |
11
(2) |
12
|
13
(1) |
14
(5) |
15
|
16
(3) |
17
(4) |
18
(8) |
19
(4) |
20
(2) |
21
|
22
|
23
(2) |
24
(2) |
25
(1) |
26
|
27
(3) |
28
(2) |
29
(2) |
30
(1) |
31
(6) |
|
|
|
|
From: <fer...@us...> - 2009-03-18 19:44:35
|
Revision: 6994 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6994&view=rev Author: fer_perez Date: 2009-03-18 19:44:31 +0000 (Wed, 18 Mar 2009) Log Message: ----------- Add forgotten file Added Paths: ----------- trunk/py4science/examples/sphinx_template2/pyplots/fancy.py Added: trunk/py4science/examples/sphinx_template2/pyplots/fancy.py =================================================================== --- trunk/py4science/examples/sphinx_template2/pyplots/fancy.py (rev 0) +++ trunk/py4science/examples/sphinx_template2/pyplots/fancy.py 2009-03-18 19:44:31 UTC (rev 6994) @@ -0,0 +1,3 @@ +import matplotlib.pyplot as plt +plt.plot([1,2,3], [4,5,6]) +plt.title(r'A great result with math! $x=1$') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jd...@us...> - 2009-03-18 17:22:23
|
Revision: 6992 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6992&view=rev Author: jdh2358 Date: 2009-03-18 16:07:19 +0000 (Wed, 18 Mar 2009) Log Message: ----------- some cleanups to the volume overlay Modified Paths: -------------- trunk/matplotlib/examples/pylab_examples/finance_work2.py Modified: trunk/matplotlib/examples/pylab_examples/finance_work2.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/finance_work2.py 2009-03-18 15:52:00 UTC (rev 6991) +++ trunk/matplotlib/examples/pylab_examples/finance_work2.py 2009-03-18 16:07:19 UTC (rev 6992) @@ -80,7 +80,7 @@ up = seed[seed>=0].sum()/n down = -seed[seed<0].sum()/n rs = up/down - rsi = np.zeros_like(r.adj_close) + rsi = np.zeros_like(prices) rsi[:n] = 100. - 100./(1.+rs) for i in range(n, len(prices)): @@ -129,6 +129,8 @@ ax2t = ax2.twinx() ax3 = fig.add_axes(rect3, axisbg=axescolor, sharex=ax1) + + ### plot the relative strength indicator prices = r.adj_close rsi = relative_strength(prices) @@ -176,14 +178,14 @@ leg = ax2.legend(loc='center left', shadow=True, fancybox=True, prop=props) leg.get_frame().set_alpha(0.5) -vmax = r.volume.max()/1e6 -poly = ax2t.fill_between(r.date, r.volume/1e6, 0, facecolor=fillcolor, label='Volume') + +volume = (r.close*r.volume)/1e6 # dollar volume in millions +vmax = volume.max() +poly = ax2t.fill_between(r.date, volume, 0, facecolor=fillcolor, label='Volume') ax2t.set_ylim(0, 5*vmax) -ymax = np.int(vmax) -yticks = [vmax/2., vmax] -ax2t.set_yticks(yticks) -ax2t.set_yticklabels(['%d M'%val for val in yticks]) +ax2t.set_yticks([]) + ### compute the MACD indicator fillcolor = 'darkslategrey' nslow = 26 @@ -220,7 +222,6 @@ return '' else: return mticker.FormatStrFormatter.__call__(self, x, pos=None) - ax2.yaxis.set_major_formatter(PriceFormatter('%d')) plt.show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jd...@us...> - 2009-03-18 16:40:38
|
Revision: 6993 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6993&view=rev Author: jdh2358 Date: 2009-03-18 16:40:26 +0000 (Wed, 18 Mar 2009) Log Message: ----------- use urllib2 for yahoo finace; more cleanups to demo Modified Paths: -------------- trunk/matplotlib/examples/pylab_examples/finance_work2.py trunk/matplotlib/lib/matplotlib/finance.py Modified: trunk/matplotlib/examples/pylab_examples/finance_work2.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/finance_work2.py 2009-03-18 16:07:19 UTC (rev 6992) +++ trunk/matplotlib/examples/pylab_examples/finance_work2.py 2009-03-18 16:40:26 UTC (rev 6993) @@ -139,8 +139,8 @@ ax1.plot(r.date, rsi, color=fillcolor) ax1.axhline(70, color=fillcolor) ax1.axhline(30, color=fillcolor) -ax1.fill_between(r.date, rsi, 70, facecolor=fillcolor, where=(rsi>=70)) -ax1.fill_between(r.date, rsi, 30, facecolor=fillcolor, where=(rsi<=30)) +ax1.fill_between(r.date, rsi, 70, where=(rsi>=70), facecolor=fillcolor, edgecolor=fillcolor) +ax1.fill_between(r.date, rsi, 30, where=(rsi<=30), facecolor=fillcolor, edgecolor=fillcolor) ax1.text(0.6, 0.9, '>70 = overbought', va='top', transform=ax1.transAxes, fontsize=textsize) ax1.text(0.6, 0.1, '<30 = oversold', transform=ax1.transAxes, fontsize=textsize) ax1.set_ylim(0, 100) @@ -181,7 +181,7 @@ volume = (r.close*r.volume)/1e6 # dollar volume in millions vmax = volume.max() -poly = ax2t.fill_between(r.date, volume, 0, facecolor=fillcolor, label='Volume') +poly = ax2t.fill_between(r.date, volume, 0, label='Volume', facecolor=fillcolor, edgecolor=fillcolor) ax2t.set_ylim(0, 5*vmax) ax2t.set_yticks([]) @@ -195,14 +195,14 @@ ema9 = moving_average(macd, nema, type='exponential') ax3.plot(r.date, macd, color='black', lw=2) ax3.plot(r.date, ema9, color='blue', lw=1) -ax3.fill_between(r.date, macd-ema9, 0, facecolor=fillcolor, alpha=0.5) +ax3.fill_between(r.date, macd-ema9, 0, alpha=0.5, facecolor=fillcolor, edgecolor=fillcolor) ax3.text(0.025, 0.95, 'MACD (%d, %d, %d)'%(nfast, nslow, nema), va='top', transform=ax3.transAxes, fontsize=textsize) ax3.set_yticks([]) -# turn off tick labels, rorate them, etc +# turn off upper axis tick labels, rotate the lower ones, etc for ax in ax1, ax2, ax2t, ax3: if ax!=ax3: for label in ax.get_xticklabels(): Modified: trunk/matplotlib/lib/matplotlib/finance.py =================================================================== --- trunk/matplotlib/lib/matplotlib/finance.py 2009-03-18 16:07:19 UTC (rev 6992) +++ trunk/matplotlib/lib/matplotlib/finance.py 2009-03-18 16:40:26 UTC (rev 6993) @@ -5,7 +5,7 @@ """ #from __future__ import division import os, time, warnings -from urllib import urlopen +from urllib2 import urlopen try: from hashlib import md5 @@ -121,8 +121,10 @@ verbose.report('Using cachefile %s for %s'%(cachename, ticker)) else: if not os.path.isdir(cachedir): os.mkdir(cachedir) + urlfh = urlopen(url) + fh = file(cachename, 'w') - fh.write(urlopen(url).read()) + fh.write(urlfh.read()) fh.close() verbose.report('Saved %s data to cache file %s'%(ticker, cachename)) fh = file(cachename, 'r') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2009-03-18 15:52:10
|
Revision: 6991 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6991&view=rev Author: mdboom Date: 2009-03-18 15:52:00 +0000 (Wed, 18 Mar 2009) Log Message: ----------- Merged revisions 6990 via svnmerge from https://matplotlib.svn.sf.net/svnroot/matplotlib/branches/v0_98_5_maint ........ r6990 | mdboom | 2009-03-18 11:48:30 -0400 (Wed, 18 Mar 2009) | 2 lines Fix race condition in tempfile creation in PS backend. If two mpl processes try to create PS files with the same file name and the same time, they will use the same tempfile, and madness, crashing and burning will ensue. ........ Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py Property Changed: ---------------- trunk/matplotlib/ trunk/matplotlib/doc/pyplots/README trunk/matplotlib/doc/sphinxext/gen_gallery.py trunk/matplotlib/doc/sphinxext/gen_rst.py trunk/matplotlib/lib/matplotlib/sphinxext/mathmpl.py trunk/matplotlib/lib/matplotlib/sphinxext/only_directives.py trunk/matplotlib/lib/matplotlib/sphinxext/plot_directive.py Property changes on: trunk/matplotlib ___________________________________________________________________ Modified: svnmerge-integrated - /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6985 + /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6990 Modified: svn:mergeinfo - /branches/v0_91_maint:5753-5771 /branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6809,6811,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6906-6909,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 + /branches/v0_91_maint:5753-5771 /branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6809,6811,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6906-6909,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985,6990 Property changes on: trunk/matplotlib/doc/pyplots/README ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 + /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985,6990 Property changes on: trunk/matplotlib/doc/sphinxext/gen_gallery.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 + /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985,6990 Property changes on: trunk/matplotlib/doc/sphinxext/gen_rst.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 + /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985,6990 Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2009-03-18 15:48:30 UTC (rev 6990) +++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2009-03-18 15:52:00 UTC (rev 6991) @@ -11,7 +11,7 @@ except ImportError: from md5 import md5 #Deprecated in 2.5 -from tempfile import gettempdir +from tempfile import mkstemp from cStringIO import StringIO from matplotlib import verbose, __version__, rcParams from matplotlib._pylab_helpers import Gcf @@ -886,15 +886,15 @@ """ isEPSF = format == 'eps' passed_in_file_object = False + fd, tmpfile = mkstemp() if is_string_like(outfile): title = outfile - tmpfile = os.path.join(gettempdir(), md5(outfile).hexdigest()) elif is_writable_file_like(outfile): title = None - tmpfile = os.path.join(gettempdir(), md5(str(hash(outfile))).hexdigest()) passed_in_file_object = True else: raise ValueError("outfile must be a path or a file-like object") + os.close(fd) fh = file(tmpfile, 'w') # find the appropriate papertype @@ -1029,7 +1029,8 @@ title = outfile # write to a temp file, we'll move it to outfile when done - tmpfile = os.path.join(gettempdir(), md5(outfile).hexdigest()) + fd, tmpfile = mkstemp() + os.close(fd) fh = file(tmpfile, 'w') self.figure.dpi = 72 # ignore the dpi kwarg Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/mathmpl.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/mathmpl.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/mathmpl.py:6946,6948,6950,6952,6960,6972,6984-6985 + /branches/v0_91_maint/doc/sphinxext/mathmpl.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/mathmpl.py:6946,6948,6950,6952,6960,6972,6984-6985,6990 Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/only_directives.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/only_directives.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/only_directives.py:6946,6948,6950,6952,6960,6972,6984-6985 + /branches/v0_91_maint/doc/sphinxext/only_directives.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/only_directives.py:6946,6948,6950,6952,6960,6972,6984-6985,6990 Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/plot_directive.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/plot_directive.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/plot_directive.py:6920-6925,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 + /branches/v0_91_maint/doc/sphinxext/plot_directive.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/plot_directive.py:6920-6925,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985,6990 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2009-03-18 15:48:46
|
Revision: 6990 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6990&view=rev Author: mdboom Date: 2009-03-18 15:48:30 +0000 (Wed, 18 Mar 2009) Log Message: ----------- Fix race condition in tempfile creation in PS backend. If two mpl processes try to create PS files with the same file name and the same time, they will use the same tempfile, and madness, crashing and burning will ensue. Modified Paths: -------------- branches/v0_98_5_maint/lib/matplotlib/backends/backend_ps.py Modified: branches/v0_98_5_maint/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/v0_98_5_maint/lib/matplotlib/backends/backend_ps.py 2009-03-18 15:45:07 UTC (rev 6989) +++ branches/v0_98_5_maint/lib/matplotlib/backends/backend_ps.py 2009-03-18 15:48:30 UTC (rev 6990) @@ -11,7 +11,7 @@ except ImportError: from md5 import md5 #Deprecated in 2.5 -from tempfile import gettempdir +from tempfile import mkstemp from cStringIO import StringIO from matplotlib import verbose, __version__, rcParams from matplotlib._pylab_helpers import Gcf @@ -911,15 +911,15 @@ """ isEPSF = format == 'eps' passed_in_file_object = False + fd, tmpfile = mkstemp() if is_string_like(outfile): title = outfile - tmpfile = os.path.join(gettempdir(), md5(outfile).hexdigest()) elif is_writable_file_like(outfile): title = None - tmpfile = os.path.join(gettempdir(), md5(str(hash(outfile))).hexdigest()) passed_in_file_object = True else: raise ValueError("outfile must be a path or a file-like object") + os.close(fd) fh = file(tmpfile, 'w') # find the appropriate papertype @@ -1054,7 +1054,8 @@ title = outfile # write to a temp file, we'll move it to outfile when done - tmpfile = os.path.join(gettempdir(), md5(outfile).hexdigest()) + fd, tmpfile = mkstemp() + os.close(fd) fh = file(tmpfile, 'w') self.figure.dpi = 72 # ignore the dpi kwarg This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jd...@us...> - 2009-03-18 15:45:49
|
Revision: 6989 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6989&view=rev Author: jdh2358 Date: 2009-03-18 15:45:07 +0000 (Wed, 18 Mar 2009) Log Message: ----------- fixed high/low for adjustment factor Modified Paths: -------------- trunk/matplotlib/examples/pylab_examples/finance_work2.py Modified: trunk/matplotlib/examples/pylab_examples/finance_work2.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/finance_work2.py 2009-03-18 15:22:41 UTC (rev 6988) +++ trunk/matplotlib/examples/pylab_examples/finance_work2.py 2009-03-18 15:45:07 UTC (rev 6989) @@ -63,6 +63,7 @@ weights /= weights.sum() + a = np.convolve(x, weights, mode='full')[:len(x)] a[:n] = a[n] return a @@ -146,11 +147,15 @@ ax1.set_title('%s daily'%ticker) ### plot the price and volume data +dx = r.adj_close - r.close +low = r.low + dx +high = r.high + dx + deltas = np.zeros_like(prices) deltas[1:] = np.diff(prices) up = deltas>0 -ax2.vlines(r.date[up], r.low[up], r.high[up], color='black', label='_nolegend_') -ax2.vlines(r.date[~up], r.low[~up], r.high[~up], color='black', label='_nolegend_') +ax2.vlines(r.date[up], low[up], high[up], color='black', label='_nolegend_') +ax2.vlines(r.date[~up], low[~up], high[~up], color='black', label='_nolegend_') ma20 = moving_average(prices, 20, type='simple') ma200 = moving_average(prices, 200, type='simple') @@ -207,6 +212,7 @@ ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d') + class PriceFormatter(mticker.FormatStrFormatter): 'suppress the lowest tick label to prevent overlap' def __call__(self, x, pos=None): @@ -216,6 +222,7 @@ return mticker.FormatStrFormatter.__call__(self, x, pos=None) ax2.yaxis.set_major_formatter(PriceFormatter('%d')) + plt.show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jd...@us...> - 2009-03-18 15:22:44
|
Revision: 6988 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6988&view=rev Author: jdh2358 Date: 2009-03-18 15:22:41 +0000 (Wed, 18 Mar 2009) Log Message: ----------- updated finance_work2.py demo Modified Paths: -------------- trunk/matplotlib/examples/pylab_examples/finance_work2.py trunk/matplotlib/examples/pylab_examples/legend_demo3.py Modified: trunk/matplotlib/examples/pylab_examples/finance_work2.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/finance_work2.py 2009-03-18 07:39:43 UTC (rev 6987) +++ trunk/matplotlib/examples/pylab_examples/finance_work2.py 2009-03-18 15:22:41 UTC (rev 6988) @@ -1,278 +1,221 @@ -""" -You need a additional files to run this example. Save the following -in the same dir as this file +## Plot the stock price with some technical indicators +## Example usage:: +## python stocks2.py --ticker=GE --startdate=2003 +## +import datetime, os, urllib, optparse +import numpy as np +import dateutil.parser +import matplotlib.colors as colors +import matplotlib.finance as finance +import matplotlib.dates as mdates +import matplotlib.ticker as mticker +import matplotlib.mlab as mlab +import matplotlib.pyplot as plt +import matplotlib.font_manager as font_manager - http://matplotlib.sourceforge.net/screenshots/helpers.py +today = datetime.date.today() - http://matplotlib.sourceforge.net/screenshots/msft_nasdaq_d.csv +optionparser = optparse.OptionParser() - http://matplotlib.sourceforge.net/screenshots/__init__.py +optionparser.add_option('-t', '--ticker', + dest='ticker', + help='a stock market ticker', + default='SPY') -""" +optionparser.add_option('-s', '--startdate', + dest='startdate', + help='the start date', + default=(today-datetime.timedelta(days=365*2)).strftime('%Y-%m-%d')) -import time, os, sys, datetime +optionparser.add_option('-e', '--enddate', + dest='enddate', + help='the end date', + default=today.strftime('%Y-%m-%d')) -from matplotlib import rcParams -from matplotlib.ticker import IndexLocator, FuncFormatter, NullFormatter, MultipleLocator -from matplotlib.dates import IndexDateFormatter, date2num -from matplotlib.finance import candlestick2, plot_day_summary2, \ - volume_overlay, index_bar -from pylab import * -rcParams['timezone'] = 'US/Eastern' -rc('grid', color='0.75', linestyle='-', linewidth=0.5) +(commandoptions, commandargs) = optionparser.parse_args() -def ema(s, n): - """ - returns an n period exponential moving average for - the time series s - s is a list ordered from oldest (index 0) to most recent (index - -1) n is an integer +startdate = dateutil.parser.parse(commandoptions.startdate) +enddate = dateutil.parser.parse(commandoptions.enddate) +ticker = commandoptions.ticker - returns a numeric array of the exponential moving average - """ - s = array(s) - ema = [] - j = 1 - #get n sma first and calculate the next n period ema - sma = sum(s[:n]) / n - multiplier = 2 / float(1 + n) - ema.append(sma) - #EMA(current) = ( (Price(current) - EMA(prev) ) xMultiplier) + EMA(prev) - ema.append(( (s[n] - sma) * multiplier) + sma) - #now calculate the rest of the values - for i in s[n+1:]: - tmp = ( (i - ema[j]) * multiplier) + ema[j] - j = j + 1 - ema.append(tmp) - return ema -def movavg(s, n): - """ - returns an n period moving average for the time series s +fh = finance.fetch_historical_yahoo(ticker, startdate, enddate) +# a numpy record array with fields: date, open, high, low, close, volume, adj_close) - s is a list ordered from oldest (index 0) to most recent (index -1) - n is an integer +r = mlab.csv2rec(fh); fh.close() +r.sort() - returns a numeric array of the moving average - See also ema in this module for the exponential moving average. +def moving_average(x, n, type='simple'): """ - s = array(s) - c = cumsum(s) - return (c[n-1:] - c[:-n+1]) / float(n-1) + compute an n period moving average. -def fill_over(ax, x, y, val, color, over=True): + type is 'simple' | 'exponential' + """ - Plot filled x,y for all y over val - if over = False, fill all areas < val - """ - ybase = asarray(y)-val - crossings = nonzero(less(ybase[:-1] * ybase[1:],0)) + x = np.asarray(x) + if type=='simple': + weights = np.ones(n) + else: + weights = np.exp(np.linspace(-1., 0., n)) - if ybase[0]>=0: fillon = over - else: fillon = not over + weights /= weights.sum() + a = np.convolve(x, weights, mode='full')[:len(x)] + a[:n] = a[n] + return a - indLast = 0 - for ind in crossings: - if fillon: - thisX = x[indLast:ind+1] - thisY = y[indLast:ind+1] - thisY[0] = val - thisY[-1] = val - ax.fill(thisX, thisY, facecolor=color) - fillon = not fillon - indLast = ind +def relative_strength(prices, n=14): + """ + compute the n period relative strength indicator + http://stockcharts.com/school/doku.php?id=chart_school:glossary_r#relativestrengthindex + http://www.investopedia.com/terms/r/rsi.asp + """ + deltas = np.diff(prices) + seed = deltas[:n+1] + up = seed[seed>=0].sum()/n + down = -seed[seed<0].sum()/n + rs = up/down + rsi = np.zeros_like(r.adj_close) + rsi[:n] = 100. - 100./(1.+rs) -def random_signal(N, tau): - 'generate a length N random signal with time constant tau' - t = arange(float(N)) - filter = exp(-t/tau) - return convolve( randn(N), filter, mode=2)[:len(t)] + for i in range(n, len(prices)): + delta = deltas[i-1] # cause the diff is 1 shorter + if delta>0: + upval = delta + downval = 0. + else: + upval = 0. + downval = -delta -# load a numpy record array from yahoo csv data with fields date, -# open, close, volume, adj_close from the mpl-data/example directory. -# The record array stores python datetime.date as an object array in -# the date column -datafile = matplotlib.get_example_data('goog.npy') -r = np.load(datafile).view(np.recarray) -r = r[-250:] + up = (up*(n-1) + upval)/n + down = (down*(n-1) + downval)/n -N = len(r) + rs = up/down + rsi[i] = 100. - 100./(1.+rs) -vind = np.arange(N) + return rsi -figBG = 'w' # the figure background color -axesBG = '#f6f6f6' # the axies background color -textsize = 8 # size for axes text - -# the demo data are intc from (2003, 9, 1) to (2004, 4, 12 ) with -# dates as epoch; I saved these to a file for ease of debugginh -ticker = 'MSFT' - - -figure(1, facecolor=figBG) - -def get_locator(): +def moving_average_convergence(x, nslow=26, nfast=12): """ - the axes cannot share the same locator, so this is a helper - function to generate locators that have identical functionality + compute the MACD (Moving Average Convergence/Divergence) using a fast and slow exponential moving avg' + return value is emaslow, emafast, macd which are len(x) arrays """ + emaslow = moving_average(x, nslow, type='exponential') + emafast = moving_average(x, nfast, type='exponential') + return emaslow, emafast, emafast - emaslow - return IndexLocator(10, 1) +plt.rc('axes', grid=True) +plt.rc('grid', color='0.75', linestyle='-', linewidth=0.5) -formatter = IndexDateFormatter(date2num(r.date), '%b %d %y') - -nullfmt = NullFormatter() # no labels - -def fmt_vol(x,pos): - if pos>3: return '' # only label the first 3 ticks - return '%dM' % int(x*1e-6) - -volumeFmt = FuncFormatter(fmt_vol) - +textsize = 9 left, width = 0.1, 0.8 rect1 = [left, 0.7, width, 0.2] rect2 = [left, 0.3, width, 0.4] rect3 = [left, 0.1, width, 0.2] -axUpper = axes(rect1, axisbg=axesBG) #left, bottom, width, height -axMiddle = axes(rect2, axisbg=axesBG, sharex=axUpper) -axMiddleVol = axMiddle.twinx() -axLower = axes(rect3, axisbg=axesBG, sharex=axUpper) -axUpper.xaxis.set_major_locator( get_locator() ) -axUpper.xaxis.set_major_formatter(nullfmt) -axUpper.grid(True) +fig = plt.figure(facecolor='white') +axescolor = '#f6f6f6' # the axies background color -# set up two scales on middle axes with left and right ticks -axMiddle.yaxis.tick_left() -axMiddle.xaxis.set_major_formatter(nullfmt) +ax1 = fig.add_axes(rect1, axisbg=axescolor) #left, bottom, width, height +ax2 = fig.add_axes(rect2, axisbg=axescolor, sharex=ax1) +ax2t = ax2.twinx() +ax3 = fig.add_axes(rect3, axisbg=axescolor, sharex=ax1) -axMiddleVol.yaxis.set_major_formatter(volumeFmt) -axMiddle.grid(True) +### plot the relative strength indicator +prices = r.adj_close +rsi = relative_strength(prices) +fillcolor = 'darkgoldenrod' -axLower.xaxis.set_major_locator( get_locator() ) -axLower.xaxis.set_major_formatter( formatter ) -axLower.grid(True) +ax1.plot(r.date, rsi, color=fillcolor) +ax1.axhline(70, color=fillcolor) +ax1.axhline(30, color=fillcolor) +ax1.fill_between(r.date, rsi, 70, facecolor=fillcolor, where=(rsi>=70)) +ax1.fill_between(r.date, rsi, 30, facecolor=fillcolor, where=(rsi<=30)) +ax1.text(0.6, 0.9, '>70 = overbought', va='top', transform=ax1.transAxes, fontsize=textsize) +ax1.text(0.6, 0.1, '<30 = oversold', transform=ax1.transAxes, fontsize=textsize) +ax1.set_ylim(0, 100) +ax1.set_yticks([30,70]) +ax1.text(0.025, 0.95, 'RSI (14)', va='top', transform=ax1.transAxes, fontsize=textsize) +ax1.set_title('%s daily'%ticker) -if 1: ############### Upper axes ################# +### plot the price and volume data +deltas = np.zeros_like(prices) +deltas[1:] = np.diff(prices) +up = deltas>0 +ax2.vlines(r.date[up], r.low[up], r.high[up], color='black', label='_nolegend_') +ax2.vlines(r.date[~up], r.low[~up], r.high[~up], color='black', label='_nolegend_') +ma20 = moving_average(prices, 20, type='simple') +ma200 = moving_average(prices, 200, type='simple') - # make up a pseudo signal - purple = '#660033' - s = random_signal(N, tau=20) - thresh = 4 - axUpper.plot(s, color=purple) - # upper horiz line +linema20, = ax2.plot(r.date, ma20, color='blue', lw=2, label='MA (20)') +linema200, = ax2.plot(r.date, ma200, color='red', lw=2, label='MA (200)') +last = r[-1] +s = '%s O:%1.2f H:%1.2f L:%1.2f C:%1.2f, V:%1.1fM Chg:%+1.2f' % ( + today.strftime('%d-%b-%Y'), + last.open, last.high, + last.low, last.close, + last.volume*1e-6, + last.close-last.open ) +t4 = ax2.text(0.3, 0.9, s, transform=ax2.transAxes, fontsize=textsize) - axUpper.plot( (0, N), [thresh, thresh], color=purple, linewidth=1) - # lower horiz line - axUpper.plot( (0, N), [-thresh, -thresh], color=purple, linewidth=1) +props = font_manager.FontProperties(size=10) +leg = ax2.legend(loc='center left', shadow=True, fancybox=True, prop=props) +leg.get_frame().set_alpha(0.5) +vmax = r.volume.max()/1e6 +poly = ax2t.fill_between(r.date, r.volume/1e6, 0, facecolor=fillcolor, label='Volume') +ax2t.set_ylim(0, 5*vmax) +ymax = np.int(vmax) +yticks = [vmax/2., vmax] +ax2t.set_yticks(yticks) +ax2t.set_yticklabels(['%d M'%val for val in yticks]) - # fill above threshold - fill_over(axUpper, vind, s, thresh, purple, over=True) - fill_over(axUpper, vind, s, -thresh, purple, over=False) +### compute the MACD indicator +fillcolor = 'darkslategrey' +nslow = 26 +nfast = 12 +nema = 9 +emaslow, emafast, macd = moving_average_convergence(prices, nslow=nslow, nfast=nfast) +ema9 = moving_average(macd, nema, type='exponential') +ax3.plot(r.date, macd, color='black', lw=2) +ax3.plot(r.date, ema9, color='blue', lw=1) +ax3.fill_between(r.date, macd-ema9, 0, facecolor=fillcolor, alpha=0.5) - t = axUpper.set_title('Google (GOOG)', fontsize=12) - t.set_y(1.05) # move it up a bit higher than the default - t.set_x(0) # align the title left, axes coords - t.set_horizontalalignment('left') # align the title left, axes coords - axUpper.yaxis.set_major_locator( MultipleLocator(5) ) +ax3.text(0.025, 0.95, 'MACD (%d, %d, %d)'%(nfast, nslow, nema), va='top', + transform=ax3.transAxes, fontsize=textsize) +ax3.set_yticks([]) +# turn off tick labels, rorate them, etc +for ax in ax1, ax2, ax2t, ax3: + if ax!=ax3: + for label in ax.get_xticklabels(): + label.set_visible(False) + else: + for label in ax.get_xticklabels(): + label.set_rotation(30) + label.set_horizontalalignment('right') - # now add some text - left, height, top = 0.025, 0.06, 0.85 - t = axUpper.text(left, top, 'RSI(14) 51.0', fontsize=textsize, - transform=axUpper.transAxes) + ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d') +class PriceFormatter(mticker.FormatStrFormatter): + 'suppress the lowest tick label to prevent overlap' + def __call__(self, x, pos=None): + if pos==0: + return '' + else: + return mticker.FormatStrFormatter.__call__(self, x, pos=None) -if 1: ############### Middle axes ################# +ax2.yaxis.set_major_formatter(PriceFormatter('%d')) +plt.show() - candlestick2(axMiddle, r.open, r.close, r.high, r.low, width=0.9) - - # specify the text in axes (0,1) coords. 0,0 is lower left and 1,1 is - # upper right - - left, height, top = 0.025, 0.06, 0.9 - t1 = axMiddle.text(left, top, '%s daily'%ticker, fontsize=textsize, - transform=axMiddle.transAxes) - t2 = axMiddle.text(left, top-height, 'MA(5)', color='b', fontsize=textsize, - transform=axMiddle.transAxes) - t3 = axMiddle.text(left, top-2*height, 'MA(20)', color='r', fontsize=textsize, - transform=axMiddle.transAxes) - - s = '%s O:%1.2f H:%1.2f L:%1.2f C:%1.2f, V:%1.1fM Chg:%+1.2f' %( - time.strftime('%d-%b-%Y'), - r.open[-1], r.high[-1], - r.low[-1], r.close[-1], - r.volume[-1]*1e-6, - r.close[-1]-r.open[-1]) - t4 = axMiddle.text(0.4, top, s, fontsize=textsize, - transform=axMiddle.transAxes) - - - # now do the moviing average. I'll use a convolution to simulate a - # real moving average - ma5 = movavg(r.adj_close, 5) - ma20 = movavg(r.adj_close, 20) - axMiddle.plot(vind[5-1:], ma5, 'b', linewidth=1) - axMiddle.plot(vind[20-1:], ma20, 'r', linewidth=1) - - axMiddle.set_ylim((300, 800)) - axMiddle.set_yticks(np.arange(800, 800, 100)) - - # Now do the volume overlay - - # todo - this is broken - bars = volume_overlay(axMiddleVol, r.open, r.close, r.volume, alpha=0.5) - #axMiddleVol.set_ylim(0, 3*r.volume.max()) # use only a third of the viewlim - - -if 1: ############### Lower axes ################# - - # make up two signals; I don't know what the signals are in real life - # so I'll just illustrate the plotting stuff - s1 = random_signal(N, 10) - s2 = random_signal(N, 20) - - axLower.plot(vind, s1, color=purple) - axLower.plot(vind, s2, color='k', linewidth=1.0) - s3 = s2-s1 - axLower.plot(vind, s3, color='#cccc99') # wheat - bars = index_bar(axLower, s3, width=2, alpha=0.5, - facecolor='#3087c7', edgecolor='#cccc99') - axLower.yaxis.set_major_locator(MultipleLocator(5)) - - - # now add some text - left, height, top = 0.025, 0.06, 0.85 - - t = axLower.text(left, top, 'MACD(12,26,9) -0.26', fontsize=textsize, - transform=axLower.transAxes) - - # make sure everyone has the same axes limits - - setp(axLower.get_xticklabels(), 'rotation', 45, - 'horizontalalignment', 'right', fontsize=8) - -# force all the axes to have the same x data limits -allAxes = (axUpper, axMiddle, axMiddleVol, axLower) -xlim = 0, N -for a in allAxes: - a.set_xlim(xlim) - -for ax in axUpper, axMiddle, axMiddleVol: - for ticklabel in ax.get_xticklabels(): - ticklabel.set_visible(False) - -show() Modified: trunk/matplotlib/examples/pylab_examples/legend_demo3.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/legend_demo3.py 2009-03-18 07:39:43 UTC (rev 6987) +++ trunk/matplotlib/examples/pylab_examples/legend_demo3.py 2009-03-18 15:22:41 UTC (rev 6988) @@ -23,7 +23,7 @@ ax3 = plt.subplot(3,1,3) myplot(ax3) -ax3.legend(loc=1, ncol=4, mode="expand", shadow=True) +ax3.legend(shadow=True, fancybox=True) plt.draw() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fer...@us...> - 2009-03-18 07:39:53
|
Revision: 6987 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6987&view=rev Author: fer_perez Date: 2009-03-18 07:39:43 +0000 (Wed, 18 Mar 2009) Log Message: ----------- Update to current versions of tools, add API auto generation. Modified Paths: -------------- trunk/py4science/examples/sphinx_template2/Makefile trunk/py4science/examples/sphinx_template2/conf.py trunk/py4science/examples/sphinx_template2/index.rst trunk/py4science/examples/sphinx_template2/model/sphinx_helpers.rst trunk/py4science/examples/sphinx_template2/simulations/finale.rst trunk/py4science/examples/sphinx_template2/simulations/preliminary.rst trunk/py4science/examples/sphinx_template2/tools/sphinxext/inheritance_diagram.py Added Paths: ----------- trunk/py4science/examples/sphinx_template2/_static/ trunk/py4science/examples/sphinx_template2/_templates/ trunk/py4science/examples/sphinx_template2/api/ trunk/py4science/examples/sphinx_template2/api/generated/ trunk/py4science/examples/sphinx_template2/api/index.rst trunk/py4science/examples/sphinx_template2/autogen_api.py trunk/py4science/examples/sphinx_template2/tools/sphinxext/apigen.py trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape.py trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape_sphinx.py trunk/py4science/examples/sphinx_template2/tools/sphinxext/numpydoc.py Removed Paths: ------------- trunk/py4science/examples/sphinx_template2/tools/sphinxext/mathmpl.py trunk/py4science/examples/sphinx_template2/tools/sphinxext/only_directives.py trunk/py4science/examples/sphinx_template2/tools/sphinxext/plot_directive.py trunk/py4science/examples/sphinx_template2/tools/static/ trunk/py4science/examples/sphinx_template2/tools/templates/ Modified: trunk/py4science/examples/sphinx_template2/Makefile =================================================================== --- trunk/py4science/examples/sphinx_template2/Makefile 2009-03-17 19:45:05 UTC (rev 6986) +++ trunk/py4science/examples/sphinx_template2/Makefile 2009-03-18 07:39:43 UTC (rev 6987) @@ -14,7 +14,8 @@ PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR) -.PHONY: help clean html web pickle htmlhelp latex changes linkcheck pdf all dist +.PHONY: help clean html web pickle htmlhelp latex changes linkcheck pdf all \ + dist api help: @echo "Please use \`make <target>' where <target> is one of" @@ -31,7 +32,7 @@ @echo " dist all, and then puts the results in dist/" clean: - -rm -rf build/ dist/ _static/ pyplots/*png pyplots/*pdf + -rm -rf build/ dist/ _static/* api/generated/*rst pyplots/*png pyplots/*pdf pdf: latex cd build/latex && make all-pdf @@ -44,12 +45,16 @@ cp -al build/html dist/ @echo "Build finished. Final docs are in dist/" -html: +html: api mkdir -p build/html build/doctrees $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html @echo @echo "Build finished. The HTML pages are in build/html." +api: + python autogen_api.py + @echo "Build API docs finished." + pickle: mkdir -p build/pickle build/doctrees $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle @@ -60,14 +65,14 @@ web: pickle -htmlhelp: +htmlhelp: api mkdir -p build/htmlhelp build/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in build/htmlhelp." -latex: +latex: api mkdir -p build/latex build/doctrees $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex @echo Property changes on: trunk/py4science/examples/sphinx_template2/_static ___________________________________________________________________ Added: svn:mergeinfo + Property changes on: trunk/py4science/examples/sphinx_template2/_templates ___________________________________________________________________ Added: svn:mergeinfo + Added: trunk/py4science/examples/sphinx_template2/api/index.rst =================================================================== --- trunk/py4science/examples/sphinx_template2/api/index.rst (rev 0) +++ trunk/py4science/examples/sphinx_template2/api/index.rst 2009-03-18 07:39:43 UTC (rev 6987) @@ -0,0 +1,12 @@ +.. _api-index: + +######################## + The Python email API +######################## + +.. htmlonly:: + + :Release: |version| + :Date: |today| + +.. include:: generated/gen.rst Added: trunk/py4science/examples/sphinx_template2/autogen_api.py =================================================================== --- trunk/py4science/examples/sphinx_template2/autogen_api.py (rev 0) +++ trunk/py4science/examples/sphinx_template2/autogen_api.py 2009-03-18 07:39:43 UTC (rev 6987) @@ -0,0 +1,28 @@ +#!/usr/bin/env python +"""Script to auto-generate our API docs. +""" +# stdlib imports +import os +import sys + +# local imports +sys.path.append(os.path.abspath('tools/sphinxext')) +from apigen import ApiDocWriter + +#***************************************************************************** +if __name__ == '__main__': + pjoin = os.path.join + package = 'email' + outdir = pjoin('api','generated') + docwriter = ApiDocWriter(package,rst_extension='.rst') + # Skip packages you don't want to document + docwriter.package_skip_patterns += [r'\.mime', + ] + # For modules, there are also skip patterns + docwriter.module_skip_patterns += [ r'\.mime', + ] + docwriter.write_api_docs(outdir) + docwriter.write_index(outdir, 'gen', + relative_to = 'api' + ) + print '%d files written' % len(docwriter.written_modules) Property changes on: trunk/py4science/examples/sphinx_template2/autogen_api.py ___________________________________________________________________ Added: svn:executable + * Modified: trunk/py4science/examples/sphinx_template2/conf.py =================================================================== --- trunk/py4science/examples/sphinx_template2/conf.py 2009-03-17 19:45:05 UTC (rev 6986) +++ trunk/py4science/examples/sphinx_template2/conf.py 2009-03-18 07:39:43 UTC (rev 6987) @@ -28,14 +28,17 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [#'mathmpl', - 'ipython_console_highlighting', 'sphinx.ext.autodoc', - 'inheritance_diagram', 'only_directives', 'plot_directive', - 'sphinx.ext.pngmath', - ] +extensions = ['matplotlib.sphinxext.mathmpl', + 'matplotlib.sphinxext.only_directives', + 'matplotlib.sphinxext.plot_directive', + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'ipython_console_highlighting', + 'inheritance_diagram', + 'numpydoc'] # Add any paths that contain templates here, relative to this directory. -templates_path = ['tools/templates'] +templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' @@ -102,7 +105,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['tools/static','_static'] +html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. Modified: trunk/py4science/examples/sphinx_template2/index.rst =================================================================== --- trunk/py4science/examples/sphinx_template2/index.rst 2009-03-17 19:45:05 UTC (rev 6986) +++ trunk/py4science/examples/sphinx_template2/index.rst 2009-03-18 07:39:43 UTC (rev 6987) @@ -13,8 +13,9 @@ .. toctree:: :maxdepth: 2 - model/index.rst - simulations/index.rst + model/index + simulations/index + api/index .. htmlonly:: Modified: trunk/py4science/examples/sphinx_template2/model/sphinx_helpers.rst =================================================================== --- trunk/py4science/examples/sphinx_template2/model/sphinx_helpers.rst 2009-03-17 19:45:05 UTC (rev 6986) +++ trunk/py4science/examples/sphinx_template2/model/sphinx_helpers.rst 2009-03-18 07:39:43 UTC (rev 6987) @@ -157,7 +157,7 @@ original source code, a high-resolution PNG and a PDF. In the PDF version of the document, the plot is included as a scalable PDF. -.. plot:: ../pyplots/elegant.py +.. plot:: pyplots/elegant.py :include-source: Inheritance diagrams Modified: trunk/py4science/examples/sphinx_template2/simulations/finale.rst =================================================================== --- trunk/py4science/examples/sphinx_template2/simulations/finale.rst 2009-03-17 19:45:05 UTC (rev 6986) +++ trunk/py4science/examples/sphinx_template2/simulations/finale.rst 2009-03-18 07:39:43 UTC (rev 6987) @@ -8,5 +8,6 @@ After much head scratching, I wrote this big elegant piece of code, to produce this much more elegant figure: -.. plot:: ../pyplots/elegant.py +.. plot:: pyplots/fancy.py :include-source: + Modified: trunk/py4science/examples/sphinx_template2/simulations/preliminary.rst =================================================================== --- trunk/py4science/examples/sphinx_template2/simulations/preliminary.rst 2009-03-17 19:45:05 UTC (rev 6986) +++ trunk/py4science/examples/sphinx_template2/simulations/preliminary.rst 2009-03-18 07:39:43 UTC (rev 6987) @@ -6,6 +6,6 @@ I wrote this big hairy piece of code to make the following plot: -.. plot:: ../pyplots/hairy.py +.. plot:: pyplots/hairy.py :include-source: Added: trunk/py4science/examples/sphinx_template2/tools/sphinxext/apigen.py =================================================================== --- trunk/py4science/examples/sphinx_template2/tools/sphinxext/apigen.py (rev 0) +++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/apigen.py 2009-03-18 07:39:43 UTC (rev 6987) @@ -0,0 +1,426 @@ +"""Attempt to generate templates for module reference with Sphinx + +XXX - we exclude extension modules + +To include extension modules, first identify them as valid in the +``_uri2path`` method, then handle them in the ``_parse_module`` script. + +We get functions and classes by parsing the text of .py files. +Alternatively we could import the modules for discovery, and we'd have +to do that for extension modules. This would involve changing the +``_parse_module`` method to work via import and introspection, and +might involve changing ``discover_modules`` (which determines which +files are modules, and therefore which module URIs will be passed to +``_parse_module``). + +NOTE: this is a modified version of a script originally shipped with the +PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed +project.""" + +# Stdlib imports +import os +import re + +# Functions and classes +class ApiDocWriter(object): + ''' Class for automatic detection and parsing of API docs + to Sphinx-parsable reST format''' + + # only separating first two levels + rst_section_levels = ['*', '=', '-', '~', '^'] + + def __init__(self, + package_name, + rst_extension='.rst', + package_skip_patterns=None, + module_skip_patterns=None, + ): + ''' Initialize package for parsing + + Parameters + ---------- + package_name : string + Name of the top-level package. *package_name* must be the + name of an importable package + rst_extension : string, optional + Extension for reST files, default '.rst' + package_skip_patterns : None or sequence of {strings, regexps} + Sequence of strings giving URIs of packages to be excluded + Operates on the package path, starting at (including) the + first dot in the package path, after *package_name* - so, + if *package_name* is ``sphinx``, then ``sphinx.util`` will + result in ``.util`` being passed for earching by these + regexps. If is None, gives default. Default is: + ['\.tests$'] + module_skip_patterns : None or sequence + Sequence of strings giving URIs of modules to be excluded + Operates on the module name including preceding URI path, + back to the first dot after *package_name*. For example + ``sphinx.util.console`` results in the string to search of + ``.util.console`` + If is None, gives default. Default is: + ['\.setup$', '\._'] + ''' + if package_skip_patterns is None: + package_skip_patterns = ['\\.tests$'] + if module_skip_patterns is None: + module_skip_patterns = ['\\.setup$', '\\._'] + self.package_name = package_name + self.rst_extension = rst_extension + self.package_skip_patterns = package_skip_patterns + self.module_skip_patterns = module_skip_patterns + + def get_package_name(self): + return self._package_name + + def set_package_name(self, package_name): + ''' Set package_name + + >>> docwriter = ApiDocWriter('sphinx') + >>> import sphinx + >>> docwriter.root_path == sphinx.__path__[0] + True + >>> docwriter.package_name = 'docutils' + >>> import docutils + >>> docwriter.root_path == docutils.__path__[0] + True + ''' + # It's also possible to imagine caching the module parsing here + self._package_name = package_name + self.root_module = __import__(package_name) + self.root_path = self.root_module.__path__[0] + self.written_modules = None + + package_name = property(get_package_name, set_package_name, None, + 'get/set package_name') + + def _get_object_name(self, line): + ''' Get second token in line + >>> docwriter = ApiDocWriter('sphinx') + >>> docwriter._get_object_name(" def func(): ") + 'func' + >>> docwriter._get_object_name(" class Klass(object): ") + 'Klass' + >>> docwriter._get_object_name(" class Klass: ") + 'Klass' + ''' + name = line.split()[1].split('(')[0].strip() + # in case we have classes which are not derived from object + # ie. old style classes + return name.rstrip(':') + + def _uri2path(self, uri): + ''' Convert uri to absolute filepath + + Parameters + ---------- + uri : string + URI of python module to return path for + + Returns + ------- + path : None or string + Returns None if there is no valid path for this URI + Otherwise returns absolute file system path for URI + + Examples + -------- + >>> docwriter = ApiDocWriter('sphinx') + >>> import sphinx + >>> modpath = sphinx.__path__[0] + >>> res = docwriter._uri2path('sphinx.builder') + >>> res == os.path.join(modpath, 'builder.py') + True + >>> res = docwriter._uri2path('sphinx') + >>> res == os.path.join(modpath, '__init__.py') + True + >>> docwriter._uri2path('sphinx.does_not_exist') + + ''' + if uri == self.package_name: + return os.path.join(self.root_path, '__init__.py') + path = uri.replace('.', os.path.sep) + path = path.replace(self.package_name + os.path.sep, '') + path = os.path.join(self.root_path, path) + # XXX maybe check for extensions as well? + if os.path.exists(path + '.py'): # file + path += '.py' + elif os.path.exists(os.path.join(path, '__init__.py')): + path = os.path.join(path, '__init__.py') + else: + return None + return path + + def _path2uri(self, dirpath): + ''' Convert directory path to uri ''' + relpath = dirpath.replace(self.root_path, self.package_name) + if relpath.startswith(os.path.sep): + relpath = relpath[1:] + return relpath.replace(os.path.sep, '.') + + def _parse_module(self, uri): + ''' Parse module defined in *uri* ''' + filename = self._uri2path(uri) + if filename is None: + # nothing that we could handle here. + return ([],[]) + f = open(filename, 'rt') + functions, classes = self._parse_lines(f) + f.close() + return functions, classes + + def _parse_lines(self, linesource): + ''' Parse lines of text for functions and classes ''' + functions = [] + classes = [] + for line in linesource: + if line.startswith('def ') and line.count('('): + # exclude private stuff + name = self._get_object_name(line) + if not name.startswith('_'): + functions.append(name) + elif line.startswith('class '): + # exclude private stuff + name = self._get_object_name(line) + if not name.startswith('_'): + classes.append(name) + else: + pass + functions.sort() + classes.sort() + return functions, classes + + def generate_api_doc(self, uri): + '''Make autodoc documentation template string for a module + + Parameters + ---------- + uri : string + python location of module - e.g 'sphinx.builder' + + Returns + ------- + S : string + Contents of API doc + ''' + # get the names of all classes and functions + functions, classes = self._parse_module(uri) + if not len(functions) and not len(classes): + print 'WARNING: Empty -',uri # dbg + return '' + + # Make a shorter version of the uri that omits the package name for + # titles + uri_short = re.sub(r'^%s\.' % self.package_name,'',uri) + + ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n' + + chap_title = uri_short + ad += (chap_title+'\n'+ self.rst_section_levels[1] * len(chap_title) + + '\n\n') + + # Set the chapter title to read 'module' for all modules except for the + # main packages + if '.' in uri: + title = 'Module: :mod:`' + uri_short + '`' + else: + title = ':mod:`' + uri_short + '`' + ad += title + '\n' + self.rst_section_levels[2] * len(title) + + if len(classes): + ad += '\nInheritance diagram for ``%s``:\n\n' % uri + ad += '.. inheritance-diagram:: %s \n' % uri + ad += ' :parts: 3\n' + + ad += '\n.. automodule:: ' + uri + '\n' + ad += '\n.. currentmodule:: ' + uri + '\n' + multi_class = len(classes) > 1 + multi_fx = len(functions) > 1 + if multi_class: + ad += '\n' + 'Classes' + '\n' + \ + self.rst_section_levels[2] * 7 + '\n' + elif len(classes) and multi_fx: + ad += '\n' + 'Class' + '\n' + \ + self.rst_section_levels[2] * 5 + '\n' + for c in classes: + ad += '\n:class:`' + c + '`\n' \ + + self.rst_section_levels[multi_class + 2 ] * \ + (len(c)+9) + '\n\n' + ad += '\n.. autoclass:: ' + c + '\n' + # must NOT exclude from index to keep cross-refs working + ad += ' :members:\n' \ + ' :undoc-members:\n' \ + ' :show-inheritance:\n' \ + '\n' \ + ' .. automethod:: __init__\n' + if multi_fx: + ad += '\n' + 'Functions' + '\n' + \ + self.rst_section_levels[2] * 9 + '\n\n' + elif len(functions) and multi_class: + ad += '\n' + 'Function' + '\n' + \ + self.rst_section_levels[2] * 8 + '\n\n' + for f in functions: + # must NOT exclude from index to keep cross-refs working + ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n' + return ad + + def _survives_exclude(self, matchstr, match_type): + ''' Returns True if *matchstr* does not match patterns + + ``self.package_name`` removed from front of string if present + + Examples + -------- + >>> dw = ApiDocWriter('sphinx') + >>> dw._survives_exclude('sphinx.okpkg', 'package') + True + >>> dw.package_skip_patterns.append('^\\.badpkg$') + >>> dw._survives_exclude('sphinx.badpkg', 'package') + False + >>> dw._survives_exclude('sphinx.badpkg', 'module') + True + >>> dw._survives_exclude('sphinx.badmod', 'module') + True + >>> dw.module_skip_patterns.append('^\\.badmod$') + >>> dw._survives_exclude('sphinx.badmod', 'module') + False + ''' + if match_type == 'module': + patterns = self.module_skip_patterns + elif match_type == 'package': + patterns = self.package_skip_patterns + else: + raise ValueError('Cannot interpret match type "%s"' + % match_type) + # Match to URI without package name + L = len(self.package_name) + if matchstr[:L] == self.package_name: + matchstr = matchstr[L:] + for pat in patterns: + try: + pat.search + except AttributeError: + pat = re.compile(pat) + if pat.search(matchstr): + return False + return True + + def discover_modules(self): + ''' Return module sequence discovered from ``self.package_name`` + + + Parameters + ---------- + None + + Returns + ------- + mods : sequence + Sequence of module names within ``self.package_name`` + + Examples + -------- + >>> dw = ApiDocWriter('sphinx') + >>> mods = dw.discover_modules() + >>> 'sphinx.util' in mods + True + >>> dw.package_skip_patterns.append('\.util$') + >>> 'sphinx.util' in dw.discover_modules() + False + >>> + ''' + modules = [self.package_name] + # raw directory parsing + for dirpath, dirnames, filenames in os.walk(self.root_path): + # Check directory names for packages + root_uri = self._path2uri(os.path.join(self.root_path, + dirpath)) + for dirname in dirnames[:]: # copy list - we modify inplace + package_uri = '.'.join((root_uri, dirname)) + if (self._uri2path(package_uri) and + self._survives_exclude(package_uri, 'package')): + modules.append(package_uri) + else: + dirnames.remove(dirname) + # Check filenames for modules + for filename in filenames: + module_name = filename[:-3] + module_uri = '.'.join((root_uri, module_name)) + if (self._uri2path(module_uri) and + self._survives_exclude(module_uri, 'module')): + modules.append(module_uri) + return sorted(modules) + + def write_modules_api(self, modules,outdir): + # write the list + written_modules = [] + for m in modules: + api_str = self.generate_api_doc(m) + if not api_str: + continue + # write out to file + outfile = os.path.join(outdir, + m + self.rst_extension) + fileobj = open(outfile, 'wt') + fileobj.write(api_str) + fileobj.close() + written_modules.append(m) + self.written_modules = written_modules + + def write_api_docs(self, outdir): + """Generate API reST files. + + Parameters + ---------- + outdir : string + Directory name in which to store files + We create automatic filenames for each module + + Returns + ------- + None + + Notes + ----- + Sets self.written_modules to list of written modules + """ + if not os.path.exists(outdir): + os.mkdir(outdir) + # compose list of modules + modules = self.discover_modules() + self.write_modules_api(modules,outdir) + + def write_index(self, outdir, froot='gen', relative_to=None): + """Make a reST API index file from written files + + Parameters + ---------- + path : string + Filename to write index to + outdir : string + Directory to which to write generated index file + froot : string, optional + root (filename without extension) of filename to write to + Defaults to 'gen'. We add ``self.rst_extension``. + relative_to : string + path to which written filenames are relative. This + component of the written file path will be removed from + outdir, in the generated index. Default is None, meaning, + leave path as it is. + """ + if self.written_modules is None: + raise ValueError('No modules written') + # Get full filename path + path = os.path.join(outdir, froot+self.rst_extension) + # Path written into index is relative to rootpath + if relative_to is not None: + relpath = outdir.replace(relative_to + os.path.sep, '') + else: + relpath = outdir + idx = open(path,'wt') + w = idx.write + w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n') + w('.. toctree::\n\n') + for f in self.written_modules: + w(' %s\n' % os.path.join(relpath,f)) + idx.close() Added: trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape.py =================================================================== --- trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape.py (rev 0) +++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape.py 2009-03-18 07:39:43 UTC (rev 6987) @@ -0,0 +1,497 @@ +"""Extract reference documentation from the NumPy source tree. + +""" + +import inspect +import textwrap +import re +import pydoc +from StringIO import StringIO +from warnings import warn +4 +class Reader(object): + """A line-based string reader. + + """ + def __init__(self, data): + """ + Parameters + ---------- + data : str + String with lines separated by '\n'. + + """ + if isinstance(data,list): + self._str = data + else: + self._str = data.split('\n') # store string as list of lines + + self.reset() + + def __getitem__(self, n): + return self._str[n] + + def reset(self): + self._l = 0 # current line nr + + def read(self): + if not self.eof(): + out = self[self._l] + self._l += 1 + return out + else: + return '' + + def seek_next_non_empty_line(self): + for l in self[self._l:]: + if l.strip(): + break + else: + self._l += 1 + + def eof(self): + return self._l >= len(self._str) + + def read_to_condition(self, condition_func): + start = self._l + for line in self[start:]: + if condition_func(line): + return self[start:self._l] + self._l += 1 + if self.eof(): + return self[start:self._l+1] + return [] + + def read_to_next_empty_line(self): + self.seek_next_non_empty_line() + def is_empty(line): + return not line.strip() + return self.read_to_condition(is_empty) + + def read_to_next_unindented_line(self): + def is_unindented(line): + return (line.strip() and (len(line.lstrip()) == len(line))) + return self.read_to_condition(is_unindented) + + def peek(self,n=0): + if self._l + n < len(self._str): + return self[self._l + n] + else: + return '' + + def is_empty(self): + return not ''.join(self._str).strip() + + +class NumpyDocString(object): + def __init__(self,docstring): + docstring = textwrap.dedent(docstring).split('\n') + + self._doc = Reader(docstring) + self._parsed_data = { + 'Signature': '', + 'Summary': [''], + 'Extended Summary': [], + 'Parameters': [], + 'Returns': [], + 'Raises': [], + 'Warns': [], + 'Other Parameters': [], + 'Attributes': [], + 'Methods': [], + 'See Also': [], + 'Notes': [], + 'Warnings': [], + 'References': '', + 'Examples': '', + 'index': {} + } + + self._parse() + + def __getitem__(self,key): + return self._parsed_data[key] + + def __setitem__(self,key,val): + if not self._parsed_data.has_key(key): + warn("Unknown section %s" % key) + else: + self._parsed_data[key] = val + + def _is_at_section(self): + self._doc.seek_next_non_empty_line() + + if self._doc.eof(): + return False + + l1 = self._doc.peek().strip() # e.g. Parameters + + if l1.startswith('.. index::'): + return True + + l2 = self._doc.peek(1).strip() # ---------- or ========== + return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1)) + + def _strip(self,doc): + i = 0 + j = 0 + for i,line in enumerate(doc): + if line.strip(): break + + for j,line in enumerate(doc[::-1]): + if line.strip(): break + + return doc[i:len(doc)-j] + + def _read_to_next_section(self): + section = self._doc.read_to_next_empty_line() + + while not self._is_at_section() and not self._doc.eof(): + if not self._doc.peek(-1).strip(): # previous line was empty + section += [''] + + section += self._doc.read_to_next_empty_line() + + return section + + def _read_sections(self): + while not self._doc.eof(): + data = self._read_to_next_section() + name = data[0].strip() + + if name.startswith('..'): # index section + yield name, data[1:] + elif len(data) < 2: + yield StopIteration + else: + yield name, self._strip(data[2:]) + + def _parse_param_list(self,content): + r = Reader(content) + params = [] + while not r.eof(): + header = r.read().strip() + if ' : ' in header: + arg_name, arg_type = header.split(' : ')[:2] + else: + arg_name, arg_type = header, '' + + desc = r.read_to_next_unindented_line() + desc = dedent_lines(desc) + + params.append((arg_name,arg_type,desc)) + + return params + + + _name_rgx = re.compile(r"^\s*(:(?P<role>\w+):`(?P<name>[a-zA-Z0-9_.-]+)`|" + r" (?P<name2>[a-zA-Z0-9_.-]+))\s*", re.X) + def _parse_see_also(self, content): + """ + func_name : Descriptive text + continued text + another_func_name : Descriptive text + func_name1, func_name2, :meth:`func_name`, func_name3 + + """ + items = [] + + def parse_item_name(text): + """Match ':role:`name`' or 'name'""" + m = self._name_rgx.match(text) + if m: + g = m.groups() + if g[1] is None: + return g[3], None + else: + return g[2], g[1] + raise ValueError("%s is not a item name" % text) + + def push_item(name, rest): + if not name: + return + name, role = parse_item_name(name) + items.append((name, list(rest), role)) + del rest[:] + + current_func = None + rest = [] + + for line in content: + if not line.strip(): continue + + m = self._name_rgx.match(line) + if m and line[m.end():].strip().startswith(':'): + push_item(current_func, rest) + current_func, line = line[:m.end()], line[m.end():] + rest = [line.split(':', 1)[1].strip()] + if not rest[0]: + rest = [] + elif not line.startswith(' '): + push_item(current_func, rest) + current_func = None + if ',' in line: + for func in line.split(','): + push_item(func, []) + elif line.strip(): + current_func = line + elif current_func is not None: + rest.append(line.strip()) + push_item(current_func, rest) + return items + + def _parse_index(self, section, content): + """ + .. index: default + :refguide: something, else, and more + + """ + def strip_each_in(lst): + return [s.strip() for s in lst] + + out = {} + section = section.split('::') + if len(section) > 1: + out['default'] = strip_each_in(section[1].split(','))[0] + for line in content: + line = line.split(':') + if len(line) > 2: + out[line[1]] = strip_each_in(line[2].split(',')) + return out + + def _parse_summary(self): + """Grab signature (if given) and summary""" + if self._is_at_section(): + return + + summary = self._doc.read_to_next_empty_line() + summary_str = " ".join([s.strip() for s in summary]).strip() + if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): + self['Signature'] = summary_str + if not self._is_at_section(): + self['Summary'] = self._doc.read_to_next_empty_line() + else: + self['Summary'] = summary + + if not self._is_at_section(): + self['Extended Summary'] = self._read_to_next_section() + + def _parse(self): + self._doc.reset() + self._parse_summary() + + for (section,content) in self._read_sections(): + if not section.startswith('..'): + section = ' '.join([s.capitalize() for s in section.split(' ')]) + if section in ('Parameters', 'Attributes', 'Methods', + 'Returns', 'Raises', 'Warns'): + self[section] = self._parse_param_list(content) + elif section.startswith('.. index::'): + self['index'] = self._parse_index(section, content) + elif section == 'See Also': + self['See Also'] = self._parse_see_also(content) + else: + self[section] = content + + # string conversion routines + + def _str_header(self, name, symbol='-'): + return [name, len(name)*symbol] + + def _str_indent(self, doc, indent=4): + out = [] + for line in doc: + out += [' '*indent + line] + return out + + def _str_signature(self): + if self['Signature']: + return [self['Signature'].replace('*','\*')] + [''] + else: + return [''] + + def _str_summary(self): + if self['Summary']: + return self['Summary'] + [''] + else: + return [] + + def _str_extended_summary(self): + if self['Extended Summary']: + return self['Extended Summary'] + [''] + else: + return [] + + def _str_param_list(self, name): + out = [] + if self[name]: + out += self._str_header(name) + for param,param_type,desc in self[name]: + out += ['%s : %s' % (param, param_type)] + out += self._str_indent(desc) + out += [''] + return out + + def _str_section(self, name): + out = [] + if self[name]: + out += self._str_header(name) + out += self[name] + out += [''] + return out + + def _str_see_also(self, func_role): + if not self['See Also']: return [] + out = [] + out += self._str_header("See Also") + last_had_desc = True + for func, desc, role in self['See Also']: + if role: + link = ':%s:`%s`' % (role, func) + elif func_role: + link = ':%s:`%s`' % (func_role, func) + else: + link = "`%s`_" % func + if desc or last_had_desc: + out += [''] + out += [link] + else: + out[-1] += ", %s" % link + if desc: + out += self._str_indent([' '.join(desc)]) + last_had_desc = True + else: + last_had_desc = False + out += [''] + return out + + def _str_index(self): + idx = self['index'] + out = [] + out += ['.. index:: %s' % idx.get('default','')] + for section, references in idx.iteritems(): + if section == 'default': + continue + out += [' :%s: %s' % (section, ', '.join(references))] + return out + + def __str__(self, func_role=''): + out = [] + out += self._str_signature() + out += self._str_summary() + out += self._str_extended_summary() + for param_list in ('Parameters','Returns','Raises'): + out += self._str_param_list(param_list) + out += self._str_section('Warnings') + out += self._str_see_also(func_role) + for s in ('Notes','References','Examples'): + out += self._str_section(s) + out += self._str_index() + return '\n'.join(out) + + +def indent(str,indent=4): + indent_str = ' '*indent + if str is None: + return indent_str + lines = str.split('\n') + return '\n'.join(indent_str + l for l in lines) + +def dedent_lines(lines): + """Deindent a list of lines maximally""" + return textwrap.dedent("\n".join(lines)).split("\n") + +def header(text, style='-'): + return text + '\n' + style*len(text) + '\n' + + +class FunctionDoc(NumpyDocString): + def __init__(self, func, role='func', doc=None): + self._f = func + self._role = role # e.g. "func" or "meth" + if doc is None: + doc = inspect.getdoc(func) or '' + try: + NumpyDocString.__init__(self, doc) + except ValueError, e: + print '*'*78 + print "ERROR: '%s' while parsing `%s`" % (e, self._f) + print '*'*78 + #print "Docstring follows:" + #print doclines + #print '='*78 + + if not self['Signature']: + func, func_name = self.get_func() + try: + # try to read signature + argspec = inspect.getargspec(func) + argspec = inspect.formatargspec(*argspec) + argspec = argspec.replace('*','\*') + signature = '%s%s' % (func_name, argspec) + except TypeError, e: + signature = '%s()' % func_name + self['Signature'] = signature + + def get_func(self): + func_name = getattr(self._f, '__name__', self.__class__.__name__) + if inspect.isclass(self._f): + func = getattr(self._f, '__call__', self._f.__init__) + else: + func = self._f + return func, func_name + + def __str__(self): + out = '' + + func, func_name = self.get_func() + signature = self['Signature'].replace('*', '\*') + + roles = {'func': 'function', + 'meth': 'method'} + + if self._role: + if not roles.has_key(self._role): + print "Warning: invalid role %s" % self._role + out += '.. %s:: %s\n \n\n' % (roles.get(self._role,''), + func_name) + + out += super(FunctionDoc, self).__str__(func_role=self._role) + return out + + +class ClassDoc(NumpyDocString): + def __init__(self,cls,modulename='',func_doc=FunctionDoc,doc=None): + if not inspect.isclass(cls): + raise ValueError("Initialise using a class. Got %r" % cls) + self._cls = cls + + if modulename and not modulename.endswith('.'): + modulename += '.' + self._mod = modulename + self._name = cls.__name__ + self._func_doc = func_doc + + if doc is None: + doc = pydoc.getdoc(cls) + + NumpyDocString.__init__(self, doc) + + @property + def methods(self): + return [name for name,func in inspect.getmembers(self._cls) + if not name.startswith('_') and callable(func)] + + def __str__(self): + out = '' + out += super(ClassDoc, self).__str__() + out += "\n\n" + + #for m in self.methods: + # print "Parsing `%s`" % m + # out += str(self._func_doc(getattr(self._cls,m), 'meth')) + '\n\n' + # out += '.. index::\n single: %s; %s\n\n' % (self._name, m) + + return out + + Added: trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape_sphinx.py =================================================================== --- trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape_sphinx.py (rev 0) +++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape_sphinx.py 2009-03-18 07:39:43 UTC (rev 6987) @@ -0,0 +1,136 @@ +import re, inspect, textwrap, pydoc +from docscrape import NumpyDocString, FunctionDoc, ClassDoc + +class SphinxDocString(NumpyDocString): + # string conversion routines + def _str_header(self, name, symbol='`'): + return ['.. rubric:: ' + name, ''] + + def _str_field_list(self, name): + return [':' + name + ':'] + + def _str_indent(self, doc, indent=4): + out = [] + for line in doc: + out += [' '*indent + line] + return out + + def _str_signature(self): + return [''] + if self['Signature']: + return ['``%s``' % self['Signature']] + [''] + else: + return [''] + + def _str_summary(self): + return self['Summary'] + [''] + + def _str_extended_summary(self): + return self['Extended Summary'] + [''] + + def _str_param_list(self, name): + out = [] + if self[name]: + out += self._str_field_list(name) + out += [''] + for param,param_type,desc in self[name]: + out += self._str_indent(['**%s** : %s' % (param.strip(), + param_type)]) + out += [''] + out += self._str_indent(desc,8) + out += [''] + return out + + def _str_section(self, name): + out = [] + if self[name]: + out += self._str_header(name) + out += [''] + content = textwrap.dedent("\n".join(self[name])).split("\n") + out += content + out += [''] + return out + + def _str_see_also(self, func_role): + out = [] + if self['See Also']: + see_also = super(SphinxDocString, self)._str_see_also(func_role) + out = ['.. seealso::', ''] + out += self._str_indent(see_also[2:]) + return out + + def _str_warnings(self): + out = [] + if self['Warnings']: + out = ['.. warning::', ''] + out += self._str_indent(self['Warnings']) + return out + + def _str_index(self): + idx = self['index'] + out = [] + if len(idx) == 0: + return out + + out += ['.. index:: %s' % idx.get('default','')] + for section, references in idx.iteritems(): + if section == 'default': + continue + elif section == 'refguide': + out += [' single: %s' % (', '.join(references))] + else: + out += [' %s: %s' % (section, ','.join(references))] + return out + + def _str_references(self): + out = [] + if self['References']: + out += self._str_header('References') + if isinstance(self['References'], str): + self['References'] = [self['References']] + out.extend(self['References']) + out += [''] + return out + + def __str__(self, indent=0, func_role="obj"): + out = [] + out += self._str_signature() + out += self._str_index() + [''] + out += self._str_summary() + out += self._str_extended_summary() + for param_list in ('Parameters', 'Attributes', 'Methods', + 'Returns','Raises'): + out += self._str_param_list(param_list) + out += self._str_warnings() + out += self._str_see_also(func_role) + out += self._str_section('Notes') + out += self._str_references() + out += self._str_section('Examples') + out = self._str_indent(out,indent) + return '\n'.join(out) + +class SphinxFunctionDoc(SphinxDocString, FunctionDoc): + pass + +class SphinxClassDoc(SphinxDocString, ClassDoc): + pass + +def get_doc_object(obj, what=None, doc=None): + if what is None: + if inspect.isclass(obj): + what = 'class' + elif inspect.ismodule(obj): + what = 'module' + elif callable(obj): + what = 'function' + else: + what = 'object' + if what == 'class': + return SphinxClassDoc(obj, '', func_doc=SphinxFunctionDoc, doc=doc) + elif what in ('function', 'method'): + return SphinxFunctionDoc(obj, '', doc=doc) + else: + if doc is None: + doc = pydoc.getdoc(obj) + return SphinxDocString(doc) + Modified: trunk/py4science/examples/sphinx_template2/tools/sphinxext/inheritance_diagram.py =================================================================== --- trunk/py4science/examples/sphinx_template2/tools/sphinxext/inheritance_diagram.py 2009-03-17 19:45:05 UTC (rev 6986) +++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/inheritance_diagram.py 2009-03-18 07:39:43 UTC (rev 6987) @@ -29,42 +29,30 @@ LaTeX. """ -#----------------------------------------------------------------------------- -# Module and package imports - -# From the standard library - import inspect import os import re import subprocess - try: from hashlib import md5 except ImportError: from md5 import md5 -# Third party from docutils.nodes import Body, Element -from docutils.writers.html4css1 import HTMLTranslator from docutils.parsers.rst import directives - -from sphinx.latexwriter import LaTeXTranslator from sphinx.roles import xfileref_role -#----------------------------------------------------------------------------- -# Global Constants -# Sphinx automatically copies out the contents of this directory to the html -# output, so by putting things in here they get correctly picked up in the end -STATIC_DIR='_static' +def my_import(name): + """Module importer - taken from the python documentation. -options_spec = { - 'parts': directives.nonnegative_int - } + This function allows importing names with dots in them.""" + + mod = __import__(name) + components = name.split('.') + for comp in components[1:]: + mod = getattr(mod, comp) + return mod -#----------------------------------------------------------------------------- -# Main code begins, classes and functions - class DotException(Exception): pass @@ -105,11 +93,15 @@ path = (path and path.rstrip('.')) if not path: path = base - if not path: - raise ValueError( - "Invalid class or module '%s' specified for inheritance diagram" % name) try: module = __import__(path, None, None, []) + # We must do an import of the fully qualified name. Otherwise if a + # subpackage 'a.b' is requested where 'import a' does NOT provide + # 'a.b' automatically, then 'a.b' will not be found below. This + # second call will force the equivalent of 'import a.b' to happen + # after the top-level import above. + my_import(fullname) + except ImportError: raise ValueError( "Could not import class or module '%s' specified for inheritance diagram" % name) @@ -201,7 +193,6 @@ def _format_node_options(self, options): return ','.join(["%s=%s" % x for x in options.items()]) - def _format_graph_options(self, options): return ''.join(["%s=%s;\n" % x for x in options.items()]) @@ -292,7 +283,6 @@ raise DotException("'dot' returned the errorcode %d" % returncode) return result - class inheritance_diagram(Body, Element): """ A docutils node to use as a placeholder for the inheritance @@ -300,13 +290,16 @@ """ pass - -def inheritance_diagram_directive_run(class_names, options, state): +def inheritance_diagram_directive(name, arguments, options, content, lineno, + content_offset, block_text, state, + state_machine): """ Run when the inheritance_diagram directive is first encountered. """ node = inheritance_diagram() + class_names = arguments + # Create a graph starting with the list of classes graph = InheritanceGraph(class_names) @@ -326,11 +319,9 @@ node['content'] = " ".join(class_names) return [node] - def get_graph_hash(node): return md5(node['content'] + str(node['parts'])).hexdigest()[-10:] - def html_output_graph(self, node): """ Output the graph for HTML. This will insert a PNG with clickable @@ -341,16 +332,13 @@ graph_hash = get_graph_hash(node) name = "inheritance%s" % graph_hash - png_path = os.path.join(STATIC_DIR, name + ".png") + path = '_images' + dest_path = os.path.join(setup.app.builder.outdir, path) + if not os.path.exists(dest_path): + os.makedirs(dest_path) + png_path = os.path.join(dest_path, name + ".png") + path = setup.app.builder.imgpath - path = STATIC_DIR - source = self.document.attributes['source'] - count = source.split('/doc/')[-1].count('/') - for i in range(count): - if os.path.exists(path): break - path = '../'+path - path = '../'+path #specifically added for matplotlib - # Create a mapping from fully-qualified class names to URLs. urls = {} for child in node: @@ -366,7 +354,6 @@ return ('<img src="%s/%s.png" usemap="#%s" class="inheritance"/>%s' % (path, name, name, image_map)) - def latex_output_graph(self, node): """ Output the graph for LaTeX. This will insert a PDF. @@ -376,13 +363,15 @@ graph_hash = get_graph_hash(node) name = "inheritance%s" % graph_hash - pdf_path = os.path.join(STATIC_DIR, name + ".pdf") + dest_path = os.path.abspath(os.path.join(setup.app.builder.outdir, '_images')) + if not os.path.exists(dest_path): + os.makedirs(dest_path) + pdf_path = os.path.abspath(os.path.join(dest_path, name + ".pdf")) graph.run_dot(['-Tpdf', '-o%s' % pdf_path], name, parts, graph_options={'size': '"6.0,6.0"'}) - return '\\includegraphics{../../%s}' % pdf_path + return '\n\\includegraphics{%s}\n\n' % pdf_path - def visit_inheritance_diagram(inner_func): """ This is just a wrapper around html/latex_output_graph to make it @@ -402,57 +391,17 @@ node.children = [] return visitor - def do_nothing(self, node): pass - def setup(app): - app.add_node(inheritance_diagram) + setup.app = app + setup.confdir = app.confdir - HTMLTranslator.visit_inheritance_diagram = \ - visit_inheritance_diagram(html_output_graph) - HTMLTranslator.depart_inheritance_diagram = do_nothing - - LaTeXTranslator.visit_inheritance_diagram = \ - visit_inheritance_diagram(latex_output_graph) - LaTeXTranslator.depart_inheritance_diagram = do_nothing - -#----------------------------------------------------------------------------- -# Main code - register the directives. Do it in a way that's compatible with -# the old and current docutils APIs. - -try: - from docutils.parsers.rst import Directive -except ImportError: - # Legacy API - from docutils.parsers.rst.directives import _directives - - def inheritance_diagram_directive(name, arguments, options, content, lineno, - content_offset, block_text, state, - state_machine): - return inheritance_diagram_directive_run(arguments, options, state) - - inheritance_diagram_directive.__doc__ = __doc__ - inheritance_diagram_directive.arguments = (1, 100, 0) - inheritance_diagram_directive.options = options_spec - inheritance_diagram_directive.content = 0 - _directives['inheritance-diagram'] = inheritance_diagram_directive - -else: - # New API - class inheritance_diagram_directive(Directive): - has_content = False - required_arguments = 1 - optional_arguments = 100 - final_argument_whitespace = False - option_spec = options_spec - - def run(self): - return inheritance_diagram_directive_run( - self.arguments, self.options, self.state) - - inheritance_diagram_directive.__doc__ = __doc__ - - directives.register_directive('inheritance-diagram', - inheritance_diagram_directive) + app.add_node( + inheritance_diagram, + latex=(visit_inheritance_diagram(latex_output_graph), do_nothing), + html=(visit_inheritance_diagram(html_output_graph), do_nothing)) + app.add_directive( + 'inheritance-diagram', inheritance_diagram_directive, + False, (1, 100, 0), parts = directives.nonnegative_int) Deleted: trunk/py4science/examples/sphinx_template2/tools/sphinxext/mathmpl.py =================================================================== --- trunk/py4science/examples/sphinx_template2/tools/sphinxext/mathmpl.py 2009-03-17 19:45:05 UTC (rev 6986) +++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/mathmpl.py 2009-03-18 07:39:43 UTC (rev 6987) @@ -1,166 +0,0 @@ -"""matplotlib-based directive for math rendering in reST using sphinx. - -To use this extension, add ``mathmpl`` to the list of extensions in -:file:`conf.py`. - -*Warning*: this code is currently untested. ***MAY NOT WORK*** - -Note: - -Current SVN versions of Sphinx now include built-in support for math. -There are two flavors: - - - pngmath: uses dvipng to render the equation - - - jsmath: renders the math in the browser using Javascript - -To use these extensions instead of the code in this module, add -``sphinx.ext.pngmath`` or ``sphinx.ext.jsmath`` to the list of extensions in -:file:`conf.py`. - -All three of these options for math are designed to behave in the same -way. -""" - -import os -try: - from hashlib import md5 -except ImportError: - from md5 import md5 - -from docutils import nodes -from docutils.parsers.rst import directives -from docutils.writers.html4css1 import HTMLTranslator -from sphinx.latexwriter import LaTeXTranslator -import warnings - -# Constants -STATIC_DIR='_static' - -# Define LaTeX math node: -class latex_math(nodes.General, nodes.Element): - pass - -def fontset_choice(arg): - return directives.choice(arg, ['cm', 'stix', 'stixsans']) - -options_spec = {'fontset': fontset_choice} - -def math_role(role, rawtext, text, lineno, inliner, - options={}, content=[]): - i = rawtext.find('`') - latex = rawtext[i+1:-1] - node = latex_math(rawtext) - node['latex'] = latex - node['fontset'] = options.get('fontset', 'cm') - return [node], [] -math_role.options = options_spec - -def math_directive_run(content, block_text, options): - latex = ''.join(content) - node = latex_math(block_text) - node['latex'] = latex - node['fontset'] = options.get('fontset', 'cm') - return [node] - -try: - from docutils.parsers.rst import Directive -except ImportError: - # Register directive the old way: - from docutils.parsers.rst.directives import _directives - def math_directive(name, arguments, options, content, lineno, - content_offset, block_text, state, state_machine): - return math_directive_run(content, block_text, options) - math_directive.arguments = None - math_directive.options = options_spec - math_directive.content = 1 - _directives['math'] = math_directive -else: - class math_directive(Directive): - has_content = True - option_spec = options_spec - - def run(self): - return math_directive_run(self.content, self.block_text, - self.options) - from docutils.parsers.rst import directives - directives.register_directive('math', math_directive) - -def setup(app): - app.add_node(latex_math) - app.add_role('math', math_role) - - # Add visit/depart methods to HTML-Translator: - def visit_latex_math_html(self, node): - source = self.document.attributes['source'] - self.body.append(latex2html(node, source)) - def depart_latex_math_html(self, node): - pass - HTMLTranslator.visit_latex_math = visit_latex_math_html - HTMLTranslator.depart_latex_math = depart_latex_math_html - - # Add visit/depart methods to LaTeX-Translator: - def visit_latex_math_latex(self, node): - inline = isinstance(node.parent, nodes.TextElement) - if inline: - self.body.append('$%s$' % node['latex']) - else: - self.body.extend(['\\begin{equation}', - node['latex'], - '\\end{equation}']) - def depart_latex_math_latex(self, node): - pass - LaTeXTranslator.visit_latex_math = visit_latex_math_latex - LaTeXTranslator.depart_latex_math = depart_latex_math_latex - -from matplotlib import rcParams -from matplotlib.mathtext import MathTextParser -rcParams['mathtext.fontset'] = 'cm' -mathtext_parser = MathTextParser("Bitmap") - - -# This uses mathtext to render the expression -def latex2png(latex, filename, fontset='cm'): - latex = "$%s$" % latex - orig_fontset = rcParams['mathtext.fontset'] - rcParams['mathtext.fontset'] = fontset - if os.path.exists(filename): - depth = mathtext_parser.get_depth(latex, dpi=100) - else: - print latex.encode("ascii", "backslashreplace") - try: - depth = mathtext_parser.to_png(filename, latex, dpi=100) - except: - warnings.warn("Could not render math expression %s" % latex, - Warning) - depth = 0 - rcParams['mathtext.fontset'] = orig_fontset - return depth - -# LaTeX to HTML translation stuff: -def latex2html(node, source): - inline = isinstance(node.parent, nodes.TextElement) - latex = node['latex'] - name = 'math-%s' % md5(latex).hexdigest()[-10:] - dest = os.path.join(STATIC_DIR, name + ".png") - - depth = latex2png(latex, dest, node.get('fontset', - rcParams['mathtext.fontset'])) - - path = STATIC_DIR - count = source.split('/doc/')[-1].count('/') - for i in range(count): - if os.path.exists(path): break - path = '../'+path - path = '../'+path #s... [truncated message content] |
From: <ef...@us...> - 2009-03-17 19:45:15
|
Revision: 6986 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6986&view=rev Author: efiring Date: 2009-03-17 19:45:05 +0000 (Tue, 17 Mar 2009) Log Message: ----------- Merged revisions 6984-6985 via svnmerge from https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint ........ r6984 | efiring | 2009-03-17 09:15:01 -1000 (Tue, 17 Mar 2009) | 4 lines Fix bug in alpha handling. The alpha kwarg was multiplying the existing alpha instead of replacing it. Thanks to Jae-Joon Lee. ........ r6985 | efiring | 2009-03-17 09:34:27 -1000 (Tue, 17 Mar 2009) | 2 lines In contourf, don't accidentally set the edgecolor. ........ Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/colors.py trunk/matplotlib/lib/matplotlib/contour.py Property Changed: ---------------- trunk/matplotlib/ trunk/matplotlib/doc/pyplots/README trunk/matplotlib/doc/sphinxext/gen_gallery.py trunk/matplotlib/doc/sphinxext/gen_rst.py trunk/matplotlib/lib/matplotlib/sphinxext/mathmpl.py trunk/matplotlib/lib/matplotlib/sphinxext/only_directives.py trunk/matplotlib/lib/matplotlib/sphinxext/plot_directive.py Property changes on: trunk/matplotlib ___________________________________________________________________ Modified: svnmerge-integrated - /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6972 + /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6985 Modified: svn:mergeinfo - /branches/v0_91_maint:5753-5771 /branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6809,6811,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6906-6909,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972 + /branches/v0_91_maint:5753-5771 /branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6809,6811,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6906-6909,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-03-17 19:34:27 UTC (rev 6985) +++ trunk/matplotlib/CHANGELOG 2009-03-17 19:45:05 UTC (rev 6986) @@ -1,4 +1,7 @@ -2009-03-14 Added 'lightsource' class to colors module for +2009-03-17 Fix bugs in edge color handling by contourf, found + by Jae-Joon Lee. - EF + +2009-03-14 Added 'lightsource' class to colors module for creating shaded relief maps. shading_example.py added to illustrate usage. - JSW Property changes on: trunk/matplotlib/doc/pyplots/README ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972 + /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 Property changes on: trunk/matplotlib/doc/sphinxext/gen_gallery.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972 + /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 Property changes on: trunk/matplotlib/doc/sphinxext/gen_rst.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972 + /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 Modified: trunk/matplotlib/lib/matplotlib/colors.py =================================================================== --- trunk/matplotlib/lib/matplotlib/colors.py 2009-03-17 19:34:27 UTC (rev 6985) +++ trunk/matplotlib/lib/matplotlib/colors.py 2009-03-17 19:45:05 UTC (rev 6986) @@ -331,7 +331,7 @@ return tuple(arg) if alpha < 0.0 or alpha > 1.0: raise ValueError("alpha must be in range 0-1") - return arg[0], arg[1], arg[2], arg[3] * alpha + return arg[0], arg[1], arg[2], alpha r,g,b = arg[:3] if [x for x in (r,g,b) if (float(x) < 0) or (x > 1)]: raise ValueError('number in rbg sequence outside 0-1 range') Modified: trunk/matplotlib/lib/matplotlib/contour.py =================================================================== --- trunk/matplotlib/lib/matplotlib/contour.py 2009-03-17 19:34:27 UTC (rev 6985) +++ trunk/matplotlib/lib/matplotlib/contour.py 2009-03-17 19:45:05 UTC (rev 6986) @@ -629,8 +629,10 @@ self.to_rgba(self.cvalues, alpha=self.alpha)] self.tcolors = tcolors for color, collection in zip(tcolors, self.collections): - collection.set_alpha(self.alpha) - collection.set_color(color) + if self.filled: + collection.set_facecolor(color) + else: + collection.set_color(color) for label, cv in zip(self.labelTexts, self.labelCValues): label.set_alpha(self.alpha) label.set_color(self.labelMappable.to_rgba(cv)) Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/mathmpl.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/mathmpl.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/mathmpl.py:6946,6948,6950,6952,6960,6972 + /branches/v0_91_maint/doc/sphinxext/mathmpl.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/mathmpl.py:6946,6948,6950,6952,6960,6972,6984-6985 Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/only_directives.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/only_directives.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/only_directives.py:6946,6948,6950,6952,6960,6972 + /branches/v0_91_maint/doc/sphinxext/only_directives.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/only_directives.py:6946,6948,6950,6952,6960,6972,6984-6985 Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/plot_directive.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/plot_directive.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/plot_directive.py:6920-6925,6934,6941,6946,6948,6950,6952,6960,6972 + /branches/v0_91_maint/doc/sphinxext/plot_directive.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/plot_directive.py:6920-6925,6934,6941,6946,6948,6950,6952,6960,6972,6984-6985 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ef...@us...> - 2009-03-17 19:34:45
|
Revision: 6985 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6985&view=rev Author: efiring Date: 2009-03-17 19:34:27 +0000 (Tue, 17 Mar 2009) Log Message: ----------- In contourf, don't accidentally set the edgecolor. Modified Paths: -------------- branches/v0_98_5_maint/CHANGELOG branches/v0_98_5_maint/lib/matplotlib/contour.py Modified: branches/v0_98_5_maint/CHANGELOG =================================================================== --- branches/v0_98_5_maint/CHANGELOG 2009-03-17 19:15:01 UTC (rev 6984) +++ branches/v0_98_5_maint/CHANGELOG 2009-03-17 19:34:27 UTC (rev 6985) @@ -1,3 +1,6 @@ +2009-03-17 Fix bugs in edge color handling by contourf, found + by Jae-Joon Lee. - EF + 2009-03-11 Ensure wx version >= 2.8; thanks to Sandro Tosi and Chris Barker. - EF Modified: branches/v0_98_5_maint/lib/matplotlib/contour.py =================================================================== --- branches/v0_98_5_maint/lib/matplotlib/contour.py 2009-03-17 19:15:01 UTC (rev 6984) +++ branches/v0_98_5_maint/lib/matplotlib/contour.py 2009-03-17 19:34:27 UTC (rev 6985) @@ -629,8 +629,10 @@ self.to_rgba(self.cvalues, alpha=self.alpha)] self.tcolors = tcolors for color, collection in zip(tcolors, self.collections): - collection.set_alpha(self.alpha) - collection.set_color(color) + if self.filled: + collection.set_facecolor(color) + else: + collection.set_color(color) for label, cv in zip(self.labelTexts, self.labelCValues): label.set_alpha(self.alpha) label.set_color(self.labelMappable.to_rgba(cv)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ef...@us...> - 2009-03-17 19:15:44
|
Revision: 6984 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6984&view=rev Author: efiring Date: 2009-03-17 19:15:01 +0000 (Tue, 17 Mar 2009) Log Message: ----------- Fix bug in alpha handling. The alpha kwarg was multiplying the existing alpha instead of replacing it. Thanks to Jae-Joon Lee. Modified Paths: -------------- branches/v0_98_5_maint/lib/matplotlib/colors.py Modified: branches/v0_98_5_maint/lib/matplotlib/colors.py =================================================================== --- branches/v0_98_5_maint/lib/matplotlib/colors.py 2009-03-17 11:49:57 UTC (rev 6983) +++ branches/v0_98_5_maint/lib/matplotlib/colors.py 2009-03-17 19:15:01 UTC (rev 6984) @@ -331,7 +331,7 @@ return tuple(arg) if alpha < 0.0 or alpha > 1.0: raise ValueError("alpha must be in range 0-1") - return arg[0], arg[1], arg[2], arg[3] * alpha + return arg[0], arg[1], arg[2], alpha r,g,b = arg[:3] if [x for x in (r,g,b) if (float(x) < 0) or (x > 1)]: raise ValueError('number in rbg sequence outside 0-1 range') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2009-03-17 11:50:02
|
Revision: 6983 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6983&view=rev Author: mdboom Date: 2009-03-17 11:49:57 +0000 (Tue, 17 Mar 2009) Log Message: ----------- Bugfix for Mac OS-X backend build. Modified Paths: -------------- trunk/matplotlib/setupext.py Modified: trunk/matplotlib/setupext.py =================================================================== --- trunk/matplotlib/setupext.py 2009-03-16 19:32:22 UTC (rev 6982) +++ trunk/matplotlib/setupext.py 2009-03-17 11:49:57 UTC (rev 6983) @@ -1160,12 +1160,16 @@ global BUILT_MACOSX if BUILT_MACOSX: return # only build it if you you haven't already deps = ['src/_macosx.m', + 'CXX/cxx_extensions.cxx', + 'CXX/cxxextensions.c', + 'CXX/cxxsupport.cxx', + 'CXX/IndirectPythonInterface.cxx', 'src/agg_py_transforms.cpp', - 'src/path_cleanup.cpp', - 'src/_path.cpp'] + 'src/path_cleanup.cpp'] module = Extension('matplotlib.backends._macosx', deps, extra_link_args = ['-framework','Cocoa'], + define_macros=[('PY_ARRAY_UNIQUE_SYMBOL', 'MPL_ARRAY_API')] ) add_numpy_flags(module) add_agg_flags(module) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2009-03-16 19:32:33
|
Revision: 6982 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6982&view=rev Author: jswhit Date: 2009-03-16 19:32:22 +0000 (Mon, 16 Mar 2009) Log Message: ----------- fix small bug in relief plot shading algorithm Modified Paths: -------------- trunk/matplotlib/examples/pylab_examples/shading_example.py trunk/matplotlib/lib/matplotlib/colors.py Modified: trunk/matplotlib/examples/pylab_examples/shading_example.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/shading_example.py 2009-03-16 17:22:07 UTC (rev 6981) +++ trunk/matplotlib/examples/pylab_examples/shading_example.py 2009-03-16 19:32:22 UTC (rev 6982) @@ -9,10 +9,10 @@ # (http://gmt.soest.hawaii.edu/gmt/doc/gmt/html/GMT_Docs/node145.html) # test data -X,Y=np.mgrid[-5:5:0.1,-5:5:0.1] -Z=X+np.sin(X**2+Y**2) +X,Y=np.mgrid[-5:5:0.05,-5:5:0.05] +Z=np.sqrt(X**2+Y**2)+np.sin(X**2+Y**2) # creat light source object. -ls = lightsource(azdeg=270,altdeg=60) +ls = lightsource(azdeg=0,altdeg=65) # shade data, creating an rgb array. rgb = ls.shade(Z,plt.cm.copper) # plot un-shaded and shaded images. Modified: trunk/matplotlib/lib/matplotlib/colors.py =================================================================== --- trunk/matplotlib/lib/matplotlib/colors.py 2009-03-16 17:22:07 UTC (rev 6981) +++ trunk/matplotlib/lib/matplotlib/colors.py 2009-03-16 19:32:22 UTC (rev 6982) @@ -1018,11 +1018,11 @@ # modify hsv values to simulate illumination. hsv[:,:,1] = np.where(np.logical_and(np.abs(hsv[:,:,1])>1.e-10,intensity>0),\ (1.-intensity)*hsv[:,:,1]+intensity*self.hsv_max_sat, hsv[:,:,1]) - hsv[:,:,2] = np.where(intensity > 0, (1.-intensity)*hsv[:,:,1] +\ + hsv[:,:,2] = np.where(intensity > 0, (1.-intensity)*hsv[:,:,2] +\ intensity*self.hsv_max_val, hsv[:,:,2]) hsv[:,:,1] = np.where(np.logical_and(np.abs(hsv[:,:,1])>1.e-10,intensity<0),\ (1.+intensity)*hsv[:,:,1]-intensity*self.hsv_min_sat, hsv[:,:,1]) - hsv[:,:,2] = np.where(intensity < 0, (1.+intensity)*hsv[:,:,1] -\ + hsv[:,:,2] = np.where(intensity < 0, (1.+intensity)*hsv[:,:,2] -\ intensity*self.hsv_min_val, hsv[:,:,2]) hsv[:,:,1:] = np.where(hsv[:,:,1:]<0.,0,hsv[:,:,1:]) hsv[:,:,1:] = np.where(hsv[:,:,1:]>1.,1,hsv[:,:,1:]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ry...@us...> - 2009-03-16 17:22:22
|
Revision: 6981 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6981&view=rev Author: ryanmay Date: 2009-03-16 17:22:07 +0000 (Mon, 16 Mar 2009) Log Message: ----------- Remove duplicate debugging print. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_gtkagg.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_gtkagg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_gtkagg.py 2009-03-16 15:59:45 UTC (rev 6980) +++ trunk/matplotlib/lib/matplotlib/backends/backend_gtkagg.py 2009-03-16 17:22:07 UTC (rev 6981) @@ -88,7 +88,6 @@ if DEBUG: print 'FigureCanvasGTKAgg.render_figure done' def blit(self, bbox=None): - if DEBUG: print 'FigureCanvasGTKAgg.blit' if DEBUG: print 'FigureCanvasGTKAgg.blit', self._pixmap agg_to_gtk_drawable(self._pixmap, self.renderer._renderer, bbox) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2009-03-16 15:59:57
|
Revision: 6980 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6980&view=rev Author: jswhit Date: 2009-03-16 15:59:45 +0000 (Mon, 16 Mar 2009) Log Message: ----------- add some comments. Modified Paths: -------------- trunk/toolkits/basemap/examples/plotmap_shaded.py Modified: trunk/toolkits/basemap/examples/plotmap_shaded.py =================================================================== --- trunk/toolkits/basemap/examples/plotmap_shaded.py 2009-03-14 23:44:09 UTC (rev 6979) +++ trunk/toolkits/basemap/examples/plotmap_shaded.py 2009-03-16 15:59:45 UTC (rev 6980) @@ -26,12 +26,15 @@ # transform to nx x ny regularly spaced native projection grid nx = int((m.xmax-m.xmin)/40000.)+1; ny = int((m.ymax-m.ymin)/40000.)+1 topodat,x,y = m.transform_scalar(topoin,lons,lats,nx,ny,returnxy=True) +# create light source object. ls = lightsource(azdeg = 90, altdeg = 20) -print topodat.shape +# convert data to rgb array including shading from light source. +# (must specify color map) rgb = ls.shade(topodat, plt.cm.jet) # create the figure. fig=plt.figure(figsize=(8,8)) -# plot image over map with imshow. +# plot image over map with imshow (pass rgb values +# that include light shading). im = m.imshow(rgb) # draw coastlines and political boundaries. m.drawcoastlines() @@ -44,5 +47,4 @@ m.drawmeridians(meridians,labels=[1,1,0,1]) # set title. plt.title('ETOPO Shaded Relief - Lambert Conformal Conic') -#plt.savefig('plotmap.pdf') plt.show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2009-03-14 23:44:15
|
Revision: 6979 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6979&view=rev Author: jswhit Date: 2009-03-14 23:44:09 +0000 (Sat, 14 Mar 2009) Log Message: ----------- change sun elevation angle. Modified Paths: -------------- trunk/matplotlib/examples/pylab_examples/shading_example.py Modified: trunk/matplotlib/examples/pylab_examples/shading_example.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/shading_example.py 2009-03-14 13:54:37 UTC (rev 6978) +++ trunk/matplotlib/examples/pylab_examples/shading_example.py 2009-03-14 23:44:09 UTC (rev 6979) @@ -12,7 +12,7 @@ X,Y=np.mgrid[-5:5:0.1,-5:5:0.1] Z=X+np.sin(X**2+Y**2) # creat light source object. -ls = lightsource(azdeg=270,altdeg=20) +ls = lightsource(azdeg=270,altdeg=60) # shade data, creating an rgb array. rgb = ls.shade(Z,plt.cm.copper) # plot un-shaded and shaded images. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2009-03-14 13:54:39
|
Revision: 6978 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6978&view=rev Author: jswhit Date: 2009-03-14 13:54:37 +0000 (Sat, 14 Mar 2009) Log Message: ----------- docstring fix for lightsource class Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/colors.py Modified: trunk/matplotlib/lib/matplotlib/colors.py =================================================================== --- trunk/matplotlib/lib/matplotlib/colors.py 2009-03-14 13:53:24 UTC (rev 6977) +++ trunk/matplotlib/lib/matplotlib/colors.py 2009-03-14 13:54:37 UTC (rev 6978) @@ -959,7 +959,7 @@ """ Create a light source coming from the specified azimuth and elevation. Angles are in degrees, with the azimuth measured - clockwise from south and elevation up from the zero plane of the surface. + clockwise from north and elevation up from the zero plane of the surface. The :meth:`shade` is used to produce rgb values for a shaded relief image given a data array. """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2009-03-14 13:53:42
|
Revision: 6977 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6977&view=rev Author: jswhit Date: 2009-03-14 13:53:24 +0000 (Sat, 14 Mar 2009) Log Message: ----------- added shaded relief plot example. Modified Paths: -------------- trunk/toolkits/basemap/Changelog trunk/toolkits/basemap/MANIFEST.in trunk/toolkits/basemap/examples/README Added Paths: ----------- trunk/toolkits/basemap/examples/plotmap_shaded.py Modified: trunk/toolkits/basemap/Changelog =================================================================== --- trunk/toolkits/basemap/Changelog 2009-03-14 13:49:09 UTC (rev 6976) +++ trunk/toolkits/basemap/Changelog 2009-03-14 13:53:24 UTC (rev 6977) @@ -1,4 +1,5 @@ version 0.99.4 (not yet released) + * added new example "plotmap_shaded.py" (shaded relief plot). * added new example "plothighsandlows.py". * add fix_aspect kwarg to Basemap.__init__, when False axes.set_aspect is set to 'auto' instead of default 'equal'. Modified: trunk/toolkits/basemap/MANIFEST.in =================================================================== --- trunk/toolkits/basemap/MANIFEST.in 2009-03-14 13:49:09 UTC (rev 6976) +++ trunk/toolkits/basemap/MANIFEST.in 2009-03-14 13:53:24 UTC (rev 6977) @@ -40,6 +40,7 @@ include examples/plotmap.py include examples/plotmap_oo.py include examples/plotmap_masked.py +include examples/plotmap_shaded.py include examples/contour_demo.py include examples/customticks.py include examples/quiver_demo.py Modified: trunk/toolkits/basemap/examples/README =================================================================== --- trunk/toolkits/basemap/examples/README 2009-03-14 13:49:09 UTC (rev 6976) +++ trunk/toolkits/basemap/examples/README 2009-03-14 13:53:24 UTC (rev 6977) @@ -20,6 +20,9 @@ in test.py) which shows the ETOPO topography as an image on a Lambert Conformal projection (using imshow). +plotmap_shaded.py shows how to make a 'shaded relief' plot by specifying +the location of a lightsource. + plotmap_oo.py is a version of plotmap.py that does not import pylab - it uses the matplotlib OO interface instead. Added: trunk/toolkits/basemap/examples/plotmap_shaded.py =================================================================== --- trunk/toolkits/basemap/examples/plotmap_shaded.py (rev 0) +++ trunk/toolkits/basemap/examples/plotmap_shaded.py 2009-03-14 13:53:24 UTC (rev 6977) @@ -0,0 +1,48 @@ +# make shaded relief plot of etopo bathymetry/topography data on +# lambert conformal conic map projection. + +# the data is interpolated to the native projection grid. + +from mpl_toolkits.basemap import Basemap, shiftgrid +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.mlab as mlab +from matplotlib.colors import lightsource + +# read in topo data (on a regular lat/lon grid) +# longitudes go from 20 to 380. +topoin = mlab.load('etopo20data.gz') +lons = mlab.load('etopo20lons.gz') +lats = mlab.load('etopo20lats.gz') +# shift data so lons go from -180 to 180 instead of 20 to 380. +topoin,lons = shiftgrid(180.,topoin,lons,start=False) + +# setup of basemap ('lcc' = lambert conformal conic). +# use major and minor sphere radii from WGS84 ellipsoid. +m = Basemap(llcrnrlon=-145.5,llcrnrlat=1.,urcrnrlon=-2.566,urcrnrlat=46.352,\ + rsphere=(6378137.00,6356752.3142),\ + resolution='l',area_thresh=1000.,projection='lcc',\ + lat_1=50.,lon_0=-107.) +# transform to nx x ny regularly spaced native projection grid +nx = int((m.xmax-m.xmin)/40000.)+1; ny = int((m.ymax-m.ymin)/40000.)+1 +topodat,x,y = m.transform_scalar(topoin,lons,lats,nx,ny,returnxy=True) +ls = lightsource(azdeg = 90, altdeg = 20) +print topodat.shape +rgb = ls.shade(topodat, plt.cm.jet) +# create the figure. +fig=plt.figure(figsize=(8,8)) +# plot image over map with imshow. +im = m.imshow(rgb) +# draw coastlines and political boundaries. +m.drawcoastlines() +m.drawcountries() +# draw parallels and meridians. +# label on left, right and bottom of map. +parallels = np.arange(0.,80,20.) +m.drawparallels(parallels,labels=[1,1,0,1]) +meridians = np.arange(10.,360.,30.) +m.drawmeridians(meridians,labels=[1,1,0,1]) +# set title. +plt.title('ETOPO Shaded Relief - Lambert Conformal Conic') +#plt.savefig('plotmap.pdf') +plt.show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2009-03-14 13:49:16
|
Revision: 6976 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6976&view=rev Author: jswhit Date: 2009-03-14 13:49:09 +0000 (Sat, 14 Mar 2009) Log Message: ----------- fix bug in hsv_to_rgb (returned rgb array wrong shape) Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/colors.py Modified: trunk/matplotlib/lib/matplotlib/colors.py =================================================================== --- trunk/matplotlib/lib/matplotlib/colors.py 2009-03-14 13:22:32 UTC (rev 6975) +++ trunk/matplotlib/lib/matplotlib/colors.py 2009-03-14 13:49:09 UTC (rev 6976) @@ -951,7 +951,9 @@ r[idx] = v[idx]; g[idx] = p[idx]; b[idx] = q[idx] idx = s == 0 r[idx] = v[idx]; g[idx] = v[idx]; b[idx] = v[idx] - return np.array((r,g,b)).T + rgb = np.empty_like(hsv) + rgb[:,:,0]=r; rgb[:,:,1]=g; rgb[:,:,2]=b + return rgb class lightsource(object): """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2009-03-14 13:22:41
|
Revision: 6975 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6975&view=rev Author: jswhit Date: 2009-03-14 13:22:32 +0000 (Sat, 14 Mar 2009) Log Message: ----------- added 'lightsource' class to colors module, shading_example.py to illustrate it's usage to create shaded relief maps with imshow. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/colors.py Added Paths: ----------- trunk/matplotlib/examples/pylab_examples/shading_example.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-03-13 17:13:49 UTC (rev 6974) +++ trunk/matplotlib/CHANGELOG 2009-03-14 13:22:32 UTC (rev 6975) @@ -1,3 +1,7 @@ +2009-03-14 Added 'lightsource' class to colors module for + creating shaded relief maps. shading_example.py + added to illustrate usage. - JSW + 2009-03-11 Ensure wx version >= 2.8; thanks to Sandro Tosi and Chris Barker. - EF Added: trunk/matplotlib/examples/pylab_examples/shading_example.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/shading_example.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/shading_example.py 2009-03-14 13:22:32 UTC (rev 6975) @@ -0,0 +1,28 @@ +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.colors import lightsource + +# example showing how to make shaded relief plots +# like mathematica +# (http://reference.wolfram.com/mathematica/ref/ReliefPlot.html ) +# or Generic Mapping Tools +# (http://gmt.soest.hawaii.edu/gmt/doc/gmt/html/GMT_Docs/node145.html) + +# test data +X,Y=np.mgrid[-5:5:0.1,-5:5:0.1] +Z=X+np.sin(X**2+Y**2) +# creat light source object. +ls = lightsource(azdeg=270,altdeg=20) +# shade data, creating an rgb array. +rgb = ls.shade(Z,plt.cm.copper) +# plot un-shaded and shaded images. +plt.figure(figsize=(12,5)) +plt.subplot(121) +plt.imshow(Z,cmap=plt.cm.copper) +plt.title('imshow') +plt.xticks([]); plt.yticks([]) +plt.subplot(122) +plt.imshow(rgb) +plt.title('imshow with shading') +plt.xticks([]); plt.yticks([]) +plt.show() Modified: trunk/matplotlib/lib/matplotlib/colors.py =================================================================== --- trunk/matplotlib/lib/matplotlib/colors.py 2009-03-13 17:13:49 UTC (rev 6974) +++ trunk/matplotlib/lib/matplotlib/colors.py 2009-03-14 13:22:32 UTC (rev 6975) @@ -900,3 +900,130 @@ # compatibility with earlier class names that violated convention: normalize = Normalize no_norm = NoNorm + +def rgb_to_hsv(arr): + """ + convert rgb values in a numpy array to hsv values + input and output arrays should have shape (M,N,3) + """ + out = np.empty_like(arr) + arr_max = arr.max(-1) + delta = arr.ptp(-1) + s = delta / arr_max + s[delta==0] = 0 + # red is max + idx = (arr[:,:,0] == arr_max) + out[idx, 0] = (arr[idx, 1] - arr[idx, 2]) / delta[idx] + # green is max + idx = (arr[:,:,1] == arr_max) + out[idx, 0] = 2. + (arr[idx, 2] - arr[idx, 0] ) / delta[idx] + # blue is max + idx = (arr[:,:,2] == arr_max) + out[idx, 0] = 4. + (arr[idx, 0] - arr[idx, 1] ) / delta[idx] + out[:,:,0] = (out[:,:,0]/6.0) % 1.0 + out[:,:,1] = s + out[:,:,2] = arr_max + return out + +def hsv_to_rgb(hsv): + """ + convert hsv values in a numpy array to rgb values + both input and output arrays have shape (M,N,3) + """ + h = hsv[:,:,0]; s = hsv[:,:,1]; v = hsv[:,:,2] + r = np.empty_like(h); g = np.empty_like(h); b = np.empty_like(h) + i = (h*6.0).astype(np.int) + f = (h*6.0) - i + p = v*(1.0 - s) + q = v*(1.0 - s*f) + t = v*(1.0 - s*(1.0-f)) + idx = i%6 == 0 + r[idx] = v[idx]; g[idx] = t[idx]; b[idx] = p[idx] + idx = i == 1 + r[idx] = q[idx]; g[idx] = v[idx]; b[idx] = p[idx] + idx = i == 2 + r[idx] = p[idx]; g[idx] = v[idx]; b[idx] = t[idx] + idx = i == 3 + r[idx] = p[idx]; g[idx] = q[idx]; b[idx] = v[idx] + idx = i == 4 + r[idx] = t[idx]; g[idx] = p[idx]; b[idx] = v[idx] + idx = i == 5 + r[idx] = v[idx]; g[idx] = p[idx]; b[idx] = q[idx] + idx = s == 0 + r[idx] = v[idx]; g[idx] = v[idx]; b[idx] = v[idx] + return np.array((r,g,b)).T + +class lightsource(object): + """ + Create a light source coming from the specified azimuth and elevation. + Angles are in degrees, with the azimuth measured + clockwise from south and elevation up from the zero plane of the surface. + The :meth:`shade` is used to produce rgb values for a shaded relief image + given a data array. + """ + def __init__(self,azdeg=315,altdeg=45,\ + hsv_min_val=0,hsv_max_val=1,hsv_min_sat=1,hsv_max_sat=0): + """ + Specify the azimuth (measured clockwise from south) and altitude + (measured up from the plane of the surface) of the light source + in degrees. + + The color of the resulting image will be darkened + by moving the (s,v) values (in hsv colorspace) toward + (hsv_min_sat, hsv_min_val) in the shaded regions, or + lightened by sliding (s,v) toward + (hsv_max_sat hsv_max_val) in regions that are illuminated. + The default extremes are chose so that completely shaded points + are nearly black (s = 1, v = 0) and completely illuminated points + are nearly white (s = 0, v = 1). + """ + self.azdeg = azdeg + self.altdeg = altdeg + self.hsv_min_val = hsv_min_val + self.hsv_max_val = hsv_max_val + self.hsv_min_sat = hsv_min_sat + self.hsv_max_sat = hsv_max_sat + + def shade(self,data,cmap): + """ + Take the input data array, convert to HSV values in the + given colormap, then adjust those color values + to given the impression of a shaded relief map with a + specified light source. + RGBA values are returned, which can then be used to + plot the shaded image with imshow. + """ + # imagine an artificial sun placed at infinity in + # some azimuth and elevation position illuminating our surface. The parts of + # the surface that slope toward the sun should brighten while those sides + # facing away should become darker. + # convert alt, az to radians + az = self.azdeg*np.pi/180.0 + alt = self.altdeg*np.pi/180.0 + # gradient in x and y directions + dx, dy = np.gradient(data) + slope = 0.5*np.pi - np.arctan(np.hypot(dx, dy)) + aspect = np.arctan2(dx, dy) + intensity = np.sin(alt)*np.sin(slope) + np.cos(alt)*np.cos(slope)*np.cos(-az -\ + aspect - 0.5*np.pi) + # rescale to interval -1,1 + # +1 means maximum sun exposure and -1 means complete shade. + intensity = (intensity - intensity.min())/(intensity.max() - intensity.min()) + intensity = 2.*intensity - 1. + # convert to rgb, then rgb to hsv + rgb = cmap((data-data.min())/(data.max()-data.min())) + hsv = rgb_to_hsv(rgb[:,:,0:3]) + # modify hsv values to simulate illumination. + hsv[:,:,1] = np.where(np.logical_and(np.abs(hsv[:,:,1])>1.e-10,intensity>0),\ + (1.-intensity)*hsv[:,:,1]+intensity*self.hsv_max_sat, hsv[:,:,1]) + hsv[:,:,2] = np.where(intensity > 0, (1.-intensity)*hsv[:,:,1] +\ + intensity*self.hsv_max_val, hsv[:,:,2]) + hsv[:,:,1] = np.where(np.logical_and(np.abs(hsv[:,:,1])>1.e-10,intensity<0),\ + (1.+intensity)*hsv[:,:,1]-intensity*self.hsv_min_sat, hsv[:,:,1]) + hsv[:,:,2] = np.where(intensity < 0, (1.+intensity)*hsv[:,:,1] -\ + intensity*self.hsv_min_val, hsv[:,:,2]) + hsv[:,:,1:] = np.where(hsv[:,:,1:]<0.,0,hsv[:,:,1:]) + hsv[:,:,1:] = np.where(hsv[:,:,1:]>1.,1,hsv[:,:,1:]) + # convert modified hsv back to rgb. + rgb[:,:,0:3] = hsv_to_rgb(hsv) + return rgb This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2009-03-13 17:14:03
|
Revision: 6974 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6974&view=rev Author: mdboom Date: 2009-03-13 17:13:49 +0000 (Fri, 13 Mar 2009) Log Message: ----------- Commit Michiel de Hoon's integration of path simplification into the Mac OS-X backend. Thanks, Michiel! Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py trunk/matplotlib/setupext.py trunk/matplotlib/src/_macosx.m trunk/matplotlib/src/path_cleanup.h Modified: trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py 2009-03-11 19:45:23 UTC (rev 6973) +++ trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py 2009-03-13 17:13:49 UTC (rev 6974) @@ -128,13 +128,13 @@ def get_text_width_height_descent(self, s, prop, ismath): if ismath=='TeX': - # TODO: handle props + # todo: handle props size = prop.get_size_in_points() texmanager = self.get_texmanager() - Z = texmanager.get_grey(s, size, self.dpi) - m,n = Z.shape - # TODO: handle descent; This is based on backend_agg.py - return n, m, 0 + fontsize = prop.get_size_in_points() + w, h, d = texmanager.get_text_width_height_descent(s, fontsize, + renderer=self) + return w, h, d if ismath: ox, oy, width, height, descent, fonts, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) @@ -143,7 +143,8 @@ size = prop.get_size_in_points() weight = prop.get_weight() style = prop.get_style() - return self.gc.get_text_width_height_descent(unicode(s), family, size, weight, style) + width, height, descent = self.gc.get_text_width_height_descent(unicode(s), family, size, weight, style) + return width, height, 0.0*descent def flipy(self): return False @@ -230,6 +231,14 @@ key_press_event, and key_release_event are called from there. """ + filetypes = FigureCanvasBase.filetypes.copy() + filetypes['bmp'] = 'Windows bitmap' + filetypes['jpeg'] = 'JPEG' + filetypes['jpg'] = 'JPEG' + filetypes['gif'] = 'Graphics Interchange Format' + filetypes['tif'] = 'Tagged Image Format File' + filetypes['tiff'] = 'Tagged Image Format File' + def __init__(self, figure): FigureCanvasBase.__init__(self, figure) width, height = self.get_width_height() @@ -243,55 +252,41 @@ height /= dpi self.figure.set_size_inches(width, height) - def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w', - orientation='portrait', **kwargs): - if dpi is None: dpi = matplotlib.rcParams['savefig.dpi'] + def _print_bitmap(self, filename, *args, **kwargs): + # In backend_bases.py, print_figure changes the dpi of the figure. + # But since we are essentially redrawing the picture, we need the + # original dpi. Pick it up from the renderer. + dpi = kwargs['dpi'] + old_dpi = self.figure.dpi + self.figure.dpi = self.renderer.dpi + width, height = self.figure.get_size_inches() + width, height = width*dpi, height*dpi filename = unicode(filename) - root, ext = os.path.splitext(filename) - ext = ext[1:].lower() - if not ext: - ext = "png" - filename = root + "." + ext - if ext=="jpg": ext = "jpeg" + self.write_bitmap(filename, width, height) + self.figure.dpi = old_dpi - # save the figure settings - origfacecolor = self.figure.get_facecolor() - origedgecolor = self.figure.get_edgecolor() + def print_bmp(self, filename, *args, **kwargs): + self._print_bitmap(filename, *args, **kwargs) - # set the new parameters - self.figure.set_facecolor(facecolor) - self.figure.set_edgecolor(edgecolor) + def print_jpg(self, filename, *args, **kwargs): + self._print_bitmap(filename, *args, **kwargs) - if ext in ('jpeg', 'png', 'tiff', 'gif', 'bmp'): - width, height = self.figure.get_size_inches() - width, height = width*dpi, height*dpi - self.write_bitmap(filename, width, height) - elif ext == 'pdf': - self.write_pdf(filename) - elif ext in ('ps', 'eps'): - from backend_ps import FigureCanvasPS - # Postscript backend changes figure.dpi, but doesn't change it back - origDPI = self.figure.dpi - fc = self.switch_backends(FigureCanvasPS) - fc.print_figure(filename, dpi, facecolor, edgecolor, - orientation, **kwargs) - self.figure.dpi = origDPI - self.figure.set_canvas(self) - elif ext=='svg': - from backend_svg import FigureCanvasSVG - fc = self.switch_backends(FigureCanvasSVG) - fc.print_figure(filename, dpi, facecolor, edgecolor, - orientation, **kwargs) - self.figure.set_canvas(self) - else: - raise ValueError("Figure format not available (extension %s)" % ext) + def print_jpeg(self, filename, *args, **kwargs): + self._print_bitmap(filename, *args, **kwargs) - # restore original figure settings - self.figure.set_facecolor(origfacecolor) - self.figure.set_edgecolor(origedgecolor) + def print_tif(self, filename, *args, **kwargs): + self._print_bitmap(filename, *args, **kwargs) + def print_tiff(self, filename, *args, **kwargs): + self._print_bitmap(filename, *args, **kwargs) + def print_gif(self, filename, *args, **kwargs): + self._print_bitmap(filename, *args, **kwargs) + def get_default_filetype(self): + return 'png' + + class FigureManagerMac(_macosx.FigureManager, FigureManagerBase): """ Wrap everything up into a window for the pylab interface Modified: trunk/matplotlib/setupext.py =================================================================== --- trunk/matplotlib/setupext.py 2009-03-11 19:45:23 UTC (rev 6973) +++ trunk/matplotlib/setupext.py 2009-03-13 17:13:49 UTC (rev 6974) @@ -1156,20 +1156,22 @@ ext_modules.append(module) BUILT_WXAGG = True - def build_macosx(ext_modules, packages): global BUILT_MACOSX if BUILT_MACOSX: return # only build it if you you haven't already + deps = ['src/_macosx.m', + 'src/agg_py_transforms.cpp', + 'src/path_cleanup.cpp', + 'src/_path.cpp'] module = Extension('matplotlib.backends._macosx', - ['src/_macosx.m'], + deps, extra_link_args = ['-framework','Cocoa'], - define_macros=[('PY_ARRAY_UNIQUE_SYMBOL', 'MPL_ARRAY_API')] ) add_numpy_flags(module) + add_agg_flags(module) ext_modules.append(module) BUILT_MACOSX = True - def build_png(ext_modules, packages): global BUILT_PNG if BUILT_PNG: return # only build it if you you haven't already Modified: trunk/matplotlib/src/_macosx.m =================================================================== --- trunk/matplotlib/src/_macosx.m 2009-03-11 19:45:23 UTC (rev 6973) +++ trunk/matplotlib/src/_macosx.m 2009-03-13 17:13:49 UTC (rev 6974) @@ -3,7 +3,9 @@ #include <sys/socket.h> #include <Python.h> #include "numpy/arrayobject.h" +#include "path_cleanup.h" + static int nwin = 0; /* The number of open windows */ static int ngc = 0; /* The number of graphics contexts in use */ @@ -17,24 +19,7 @@ #define CGFloat float #endif -/* This is the same as CGAffineTransform, except that the data members are - * doubles rather than CGFloats. - * Matrix structure: - * [ a b 0] - * [ c d 0] - * [ tx ty 1] - */ -typedef struct -{ - double a; - double b; - double c; - double d; - double tx; - double ty; -} AffineTransform; - /* Various NSApplicationDefined event subtypes */ #define STDIN_READY 0 #define SIGINT_CALLED 1 @@ -186,19 +171,6 @@ return 1; } -static AffineTransform -AffineTransformConcat(AffineTransform t1, AffineTransform t2) -{ - AffineTransform t; - t.a = t1.a * t2.a + t1.b * t2.c; - t.b = t1.a * t2.b + t1.b * t2.d; - t.c = t1.c * t2.a + t1.d * t2.c; - t.d = t1.c * t2.b + t1.d * t2.d; - t.tx = t1.tx * t2.a + t1.ty * t2.c + t2.tx; - t.ty = t1.tx * t2.b + t1.ty * t2.d + t2.ty; - return t; -} - static int _init_atsui(void) { OSStatus status; @@ -237,243 +209,91 @@ PyErr_WarnEx(PyExc_RuntimeWarning, "ATSUDisposeTextLayout failed", 1); } -static int -_draw_path(CGContextRef cr, PyObject* path, AffineTransform affine) +static int _draw_path(CGContextRef cr, void* iterator) { double x1, y1, x2, y2, x3, y3; - CGFloat fx1, fy1, fx2, fy2, fx3, fy3; + int n = 0; + unsigned code; - PyObject* vertices = PyObject_GetAttrString(path, "vertices"); - if (vertices==NULL) + while (true) { - PyErr_SetString(PyExc_AttributeError, "path has no vertices"); - return -1; - } - Py_DECREF(vertices); /* Don't keep a reference here */ - - PyObject* codes = PyObject_GetAttrString(path, "codes"); - if (codes==NULL) - { - PyErr_SetString(PyExc_AttributeError, "path has no codes"); - return -1; - } - Py_DECREF(codes); /* Don't keep a reference here */ - - PyArrayObject* coordinates; - coordinates = (PyArrayObject*)PyArray_FromObject(vertices, - NPY_DOUBLE, 2, 2); - if (!coordinates) - { - PyErr_SetString(PyExc_ValueError, "failed to convert vertices array"); - return -1; - } - - if (PyArray_NDIM(coordinates) != 2 || PyArray_DIM(coordinates, 1) != 2) - { - Py_DECREF(coordinates); - PyErr_SetString(PyExc_ValueError, "invalid vertices array"); - return -1; - } - - npy_intp n = PyArray_DIM(coordinates, 0); - - if (n==0) /* Nothing to do here */ - { - Py_DECREF(coordinates); - return 0; - } - - PyArrayObject* codelist = NULL; - if (codes != Py_None) - { - codelist = (PyArrayObject*)PyArray_FromObject(codes, - NPY_UINT8, 1, 1); - if (!codelist) + code = get_vertex(iterator, &x1, &y1); + if (code == CLOSEPOLY) { - Py_DECREF(coordinates); - PyErr_SetString(PyExc_ValueError, "invalid codes array"); - return -1; + CGContextClosePath(cr); + n++; } - } - - if (codelist==NULL) - { - npy_intp i; - npy_uint8 code = MOVETO; - for (i = 0; i < n; i++) + else if (code == STOP) { - x1 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y1 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - if (isnan(x1) || isnan(y1)) - { - code = MOVETO; - } - else - { - fx1 = (CGFloat)(affine.a*x1 + affine.c*y1 + affine.tx); - fy1 = (CGFloat)(affine.b*x1 + affine.d*y1 + affine.ty); - switch (code) - { - case MOVETO: - CGContextMoveToPoint(cr, fx1, fy1); - break; - case LINETO: - CGContextAddLineToPoint(cr, fx1, fy1); - break; - } - code = LINETO; - } + break; } - } - else - { - npy_intp i = 0; - BOOL was_nan = false; - npy_uint8 code; - while (i < n) + else if (code == MOVETO) { - code = *(npy_uint8*)PyArray_GETPTR1(codelist, i); - if (code == CLOSEPOLY) - { - CGContextClosePath(cr); - i++; - } - else if (code == STOP) - { - break; - } - else if (was_nan) - { - if (code==CURVE3) i++; - else if (code==CURVE4) i+=2; - x1 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y1 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - i++; - if (isnan(x1) || isnan(y1)) - { - was_nan = true; - } - else - { - fx1 = (CGFloat) (affine.a*x1 + affine.c*y1 + affine.tx); - fy1 = (CGFloat) (affine.b*x1 + affine.d*y1 + affine.ty); - CGContextMoveToPoint(cr, fx1, fy1); - was_nan = false; - } - } - else if (code==MOVETO) - { - x1 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y1 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - i++; - if (isnan(x1) || isnan(y1)) - { - was_nan = true; - } - else - { - fx1 = (CGFloat) (affine.a*x1 + affine.c*y1 + affine.tx); - fy1 = (CGFloat) (affine.b*x1 + affine.d*y1 + affine.ty); - CGContextMoveToPoint(cr, fx1, fy1); - was_nan = false; - } - } - else if (code==LINETO) - { - x1 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y1 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - i++; - if (isnan(x1) || isnan(y1)) - { - was_nan = true; - } - else - { - fx1 = (CGFloat) (affine.a*x1 + affine.c*y1 + affine.tx); - fy1 = (CGFloat) (affine.b*x1 + affine.d*y1 + affine.ty); - CGContextAddLineToPoint(cr, fx1, fy1); - was_nan = false; - } - } - else if (code==CURVE3) - { - x1 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y1 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - i++; - x2 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y2 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - i++; - if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2)) - { - was_nan = true; - } - else - { - fx1 = (CGFloat) (affine.a*x1 + affine.c*y1 + affine.tx); - fy1 = (CGFloat) (affine.b*x1 + affine.d*y1 + affine.ty); - fx2 = (CGFloat) (affine.a*x2 + affine.c*y2 + affine.tx); - fy2 = (CGFloat) (affine.b*x2 + affine.d*y2 + affine.ty); - CGContextAddQuadCurveToPoint(cr, fx1, fy1, fx2, fy2); - was_nan = false; - } - } - else if (code==CURVE4) - { - x1 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y1 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - i++; - x2 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y2 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - i++; - x3 = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y3 = *(double*)PyArray_GETPTR2(coordinates, i, 1); - i++; - if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2) || isnan(x3) || isnan(y3)) - { - was_nan = true; - } - else - { - fx1 = (CGFloat) (affine.a*x1 + affine.c*y1 + affine.tx); - fy1 = (CGFloat) (affine.b*x1 + affine.d*y1 + affine.ty); - fx2 = (CGFloat) (affine.a*x2 + affine.c*y2 + affine.tx); - fy2 = (CGFloat) (affine.b*x2 + affine.d*y2 + affine.ty); - fx3 = (CGFloat) (affine.a*x3 + affine.c*y3 + affine.tx); - fy3 = (CGFloat) (affine.b*x3 + affine.d*y3 + affine.ty); - CGContextAddCurveToPoint(cr, fx1, fy1, fx2, fy2, fx3, fy3); - was_nan = false; - } - } + CGContextMoveToPoint(cr, x1, y1); + n++; } + else if (code==LINETO) + { + CGContextAddLineToPoint(cr, x1, y1); + n++; + } + else if (code==CURVE3) + { + get_vertex(iterator, &x2, &y2); + CGContextAddQuadCurveToPoint(cr, x1, y1, x2, y2); + n+=2; + } + else if (code==CURVE4) + { + get_vertex(iterator, &x2, &y2); + get_vertex(iterator, &x3, &y3); + CGContextAddCurveToPoint(cr, x1, y1, x2, y2, x3, y3); + n+=3; + } } - - Py_DECREF(coordinates); - Py_XDECREF(codelist); return n; } -static void _draw_hatch (void *info, CGContextRef cr) +static void _draw_hatch(void *info, CGContextRef cr) { PyObject* hatchpath = (PyObject*)info; - AffineTransform affine = {HATCH_SIZE, 0, 0, HATCH_SIZE, 0, 0}; - int n = _draw_path(cr, hatchpath, affine); - if (n < 0) + PyObject* transform; + int nd = 2; + npy_intp dims[2] = {3, 3}; + int typenum = NPY_DOUBLE; + double data[9] = {HATCH_SIZE, 0, 0, 0, HATCH_SIZE, 0, 0, 0, 1}; + double rect[4] = { 0.0, 0.0, HATCH_SIZE, HATCH_SIZE}; + int n; + transform = PyArray_SimpleNewFromData(nd, dims, typenum, data); + if (!transform) { PyGILState_STATE gstate = PyGILState_Ensure(); PyErr_Print(); PyGILState_Release(gstate); return; } - else if (n==0) + void* iterator = get_path_iterator(hatchpath, + transform, + 0, + 0, + rect, + QUANTIZE_FALSE, + 0); + Py_DECREF(transform); + if (!iterator) { + PyGILState_STATE gstate = PyGILState_Ensure(); + PyErr_SetString(PyExc_RuntimeError, "failed to obtain path iterator for hatching"); + PyErr_Print(); + PyGILState_Release(gstate); return; } - else - { - CGContextSetLineWidth(cr, 1.0); - CGContextSetLineCap(cr, kCGLineCapSquare); - CGContextDrawPath(cr, kCGPathFillStroke); - } + n = _draw_path(cr, iterator); + free_path_iterator(iterator); + if (n==0) return; + CGContextSetLineWidth(cr, 1.0); + CGContextSetLineCap(cr, kCGLineCapSquare); + CGContextDrawPath(cr, kCGPathFillStroke); } static void _release_hatch(void* info) @@ -553,8 +373,64 @@ typedef struct { PyObject_HEAD CGContextRef cr; + NSSize size; } GraphicsContext; +static CGMutablePathRef _create_path(void* iterator) +{ + unsigned code; + CGMutablePathRef p; + double x1, y1, x2, y2, x3, y3; + + p = CGPathCreateMutable(); + if (!p) return NULL; + + while (true) + { + code = get_vertex(iterator, &x1, &y1); + if (code == CLOSEPOLY) + { + CGPathCloseSubpath(p); + } + else if (code == STOP) + { + break; + } + else if (code == MOVETO) + { + CGPathMoveToPoint(p, NULL, x1, y1); + } + else if (code==LINETO) + { + CGPathAddLineToPoint(p, NULL, x1, y1); + } + else if (code==CURVE3) + { + get_vertex(iterator, &x2, &y2); + CGPathAddQuadCurveToPoint(p, NULL, x1, y1, x2, y2); + } + else if (code==CURVE4) + { + get_vertex(iterator, &x2, &y2); + get_vertex(iterator, &x3, &y3); + CGPathAddCurveToPoint(p, NULL, x1, y1, x2, y2, x3, y3); + } + } + + return p; +} + +static int _get_snap(GraphicsContext* self, enum e_quantize_mode* mode) +{ + PyObject* snap = PyObject_CallMethod((PyObject*)self, "get_snap", ""); + if(!snap) return 0; + if(snap==Py_None) *mode = QUANTIZE_AUTO; + else if (PyBool_Check(snap)) *mode = QUANTIZE_TRUE; + else *mode = QUANTIZE_FALSE; + Py_DECREF(snap); + return 1; +} + static PyObject* GraphicsContext_new(PyTypeObject* type, PyObject *args, PyObject *kwds) { @@ -587,7 +463,7 @@ static PyObject* GraphicsContext_repr(GraphicsContext* self) { - return PyString_FromFormat("GraphicsContext object %p wrapping the Quartz 2D graphics context %p", self, self->cr); + return PyString_FromFormat("GraphicsContext object %p wrapping the Quartz 2D graphics context %p", (void*)self, (void*)(self->cr)); } static PyObject* @@ -622,18 +498,30 @@ return Py_None; } +static BOOL +_set_antialiased(CGContextRef cr, PyObject* antialiased) +{ + const int shouldAntialias = PyObject_IsTrue(antialiased); + if (shouldAntialias < 0) + { + PyErr_SetString(PyExc_ValueError, + "Failed to read antialiaseds variable"); + return false; + } + CGContextSetShouldAntialias(cr, shouldAntialias); + return true; +} + static PyObject* GraphicsContext_set_antialiased (GraphicsContext* self, PyObject* args) { - int shouldAntialias; - if (!PyArg_ParseTuple(args, "i", &shouldAntialias)) return NULL; CGContextRef cr = self->cr; if (!cr) { PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL"); return NULL; } - CGContextSetShouldAntialias(cr, shouldAntialias); + if (!_set_antialiased(cr, args)) return NULL; Py_INCREF(Py_None); return Py_None; } @@ -694,218 +582,64 @@ static PyObject* GraphicsContext_set_clip_path (GraphicsContext* self, PyObject* args) { + int n; CGContextRef cr = self->cr; + + PyObject* path; + int nd = 2; + npy_intp dims[2] = {3, 3}; + int typenum = NPY_DOUBLE; + double data[] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; + if (!cr) { PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL"); return NULL; } - PyObject* path; - if(!PyArg_ParseTuple(args, "O", &path)) return NULL; - PyObject* vertices = PyObject_GetAttrString(path, "vertices"); - if (vertices==NULL) - { - PyErr_SetString(PyExc_AttributeError, "path has no vertices"); - return NULL; - } - Py_DECREF(vertices); /* Don't keep a reference here */ + PyObject* transform = PyArray_SimpleNewFromData(nd, dims, typenum, data); + if (!transform) return NULL; - PyObject* codes = PyObject_GetAttrString(path, "codes"); - if (codes==NULL) + double rect[4] = {0.0, 0.0, self->size.width, self->size.height}; + void* iterator = get_path_iterator(path, + transform, + 0, + 0, + rect, + QUANTIZE_AUTO, + 0); + Py_DECREF(transform); + if (!iterator) { - PyErr_SetString(PyExc_AttributeError, "path has no codes"); + PyErr_SetString(PyExc_RuntimeError, + "set_clip_path: failed to obtain path iterator for clipping"); return NULL; } - Py_DECREF(codes); /* Don't keep a reference here */ + n = _draw_path(cr, iterator); + free_path_iterator(iterator); - PyArrayObject* coordinates; - coordinates = (PyArrayObject*)PyArray_FromObject(vertices, - NPY_DOUBLE, 2, 2); - if (!coordinates) - { - PyErr_SetString(PyExc_ValueError, "failed to convert vertices array"); - return NULL; - } + if (n > 0) CGContextClip(cr); - if (PyArray_NDIM(coordinates) != 2 || PyArray_DIM(coordinates, 1) != 2) - { - Py_DECREF(coordinates); - PyErr_SetString(PyExc_ValueError, "invalid vertices array"); - return NULL; - } - - npy_intp n = PyArray_DIM(coordinates, 0); - - if (n==0) /* Nothing to do here */ - { - Py_DECREF(coordinates); - return NULL; - } - - PyArrayObject* codelist = NULL; - if (codes != Py_None) - { - codelist = (PyArrayObject*)PyArray_FromObject(codes, - NPY_UINT8, 1, 1); - if (!codelist) - { - Py_DECREF(coordinates); - PyErr_SetString(PyExc_ValueError, "invalid codes array"); - return NULL; - } - } - - CGFloat x, y; - - if (codelist==NULL) - { - npy_intp i; - npy_uint8 code = MOVETO; - for (i = 0; i < n; i++) - { - x = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 1)); - if (isnan(x) || isnan(y)) - { - code = MOVETO; - } - else - { - switch (code) - { - case MOVETO: - CGContextMoveToPoint(cr, x, y); - break; - case LINETO: - CGContextAddLineToPoint(cr, x, y); - break; - } - code = LINETO; - } - } - } - else - { - npy_intp i = 0; - BOOL was_nan = false; - npy_uint8 code; - CGFloat x1, y1, x2, y2, x3, y3; - while (i < n) - { - code = *(npy_uint8*)PyArray_GETPTR1(codelist, i); - if (code == CLOSEPOLY) - { - CGContextClosePath(cr); - i++; - } - else if (code == STOP) - { - break; - } - else if (was_nan) - { - if (code==CURVE3) i++; - else if (code==CURVE4) i+=2; - x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1)); - i++; - if (isnan(x1) || isnan(y1)) - { - was_nan = true; - } - else - { - CGContextMoveToPoint(cr, x1, y1); - was_nan = false; - } - } - else if (code==MOVETO) - { - x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1)); - i++; - if (isnan(x1) || isnan(y1)) - { - was_nan = true; - } - else - { - CGContextMoveToPoint(cr, x1, y1); - was_nan = false; - } - } - else if (code==LINETO) - { - x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1)); - i++; - if (isnan(x1) || isnan(y1)) - { - was_nan = true; - } - else - { - CGContextAddLineToPoint(cr, x1, y1); - was_nan = false; - } - } - else if (code==CURVE3) - { - x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1)); - i++; - x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1)); - i++; - if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2)) - { - was_nan = true; - } - else - { - CGContextAddQuadCurveToPoint(cr, x1, y1, x2, y2); - was_nan = false; - } - } - else if (code==CURVE4) - { - x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1)); - i++; - x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1)); - i++; - x3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0)); - y3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1)); - i++; - if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2) || isnan(x3) || isnan(y3)) - { - was_nan = true; - } - else - { - CGContextAddCurveToPoint(cr, x1, y1, x2, y2, x3, y3); - was_nan = false; - } - } - } - Py_DECREF(codelist); - } - - Py_DECREF(coordinates); - - CGContextClip(cr); Py_INCREF(Py_None); return Py_None; } static BOOL -_set_dashes(CGContextRef cr, PyObject* offset, PyObject* dashes) +_set_dashes(CGContextRef cr, PyObject* linestyle) { float phase = 0.0; + PyObject* offset; + PyObject* dashes; + + if (!PyArg_ParseTuple(linestyle, "OO", &offset, &dashes)) + { + PyErr_SetString(PyExc_TypeError, + "failed to obtain the offset and dashes from the linestyle"); + return false; + } + if (offset!=Py_None) { if (PyFloat_Check(offset)) phase = PyFloat_AsDouble(offset); @@ -965,11 +699,6 @@ static PyObject* GraphicsContext_set_dashes (GraphicsContext* self, PyObject* args) { - PyObject* offset; - PyObject* dashes; - - if (!PyArg_ParseTuple(args, "OO", &offset, &dashes)) return NULL; - CGContextRef cr = self->cr; if (!cr) { @@ -977,14 +706,11 @@ return NULL; } - BOOL ok = _set_dashes(cr, offset, dashes); - if (ok) - { - Py_INCREF(Py_None); - return Py_None; - } - else + if (!_set_dashes(cr, args)) return NULL; + + Py_INCREF(Py_None); + return Py_None; } static PyObject* @@ -1072,54 +798,6 @@ return Py_None; } -static int -_convert_affine_transform(PyObject* object, AffineTransform* transform) -/* Reads a Numpy affine transformation matrix and returns an - * AffineTransform structure - */ -{ - PyArrayObject* matrix = NULL; - if (object==Py_None) - { - PyErr_SetString(PyExc_ValueError, - "Found affine transformation matrix equal to None"); - return 0; - } - matrix = (PyArrayObject*) PyArray_FromObject(object, NPY_DOUBLE, 2, 2); - if (!matrix) - { - PyErr_SetString(PyExc_ValueError, - "Invalid affine transformation matrix"); - return 0; - } - if (PyArray_NDIM(matrix) != 2 || PyArray_DIM(matrix, 0) != 3 || PyArray_DIM(matrix, 1) != 3) - { - Py_DECREF(matrix); - PyErr_SetString(PyExc_ValueError, - "Affine transformation matrix has invalid dimensions"); - return 0; - } - - size_t stride0 = (size_t)PyArray_STRIDE(matrix, 0); - size_t stride1 = (size_t)PyArray_STRIDE(matrix, 1); - char* row0 = PyArray_BYTES(matrix); - char* row1 = row0 + stride0; - - transform->a = *(double*)(row0); - row0 += stride1; - transform->c = *(double*)(row0); - row0 += stride1; - transform->tx = *(double*)(row0); - transform->b = *(double*)(row1); - row1 += stride1; - transform->d = *(double*)(row1); - row1 += stride1; - transform->ty = *(double*)(row1); - - Py_DECREF(matrix); - return 1; -} - static PyObject* GraphicsContext_draw_path (GraphicsContext* self, PyObject* args) { @@ -1127,9 +805,12 @@ PyObject* transform; PyObject* rgbFace; - int ok; + int n; + void* iterator; + CGContextRef cr = self->cr; + double rect[4] = { 0.0, 0.0, self->size.width, self->size.height}; if (!cr) { @@ -1144,24 +825,30 @@ if(rgbFace==Py_None) rgbFace = NULL; - AffineTransform affine; - ok = _convert_affine_transform(transform, &affine); - if (!ok) return NULL; + iterator = get_path_iterator(path, + transform, + 1, + 0, + rect, + QUANTIZE_AUTO, + 1); + if (!iterator) + { + PyErr_SetString(PyExc_RuntimeError, + "draw_path: failed to obtain path iterator"); + return NULL; + } + n = _draw_path(cr, iterator); + free_path_iterator(iterator); - int n = _draw_path(cr, path, affine); - if (n==-1) return NULL; - if (n > 0) { PyObject* hatchpath; if(rgbFace) { float r, g, b; - ok = PyArg_ParseTuple(rgbFace, "fff", &r, &g, &b); - if (!ok) - { + if (!PyArg_ParseTuple(rgbFace, "fff", &r, &g, &b)) return NULL; - } CGContextSaveGState(cr); CGContextSetRGBFillColor(cr, r, g, b, 1.0); CGContextDrawPath(cr, kCGPathFillStroke); @@ -1180,8 +867,11 @@ } else { + int ok; float color[4] = {0, 0, 0, 1}; CGPatternRef pattern; + CGColorSpaceRef baseSpace; + CGColorSpaceRef patternSpace; static const CGPatternCallbacks callbacks = {0, &_draw_hatch, &_release_hatch}; @@ -1199,9 +889,23 @@ return NULL; } - CGColorSpaceRef baseSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(baseSpace); + baseSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + if (!baseSpace) + { + Py_DECREF(hatchpath); + PyErr_SetString(PyExc_RuntimeError, + "draw_path: CGColorSpaceCreateWithName failed"); + return NULL; + } + patternSpace = CGColorSpaceCreatePattern(baseSpace); CGColorSpaceRelease(baseSpace); + if (!patternSpace) + { + Py_DECREF(hatchpath); + PyErr_SetString(PyExc_RuntimeError, + "draw_path: CGColorSpaceCreatePattern failed"); + return NULL; + } CGContextSetFillColorSpace(cr, patternSpace); CGColorSpaceRelease(patternSpace); @@ -1214,7 +918,22 @@ &callbacks); CGContextSetFillPattern(cr, pattern, color); CGPatternRelease(pattern); - _draw_path(cr, path, affine); + iterator = get_path_iterator(path, + transform, + 1, + 0, + rect, + QUANTIZE_AUTO, + 1); + if (!iterator) + { + Py_DECREF(hatchpath); + PyErr_SetString(PyExc_RuntimeError, + "draw_path: failed to obtain path iterator for hatching"); + return NULL; + } + n = _draw_path(cr, iterator); + free_path_iterator(iterator); CGContextFillPath(cr); } } @@ -1234,8 +953,14 @@ int ok; float r, g, b; - double x, y; + CGMutablePathRef marker; + void* iterator; + double rect[4] = {0.0, 0.0, self->size.width, self->size.height}; + enum e_quantize_mode mode; + double xc, yc; + unsigned code; + CGContextRef cr = self->cr; if (!cr) @@ -1263,60 +988,68 @@ CGContextSetRGBFillColor(cr, r, g, b, 1.0); } - AffineTransform affine; - ok = _convert_affine_transform(transform, &affine); - if (!ok) return NULL; - - AffineTransform marker_affine; - ok = _convert_affine_transform(marker_transform, &marker_affine); - if (!ok) return NULL; - - PyObject* vertices = PyObject_GetAttrString(path, "vertices"); - if (vertices==NULL) + ok = _get_snap(self, &mode); + if (!ok) { - PyErr_SetString(PyExc_AttributeError, "path has no vertices"); return NULL; } - Py_DECREF(vertices); /* Don't keep a reference here */ - PyArrayObject* coordinates; - coordinates = (PyArrayObject*)PyArray_FromObject(vertices, - NPY_DOUBLE, 2, 2); - if (!coordinates) + iterator = get_path_iterator(marker_path, + marker_transform, + 0, + 0, + rect, + mode, + 0); + if (!iterator) { - PyErr_SetString(PyExc_ValueError, "failed to convert vertices array"); + PyErr_SetString(PyExc_RuntimeError, + "draw_markers: failed to obtain path iterator for marker"); return NULL; } - - if (PyArray_NDIM(coordinates) != 2 || PyArray_DIM(coordinates, 1) != 2) + marker = _create_path(iterator); + free_path_iterator(iterator); + if (!marker) { - Py_DECREF(coordinates); - PyErr_SetString(PyExc_ValueError, "invalid vertices array"); + PyErr_SetString(PyExc_RuntimeError, + "draw_markers: failed to draw marker path"); return NULL; } - - npy_intp i; - npy_intp n = PyArray_DIM(coordinates, 0); - AffineTransform t; - int m = 0; - for (i = 0; i < n; i++) + iterator = get_path_iterator(path, + transform, + 1, + 1, + rect, + QUANTIZE_TRUE, + 0); + if (!iterator) { - x = *(double*)PyArray_GETPTR2(coordinates, i, 0); - y = *(double*)PyArray_GETPTR2(coordinates, i, 1); - t = marker_affine; - t.tx += affine.a*x + affine.c*y + affine.tx; - t.ty += affine.b*x + affine.d*y + affine.ty; - m = _draw_path(cr, marker_path, t); + CGPathRelease(marker); + PyErr_SetString(PyExc_RuntimeError, + "draw_markers: failed to obtain path iterator"); + return NULL; + } - if (m > 0) + while (true) + { + code = get_vertex(iterator, &xc, &yc); + if (code == STOP) { - if(rgbFace) CGContextDrawPath(cr, kCGPathFillStroke); - else CGContextStrokePath(cr); + break; } + else if (code == MOVETO || code == LINETO || code == CURVE3 || code ==CURVE4) + { + CGContextSaveGState(cr); + CGContextTranslateCTM(cr, xc, yc); + CGContextAddPath(cr, marker); + CGContextRestoreGState(cr); + } + if(rgbFace) CGContextDrawPath(cr, kCGPathFillStroke); + else CGContextStrokePath(cr); } + free_path_iterator(iterator); + CGPathRelease(marker); - Py_DECREF(coordinates); - Py_INCREF(Py_None); return Py_None; } @@ -1358,20 +1091,53 @@ return true; } +static BOOL +_set_offset(CGContextRef cr, PyObject* offsets, int index, PyObject* transform) +{ + CGFloat tx; + CGFloat ty; + double x = *(double*)PyArray_GETPTR2(offsets, index, 0); + double y = *(double*)PyArray_GETPTR2(offsets, index, 1); + PyObject* translation = PyObject_CallMethod(transform, "transform_point", + "((ff))", x, y); + if (!translation) + { + return false; + } + if (!PyArray_Check(translation)) + { + Py_DECREF(translation); + PyErr_SetString(PyExc_ValueError, + "transform_point did not return a NumPy array"); + return false; + } + if (PyArray_NDIM(translation)!=1 || PyArray_DIM(translation, 0)!=2) + { + Py_DECREF(translation); + PyErr_SetString(PyExc_ValueError, + "transform_point did not return an approriate array"); + return false; + } + tx = (CGFloat)(*(double*)PyArray_GETPTR1(translation, 0)); + ty = (CGFloat)(*(double*)PyArray_GETPTR1(translation, 1)); + Py_DECREF(translation); + CGContextTranslateCTM(cr, tx, ty); + return true; +} static PyObject* GraphicsContext_draw_path_collection (GraphicsContext* self, PyObject* args) { - PyObject* master_transform_obj; + PyObject* master_transform; PyObject* cliprect; PyObject* clippath; PyObject* clippath_transform; PyObject* paths; - PyObject* transforms_obj; - PyObject* offsets_obj; - PyObject* offset_transform_obj; - PyObject* facecolors_obj; - PyObject* edgecolors_obj; + PyObject* transforms; + PyObject* offsets; + PyObject* offset_transform; + PyObject* facecolors; + PyObject* edgecolors; PyObject* linewidths; PyObject* linestyles; PyObject* antialiaseds; @@ -1384,172 +1150,298 @@ return NULL; } - if(!PyArg_ParseTuple(args, "OOOOOOOOOOOOO", &master_transform_obj, + if(!PyArg_ParseTuple(args, "OOOOOOOOOOOOO", &master_transform, &cliprect, &clippath, &clippath_transform, &paths, - &transforms_obj, - &offsets_obj, - &offset_transform_obj, - &facecolors_obj, - &edgecolors_obj, + &transforms, + &offsets, + &offset_transform, + &facecolors, + &edgecolors, &linewidths, &linestyles, &antialiaseds)) return NULL; - CGContextSaveGState(cr); + int ok = 1; + Py_ssize_t i; + Py_ssize_t Np = 0; + Py_ssize_t N = 0; - AffineTransform transform; - AffineTransform master_transform; - AffineTransform offset_transform; - AffineTransform* transforms = NULL; + CGMutablePathRef* p = NULL; - if (!_convert_affine_transform(master_transform_obj, &master_transform)) return NULL; - if (!_convert_affine_transform(offset_transform_obj, &offset_transform)) return NULL; + /* --------- Prepare some variables for the path iterator ------------- */ + void* iterator; + double rect[4] = {0.0, 0.0, self->size.width, self->size.height}; + enum e_quantize_mode mode; + ok = _get_snap(self, &mode); + if (!ok) + { + return NULL; + } - if (!_clip(cr, cliprect)) return NULL; - if (clippath!=Py_None) + /* ------------------- Check paths ------------------------------------ */ + + if (!PySequence_Check(paths)) { - if (!_convert_affine_transform(clippath_transform, &transform)) return NULL; - int n = _draw_path(cr, clippath, transform); - if (n==-1) return NULL; - else if (n > 0) CGContextClip(cr); + PyErr_SetString(PyExc_ValueError, "paths must be a sequence object"); + return NULL; } + const Py_ssize_t Npaths = PySequence_Size(paths); - PyArrayObject* offsets = NULL; - PyArrayObject* facecolors = NULL; - PyArrayObject* edgecolors = NULL; + /* ------------------- Check transforms ------------------------------- */ + if (!PySequence_Check(transforms)) + { + PyErr_SetString(PyExc_ValueError, "transforms must be a sequence object"); + return NULL; + } + Py_ssize_t Ntransforms = PySequence_Size(transforms); + + CGContextSaveGState(cr); + /* ------------------- Set master transform --------------------------- */ + + if (Ntransforms) + { + PyObject* values = PyObject_CallMethod(master_transform, "to_values", ""); + if (!values) + { + ok = 0; + goto exit; + } + if (!PyTuple_Check(values)) + { + Py_DECREF(values); + ok = 0; + goto exit; + } + CGAffineTransform master; + ok = PyArg_ParseTuple(values, "ffffff", + &master.a, + &master.b, + &master.c, + &master.d, + &master.tx, + &master.ty); + Py_DECREF(values); + if (!ok) goto exit; + CGContextConcatCTM(cr, master); + } + /* ------------------- Check offsets array ---------------------------- */ - offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj, NPY_DOUBLE, 0, 2); + offsets = PyArray_FromObject(offsets, NPY_DOUBLE, 0, 2); if (!offsets || (PyArray_NDIM(offsets)==2 && PyArray_DIM(offsets, 1)!=2) || (PyArray_NDIM(offsets)==1 && PyArray_DIM(offsets, 0)!=0)) { PyErr_SetString(PyExc_ValueError, "Offsets array must be Nx2"); - goto error; + ok = 0; + goto exit; } + const Py_ssize_t Noffsets = PyArray_DIM(offsets, 0); + /* -------------------------------------------------------------------- */ + + Np = Npaths > Ntransforms ? Npaths : Ntransforms; + N = Np > Noffsets ? Np : Noffsets; + if (N < Ntransforms) Ntransforms = N; + + p = malloc(Np*sizeof(CGMutablePathRef)); + if (!p) + { + ok = 0; + goto exit; + } + for (i = 0; i < Np; i++) + { + PyObject* path; + PyObject* transform; + p[i] = NULL; + path = PySequence_ITEM(paths, i % Npaths); + if (!path) + { + ok = 0; + goto exit; + } + if (Ntransforms) + { + transform = PySequence_ITEM(transforms, i % Ntransforms); + if (!transform) + { + PyErr_SetString(PyExc_RuntimeError, + "failed to obtain transform"); + ok = 0; + goto exit; + } + iterator = get_path_iterator(path, + transform, + 1, + 0, + rect, + mode, + 0); + Py_DECREF(transform); + } + else + { + iterator = get_path_iterator(path, + master_transform, + 1, + 0, + rect, + mode, + 0); + } + Py_DECREF(path); + if (!iterator) + { + PyErr_SetString(PyExc_RuntimeError, + "failed to obtain path iterator"); + ok = 0; + goto exit; + } + p[i] = _create_path(iterator); + free_path_iterator(iterator); + if (!p[i]) + { + PyErr_SetString(PyExc_RuntimeError, "failed to create path"); + ok = 0; + goto exit; + } + } + + /* ------------------- Set clipping path ------------------------------ */ + + if (!_clip(cr, cliprect)) + { + ok = 0; + goto exit; + } + if (clippath!=Py_None) + { + int n; + iterator = get_path_iterator(clippath, + clippath_transform, + 0, + 0, + rect, + QUANTIZE_AUTO, + 0); + if (!iterator) + { + PyErr_SetString(PyExc_RuntimeError, + "draw_path_collection: failed to obtain path iterator for clipping"); + ok = 0; + goto exit; + } + n = _draw_path(cr, iterator); + free_path_iterator(iterator); + if (n > 0) CGContextClip(cr); + } + /* ------------------- Check facecolors array ------------------------- */ - facecolors = (PyArrayObject*)PyArray_FromObject(facecolors_obj, - NPY_DOUBLE, 1, 2); + facecolors = PyArray_FromObject(facecolors, NPY_DOUBLE, 1, 2); if (!facecolors || (PyArray_NDIM(facecolors)==1 && PyArray_DIM(facecolors, 0)!=0) || (PyArray_NDIM(facecolors)==2 && PyArray_DIM(facecolors, 1)!=4)) { PyErr_SetString(PyExc_ValueError, "Facecolors must by a Nx4 numpy array or empty"); - goto error; + ok = 0; + goto exit; } /* ------------------- Check edgecolors array ------------------------- */ - edgecolors = (PyArrayObject*)PyArray_FromObject(edgecolors_obj, - NPY_DOUBLE, 1, 2); + edgecolors = PyArray_FromObject(edgecolors, NPY_DOUBLE, 1, 2); if (!edgecolors || (PyArray_NDIM(edgecolors)==1 && PyArray_DIM(edgecolors, 0)!=0) || (PyArray_NDIM(edgecolors)==2 && PyArray_DIM(edgecolors, 1)!=4)) { PyErr_SetString(PyExc_ValueError, "Edgecolors must by a Nx4 numpy array or empty"); - goto error; + ok = 0; + goto exit; } /* ------------------- Check the other arguments ---------------------- */ - if (!PySequence_Check(paths)) - { - PyErr_SetString(PyExc_ValueError, "paths must be a sequence object"); - goto error; - } - if (!PySequence_Check(transforms_obj)) - { - PyErr_SetString(PyExc_ValueError, "transforms must be a sequence object"); - goto error; - } if (!PySequence_Check(linewidths)) { PyErr_SetString(PyExc_ValueError, "linewidths must be a sequence object"); - goto error; + ok = 0; + goto exit; } if (!PySequence_Check(linestyles)) { PyErr_SetString(PyExc_ValueError, "linestyles must be a sequence object"); - goto error; + ok = 0; + goto exit; } if (!PySequence_Check(antialiaseds)) { PyErr_SetString(PyExc_ValueError, "antialiaseds must be a sequence object"); - goto error; + ok = 0; + goto exit; } - size_t Npaths = (size_t) PySequence_Size(paths); - size_t Noffsets = (size_t) PyArray_DIM(offsets, 0); - size_t N = Npaths > Noffsets ? Npaths : Noffsets; - size_t Ntransforms = (size_t) PySequence_Size(transforms_obj); - size_t Nfacecolors = (size_t) PyArray_DIM(facecolors, 0); - size_t Nedgecolors = (size_t) PyArray_DIM(edgecolors, 0); - size_t Nlinewidths = (size_t) PySequence_Size(linewidths); - size_t Nlinestyles = (size_t) PySequence_Size(linestyles); - size_t Naa = (size_t) PySequence_Size(antialiaseds); - if (N < Ntransforms) Ntransforms = N; + Py_ssize_t Nfacecolors = PyArray_DIM(facecolors, 0); + Py_ssize_t Nedgecolors = PyArray_DIM(edgecolors, 0); + Py_ssize_t Nlinewidths = PySequence_Size(linewidths); + Py_ssize_t Nlinestyles = PySequence_Size(linestyles); + Py_ssize_t Naa = PySequence_Size(antialiaseds); if (N < Nlinestyles) Nlinestyles = N; - if ((Nfacecolors == 0 && Nedgecolors == 0) || Npaths == 0) - { - goto success; - } + if ((Nfacecolors == 0 && Nedgecolors == 0) || Np == 0) goto exit; - size_t i = 0; - - /* Convert all of the transforms up front */ - if (Ntransforms > 0) - { - transforms = malloc(Ntransforms*sizeof(AffineTransform)); - if (!transforms) goto error; - for (i = 0; i < Ntransforms; i++) - { - PyObject* transform_obj = PySequence_ITEM(transforms_obj, i); - if(!_convert_affine_transform(transform_obj, &transforms[i])) goto error; - transforms[i] = AffineTransformConcat(transforms[i], master_transform); - } - } - - PyObject* path; - double x, y; - /* Preset graphics context properties if possible */ if (Naa==1) { - switch(PyObject_IsTrue(PySequence_ITEM(antialiaseds, 0))) + PyObject* antialiased = PySequence_ITEM(antialiaseds, 0); + if (antialiased) { - case 1: CGContextSetShouldAntialias(cr, true); break; - case 0: CGContextSetShouldAntialias(cr, false); break; - case -1: - { - PyErr_SetString(PyExc_ValueError, - "Failed to read antialiaseds array"); - goto error; - } + ok = _set_antialiased(cr, antialiased); + Py_DECREF(antialiased); } + else + { + PyErr_SetString(PyExc_SystemError, + "Failed to read element from antialiaseds array"); + ok = 0; + } + if (!ok) goto exit; } if (Nlinewidths==1) { - double linewidth = PyFloat_AsDouble(PySequence_ITEM(linewidths, 0)); - CGContextSetLineWidth(cr, (CGFloat)linewidth); + PyObject* linewidth = PySequence_ITEM(linewidths, 0); + if (!linewidth) + { + PyErr_SetString(PyExc_SystemError, + "Failed to read element from linewidths array"); + ok = 0; + goto exit; + } + CGContextSetLineWidth(cr, (CGFloat)PyFloat_AsDouble(linewidth)); + Py_DECREF(linewidth); } else if (Nlinewidths==0) CGContextSetLineWidth(cr, 0.0); if (Nlinestyles==1) { - PyObject* offset; - PyObject* dashes; PyObject* linestyle = PySequence_ITEM(linestyles, 0); - if (!PyArg_ParseTuple(linestyle, "OO", &offset, &dashes)) goto error; - if (!_set_dashes(cr, offset, dashes)) goto error; + if (!linestyle) + { + PyErr_SetString(PyExc_SystemError, + "Failed to read element from linestyles array"); + ok = 0; + goto exit; + } + ok = _set_dashes(cr, linestyle); + Py_DECREF(linestyle); + if (!ok) goto exit; } if (Nedgecolors==1) @@ -1572,57 +1464,63 @@ for (i = 0; i < N; i++) { + if (CGPathIsEmpty(p[i % Np])) continue; - if (Ntransforms) - { - transform = transforms[i % Ntransforms]; - } - else - { - transform = master_transform; - } - + CGContextSaveGState(cr); if (Noffsets) { - x = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); - y = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); - transform.tx += offset_transform.a*x + offset_transform.c*y + offset_transform.tx; - transform.ty += offset_transform.b*x + offset_transform.d*y + offset_transform.ty; + ok = _set_offset(cr, offsets, i % Noffsets, offset_transform); + if (!ok) + { + CGContextRestoreGState(cr); + goto exit; + } } if (Naa > 1) { - switch(PyObject_IsTrue(PySequence_ITEM(antialiaseds, i % Naa))) + PyObject* antialiased = PySequence_ITEM(antialiaseds, i % Naa); + if (antialiased) { - case 1: CGContextSetShouldAntialias(cr, true); break; - case 0: CGContextSetShouldAntialias(cr, false); break; - case -1: - { - PyErr_SetString(PyExc_ValueError, - "Failed to read antialiaseds array"); - goto error; - } + ok = _set_antialiased(cr, antialiased); + Py_DECREF(antialiased); } + else + { + PyErr_SetString(PyExc_SystemError, + "Failed to read element from antialiaseds array"); + ok = 0; + } + if (!ok) goto exit; } - path = PySequence_ITEM(paths, i % Npaths); - int n = _draw_path(cr, path, transform); - if (n==-1) goto error; - else if (n==0) continue; - if (Nlinewidths > 1) { - double linewidth = PyFloat_AsDouble(PySequence_ITEM(linewidths, i % Nlinewidths)); - CGContextSetLineWidth(cr, (CGFloat)linewidth); + PyObject* linewidth = PySequence_ITEM(linewidths, i % Nlinewidths); + if (!linewidth) + { + PyErr_SetString(PyExc_SystemError, + "Failed to read element from linewidths array"); + ok = 0; + goto exit; + } + CGContextSetLineWidth(cr, (CGFloat)PyFloat_AsDouble(linewidth)); + Py_DECREF(linewidth); } if (Nlinestyles > 1) { - PyObject* offset; - PyObject* dashes; PyObject* linestyle = PySequence_ITEM(linestyles, i % Nlinestyles); - if (!PyArg_ParseTuple(linestyle, "OO", &offset, &dashes)) goto error; - if (!_set_dashes(cr, offset, dashes)) goto error; + if (!linestyle) + { + PyErr_SetString(PyExc_SystemError, + "Failed to read element from linestyles array"); + ok = 0; + goto exit; + } + ok = _set_dashes(cr, linestyle); + Py_DECREF(linestyle); + if (!ok) goto exit; } if (Nedgecolors > 1) @@ -1635,6 +1533,8 @@ CGContextSetRGBStrokeColor(cr, r, g, b, a); } + CGContextAddPath(cr, p[i % Np]); + if (Nfacecolors > 1) { npy_intp fi = i % Nfacecolors; @@ -1649,41 +1549,42 @@ CGContextDrawPath(cr, kCGPathFillStroke); else CGContextStrokePath(cr); + CGContextRestoreGState(cr); } -success: +exit: CGContextRestoreGState(cr); - if (transforms) free(transforms); - Py_DECREF(offsets); - Py_DECREF(facecolors); - Py_DECREF(edgecolors); - - Py_INCREF(Py_None); - return Py_None; - -error: - CGContextRestoreGState(cr); - if (transforms) free(transforms); Py_XDECREF(offsets); Py_XDECREF(facecolors); Py_XDECREF(edgecolors); + if (p) + { + for (i = 0; i < Np; i++) + { + if (!p[i]) break; + CGPathRelease(p[i]); + } + free(p); + } + if (!ok) return NULL; - return NULL; + Py_INCREF(Py_None); + return Py_None; } static PyObject* GraphicsContext_draw_quad_mesh (GraphicsContext* self, PyObject* args) { - PyObject* mas... [truncated message content] |
From: <ef...@us...> - 2009-03-11 20:40:45
|
Revision: 6973 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6973&view=rev Author: efiring Date: 2009-03-11 19:45:23 +0000 (Wed, 11 Mar 2009) Log Message: ----------- Merged revisions 6972 via svnmerge from https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint ........ r6972 | efiring | 2009-03-11 09:36:22 -1000 (Wed, 11 Mar 2009) | 2 lines Ensure wx version >= 2.8; Sandro Tosi patch plus change to backend ........ Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/user_interfaces/embedding_in_wx2.py trunk/matplotlib/examples/user_interfaces/embedding_in_wx3.py trunk/matplotlib/examples/user_interfaces/embedding_in_wx4.py trunk/matplotlib/examples/user_interfaces/embedding_in_wx5.py trunk/matplotlib/lib/matplotlib/backends/backend_wx.py trunk/matplotlib/lib/matplotlib/backends/backend_wxagg.py Property Changed: ---------------- trunk/matplotlib/ trunk/matplotlib/doc/pyplots/README trunk/matplotlib/doc/sphinxext/gen_gallery.py trunk/matplotlib/doc/sphinxext/gen_rst.py trunk/matplotlib/lib/matplotlib/sphinxext/mathmpl.py trunk/matplotlib/lib/matplotlib/sphinxext/only_directives.py trunk/matplotlib/lib/matplotlib/sphinxext/plot_directive.py Property changes on: trunk/matplotlib ___________________________________________________________________ Modified: svnmerge-integrated - /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6960 + /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6972 Modified: svn:mergeinfo - /branches/v0_91_maint:5753-5771 /branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6809,6811,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6906-6909,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960 + /branches/v0_91_maint:5753-5771 /branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6809,6811,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6906-6909,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972 Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-03-11 19:36:22 UTC (rev 6972) +++ trunk/matplotlib/CHANGELOG 2009-03-11 19:45:23 UTC (rev 6973) @@ -1,3 +1,6 @@ +2009-03-11 Ensure wx version >= 2.8; thanks to Sandro Tosi and + Chris Barker. - EF + 2009-03-10 Fix join style bug in pdf. - JKS 2009-03-07 Add pyplot access to figure number list - EF Property changes on: trunk/matplotlib/doc/pyplots/README ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960 + /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972 Property changes on: trunk/matplotlib/doc/sphinxext/gen_gallery.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960 + /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673,6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972 Property changes on: trunk/matplotlib/doc/sphinxext/gen_rst.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960 + /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771 /branches/v0_98_5_maint/doc/sphinxext/gen_rst.py:6714-6715,6717-6732,6752-6754,6761-6773,6781,6792,6800,6802,6805,6822,6827,6850,6854,6856,6859,6861-6873,6883-6884,6886,6890-6891,6911-6912,6915-6916,6918,6920-6925,6927-6928,6934,6941,6946,6948,6950,6952,6960,6972 Modified: trunk/matplotlib/examples/user_interfaces/embedding_in_wx2.py =================================================================== --- trunk/matplotlib/examples/user_interfaces/embedding_in_wx2.py 2009-03-11 19:36:22 UTC (rev 6972) +++ trunk/matplotlib/examples/user_interfaces/embedding_in_wx2.py 2009-03-11 19:45:23 UTC (rev 6973) @@ -4,6 +4,10 @@ toolbar - comment out the setA_toolbar line for no toolbar """ +# Used to guarantee to use at least Wx2.8 +import wxversion +wxversion.ensureMinimal('2.8') + from numpy import arange, sin, pi import matplotlib @@ -20,15 +24,15 @@ from matplotlib.figure import Figure -from wx import * +import wx -class CanvasFrame(Frame): +class CanvasFrame(wx.Frame): def __init__(self): - Frame.__init__(self,None,-1, + wx.Frame.__init__(self,None,-1, 'CanvasFrame',size=(550,350)) - self.SetBackgroundColour(NamedColor("WHITE")) + self.SetBackgroundColour(wx.NamedColor("WHITE")) self.figure = Figure() self.axes = self.figure.add_subplot(111) @@ -38,8 +42,8 @@ self.axes.plot(t,s) self.canvas = FigureCanvas(self, -1, self.figure) - self.sizer = BoxSizer(VERTICAL) - self.sizer.Add(self.canvas, 1, LEFT | TOP | GROW) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(self.sizer) self.Fit() @@ -49,7 +53,7 @@ def add_toolbar(self): self.toolbar = NavigationToolbar2Wx(self.canvas) self.toolbar.Realize() - if Platform == '__WXMAC__': + if wx.Platform == '__WXMAC__': # Mac platform (OSX 10.3, MacPython) does not seem to cope with # having a toolbar in a sizer. This work-around gets the buttons # back, but at the expense of having the toolbar at the top @@ -62,8 +66,8 @@ # By adding toolbar in sizer, we are able to put it at the bottom # of the frame - so appearance is closer to GTK version. # As noted above, doesn't work for Mac. - self.toolbar.SetSize(Size(fw, th)) - self.sizer.Add(self.toolbar, 0, LEFT | EXPAND) + self.toolbar.SetSize(wx.Size(fw, th)) + self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) # update the axes menu on the toolbar self.toolbar.update() @@ -71,7 +75,7 @@ def OnPaint(self, event): self.canvas.draw() -class App(App): +class App(wx.App): def OnInit(self): 'Create the main window and insert the custom frame' Modified: trunk/matplotlib/examples/user_interfaces/embedding_in_wx3.py =================================================================== --- trunk/matplotlib/examples/user_interfaces/embedding_in_wx3.py 2009-03-11 19:36:22 UTC (rev 6972) +++ trunk/matplotlib/examples/user_interfaces/embedding_in_wx3.py 2009-03-11 19:45:23 UTC (rev 6973) @@ -18,6 +18,11 @@ Thanks to matplotlib and wx teams for creating such great software! """ + +# Used to guarantee to use at least Wx2.8 +import wxversion +wxversion.ensureMinimal('2.8') + import sys, time, os, gc import matplotlib matplotlib.use('WXAgg') @@ -26,18 +31,18 @@ from matplotlib.figure import Figure import numpy as npy -from wx import * -from wx.xrc import * +import wx +import wx.xrc as xrc ERR_TOL = 1e-5 # floating point slop for peak-detection matplotlib.rc('image', origin='lower') -class PlotPanel(Panel): +class PlotPanel(wx.Panel): def __init__(self, parent): - Panel.__init__(self, parent, -1) + wx.Panel.__init__(self, parent, -1) self.fig = Figure((5,4), 75) self.canvas = FigureCanvasWxAgg(self, -1, self.fig) @@ -46,11 +51,11 @@ #self.toolbar.set_active([0,1]) # Now put all into a sizer - sizer = BoxSizer(VERTICAL) + sizer = wx.BoxSizer(wx.VERTICAL) # This way of adding to sizer allows resizing - sizer.Add(self.canvas, 1, LEFT|TOP|GROW) + sizer.Add(self.canvas, 1, wx.LEFT|wx.TOP|wx.GROW) # Best to allow the toolbar to resize! - sizer.Add(self.toolbar, 0, GROW) + sizer.Add(self.toolbar, 0, wx.GROW) self.SetSizer(sizer) self.Fit() @@ -94,43 +99,43 @@ # this is supposed to prevent redraw flicker on some X servers... pass -class MyApp(App): +class MyApp(wx.App): def OnInit(self): xrcfile = os.path.join(os.path.dirname(__file__),"..","data", "embedding_in_wx3.xrc") - self.res = XmlResource(xrcfile) + self.res = xrc.XmlResource(xrcfile) # main frame and panel --------- self.frame = self.res.LoadFrame(None,"MainFrame") - self.panel = XRCCTRL(self.frame,"MainPanel") + self.panel = xrc.XRCCTRL(self.frame,"MainPanel") # matplotlib panel ------------- # container for matplotlib panel (I like to make a container # panel for our panel so I know where it'll go when in XRCed.) - plot_container = XRCCTRL(self.frame,"plot_container_panel") - sizer = BoxSizer(VERTICAL) + plot_container = xrc.XRCCTRL(self.frame,"plot_container_panel") + sizer = wx.BoxSizer(wx.VERTICAL) # matplotlib panel itself self.plotpanel = PlotPanel(plot_container) self.plotpanel.init_plot_data() # wx boilerplate - sizer.Add(self.plotpanel, 1, EXPAND) + sizer.Add(self.plotpanel, 1, wx.EXPAND) plot_container.SetSizer(sizer) # whiz button ------------------ - whiz_button = XRCCTRL(self.frame,"whiz_button") - EVT_BUTTON(whiz_button, whiz_button.GetId(), - self.plotpanel.OnWhiz) + whiz_button = xrc.XRCCTRL(self.frame,"whiz_button") + wx.EVT_BUTTON(whiz_button, whiz_button.GetId(), + self.plotpanel.OnWhiz) # bang button ------------------ - bang_button = XRCCTRL(self.frame,"bang_button") - EVT_BUTTON(bang_button, bang_button.GetId(), - self.OnBang) + bang_button = xrc.XRCCTRL(self.frame,"bang_button") + wx.EVT_BUTTON(bang_button, bang_button.GetId(), + self.OnBang) # final setup ------------------ Modified: trunk/matplotlib/examples/user_interfaces/embedding_in_wx4.py =================================================================== --- trunk/matplotlib/examples/user_interfaces/embedding_in_wx4.py 2009-03-11 19:36:22 UTC (rev 6972) +++ trunk/matplotlib/examples/user_interfaces/embedding_in_wx4.py 2009-03-11 19:45:23 UTC (rev 6973) @@ -4,6 +4,10 @@ toolbar """ +# Used to guarantee to use at least Wx2.8 +import wxversion +wxversion.ensureMinimal('2.8') + from numpy import arange, sin, pi import matplotlib @@ -16,13 +20,13 @@ from matplotlib.figure import Figure from numpy.random import rand -from wx import * +import wx class MyNavigationToolbar(NavigationToolbar2WxAgg): """ Extend the default wx toolbar with your own event handlers """ - ON_CUSTOM = NewId() + ON_CUSTOM = wx.NewId() def __init__(self, canvas, cankill): NavigationToolbar2WxAgg.__init__(self, canvas) @@ -30,7 +34,7 @@ # probably want to add your own. self.AddSimpleTool(self.ON_CUSTOM, _load_bitmap('stock_left.xpm'), 'Click me', 'Activate custom contol') - EVT_TOOL(self, self.ON_CUSTOM, self._on_custom) + wx.EVT_TOOL(self, self.ON_CUSTOM, self._on_custom) def _on_custom(self, evt): # add some text to the axes in a random location in axes (0,1) @@ -51,13 +55,13 @@ evt.Skip() -class CanvasFrame(Frame): +class CanvasFrame(wx.Frame): def __init__(self): - Frame.__init__(self,None,-1, + wx.Frame.__init__(self,None,-1, 'CanvasFrame',size=(550,350)) - self.SetBackgroundColour(NamedColor("WHITE")) + self.SetBackgroundColour(wx.NamedColor("WHITE")) self.figure = Figure(figsize=(5,4), dpi=100) self.axes = self.figure.add_subplot(111) @@ -68,14 +72,14 @@ self.canvas = FigureCanvas(self, -1, self.figure) - self.sizer = BoxSizer(VERTICAL) - self.sizer.Add(self.canvas, 1, TOP | LEFT | EXPAND) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND) # Capture the paint message - EVT_PAINT(self, self.OnPaint) + wx.EVT_PAINT(self, self.OnPaint) self.toolbar = MyNavigationToolbar(self.canvas, True) self.toolbar.Realize() - if Platform == '__WXMAC__': + if wx.Platform == '__WXMAC__': # Mac platform (OSX 10.3, MacPython) does not seem to cope with # having a toolbar in a sizer. This work-around gets the buttons # back, but at the expense of having the toolbar at the top @@ -88,8 +92,8 @@ # By adding toolbar in sizer, we are able to put it at the bottom # of the frame - so appearance is closer to GTK version. # As noted above, doesn't work for Mac. - self.toolbar.SetSize(Size(fw, th)) - self.sizer.Add(self.toolbar, 0, LEFT | EXPAND) + self.toolbar.SetSize(wx.Size(fw, th)) + self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) # update the axes menu on the toolbar self.toolbar.update() @@ -101,7 +105,7 @@ self.canvas.draw() event.Skip() -class App(App): +class App(wx.App): def OnInit(self): 'Create the main window and insert the custom frame' Modified: trunk/matplotlib/examples/user_interfaces/embedding_in_wx5.py =================================================================== --- trunk/matplotlib/examples/user_interfaces/embedding_in_wx5.py 2009-03-11 19:36:22 UTC (rev 6972) +++ trunk/matplotlib/examples/user_interfaces/embedding_in_wx5.py 2009-03-11 19:45:23 UTC (rev 6973) @@ -1,3 +1,7 @@ +# Used to guarantee to use at least Wx2.8 +import wxversion +wxversion.ensureMinimal('2.8') + import wx import wx.aui import matplotlib as mpl Modified: trunk/matplotlib/lib/matplotlib/backends/backend_wx.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_wx.py 2009-03-11 19:36:22 UTC (rev 6972) +++ trunk/matplotlib/lib/matplotlib/backends/backend_wx.py 2009-03-11 19:45:23 UTC (rev 6973) @@ -108,12 +108,23 @@ import traceback, pdb _DEBUG_lvls = {1 : 'Low ', 2 : 'Med ', 3 : 'High', 4 : 'Error' } +missingwx = "Matplotlib backend_wx and backend_wxagg require wxPython >=2.8" try: + import wxversion +except ImportError: + raise ImportError(missingwx) + +try: + wxversion.ensureMinimal('2.8') +except wxversion.AlreadyImportedError: + pass + +try: import wx backend_version = wx.VERSION_STRING -except: - raise ImportError("Matplotlib backend_wx requires wxPython be installed") +except ImportError: + raise ImportError(missingwx) #!!! this is the call that is causing the exception swallowing !!! #wx.InitAllImageHandlers() Modified: trunk/matplotlib/lib/matplotlib/backends/backend_wxagg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_wxagg.py 2009-03-11 19:36:22 UTC (rev 6972) +++ trunk/matplotlib/lib/matplotlib/backends/backend_wxagg.py 2009-03-11 19:45:23 UTC (rev 6973) @@ -16,17 +16,16 @@ """ -import wx import matplotlib from matplotlib.figure import Figure from backend_agg import FigureCanvasAgg -import backend_wx +import backend_wx # already uses wxversion.ensureMinimal('2.8') from backend_wx import FigureManager, FigureManagerWx, FigureCanvasWx, \ FigureFrameWx, DEBUG_MSG, NavigationToolbar2Wx, error_msg_wx, \ draw_if_interactive, show, Toolbar, backend_version +import wx - class FigureFrameWxAgg(FigureFrameWx): def get_canvas(self, fig): return FigureCanvasWxAgg(self, -1, fig) Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/mathmpl.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/mathmpl.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/mathmpl.py:6946,6948,6950,6952,6960 + /branches/v0_91_maint/doc/sphinxext/mathmpl.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/mathmpl.py:6946,6948,6950,6952,6960,6972 Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/only_directives.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/only_directives.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/only_directives.py:6946,6948,6950,6952,6960 + /branches/v0_91_maint/doc/sphinxext/only_directives.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/only_directives.py:6946,6948,6950,6952,6960,6972 Property changes on: trunk/matplotlib/lib/matplotlib/sphinxext/plot_directive.py ___________________________________________________________________ Modified: svn:mergeinfo - /branches/v0_91_maint/doc/sphinxext/plot_directive.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/plot_directive.py:6920-6925,6934,6941,6946,6948,6950,6952,6960 + /branches/v0_91_maint/doc/sphinxext/plot_directive.py:5753-5771 /branches/v0_98_5_maint/lib/matplotlib/sphinxext/plot_directive.py:6920-6925,6934,6941,6946,6948,6950,6952,6960,6972 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ef...@us...> - 2009-03-11 19:37:06
|
Revision: 6972 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6972&view=rev Author: efiring Date: 2009-03-11 19:36:22 +0000 (Wed, 11 Mar 2009) Log Message: ----------- Ensure wx version >= 2.8; Sandro Tosi patch plus change to backend Modified Paths: -------------- branches/v0_98_5_maint/CHANGELOG branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx2.py branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx3.py branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx4.py branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx5.py branches/v0_98_5_maint/lib/matplotlib/backends/backend_wx.py branches/v0_98_5_maint/lib/matplotlib/backends/backend_wxagg.py Modified: branches/v0_98_5_maint/CHANGELOG =================================================================== --- branches/v0_98_5_maint/CHANGELOG 2009-03-10 20:45:44 UTC (rev 6971) +++ branches/v0_98_5_maint/CHANGELOG 2009-03-11 19:36:22 UTC (rev 6972) @@ -1,3 +1,6 @@ +2009-03-11 Ensure wx version >= 2.8; thanks to Sandro Tosi and + Chris Barker. - EF + 2009-02-26 Support image clipping in pdf backend. - JKS 2009-02-16 Move plot_directive.py to the installed source tree. Add Modified: branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx2.py =================================================================== --- branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx2.py 2009-03-10 20:45:44 UTC (rev 6971) +++ branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx2.py 2009-03-11 19:36:22 UTC (rev 6972) @@ -4,6 +4,10 @@ toolbar - comment out the setA_toolbar line for no toolbar """ +# Used to guarantee to use at least Wx2.8 +import wxversion +wxversion.ensureMinimal('2.8') + from numpy import arange, sin, pi import matplotlib @@ -20,15 +24,15 @@ from matplotlib.figure import Figure -from wx import * +import wx -class CanvasFrame(Frame): +class CanvasFrame(wx.Frame): def __init__(self): - Frame.__init__(self,None,-1, + wx.Frame.__init__(self,None,-1, 'CanvasFrame',size=(550,350)) - self.SetBackgroundColour(NamedColor("WHITE")) + self.SetBackgroundColour(wx.NamedColor("WHITE")) self.figure = Figure() self.axes = self.figure.add_subplot(111) @@ -38,8 +42,8 @@ self.axes.plot(t,s) self.canvas = FigureCanvas(self, -1, self.figure) - self.sizer = BoxSizer(VERTICAL) - self.sizer.Add(self.canvas, 1, LEFT | TOP | GROW) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(self.sizer) self.Fit() @@ -49,7 +53,7 @@ def add_toolbar(self): self.toolbar = NavigationToolbar2Wx(self.canvas) self.toolbar.Realize() - if Platform == '__WXMAC__': + if wx.Platform == '__WXMAC__': # Mac platform (OSX 10.3, MacPython) does not seem to cope with # having a toolbar in a sizer. This work-around gets the buttons # back, but at the expense of having the toolbar at the top @@ -62,8 +66,8 @@ # By adding toolbar in sizer, we are able to put it at the bottom # of the frame - so appearance is closer to GTK version. # As noted above, doesn't work for Mac. - self.toolbar.SetSize(Size(fw, th)) - self.sizer.Add(self.toolbar, 0, LEFT | EXPAND) + self.toolbar.SetSize(wx.Size(fw, th)) + self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) # update the axes menu on the toolbar self.toolbar.update() @@ -71,7 +75,7 @@ def OnPaint(self, event): self.canvas.draw() -class App(App): +class App(wx.App): def OnInit(self): 'Create the main window and insert the custom frame' Modified: branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx3.py =================================================================== --- branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx3.py 2009-03-10 20:45:44 UTC (rev 6971) +++ branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx3.py 2009-03-11 19:36:22 UTC (rev 6972) @@ -18,6 +18,11 @@ Thanks to matplotlib and wx teams for creating such great software! """ + +# Used to guarantee to use at least Wx2.8 +import wxversion +wxversion.ensureMinimal('2.8') + import sys, time, os, gc import matplotlib matplotlib.use('WXAgg') @@ -26,18 +31,18 @@ from matplotlib.figure import Figure import numpy as npy -from wx import * -from wx.xrc import * +import wx +import wx.xrc as xrc ERR_TOL = 1e-5 # floating point slop for peak-detection matplotlib.rc('image', origin='lower') -class PlotPanel(Panel): +class PlotPanel(wx.Panel): def __init__(self, parent): - Panel.__init__(self, parent, -1) + wx.Panel.__init__(self, parent, -1) self.fig = Figure((5,4), 75) self.canvas = FigureCanvasWxAgg(self, -1, self.fig) @@ -46,11 +51,11 @@ #self.toolbar.set_active([0,1]) # Now put all into a sizer - sizer = BoxSizer(VERTICAL) + sizer = wx.BoxSizer(wx.VERTICAL) # This way of adding to sizer allows resizing - sizer.Add(self.canvas, 1, LEFT|TOP|GROW) + sizer.Add(self.canvas, 1, wx.LEFT|wx.TOP|wx.GROW) # Best to allow the toolbar to resize! - sizer.Add(self.toolbar, 0, GROW) + sizer.Add(self.toolbar, 0, wx.GROW) self.SetSizer(sizer) self.Fit() @@ -94,43 +99,43 @@ # this is supposed to prevent redraw flicker on some X servers... pass -class MyApp(App): +class MyApp(wx.App): def OnInit(self): xrcfile = os.path.join(os.path.dirname(__file__),"..","data", "embedding_in_wx3.xrc") - self.res = XmlResource(xrcfile) + self.res = xrc.XmlResource(xrcfile) # main frame and panel --------- self.frame = self.res.LoadFrame(None,"MainFrame") - self.panel = XRCCTRL(self.frame,"MainPanel") + self.panel = xrc.XRCCTRL(self.frame,"MainPanel") # matplotlib panel ------------- # container for matplotlib panel (I like to make a container # panel for our panel so I know where it'll go when in XRCed.) - plot_container = XRCCTRL(self.frame,"plot_container_panel") - sizer = BoxSizer(VERTICAL) + plot_container = xrc.XRCCTRL(self.frame,"plot_container_panel") + sizer = wx.BoxSizer(wx.VERTICAL) # matplotlib panel itself self.plotpanel = PlotPanel(plot_container) self.plotpanel.init_plot_data() # wx boilerplate - sizer.Add(self.plotpanel, 1, EXPAND) + sizer.Add(self.plotpanel, 1, wx.EXPAND) plot_container.SetSizer(sizer) # whiz button ------------------ - whiz_button = XRCCTRL(self.frame,"whiz_button") - EVT_BUTTON(whiz_button, whiz_button.GetId(), - self.plotpanel.OnWhiz) + whiz_button = xrc.XRCCTRL(self.frame,"whiz_button") + wx.EVT_BUTTON(whiz_button, whiz_button.GetId(), + self.plotpanel.OnWhiz) # bang button ------------------ - bang_button = XRCCTRL(self.frame,"bang_button") - EVT_BUTTON(bang_button, bang_button.GetId(), - self.OnBang) + bang_button = xrc.XRCCTRL(self.frame,"bang_button") + wx.EVT_BUTTON(bang_button, bang_button.GetId(), + self.OnBang) # final setup ------------------ Modified: branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx4.py =================================================================== --- branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx4.py 2009-03-10 20:45:44 UTC (rev 6971) +++ branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx4.py 2009-03-11 19:36:22 UTC (rev 6972) @@ -4,6 +4,10 @@ toolbar """ +# Used to guarantee to use at least Wx2.8 +import wxversion +wxversion.ensureMinimal('2.8') + from numpy import arange, sin, pi import matplotlib @@ -16,13 +20,13 @@ from matplotlib.figure import Figure from numpy.random import rand -from wx import * +import wx class MyNavigationToolbar(NavigationToolbar2WxAgg): """ Extend the default wx toolbar with your own event handlers """ - ON_CUSTOM = NewId() + ON_CUSTOM = wx.NewId() def __init__(self, canvas, cankill): NavigationToolbar2WxAgg.__init__(self, canvas) @@ -30,7 +34,7 @@ # probably want to add your own. self.AddSimpleTool(self.ON_CUSTOM, _load_bitmap('stock_left.xpm'), 'Click me', 'Activate custom contol') - EVT_TOOL(self, self.ON_CUSTOM, self._on_custom) + wx.EVT_TOOL(self, self.ON_CUSTOM, self._on_custom) def _on_custom(self, evt): # add some text to the axes in a random location in axes (0,1) @@ -51,13 +55,13 @@ evt.Skip() -class CanvasFrame(Frame): +class CanvasFrame(wx.Frame): def __init__(self): - Frame.__init__(self,None,-1, + wx.Frame.__init__(self,None,-1, 'CanvasFrame',size=(550,350)) - self.SetBackgroundColour(NamedColor("WHITE")) + self.SetBackgroundColour(wx.NamedColor("WHITE")) self.figure = Figure(figsize=(5,4), dpi=100) self.axes = self.figure.add_subplot(111) @@ -68,14 +72,14 @@ self.canvas = FigureCanvas(self, -1, self.figure) - self.sizer = BoxSizer(VERTICAL) - self.sizer.Add(self.canvas, 1, TOP | LEFT | EXPAND) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND) # Capture the paint message - EVT_PAINT(self, self.OnPaint) + wx.EVT_PAINT(self, self.OnPaint) self.toolbar = MyNavigationToolbar(self.canvas, True) self.toolbar.Realize() - if Platform == '__WXMAC__': + if wx.Platform == '__WXMAC__': # Mac platform (OSX 10.3, MacPython) does not seem to cope with # having a toolbar in a sizer. This work-around gets the buttons # back, but at the expense of having the toolbar at the top @@ -88,8 +92,8 @@ # By adding toolbar in sizer, we are able to put it at the bottom # of the frame - so appearance is closer to GTK version. # As noted above, doesn't work for Mac. - self.toolbar.SetSize(Size(fw, th)) - self.sizer.Add(self.toolbar, 0, LEFT | EXPAND) + self.toolbar.SetSize(wx.Size(fw, th)) + self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) # update the axes menu on the toolbar self.toolbar.update() @@ -101,7 +105,7 @@ self.canvas.draw() event.Skip() -class App(App): +class App(wx.App): def OnInit(self): 'Create the main window and insert the custom frame' Modified: branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx5.py =================================================================== --- branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx5.py 2009-03-10 20:45:44 UTC (rev 6971) +++ branches/v0_98_5_maint/examples/user_interfaces/embedding_in_wx5.py 2009-03-11 19:36:22 UTC (rev 6972) @@ -1,3 +1,7 @@ +# Used to guarantee to use at least Wx2.8 +import wxversion +wxversion.ensureMinimal('2.8') + import wx import wx.aui import matplotlib as mpl Modified: branches/v0_98_5_maint/lib/matplotlib/backends/backend_wx.py =================================================================== --- branches/v0_98_5_maint/lib/matplotlib/backends/backend_wx.py 2009-03-10 20:45:44 UTC (rev 6971) +++ branches/v0_98_5_maint/lib/matplotlib/backends/backend_wx.py 2009-03-11 19:36:22 UTC (rev 6972) @@ -108,12 +108,23 @@ import traceback, pdb _DEBUG_lvls = {1 : 'Low ', 2 : 'Med ', 3 : 'High', 4 : 'Error' } +missingwx = "Matplotlib backend_wx and backend_wxagg require wxPython >=2.8" try: + import wxversion +except ImportError: + raise ImportError(missingwx) + +try: + wxversion.ensureMinimal('2.8') +except wxversion.AlreadyImportedError: + pass + +try: import wx backend_version = wx.VERSION_STRING -except: - raise ImportError("Matplotlib backend_wx requires wxPython be installed") +except ImportError: + raise ImportError(missingwx) #!!! this is the call that is causing the exception swallowing !!! #wx.InitAllImageHandlers() Modified: branches/v0_98_5_maint/lib/matplotlib/backends/backend_wxagg.py =================================================================== --- branches/v0_98_5_maint/lib/matplotlib/backends/backend_wxagg.py 2009-03-10 20:45:44 UTC (rev 6971) +++ branches/v0_98_5_maint/lib/matplotlib/backends/backend_wxagg.py 2009-03-11 19:36:22 UTC (rev 6972) @@ -16,17 +16,16 @@ """ -import wx import matplotlib from matplotlib.figure import Figure from backend_agg import FigureCanvasAgg -import backend_wx +import backend_wx # already uses wxversion.ensureMinimal('2.8') from backend_wx import FigureManager, FigureManagerWx, FigureCanvasWx, \ FigureFrameWx, DEBUG_MSG, NavigationToolbar2Wx, error_msg_wx, \ draw_if_interactive, show, Toolbar, backend_version +import wx - class FigureFrameWxAgg(FigureFrameWx): def get_canvas(self, fig): return FigureCanvasWxAgg(self, -1, fig) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2009-03-10 20:45:59
|
Revision: 6971 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6971&view=rev Author: jouni Date: 2009-03-10 20:45:44 +0000 (Tue, 10 Mar 2009) Log Message: ----------- Fix join style bug in pdf. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/tests/backend_driver.py trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py Added Paths: ----------- trunk/matplotlib/examples/api/joinstyle.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-03-09 15:19:49 UTC (rev 6970) +++ trunk/matplotlib/CHANGELOG 2009-03-10 20:45:44 UTC (rev 6971) @@ -1,3 +1,5 @@ +2009-03-10 Fix join style bug in pdf. - JKS + 2009-03-07 Add pyplot access to figure number list - EF 2009-02-28 hashing of FontProperties accounts current rcParams - JJL Added: trunk/matplotlib/examples/api/joinstyle.py =================================================================== --- trunk/matplotlib/examples/api/joinstyle.py (rev 0) +++ trunk/matplotlib/examples/api/joinstyle.py 2009-03-10 20:45:44 UTC (rev 6971) @@ -0,0 +1,31 @@ +#!/usr/bin/env python +""" +Illustrate the three different join styles +""" + +import numpy as np +import matplotlib +import matplotlib.pyplot as plt + +def plot_angle(ax, x, y, angle, style): + phi = angle/180*np.pi + xx = [x+.5,x,x+.5*np.cos(phi)] + yy = [y,y,y+.5*np.sin(phi)] + ax.plot(xx, yy, lw=8, color='blue', solid_joinstyle=style) + ax.plot(xx[1:], yy[1:], lw=1, color='black') + ax.plot(xx[1::-1], yy[1::-1], lw=1, color='black') + ax.plot(xx[1:2], yy[1:2], 'o', color='red', markersize=3) + ax.text(x,y+.2,'%.0f degrees' % angle) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.set_title('Join style') + +for x,style in enumerate((('miter', 'round', 'bevel'))): + ax.text(x, 5, style) + for i in range(5): + plot_angle(ax, x, i, pow(2.0,3+i), style) + +ax.set_xlim(-.5,2.75) +ax.set_ylim(-.5,5.5) +plt.show() Modified: trunk/matplotlib/examples/tests/backend_driver.py =================================================================== --- trunk/matplotlib/examples/tests/backend_driver.py 2009-03-09 15:19:49 UTC (rev 6970) +++ trunk/matplotlib/examples/tests/backend_driver.py 2009-03-10 20:45:44 UTC (rev 6971) @@ -211,6 +211,7 @@ 'font_family_rc.py', 'histogram_demo.py', 'image_zcoord.py', + 'joinstyle.py', 'legend_demo.py', 'line_with_text.py', 'logo2.py', Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-03-09 15:19:49 UTC (rev 6970) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2009-03-10 20:45:44 UTC (rev 6971) @@ -427,6 +427,9 @@ self.beginStream(contentObject.id, self.reserveObject('length of content stream')) + # Initialize the pdf graphics state to match the default mpl + # graphics context: currently only the join style needs to be set + self.output(GraphicsContextPdf.joinstyles['round'], Op.setlinejoin) def close(self): self.endStream() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2009-03-09 15:20:08
|
Revision: 6970 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6970&view=rev Author: jswhit Date: 2009-03-09 15:19:49 +0000 (Mon, 09 Mar 2009) Log Message: ----------- tweak interp docstring to be more general (xout, yout don't actually have to be rank-2) 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 2009-03-08 13:29:00 UTC (rev 6969) +++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2009-03-09 15:19:49 UTC (rev 6970) @@ -3598,8 +3598,7 @@ y, 2nd dimension x. xin, yin rank-1 arrays containing x and y of datain grid in increasing order. - xout, yout rank-2 arrays containing x and y of desired output - grid. + xout, yout arrays containing x and y of desired output grid. ============== ==================================================== .. tabularcolumns:: |l|L| This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |