理解matplotlib绘图
matplotlib是基于Python语言的开源项目,旨在为Python提供一个数据绘图包。Matplotlib 可能是 Python 2D-绘图领域使用最广泛的套件。它能让使用者很轻松地将数据图形化,并且提供多样化的输出格式。
matplotlib使用numpy进行数组运算,并调用一系列其他的Python库来实现硬件交互。matplotlib的核心是一套由对象构成的绘图API。
你需要安装Python, numpy和matplotlib。(可以到python.org下载Python编译器。相关Python包的安装,请参看我的Python小技巧)
matplotlib的官网是: http://matplotlib.org/ 官网有丰富的图例和文档说明。
matplotlib在github的地址为:https://github.com/matplotlib 欢迎有兴趣的开发者fork。
matplotlib是受MATLAB的启发构建的,模仿MATLAB但是不模仿“收费”
1 一个简单的例子
(1) 绘图,画一条直线
import matplotlib.pyplot as plt plt.plot([0, 1], [0, 1]) # plot a line from (0, 0) to (1, 1)
plt.title("a strait line")
plt.xlabel("x value")
plt.ylabel("y value")
plt.savefig("demo.jpg")
plt.show()
(2) 解析
上面的代码实际上封装了很多,如果我们想简单的快速绘图,那么你只要简单的调用上面的代码。但是作为程序员,怎么能甘心做个调用者,让我们解开matplotlib的核心面纱吧
第一行,plt.plot([0,1],[0,1])源码
# 源码1
def plot(*args, **kwargs):
ax = gca() #(1) 获得axes
# allow callers to override the hold state by passing hold=True|False
washold = ax.ishold()
hold = kwargs.pop('hold', None)
if hold is not None:
ax.hold(hold)
try:
ret = ax.plot(*args, **kwargs) #(2) 调用ax.plot()
draw_if_interactive()
finally:
ax.hold(washold) return ret
我们看到里面代码(1) 处调用了gca,当获得了axes之后,plot是通过ax进行的,代码(2)
好的,那么继续深入ax=gca(),查看gca()的源码
# 源码2
def gca(**kwargs):
"""
Get the current :class:`~matplotlib.axes.Axes` instance on the
current figure matching the given keyword args, or create one. If the current axes doesn't exist, or isn't a polar one, the appropriate
axes will be created and then returned. """
ax = gcf().gca(**kwargs)
return ax
好吧,实际上里面还有洞天,继续追踪gcf()的源码
#源码 3
def gcf():
"Get a reference to the current figure." figManager = _pylab_helpers.Gcf.get_active() #(1) 从figure的active 列表中取出最后面的一个,如果列表为空,则返回None
if figManager is not None:
return figManager.canvas.figure #(2) 直接返回当前active figure列表中最上面的那个figure
else:
return figure() #(3) 如果没有则创建一个
在这里获得一个figure,如果程序里面有多个figure,则返回正激活的那个(激活是指如果有多个窗口,则是最上面的那个,这个窗口接触鼠标、键盘输入),如果没有则创建。创建的时候默认就将这个figure设为激活的figure。
OK,回溯到源码2。也就是这个gca()是调用figure的gca(),那么继续探索之旅。
#源码4 figure类的gca
def gca(self, **kwargs):
"""
Get the current axes, creating one if necessary The following kwargs are supported for ensuring the returned axes
adheres to the given projection etc., and for axes creation if
the active axes does not exist: %(Axes)s """
ckey, cax = self._axstack.current_key_axes() #(1) 粗糙axes的是stack
# if there exists an axes on the stack see if it maches
# the desired axes configuration
if cax is not None: # if no kwargs are given just return the current axes
# this is a convenience for gca() on axes such as polar etc.
if not kwargs:
return cax # if the user has specified particular projection detail
# then build up a key which can represent this
else:
# we don't want to modify the original kwargs
# so take a copy so that we can do what we like to it
kwargs_copy = kwargs.copy()
projection_class, _, key = process_projection_requirements(
self, **kwargs_copy) # let the returned axes have any gridspec by removing it from
# the key
ckey = ckey[1:]
key = key[1:] # if the cax matches this key then return the axes, otherwise
# continue and a new axes will be created
if key == ckey and isinstance(cax, projection_class):
return cax # no axes found, so create one which spans the figure
return self.add_subplot(1, 1, 1, **kwargs)
这里和上面gcf类似,也是看是否有已经存在的,如果存在axes,则直接调用,如果不存在,则是通过figure.add_subplot(1,1,1)创建一个axes。
好了,到这边为止,我们通过查看源码已经深入的接触了figure,axes。实际简单的一句plt.plot() 是通过figure上得axes调用plot()实现的。
因此我们可以自己写
fig1 = plt.figure('fig1') #获得一个figure, 这个figure是接下来所有画在这上面对象的载体。可以理解为边框
fig1_axes_1 = fig1.add_axes([0.1, 0.1, 0.8, 0.8])
fig1_axes_1.plot([0,1],[0,1])
2 理清关系
接下来的内容很多转载自http://www.cnblogs.com/vamei/archive/2013/01/30/2879700.html
我们将上面的直线绘图更改为面向对象式(OO, object-oriented)的,为此,我们引入两个类: Figure和FigureCanvas。(函数式编程也调用了这些类,只是调用的过程被函数调用所遮掩。)
# object-oriented plot from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) line, = ax.plot([0,1], [0,1])
ax.set_title("a straight line (OO)")
ax.set_xlabel("x value")
ax.set_ylabel("y value") canvas.print_figure('demo.jpg')
上面的例子中,我们至少构建了四个对象: fig, canvas, ax, line。它们分别属于Figure类,FigureCanvas类,Axes类和Line2D类。(使用obj.__class__.__name__来查询对象所属的类)
在深入各个对象之前,我们先来做一个比喻。看下面一个图片:
可以看到,图中有一个房子,房子上有窗户和门,窗户上有条纹,门上有把手,此外图像外还有一只小乌龟。我们所提到的房子,窗户,门,条纹,把手,都可以称其为对象。不同的对象之间有依附关系,比如窗户和门属于房子,而把手属于门。乌龟和房子则是并行的两个对象。此外,整个图像外有一个方框,用来表明可绘图的范围,所有上面提到的元素都依附于该方框。
这就是用面向对象的方式来理解一个图像。事实上,对象是描述图像的最自然的方式,面向对象编程最成功的领域就是在计算机图形方面。
我们先来看什么是Figure和Axes对象。在matplotlib中,整个图像为一个Figure对象。在Figure对象中可以包含一个,或者多个Axes对象。每个Axes对象都是一个拥有自己坐标系统的绘图区域。其逻辑关系如下:
转过头来看直线图。整个图像是fig对象。我们的绘图中只有一个坐标系区域,也就是ax。此外还有以下对象。(括号中表示对象的基本类型)
Title为标题。Axis为坐标轴,Label为坐标轴标注。Tick为刻度线,Tick Label为刻度注释。各个对象之间有下面的对象隶属关系:
(yaxis同样有tick, label和tick label,没有画出)
尽管data是数据绘图的关键部分,也就是数据本身的图形化显示,但是必须和xaxis, yaxis, title一起,才能真正构成一个绘图区域axes。一个单纯的,无法读出刻度的线是没有意义的。xaxis, yaxis, title合起来构成了数据的辅助部分(data guide)。
上面元素又包含有多种图形元素。比如说,我们的data对象是一条线(Line2D)。title, tick label和label都是文本(Text),而tick是由短线(Line 2D)和tick label构成,xaxis由坐标轴的线和tick以及label构成,ax由xaxis, yaxis, title, data构成,ax自身又构成了fig的一部分。上面的每个对象,无论是Line2D, Text还是fig,它们都来自于一个叫做Artist的基类。
OO绘图的原程序还有一个canvas对象。它代表了真正进行绘图的后端(backend)。Artist只是在程序逻辑上的绘图,它必须连接后端绘图程序才能真正在屏幕上绘制出来(或者保存为文件)。我们可以将canvas理解为绘图的物理(或者说硬件)实现。
在OO绘图程序中,我们并没有真正看到title, tick, tick label, xaxis, yaxis对象,而是使用ax.set_*的方法间接设置了这些对象。但这些对象是真实存在的,你可以从上层对象中找到其“真身”。比如,fig.axes[0].xaxis就是我们上面途中的xaxis对象。我们可以通过fig -> axes[0] (也就是ax) -> xaxis的顺序找到它。因此,重复我们刚才已经说过的,一个fig就构成了一个完整的图像。对于每个Artist类的对象,都有findobj()方法,来显示该对象所包含的所有下层对象。
坐标
坐标是计算机绘图的基础。计算机屏幕是由一个个像素点构成的。想要在屏幕上显示图像,计算机必须告诉屏幕每个像素点上显示什么。所以,最贴近硬件的坐标体系是以像素为单位的坐标体系。我们可以通过具体说明像素位置来标明显示器上的某一点。这叫做显示坐标(display coordinate),以像素为单位。
然而,像素坐标不容易被纳入绘图逻辑。相同的程序,在不同的显示器上就要调整像素值,以保证图像不变形。所以一般情况下,还会有图像坐标和数据坐标。
图像坐标将一张图的左下角视为原点,将图像的x方向和y方向总长度都看做1。x方向的0.2就是指20%的图像在x方向的总长,y方向0.8的长度指80%的y方向总长。(0.5, 0.5)是图像的中点,(1, 1)指图像的右上角。比如下面的程序,我们在使用add_axes时,传递的参数中,前两个元素为axes的左下角在fig的图像坐标上的位置,后两个元素指axes在fig的图像坐标上x方向和y方向的长度。fig的图像坐标称为Figure坐标,储存在为fig.transFigure
(类似的,每个axes,比如ax1,有属于自己的图像坐标。它以ax1绘图区域总长作为1,称为Axes坐标。也就是ax1.transAxes。(0.5, 0.5)就表示在Axes的中心。Axes坐标和Figure坐标原理相似,只是所用的基准区域不同。)
from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas fig = Figure()
canvas = FigureCanvas(fig) # first axes
ax1 = fig.add_axes([0.1, 0.1, 0.2, 0.2])
line, = ax1.plot([0,1], [0,1])
ax1.set_title("ax1") # second axes
ax2 = fig.add_axes([0.4, 0.3, 0.4, 0.5])
sca = ax2.scatter([1,3,5],[2,1,2])
ax2.set_title("ax2") canvas.print_figure('demo.jpg')
我们在绘图,比如使用plot的时候,绘制了两点间的连线。这两点分别为(0, 0)和(1, 1)。(plot中的第一个表为两个x坐标,第二个表为两个y坐标)。这时使用的坐标系为数据坐标系(ax1.transData)。我们可以通过绘出的坐标轴读出数据坐标的位置。
如果绘制的是具体数据,那么数据坐标符合我们的需求。如果绘制的是标题这样的附加信息,那么Axes坐标符合符合我们的需求。如果是整个图像的注解,那么Figure坐标更符合需求。每一个Artist对象都有一个transform属性,用于查询和改变所使用的坐标系统。如果为显示坐标,transform属性为None。
参考资料:
(1) http://www.cnblogs.com/vamei/archive/2013/01/30/2879700.html
(2) http://hyry.dip.jp/tech/book/page/scipy/matplotlib_fast_plot.html
(3) http://liam0205.me/2014/09/11/matplotlib-tutorial-zh-cn/
(4) http://reverland.org/python/2012/09/07/matplotlib-tutorial/
(5) http://www.yeolar.com/note/2011/04/28/matplotlib-tips/
理解matplotlib绘图的更多相关文章
- matplotlib 绘图
http://blog.csdn.net/jkhere/article/details/9324823 都打一遍 5 matplotlib-绘制精美的图表 matplotlib 是python最著名的 ...
- matplotlib绘图基本用法-转自(http://blog.csdn.net/mao19931004/article/details/51915016)
本文转载自http://blog.csdn.net/mao19931004/article/details/51915016 <!DOCTYPE html PUBLIC "-//W3C ...
- python实战学习之matplotlib绘图续
学习完matplotlib绘图可以设置的属性,还需要学习一下除了折线图以外其他类型的图如直方图,条形图,散点图等,matplotlib还支持更多的图,具体细节可以参考官方文档:https://matp ...
- matplotlib绘图的基本操作
转自:Laumians博客园 更简明易懂看Matplotlib Python 画图教程 (莫烦Python)_演讲•公开课_科技_bilibili_哔哩哔哩 https://www.bilibili. ...
- python中利用matplotlib绘图可视化知识归纳
python中利用matplotlib绘图可视化知识归纳: (1)matplotlib图标正常显示中文 import matplotlib.pyplot as plt plt.rcParams['fo ...
- python实战学习之matplotlib绘图
matplotlib 是最流行的Python底层绘图库,主要做数据可视化图表 可以将数据可视化,能够更直观的呈现数据 matplotlib绘图基本要点 首先实现一个简单的绘图 # 导入pyplot f ...
- 【原】在Matplotlib绘图中添加Latex风格公式
Matplotlib绘图的过程中,可以为各个轴的Label,图像的Title.Legend等元素添加Latex风格的公式. 只需要在Latex公式的文本前后各增加一个$符号,Matplotlib就可以 ...
- Matplotlib绘图双纵坐标轴设置及控制设置时间格式
双y轴坐标轴图 今天利用matplotlib绘图,想要完成一个双坐标格式的图. fig=plt.figure(figsize=(20,15)) ax1=fig.add_subplot(111) ax1 ...
- ssh调用matplotlib绘图报错RuntimeError: Invalid DISPLAY variable
1.问题:在本地用matplotlib绘图可以,但是在ssh远程绘图的时候会报错 RuntimeError: Invalid DISPLAY variable 2.原因:matplotlib的默认ba ...
随机推荐
- POJ 2014
#include <iostream> using namespace std; int main() { //freopen("acm.acm","r&qu ...
- java基础知识回顾之javaIO类---FileInputStream和FileOutputStream字节流复制图片
package com.lp.ecjtu; import java.io.FileInputStream; import java.io.FileNotFoundException; import j ...
- db2日期和时间常用汇总
1.db2可以通过SYSIBM.SYSDUMMY1.SYSIBM.DUAL获取寄存器中的值,也可以通过VALUES关键字获取寄存器中的值. SELECT 'HELLO DB2' FROM SYSIBM ...
- HDU5569/BestCoder Round #63 (div.2) C.matrix DP
matrix Problem Description Given a matrix with n rows and m columns ( n+m is an odd number ), at fir ...
- JDBC第三次学习
这是我的JDBC第三次学习了,在学习的过程中,老是会忘掉一些知识,不记下笔记实在不行啊! 使用JDBC调用存储过程 (1)关于如何使用Navicat(11.1.13) for MySQL如何创建存储过 ...
- 轻松大幅度降低 Meteor App 的首屏加载时间
许多研究表明,用户最满意的网页加载时间是在2秒以下.能够忍受的较长等待时间上限大概在6-8秒之间.如果需要等待12秒,99%以上的用户会关闭网页离开. 所以如果要给用户提供愉快的使用体验,尽量做到 2 ...
- linux下修改tomcat的默认目录
1.修改tomcat的默认目录.它的默认目录是webapps/ROOT,对应的conf目录下的server.xml里的内容是: 1.修改tomcat的默认目录.它的默认目录是webapps/ROOT, ...
- iOS开发推送--客户端 服务端
1.推送过程简介 (1)App启动过程中,使用UIApplication::registerForRemoteNotificationTypes函数与苹果的APNS服务器通信,发出注册远程推送的申请. ...
- 306. Additive Number
题目: Additive number is a string whose digits can form additive sequence. A valid additive sequence s ...
- SQL Server 高性能写入的一些总结
1.1.1 摘要 在开发过程中,我们不时会遇到系统性能瓶颈问题,而引起这一问题原因可以很多,有可能是代码不够高效.有可能是硬件或网络问题,也有可能是数据库设计的问题. 本篇博文将针对一些常用的数据库性 ...