这一系列文章原载于公众号 工程师milter,如果文章对大家有帮助,恳请大家动手关注下哈~
matplotlib是优秀的python画图工具,功能十分强大,但是使用却很复杂。你有没有如下的经历:
1、图形只差一点点就满足你的要求,可是怎么调 也调不到位
2、好不容易从stackoverflow上查到一个解决方案 ,可使用时却各种调整无法达到预期,或者好不容易搞定了。随便换个图又不好使了
3、网上一下查到好几个方案,不知道到底哪个好,只能一个一个试
4、有时候,想要调整一个地方,可是不知道怎么搜索关键字
如果你有过以上的经历,恭喜,这个教程就是为你量身定做的。这个教程和其他教程有啥区别?答案是:这个教程是从架构的高度来讲解matplotlib的,学完后,你不只是知道了怎么使用matplotlib,更是知道为什么要这样使用。当你脑子中有一个图的模样时,你知道如何组合不同的matplotlib的功能来实现它。
一:matplotlib的编程范式
matplotlib同时支持过程式和面向对象式的使用方法。也就是同一个效果,大部分情况下都有至少两种方法实现。这给初学者造成了很多困惑。所以,我们要先了解这两种方式。
首先看一下过程式的方法:
import numpy as np
import matplotlib.pyplot as plt
def f(t):
return np.exp(-t) * np.cos(2*np.pi*t)
t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)
plt.figure(1)
plt.subplot(211)
plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')
plt.subplot(212)
plt.plot(t2, np.cos(2*np.pi*t2), 'r--')
plt.show()
这段代码的效果如下:
这种风格是典型的matlab风格,也叫基于状态的绘制方法。
另一种就是官方推荐的面向对象的绘制方法。上面的图,用面向对象来写,就是这样的:3
def f(t):
return np.exp(-t) * np.cos(2*np.pi*t)
t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)
fig, (ax1, ax2) = plt.subplots(2,1)
ax1.plot(t1, f(t1), 'bo', t2, f(t2), 'k')
ax2.plot(t2, np.cos(2*np.pi*t2), 'r--')
plt.show()
这种风格的好处是绘制对象非常明确。我们这门课程主要是用面向对象的风格,这个也符合matplotlib的最佳实践!
二:figure
matplotlib中最大的概念就是figure,一个figure就是一幅图,可以把它理解成一个有大小的画布。
那么,下面的问题自然是:如何获得一个figure?如何在figure上画图?首先,我们来看看获得一个figure的办法:
fig = plt.figure()
这样就获得了一个figure。在解决如何在figure上画图之前,我们先来观察一下这个fig。既然figure是画布,那么大小如何设置呢?可以这样来设置:
fig.set_figheight(100)
fig.set_figwidth(100)
看起来比较直观,但是这里有个巨坑的地方,就是里面的100代表的是英寸!!!如果我想要一个(1200,600)像素的图,该怎么办呢?要达成目标,我们必须了解figure的另一个属性:dpi(dot per inch)。它代表的是每英寸有多少个像素点。默认值是72。我们可以使用如下的三种设置中的一种得到(1200,600)像素的图:
# figsize=(宽,高)
figsize=(15,7.5), dpi= 80
figsize=(12,6) , dpi=100
figsize=( 8,4) , dpi=150
看,光是得到一个大小确定的figure就这么麻烦。但这正是matplotlib厉害的地方,高度的可定制性。seaborn等绘图库都只是对matplotlib的封装而已。学会matplotlib,其他的绘图库可以很快学会。
既然fig代表一幅图,如果我们还想继续画一幅图怎么办呢?看如下代码:
fig1 = plt.figure()
fig2 = plt.figure()
这里,fig1和fig2代表两个不同的图,这可以通过它们的number属性看出来:
matplotlib内部维护着一个全局的计数,记录了一共创建了多少个figure。
现在我们来总整体上看看figure有哪些属性,执行fig.__dict__可以得到如下内容:
{'_stale': True,
'stale_callback': None,
'figure': None,
'_transform': None,
'_transformSet': False,
'_visible': True,
'_animated': False,
'_alpha': None,
'clipbox': None,
'_clippath': None,
'_clipon': True,
'_label': '',
'_picker': None,
'_contains': None,
'_rasterized': None,
'_agg_filter': None,
'_mouseover': False,
'eventson': False,
'_oid': 0,
'_propobservers': {},
'_remove_method': None,
'_url': None,
'_gid': None,
'_snap': None,
'_sketch': None,
'_path_effects': [],
'_sticky_edges': _XYPair(x=[], y=[]),
'_in_layout': True,
'callbacks': <matplotlib.cbook.CallbackRegistry at 0x7f75632e4410>,
'bbox_inches': Bbox([[0.0, 0.0], [6.0, 4.0]]),
'dpi_scale_trans': <matplotlib.transforms.Affine2D at 0x7f75655edc90>,
'_dpi': 72.0,
'bbox': <matplotlib.transforms.TransformedBbox at 0x7f75655ed0d0>,
'transFigure': <matplotlib.transforms.BboxTransformTo at 0x7f75655ed090>,
'patch': <matplotlib.patches.Rectangle at 0x7f7563004310>,
'canvas': <matplotlib.backends.backend_agg.FigureCanvasAgg at 0x7f75632e4e10>,
'_suptitle': None,
'subplotpars': <matplotlib.figure.SubplotParams at 0x7f75632e4e50>,
'_layoutbox': None,
'_constrained_layout_pads': {'w_pad': 0.04167,
'h_pad': 0.04167,
'wspace': 0.02,
'hspace': 0.02},
'_constrained': False,
'_tight': False,
'_tight_parameters': {},
'_axstack': <matplotlib.figure.AxesStack at 0x7f75632e4ed0>,
'suppressComposite': None,
'artists': [],
'lines': [],
'patches': [],
'texts': [],
'images': [],
'legends': [],
'_axobservers': [<function matplotlib.backend_bases.FigureManagerBase.__init__.<locals>.notify_axes_change(fig)>],
'_cachedRenderer': None,
'_align_xlabel_grp': <matplotlib.cbook.Grouper at 0x7f75655edd90>,
'_align_ylabel_grp': <matplotlib.cbook.Grouper at 0x7f75632e4090>,
'_gridspecs': [],
'number': 1}
属性非常多,主要分为两类,一类是对figure的设置,比如wspace、hspace等。另一类是和figure中画的内容有关,比如lines、texts、legends、artists等。
此时不需要理解全部的属性,只要浏览一遍,有个大致的印象就可以了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。