Skip to content

Commit c527ef8

Browse files
committed
added recipes
svn path=/branches/v1_0_maint/; revision=8769
1 parent e009bd2 commit c527ef8

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed

doc/users/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ User's Guide
2727
transforms_tutorial.rst
2828
path_tutorial.rst
2929
annotations_guide.rst
30+
recipes.rst
3031
toolkits.rst
3132
screenshots.rst
3233
whats_new.rst

doc/users/recipes.rst

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
.. _recipes:
2+
3+
********************
4+
Our Favorite Recipes
5+
********************
6+
7+
Here is a collection of short tutorials, examples and code snippets
8+
that illustrate some of the useful idioms and tricks to make snazzier
9+
figures and overcome some matplotlib warts.
10+
11+
Fixing common date annoyances
12+
=============================
13+
14+
matplotlib allows you to natively plots python datetime instances, and
15+
for the most part does a good job picking tick locations and string
16+
formats. There are a couple of things it does not handle so
17+
gracefully, and here are some tricks to help you work around them.
18+
We'll load up some sample date data which contains datetime.date
19+
objects in a numpy record array::
20+
21+
In [63]: datafile = cbook.get_sample_data('goog.npy')
22+
23+
In [64]: r = np.load(datafile).view(np.recarray)
24+
25+
In [65]: r.dtype
26+
Out[65]: dtype([('date', '|O4'), ('', '|V4'), ('open', '<f8'), ('high', '<f8'), ('low', '<f8'), ('close', '<f8'), ('volume', '<i8'), ('adj_close', '<f8')])
27+
28+
In [66]: r.date
29+
Out[66]:
30+
array([2004-08-19, 2004-08-20, 2004-08-23, ..., 2008-10-10, 2008-10-13,
31+
2008-10-14], dtype=object)
32+
33+
The dtype of the numpy record array for the field 'date' is '|O4'
34+
which means it is a 4-byte python object pointer; in this case the
35+
objects are datetime.date instances, which we can see when we print
36+
some samples in the ipython terminal window.
37+
38+
If you plot the data, you will see that the x tick labels are all
39+
squashed together::
40+
41+
In [67]: plot(r.date, r.close)
42+
Out[67]: [<matplotlib.lines.Line2D object at 0x92a6b6c>]
43+
44+
.. plot::
45+
46+
import matplotlib.cbook as cbook
47+
datafile = cbook.get_sample_data('goog.npy')
48+
r = np.load(datafile).view(np.recarray)
49+
plt.figure()
50+
plt.plot(r.date, r.close)
51+
plt.show()
52+
53+
Another annoyance is that if you hover the mouse over a the window and
54+
look in the lower right corner of the matplotlib toolbar at the x and
55+
y coordinates, you see that the x locations are formatted the same way
56+
the tick labels are, eg "Dec 2004". What we'd like is for the
57+
location in the toolbar to have a higher degree of precision, eg
58+
giving us the exact date out mouse is hovering over. To fix the first
59+
problem, we can use method:`matplotlib.figure.Figure.autofmt_xdate()`
60+
and to fix the second problem we can use the ``ax.fmt_xdata``
61+
attribute which can be set to any function that takes a position and
62+
returns a string. matplotlib has a number of date formatters built
63+
im, so we'll use one of those.
64+
65+
.. plot::
66+
67+
68+
import matplotlib.cbook as cbook
69+
datafile = cbook.get_sample_data('goog.npy')
70+
r = np.load(datafile).view(np.recarray)
71+
fig, ax = plt.subplots(1)
72+
ax.plot(r.date, r.close)
73+
74+
# rotate and align the tick labels so they look better
75+
fig.autofmt_xdate()
76+
77+
# use a more precise date string for the x axis locations in the
78+
# toolbar
79+
import matplotlib.dates as mdates
80+
ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')
81+
82+
83+
84+
Fill Between and Alpha
85+
======================
86+
87+
The :method:`~matplotlib.axes.Axes.fill_between` function generates a
88+
shaded region between a min and max boundary that is useful for
89+
illustrating ranges. It has a very handy ``where`` argument to
90+
combine filling with logical ranges, eg to just fill in a curve over
91+
some threshold value.
92+
93+
At it's most basic level, ``fill_between`` can be use to enhance a
94+
graphs visual appearance. Let's compare two graphs of a financial
95+
times with a simple line plot on the left and a filled line on the
96+
right.
97+
98+
.. plot::
99+
:include-source:
100+
101+
import matplotlib.cbook as cbook
102+
103+
# load up some sample financial data
104+
datafile = cbook.get_sample_data('goog.npy')
105+
r = np.load(datafile).view(np.recarray)
106+
107+
# create two subplots with the shared x and y axes
108+
fig, (ax1, ax2) = plt.subplots(1,2, sharex=True, sharey=True)
109+
110+
pricemin = r.close.min()
111+
112+
ax1.plot(r.date, r.close, lw=2)
113+
ax2.fill_between(r.date, pricemin, r.close, facecolor='blue', alpha=0.5)
114+
115+
for ax in ax1, ax2:
116+
ax.grid(True)
117+
118+
ax1.set_ylabel('price')
119+
fig.suptitle('Google (GOOG) daily closing price')
120+
fig.autofmt_xdate()
121+
plt.show()
122+
123+
The alpha channel is not necessary here, but it can be used to soften
124+
colors for more visually appealing plots. In other examples, as we'll
125+
see below, the alpha channel is functionally useful as the shaded
126+
regions can overlap and alpha allows you to see both. Note that the
127+
postscript format does not support alpha (this is a postscript
128+
limitation, not a matplotlib limitation), so when using alpha save
129+
your figures in PNG, PDF or SVG.
130+
131+
Our next example computes two populations of random walkers with a
132+
different mean and standard deviation of the normal distributions from
133+
which there steps are drawn. We use shared regions to plot +/- one
134+
standard deviation of the mean position of the population. Here the
135+
alpha channel is useful, not just aesthetic.
136+
137+
.. plot::
138+
:include-source:
139+
140+
Nsteps, Nwalkers = 100, 250
141+
t = np.arange(Nsteps)
142+
143+
# an Nsteps x Nwalkers array of random walk steps
144+
S1 = 0.002 + 0.01*np.random.randn(Nsteps, Nwalkers)
145+
S2 = 0.004 + 0.02*np.random.randn(Nsteps, Nwalkers)
146+
147+
# an Nsteps x Nwalkers array of random walker positions
148+
X1 = S1.cumsum(axis=0)
149+
X2 = S2.cumsum(axis=0)
150+
151+
152+
# Nsteps length arrays empirical means and standard deviations of both
153+
# populations over time
154+
mu1 = X1.mean(axis=1)
155+
sigma1 = X1.std(axis=1)
156+
mu2 = X2.mean(axis=1)
157+
sigma2 = X2.std(axis=1)
158+
159+
# plot it!
160+
fig, ax = plt.subplots(1)
161+
ax.plot(t, mu1, lw=2, label='mean population 1', color='blue')
162+
ax.plot(t, mu1, lw=2, label='mean population 2', color='yellow')
163+
ax.fill_between(t, mu1+sigma1, mu1-sigma1, facecolor='blue', alpha=0.5)
164+
ax.fill_between(t, mu2+sigma2, mu2-sigma2, facecolor='yellow', alpha=0.5)
165+
ax.set_title('random walkers empirical $\mu$ and $\pm \sigma$ interval')
166+
ax.legend(loc='upper left')
167+
ax.set_xlabel('num steps')
168+
ax.set_ylabel('position')
169+
ax.grid()
170+
plt.show()
171+
172+
173+
174+
The where keyword argument is very handy for highlighting certain
175+
regions of the graph. Where takes a boolean mask the same length as
176+
the x, ymin and ymax arguments, and only fills in the region where the
177+
boolean mask is True. In the example below, we take a a single random
178+
walker and compute the analytic mean and standard deviation of the
179+
population positions. The population mean is shown as the black
180+
dashed line, and the plus/minus one sigma deviation from the mean is
181+
showsn as the yellow filled region. We use the where mask
182+
``X>upper_bound`` to find the region where the walker is above the
183+
one sigma boundary, and shade that region blue.
184+
185+
.. plot::
186+
:include-source:
187+
188+
np.random.seed(1234)
189+
190+
Nsteps = 500
191+
t = np.arange(Nsteps)
192+
193+
mu = 0.002
194+
sigma = 0.01
195+
196+
# the steps and position
197+
S = mu + sigma*np.random.randn(Nsteps)
198+
X = S.cumsum()
199+
200+
# the 1 sigma upper and lower population bounds
201+
lower_bound = mu*t - sigma*np.sqrt(t)
202+
upper_bound = mu*t + sigma*np.sqrt(t)
203+
204+
fig, ax = plt.subplots(1)
205+
ax.plot(t, X, lw=2, label='walker position', color='blue')
206+
ax.plot(t, mu*t, lw=1, label='population mean', color='black', ls='--')
207+
ax.fill_between(t, lower_bound, upper_bound, facecolor='yellow', alpha=0.5,
208+
label='1 sigma range')
209+
ax.legend(loc='upper left')
210+
211+
# here we use the where argument to only fill the region where the
212+
# walker is above the population 1 sigma boundary
213+
ax.fill_between(t, upper_bound, X, where=X>upper_bound, facecolor='blue', alpha=0.5)
214+
ax.set_xlabel('num steps')
215+
ax.set_ylabel('position')
216+
ax.grid()
217+
plt.show()
218+
219+
220+
Another handy use of filled regions is to highlight horizontal or
221+
vertical spans of an axes -- for that matplotlib has some helper
222+
functions :method:`~matplotlib.axes.Axes.axhspan` and
223+
:method:`~matplotlib.axes.Axes.axvspan` and example
224+
:ref:`pylab_examples-axhspan_demo`.

0 commit comments

Comments
 (0)