文章目录

  • 前言
  • 一、Matplotlib架构概述
    • 1.1 Backend(后端)
    • 1.2 Artist(美工)
      • 1.2.1 Figure、Subplot与Axes
      • 1.2.2 Axis、ticks与label
      • 1.2.3 坐标与按指令做图
    • 1.3 Scripting(脚本)
      • 1.3.1 Figure、Subplot与Axes(从脚本层回到Artist层的办法)
      • 1.3.2 ticks、label、title与legend
      • 1.3.3 设置边框与添加文本
  • 二、面向对象编程绘图与函数式绘图对比与实例
    • 2.1 OO绘图与函数式绘图的对比
    • 2.2 实例:绘制各种语言流行性的条形图
  • 总结

前言

很多人入手Matplot库的时候是从matplotlib.pyplot入手的,因为看起来操作简单,但这实际上只能快速产图,如果想要对图片进行调整,例如,调整画布尺寸、调整横轴或者纵轴刻度,或者隐藏横轴或者纵轴标签等等,就会无从下手,实际上,matplotlib架构共分为三层:Backend(后端)、Artist(美工)、Scripting(脚本),待本文一一介绍。


一、Matplotlib架构概述

  Matplotlib中包含和管理给定图形中所有元素的顶级对象称为Figure(可以理解为画板),matplotlib 的核心架构任务之一是实现一个用于展现操作 Figure的框架,并与将Figure呈现到用户界面窗口或硬拷贝的行为进行分离。实现这一点的架构在逻辑上分为三层,可以看作是一个堆栈。位于另一层之上的每一层都知道如何与它下面的层对话,但较低的层不知道它上面的层。从下到上三层是:Backend(后端)、Artist(美工)、Scripting(脚本)。

1.1 Backend(后端)

  实际上,调用Matplotlib的方式可以大不相同:有些人从 Python shell 交互式地使用 Matplotlib,他们键入命令时会弹出绘图窗口,有些人在 Jupyter Notebook用%matplotlib inline或者%matplotlib notebook的magic code绘制内联图或者交互式图表以进行快速数据分析;还有人将 Matplotlib 嵌入到 PyQt 或 PyGObject 等图形用户界面中以构建丰富的应用程序;或者有一些人运行 Web 应用程序服务器来动态提供图形等等。

  为了支持所有这些用例,Matplotlib 可以针对不同的输出,这些不同的输出每一种都称为一种后端;“前端”是面向用户的代码,即绘图代码,而“后端”则在幕后完成所有艰苦的工作来制作图形。有两种类型的后端第一种后端是用户界面后端(user interface backends):用于 PyQt/PySide、PyGObject、Tkinter、wxPython 或 macOS/Cocoa,也称为“交互式后端(interactive backends)”我们在jupyter notebook中用的%matplotlib notebook就属于这一种;另一种后端是硬拷贝后端:用以制作图像文件PNG、SVG、PDF、PS,也称为“非交互式后端(non-interactive backends)”

后端也分为三块

  • FigureCanvas 封装了要绘制的表面的概念(可以理解为画纸)
  • Renderer 渲染器 (可以理解为用来画画的画笔)
  • Event 处理用户输入,例如键盘的输入和鼠标的移动与悬停。

  本文是在Jupyter Notebook的基础上,用%matplotlib notebook的magic code形成的交互式图像,在这里,我们查看所用的后端:

%matplotlib notebook
import matplotlib as mpl
mpl.get_backend()--Outputs:
'nbAgg'

  如果需要调整后端,可以参看官方网站:matplotlib.Backends,一般情况下,使用默认的后端即可

1.2 Artist(美工)

  Artist是Matplotlib的中间层,也是很多繁重的情况发生的地方,后端FigureCanvas是画纸,Artist是知道如何拿起Renderer(画笔)并将墨水涂在画布上的对象,你在Matplotlib的Figure都是Artist的实例包括title, lines, tick labels, images等等,他们都属于基类matplotlib.artist.Artist,而Artistbackend之间的关联发生在draw方法中。由于Renderer有一个指向其画布FigureCanvas的指针,并知道如何在其上绘画,因此draw方法可以将抽象的指令转换Artist为像素缓冲区中的颜色、SVG 文件中的路径或任何具体表示。
  我们用两张图来理解Artist的各个实例与层次,在这张图中,我们给出了主要的实例:Figure(图)、Axes(轴域)、Text(文本)、2Dline(二维线条)、XAxis(X轴)、YAxis(Y轴)、Xlabel(X轴标签)、Xticks(X轴刻度)、Ylabel(Y轴标签)、Yticks(Y轴刻度),注意,Axes中的ax.set_xticklabels()设置的就是plt.xticks()我们接下来将一一介绍他们的具体用法:


  他们的关系如下所示:

  最大的一类是Figure,其次是Axes,再其次是Axes中的一些实例,轴、文本、线条等等,Text可以包含图的标题、图注、图标等等一切的文本。
  另外需要注意这些美工实例又分为原始型美工(Primitive artists)复合型美工(Composite artists),例如前面提到的Text、以及背景的Rectangle、Circle都是原始型美工,而Axis、Tick、labels、Axes、Figure则是复合型美工,一个复合型美工可以包含多个复合型美工或者原始型美工,例如,Figure可以包含包含一个或多个Axes并且Figure的背景是一个基元Rectangle

  接下来我们对这些实例进行一一介绍:

1.2.1 Figure、Subplot与Axes

  • Figure

  我们可以将Figure看成是一张大的画板,可以matplotlib.figure中的fig=Figure()来创建一张画板fig,也可以在函数式绘图中用fig=plt.figure()来建立fig

  但有个画板还不够,好比你要画油画,你不能画在画板上吧,至少需要一张画纸,这里的画纸就可以理解为以横纵坐标轴为长和宽所建立起来的矩形,2D的图像都在这个矩形内。可以用canvas = FigureCanvas(fig)来产生一张画纸,或者如果你用fig=plt.figure(),那他会默认产生一张画纸。如果你觉得一张画纸不够,要在一张画板上多用几张画纸,也是可以的,可以用fig.add_subplot或plt.subplots(子图),或者fig.add_axes(轴域)来产生多的画纸,他们会将原来大的画纸进行拆分,拆分成若干张小画纸,画纸和画纸间可以嵌套,可以并列放置,我们接下来对这两者进行介绍与区分:

  • Subplot

  首先介绍Subplot,Subplot负责将整个画板分割成几块,用ax = fig.add_subplot(abc) 来创建子图,里面的参数abc代表是产生a行b列一共a*b个子图区域,c表示给这个区域添加子图。
  例如:ax1 = fig.add_subplot(221) , ax2 = fig.add_subplot(222) , ax4 = fig.add_subplot(224)就是在2*2个区域中,在左上,右上和右下建立子图:

from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfig = Figure()
canvas = FigureCanvas(fig)ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax4 = fig.add_subplot(224)canvas.print_png('test1.png')

  借用%%html来在网页上查看图片,红色字迹为注释,非做在图上的。

%%html
<img src='test1.png' />

  Subplot建立子图的方式比较基础而且整洁,另一种形式Axes则较为灵活:

  • Axes

  Axes,个人翻译为轴域,可以通过fig.add_axes([left,bottom,width,height])添加子图的左边界、下边界、宽度和高度来在合适的位置上添加子图:

from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfig    = Figure()
canvas = FigureCanvas(fig)ax1    = fig.add_axes([0.1, 0.1, 0.2, 0.2]) #代表左边空出10%,底部空出10%,宽度为20%,高度为20%
ax1.set_title("ax1")ax2    = fig.add_axes([0.3, 0.3, 0.4, 0.4]) #代表左边空出30%,底部空出30%,宽度为40%,高度为40%
ax2.set_title("ax2")canvas.print_figure('test3.jpg')

  Axes还可以嵌套,如果设置

ax1    = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax2    = fig.add_axes([0.3, 0.3, 0.4, 0.4])

  我们可以看到以下情况:

  • 快速确定用子图还是轴域

  关于Subplot和Axes本质上都是产生多张画纸,所以两者的区别并不大,如果想快速、标准的切割画板,可以用fig.add_subplot(),而如果想自定义画纸,则可以使用fig.add_axes(),这两种创建子图的方法,在脚本层都有对应的实现方式,下文我们会提到。

1.2.2 Axis、ticks与label

  Axes是轴域,Axis就是轴,对应的有X轴和Y轴,每个轴都有ticks,即轴上的刻度与label,即轴标签,对于调整刻度可以用set_xlim()和set_ylim()来调整,对于设置ticks的名称,则可以使用ax.set_xticklabels()ax.set_yticklabels()来设置。对于设置标签,则用ax.set_xlabel()ax.set_ylabel()来实现,还可以设置title,用set_title()来实现我们可以在脚本层来更方便的控制。

  示范代码如下:

ax=fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.set_xlim(-0.5,1.5)
ax.set_ylim(-0.5,1.5)
ax.set_xticklabels(['One','Two','Three'])
ax.set_xlabel('Date')
ax.set_ylabel('Units')
ax.set_title('Exponential vs. Linear performance')

1.2.3 坐标与按指令做图

  在现实生活中如果我们想要画一个多边形,我们会先想好多边形的几个顶点,并画线,在顶点出拐弯,在计算机上画图,我们则可以先固定点,再用连线的办法连起来,这时,在matplotlib中,我们可以直接调用render画笔,教它怎么确定坐标,怎么连接线,让他帮我们在画纸上画画,比如,我们可以用matplotlib中pathpatches,一个用来画线,一个用来建立图形块,path.MOVETO表示指针移动到对应位置,path.LINETO表示从当前指针位置到目标指针位置连线,path.CLOSEPLOT即停止做图,如下所示:

from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfig    = Figure()
canvas = FigureCanvas(fig) #添加画布
ax     = fig.add_axes([0.1, 0.1, 0.8, 0.8])#设置Axes位置from matplotlib.path import Path
import matplotlib.patches as patchesverts = [(0, 1),(0.5, 1.5),(1,1),(0.25,0),(0.75,0),(0,1)] #设置顶点位置codes = [Path.MOVETO,Path.LINETO,Path.LINETO,Path.LINETO,Path.LINETO,Path.CLOSEPOLY] #设置各个顶点之间的连接方式path = Path(verts, codes)patch = patches.PathPatch(path, facecolor='lightblue')
ax.add_patch(patch)
ax.set_xlim(-0.5,1.5)
ax.set_ylim(-0.5,1.5)canvas.print_figure('test5.jpg')

  得到以下鱼形图片:

1.3 Scripting(脚本)

  在这里主要介绍Python上的API,matplotlib.pyplot,通常起别名为plt。在上面的代码中,都是面向对象编程绘图(OO,object-oriented),接下来我们可以用API来简化步骤:

1.3.1 Figure、Subplot与Axes(从脚本层回到Artist层的办法)

  脚本编程和面向对象编程绘图的顺序是一样的,首先要建立一张空的画板,其次再依据需求对画板进行分割,建立画板可以用fig=plt.figure()来实现,如果不需要对画板进行分割,可以跳过fig.add_subplot()或者fig.add_axes()这一步。

  在这里如果想要从脚本层直接到Artists层操作,可以使用ax=fig.add_axes()进而对ax进行操作,或者ax=plt.gca()也可以得到当前的Axes,gca即get current Axes,而可以用fig=plt.gcf()来得到当前的Figure,gcf即get current Figure

  示范代码:

import matplotlib.pyplot as plt
fig=plt.figure()
ax=fig.add_axes([0.1,0.1,0.8,0.8])
ax=plt.gca()
fig=plt.gcf()

1.3.2 ticks、label、title与legend

  不同于直接对Axes进行set操作,API可以使用plt.xticks()来对x的ticks进行命名,作用等价于ax.set_xticklabels(),用plt.xlabel()plt.ylabel()对label进行命名,作用等价于ax.set_xlabel()ax.set_ylabel()plt.title()对title进行命名,等价于ax.set_title()同时,如果需要添加图注,只要用plt.legend()来添加就可以了,参数为list类型,对所做的图依次添加图注。但如果要在图形上添加什么数字,还是建议用ax.text(x,hight,text_value,fontsize)用画笔直接在画纸上“写字”。

  示范代码:

import numpy as nplinear_data = np.array([1,2,3,4,5,6,7,8])
exponential_data = linear_data**2plt.figure()
plt.plot(linear_data, '-o',exponential_data,'-o')
plt.xlabel('Some data')
plt.ylabel('Some other data')
plt.title('A title')
plt.xticks(linear_data,eng)
plt.legend(['Baseline', 'Competition')

1.3.3 设置边框与添加文本

  • 设置边框不可见
    可以将对应边框的spines的值设置为不可见,共四种:
    plt.gca().spines['top'].set_visible(False)
    plt.gca().spines['right'].set_visible(False)
    plt.gca().spines['left'].set_visible(False)
    plt.gca().spines['bottom'].set_visible(False)

  可以适当用LC表达式来简化语言,或用迭代器的方式简化语言,例如:

for spine in plt.gca().spines.values():spine.set_visible(False)
#LC表达式
[plt.gca().spines[loc].set_visible(False) for loc in ['top','right','bottom','left']]

  效果可见下2.2中的实例

  • 在指定位置添加文本
    plt.text(x,y,string,fontsize=,va="",ha="",bbox={‘fc’:’’, ‘ec’:’’})
    只要设置x的值和y的值,设置文本string,设置字体大小fontsizeva代表vertical alignment,即垂直对齐,ha代表horizontal alignment,即水平对齐。这里的bbox是对文本框的配置,其中fc表示filled color,文本框内填充颜色,ec表示edge color,文本框框体颜色,效果可见下2.2中的实例

二、面向对象编程绘图与函数式绘图对比与实例

2.1 OO绘图与函数式绘图的对比

  我们发现,面向对象(object-oriented,OO)绘图更加的灵活,而函数式绘图则更加快捷,现实中,在添加文本注释时,我往往会偏向于使用OO,在Axes上找到对应的位置,直接添加文字,在考虑多张表不规则排放在一张图中时,尤其是嵌套等情况,也会用Axes来规定位置;但函数式绘图明显更加方便与快速,两者结合,两种做图方式都掌握才能更好的画出想要的图。

2.2 实例:绘制各种语言流行性的条形图

  我们现在要画一张各个语言及其占比的条形图(其他具体图形下一章会介绍),首先看数据:

Language Popularity
Python 56%
SQL 39%
Java 34%
C++ 34%
JavaScript 29%

  我们可以用面向对象编程绘图,如下代码所示,也可以:

import matplotlib.pyplot as plt
import numpy as npfig=plt.figure()
ax=fig.add_axes([0.1,0.1,0.8,0.8])
Language=['Python','SQL','Java','C++','JavaScript']
pos=np.arange(1,6,1)
popularity=[56,39,34,34,29]# 法一:OO编程绘图
ax.bar(pos,popularity)
ax.set_xticklabels(languages)
ax.set_ylabel('% Popularity')
ax.set_title('Top 5 Languages for Math & Data \nby % popularity on Stack Overflow', alpha=0.8)#法二:函数式绘图
# plt.bar(pos,popularity)
# plt.barlabel()
# plt.xticks(pos,Language)
# plt.ylabel('% Popularity')
# plt.title('Top 5 Languages for Math & Data \nby % popularity on Stack Overflow', alpha=0.8)
  • 如果我们想要去掉x轴和y轴的所有标签,可以用plt.tick_params(left=False,labelleft=False,right=False,top=False,bottom=False)并把y_label也注释掉。
  • 想要去掉chart的框,可以在spines.values中把他设置为不可见:
for spine in plt.gca().spines.values():spine.set_visible(False)
  • 如果需要调整颜色,可以在Axes上用set_color()功能:
bars = plt.bar(pos, popularity, align='center', linewidth=0, color='lightslategrey')
bars[0].set_color('#1F77B4')
  • 如果要给bar备注数字,可以用Axes在对应的位置上直接添加要写的内容(就像画笔直接在指定位置上写字一样):
for bar in bars:plt.gca().text(bar.get_x() + bar.get_width()/2, bar.get_height() - 5, str(int(bar.get_height())) + '%', ha='center', color='w', fontsize=11)
  • 最后归纳我们的代码:
import matplotlib.pyplot as plt
import numpy as npplt.figure()languages =['Python', 'SQL', 'Java', 'C++', 'JavaScript']
pos = np.arange(len(languages))
popularity = [56, 39, 34, 34, 29]bars = plt.bar(pos, popularity, align='center', linewidth=0, color='lightslategrey')
bars[0].set_color('#1F77B4')plt.xticks(pos, languages, alpha=0.8)
plt.title('Top 5 Languages for Math & Data \nby % popularity on Stack Overflow', alpha=0.8)plt.tick_params(top=False, bottom=False, left=False, right=False, labelleft=False, labelbottom=True)for spine in plt.gca().spines.values():spine.set_visible(False)for bar in bars:plt.gca().text(bar.get_x() + bar.get_width()/2, bar.get_height() - 5, str(int(bar.get_height())) + '%', ha='center', color='w', fontsize=11)
plt.show()

  可以得到以下图片:


总结

  1. 需要分清matplotlib的三层构架:Backend(后端)、Artist(美工)、Scripting(脚本)
  2. 注意Artist层种重要的最复合型实例Figure、Axes。分清subplot与Axes的区别,了解其他各实例之间的关系,例如区分xticks、xticklabel与xlabel
  3. 分清面向对象编程(OO)绘图与函数式绘图(pyplot即plt)对应的语句,面对对象编程中调整多用set,而函数则直接调用class plt的函数即可,明白面对对象编程较函数式编程的灵活性与直观性。
  4. 巧妙运用ax=plt.gca(),从函数式编程中直接获得Axes,进而可以直接从Artist层处理图像。

【DS with Python】Matplotlib入门(一):架构概述、面向对象编程绘图与函数式绘图基础相关推荐

  1. python快速入门【五】---- 面向对象编程、python类

    python入门合集: python快速入门[一]-----基础语法 python快速入门[二]----常见的数据结构 python快速入门[三]-----For 循环.While 循环 python ...

  2. Python快速入门(八)面向对象1:类、对象和封装

    Python快速入门(八)面向对象1:类.对象和封装 1.类和对象 1)类的定义 2)对象的定义 3)类和对象的关系 4)类的设计 2.第一个面向对象案列 代码1 代码2 3.设置对象属性 4.ini ...

  3. python入门:正则表达式,面向对象编程,零基础视频教程分享

    正则表达式 import re #首先必须import re模块,re=Regular Expression,就是正则表达式的意思. pattern=re.compile(r'hello') #指明你 ...

  4. Python爬虫入门实战2:获取CSDN个人博客文章基础信息

    ☞ ░ 老猿Python博文目录:https://blog.csdn.net/LaoYuanPython/article/details/98245036 ░ 一.引言 当爬取博文内容时,有时需要进行 ...

  5. Python从入门到实践:面向对象之封装(二)

    目录 一.引言 二.隐藏属性 三.开放接口 3.1隐藏数据属性 3.2隐藏函数属性 四.装饰器-property 一.引言 面向对象编程的三大特性:封装.继承.多态.封装就是把"数据&quo ...

  6. python的类和实例_Python 面向对象编程——类和实例

    1面向对象编程 面向对象编程: 面向对象编程--Object OrientedProgramming OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程 ...

  7. Python 使用 attrs 和 cattrs 实现面向对象编程

    Python 是支持面向对象的,很多情况下使用面向对象编程会使得代码更加容易扩展,并且可维护性更高,但是如果你写的多了或者某一对象非常复杂了,其中的一些写法会相当相当繁琐,而且我们会经常碰到对象和 J ...

  8. python面向对象编程72讲_2020-07-22 Python学习笔记27类和面向对象编程

    一些关于自己学习Python的经历的内容,遇到的问题和思考等,方便以后查询和复习. 声明:本人学习是在扇贝编程通过网络学习的,相关的知识.案例来源于扇贝编程.如果使用请说明来源. 第27关 类与面向对 ...

  9. python004 二 Python开发入门、数据类型概述、判断吧语句、while循环

    python _day02 一,目录: 5种数据类型 1,数字 数据类型 1.数字 (1)简单理解为整数和小数即可 (2)布尔可以理解为是特殊的整数,使用True和False表示,值为1和0 (3)p ...

最新文章

  1. 20172324 2018-2019-1《程序设计与数据结构》实验2报告
  2. 20分钟教你搞懂Git!
  3. iOS安全之RSA加密/生成公钥、秘钥 pem文件
  4. 【Linux入门到精通系列讲解】内存管理malloc和free函数
  5. arcengine遍历属性表_记录一次Hive表清理过程
  6. VS2019 使用 C/C++ 动态链接库 并 进行调用
  7. php 字符串混合分割并存入数组
  8. 对“优秀工程师”的一点感悟
  9. 远程服务器格式化,怎么远程服务器做ghost备份图解
  10. protobuf 2.5.0问题
  11. 仅需6道题轻松掌握Python时间和日期处理 | Python技能树征题
  12. javah vs javac -h
  13. 中国十大芯片企业排名
  14. 小米3流量显示无服务器,因为小米3元不限流量卡,我尝到了无网可用的滋味
  15. 对控制台EXE程序的自动运行问题——以6S模型6s.exe为例
  16. 错误:Error: Could not open client transport with JDBC Uri: jdbc:hive2://ducking:10000: java.net.Connec
  17. STM32模拟读卡器,对于工控机方案谨防踩坑
  18. Android开发工程师 技能要求
  19. 发现一个很不错的东西!--百度网盘外链,下载速度很不错
  20. 计算机表格如何求和,excel怎么求和,教您excel如何进行求和

热门文章

  1. 押注泛C端交易合规:高灯推动财税科技“底层思维”革新?
  2. 什么是VOC数据集,以及如何制作?
  3. php linux下保存文件路径怎么写,详谈PHP文件目录基础操作
  4. 图解二叉树的三种遍历
  5. error adding module to project: null
  6. Android高版本网络请求失败 Cleartext HTTP traffic to xxx not permitted
  7. 踩坑:阿里云oss上传图片报空指针异常
  8. 数据库启动后报12514错误
  9. 小米CC,真配成为年轻人的第一款潮流拍照手机?
  10. 【AI】怎么让字体变粗变细?