不連續(xù)點
當(dāng)一條曲線中存在跳變點時,如果直接用plot()繪圖會用一條直線將跳變前后的點連接起來。若不想繪制跳變處的連接線,可在數(shù)組的跳變處插入Nan值,下面的程序演示了這一方法。
import numpy as np
import pylab as pl
x = np.linspace(-1, 1, 1000)
y = np.select([x<-0.5, x<0, x<0.5, True], [x**2, x**3, 1-x, 1-x**2])
ax = pl.subplot(121)
pl.plot(x, y, lw=2)
pl.subplot(122, sharey=ax)
pos = np.where(np.abs(np.diff(y))>0.05)[0]+1 ?
x2 = np.insert(x, pos, np.nan) ?
y2 = np.insert(y, pos, np.nan)
pl.plot(x2, y2, lw=2)
pl.show()
找到曲線中所有前后兩個點的高度差大于0.05的下標(biāo),?調(diào)用np.insert()在不連續(xù)點處插入np.nan。
參數(shù)曲線上繪制方向箭頭
在參數(shù)曲線中為了表示隨著參數(shù)的增大,曲線的變化情況,需要在曲線上繪制箭頭表示方向。
import numpy as np
import pylab as pl
t = np.linspace(0, 2*np.pi, 1000)
x = np.sin(3*t)
y = np.cos(5*t)
def split_positions(x, y, n):
dx = np.diff(x)
dy = np.diff(y)
l = np.sqrt(dx*dx+dy*dy) ?
cl = np.cumsum(l) ?
pos = np.linspace(0, cl[-1], n) ?
idx = np.searchsorted(cl, pos) ?
dx = x[idx+1] - x[idx] ?
dy = y[idx+1] - y[idx]
s = np.sqrt(dx*dx+dy*dy)
dx/=s
dy/=s
return x[idx], y[idx], dx, dy
for x0, y0, dx, dy in zip(*cal_arrow(x, y, 18)):
pl.arrow(x0, y0, dx*0.01, dy*0.01, head_width=0.05) ?
pl.plot(x, y)
pl.axis("equal")
pl.show()
split_positions(x, y, n)計算曲線(x,y)上等距離的n個點,以及在這n個點上的曲線切線方向。?首先計算曲線上每個小段的長度l,?對l用np.cumsum()進(jìn)行累加,得到到達(dá)曲線上每點時所走過的曲線長度cl。?cl[-1]為曲線的總長度,將這個總長度等分為n-1等分,?然后通過np.searchsorted()搜索每個等分點所對應(yīng)的下標(biāo)。?最后通過等分處前后兩個點計算出曲線在此處的切線方向。
對split_positions()得到的每個點調(diào)用pl.arrow()繪制箭頭,將dx和dy乘以一個很小的數(shù)(此處為0.01)是為了只繪制箭頭,好讓箭頭能剛好位于曲線之上。
修改缺省刻度數(shù)目
在matplotlib中,圖表的刻度的位置由Axis對象的major.locator屬性決定,而子圖對象Axes的xaxis和yaxis屬性分別表示X軸和Y軸。
>>> import pylab as pl
>>> pl.plot([1,2,3])
[]
>>> pl.gca().xaxis.major.locator
缺省使用AutoLocator計算刻度的位置,下面是其代碼:
class AutoLocator(MaxNLocator):
def __init__(self):
MaxNLocator.__init__(self, nbins=9, steps=[1, 2, 5, 10])
可以看出刻度數(shù)目由nbins決定,缺省值為9。nbins決定的是最大刻度線數(shù),根據(jù)當(dāng)前的顯示范圍和steps的設(shè)置,AutoLocator會自動調(diào)節(jié)刻度線數(shù)。
當(dāng)刻度文本較長時,過多的刻度數(shù)會導(dǎo)致刻度文本不易看清,因此我們希望能修改缺省的刻度數(shù)目。但由上面的代碼可知,我們無法通過修改matplotlib的參數(shù)配置修改缺省刻度數(shù)。這時可以通過重新定義AutoLocator.__init__()實現(xiàn)這一功能。
import numpy as np
import pylab as pl
from matplotlib import ticker
def AutoLocatorInit(self): ?
ticker.MaxNLocator.__init__(self, nbins=4, steps=[1, 2, 5, 10])
ticker.AutoLocator.__init__ = AutoLocatorInit ?
pl.rcParams["xtick.labelsize"] = 20
pl.rcParams["ytick.labelsize"] = 20
pl.plot(pl.randn(150), lw=2)
pl.show()
定義了一個和AutoLocator.__init__()類似的函數(shù),只是將nbins參數(shù)改為4,?然后將AutoLocator.__init__改為使用此函數(shù)。
Y軸不同區(qū)間使用不同顏色填充
要求實現(xiàn)的效果如下圖所示,根據(jù)Y軸的范圍,使用不同的顏色對區(qū)域進(jìn)行填充。
填充區(qū)域的最小值和最大值由mintemps和maxtemps給出,而每個范圍的顏色由colors給出:
maxtemps = [ 25, 24, 24, 25, 26, 27, 22, 21, 22, 19, 17, 14,
13, 12, 11, 12, 11, 10, 9, 9, 9, 8, 9, 9, 8 ]
mintemps = [ 21, 22, 22, 22, 23, 24, 18, 17, 16, 14, 10, 8,
8, 7, 7, 6, 5, 5, 5, 4, 4, 4, 3, 4, 3 ]
times = list(xrange(len(mintemps)))
colors = [
(25, '#FF69B4'),
(20, '#F08228'),
(15, '#E6AF2D'),
(10, '#E6DC32'),
(5, '#A0E632'),
(0, '#00DC00')
]
填充區(qū)域可使用fill_between()實現(xiàn),但是它只支持一種顏色,因此需要對每個顏色范圍調(diào)用一次fill_between()。本題的難點在于如何計算整個區(qū)域與某個范圍相交的部分。我們可以使用NumPy的線性插值函數(shù)interp()和裁剪函數(shù)clip()快速實現(xiàn)這一運算。下面是完整的源程序:
import pylab as pl
import numpy as np
x = np.linspace(times[0], times[-1], 500)
maxt = np.interp(x, times, maxtemps) ?
mint = np.interp(x, times, mintemps) ?
last_level = np.inf
for level, color in colors:
tmp_min = np.clip(mint, level, last_level) ?
tmp_max = np.clip(maxt, level, last_level) ?
pl.fill_between(x, tmp_min, tmp_max, lw=0, color=color) ?
last_level = level
pl.grid(True)
pl.show()
對mintemps和maxtemps用np.interp()進(jìn)行線性插值,得到更細(xì)分的數(shù)據(jù)。?對colors中的每個區(qū)域進(jìn)行循環(huán),并使用np.clip()對細(xì)分之后的最大值和最小值進(jìn)行剪裁。?調(diào)用pl.fill_between()使用指定的顏色對裁剪之后的區(qū)域進(jìn)行填充。
|