[Day 27] 从零开始学Python - 科学绘图Matplotlib:画着你,画不出你的骨骼

注:本文同步刊载在Medium,若习惯Medium的话亦可去那边看呦!

今天我们要来介绍的是Matplotlib,
对於Python来说,是一套非常常用於科学绘图的绘图程序库,
同时也相当良好地支援了NumPy的阵列,
此外,通常状况下,只要设定恰当,
也可以很顺利地在一些带有视窗运作的Python执行环境,
如IPython, Jupyter Notebook, colab等直接内嵌绘制图片,
可以说是相当的方便!
由於最初的目的是提供如同Matlab软件的绘图方式,
所以常用Matlab的人可能会觉得很多东西似曾相识XD

要使用matplotlib时,官方有提供pylab
将matplotlib的pyplot和numpy合并在一起,
但还是建议numpy归numpy,pyplot归pyplot

同样的,如果电脑还没有matplotlib套件的话,
请先使用pip install进行安装。

pip install matplotlib

接下来让我们来介绍一些基本的功能。
首先,我们要先将numpy和matplotlib的pyplot给import进来:

import numpy as np
import matplotlib.pyplot as plt

记得上一篇我们做过一个随积分布的阵列吗?
如果我们想将其使用直方图(Histogram)来表现出点的分布数量的话,
可以使用plt.hist(),将阵列输入给plt;
同时,plt在绘制以後,要经过plt.show()的方法才会显示出来。

>>> mu, sigma = 0, 0.1
>>> s = np.random.normal(mu, sigma, 1000)
>>> plt.hist(s) # 绘制直方图,预设分成10组
(array([ 10.,  32.,  91., 164., 238., 216., 147.,  71.,  25.,   6.]), array([-0.
30285466, -0.2403016 , -0.17774855, -0.1151955 , -0.05264245,
        0.0099106 ,  0.07246365,  0.1350167 ,  0.19756975,  0.2601228 ,
        0.32267585]), <BarContainer object of 10 artists>)
>>> plt.show()
# 在直译器的话可以按Ctrl+C回来或按X关掉plt视窗
>>> plt.hist(s, 30) # 第二个参数为30, 代表将值的范围切分成30等份(预设则为10)
(array([ 1.,  4.,  5.,  8.,  9., 15., 19., 25., 47., 46., 49., 69., 71.,
       79., 88., 87., 76., 53., 55., 55., 37., 40., 16., 15.,  9.,  9.,
        7.,  4.,  1.,  1.]), array([-0.30285466, -0.28200364, -0.26115262, -0.24
03016 , -0.21945059,
       -0.19859957, -0.17774855, -0.15689754, -0.13604652, -0.1151955 ,
       -0.09434449, -0.07349347, -0.05264245, -0.03179144, -0.01094042,
        0.0099106 ,  0.03076161,  0.05161263,  0.07246365,  0.09331467,
        0.11416568,  0.1350167 ,  0.15586772,  0.17671873,  0.19756975,
        0.21842077,  0.23927178,  0.2601228 ,  0.28097382,  0.30182483,
        0.32267585]), <BarContainer object of 30 artists>)
>>> plt.show()

应该可以看到接近如下的图(前面是分10组,後面是分30组):
https://ithelp.ithome.com.tw/upload/images/20201006/201198719AdEzN5MWh.jpg
https://ithelp.ithome.com.tw/upload/images/20201006/201198710TDtm7K4Hw.jpg

我们在绘图时,如果一般使用画线按座标的话,
通常是以plt.plot(x, y, linewidth)的型式,
此时就要刚好每个x的元素都对应到y的元素:

>>> x = np.arange(1, 9, 2)
>>> y = 2 * x
>>> plt.plot(x, y, linewidth=1.5) # 这样应该是y=2x的样子
[<matplotlib.lines.Line2D object at 0x000000000BCCB220>]
>>> plt.show()

https://ithelp.ithome.com.tw/upload/images/20201006/20119871LLSm0sNxrD.jpg
请留意一点,由於Python的阵列预设从0开始,所以当我们只给一段座标时,
会被当成y座标,且x会从0开始起算,以整数递增:

>>> plt.plot([1,2,3,4])
>>> plt.show()
>>> plt.plot([1,2,3,4], [1,2,3,4]) # 留意X座标的变化!
>>> plt.show()

https://ithelp.ithome.com.tw/upload/images/20201007/20119871igHGgJqCDs.jpg
https://ithelp.ithome.com.tw/upload/images/20201007/20119871PPCBRudvNx.jpg

以plt.plot的方式绘图时,画上去的图被称为figure,
figure的轴则是axes,可以用add_subplot(1,1,1)方法取用到,
如果同时放多张子图的话(1,1,1)代表第一张。
(这不是很好解释,如果一次只画一张图的话就不管它啦!)
我们可以在绘制完图以後再做额外的事情:

>>> fig = plt.figure()
>>> ax = fig.add_subplot(1,1,1)
>>> ax.plot([1,2,3,4], [1,2,3,4])
[<matplotlib.lines.Line2D object at 0x000000000B540B80>]
>>> ax.set_title('Title') # 表题
Text(0.5, 1.0, 'Title')
>>> ax.set_xlabel("label: x") # X轴文字
Text(0.5, 0, 'label: x')
>>> ax.set_ylabel("label: y") # Y轴文字
Text(0, 0.5, 'label: y')
>>> fig.suptitle('Sup Title', fontsize=20, fontweight='bold') # 
Text(0.5, 0.98, 'Sup Title')

https://ithelp.ithome.com.tw/upload/images/20201007/20119871dGSEwqCVL5.jpg

在plt.plot输入阵列後加上一个格式字串可以用来代表画线的样式,
指定linewidth可以修改画线的粗细。

# r代表红色,x代表用'x'来表示点,且不画线
>>> plt.plot([1,2,3,4], [3,5,15,18], 'rx')
[<matplotlib.lines.Line2D object at 0x000000000B856C10>]
# b代表蓝色,'.'代表用单个小点表示一个点,'--'表示用虚线(dashed line)来画线
>>> plt.plot([1,2,3,4], [3,9,1,6], 'b.--')
[<matplotlib.lines.Line2D object at 0x000000000B866310>]
# g代表绿色,o代表实心圆,linewidth表示粗度修为3
>>> plt.plot([1,2,3,4], [1,4,9,16], 'go-', linewidth=3) 
[<matplotlib.lines.Line2D object at 0x000000000B856F40>]
>>> plt.legend(('red', 'blue', 'green'), loc='upper left') # 画图例及决定位置
<matplotlib.legend.Legend object at 0x000000000B757730>
>>> plt.grid(True) # 画出网格
>>> plt.show()

其结果应如下所示:
https://ithelp.ithome.com.tw/upload/images/20201007/20119871NDgzNbY1zv.jpg
在处理过後可画线的图以後,如果我们的资料是零散的点,
不需要画线的话,我们可以用散点图(scatter)来进行绘制:

>>> np.random.random(5)
array([0.22612501, 0.34256502, 0.21559228, 0.17675453, 0.1082928 ])
>>> x = np.random.random(500)
>>> y = np.random.random(500)
>>> plt.scatter(x, y) # 其实用plt.plot(x, y, 'o')也可以啦!
<matplotlib.collections.PathCollection object at 0x000000000B566580>
>>> plt.show()

如果要绘制3D的图的话,要利用plt.axes(),
将其projection设为'3d'。
同时由於有三维座标,所以要使用ax.scatter3D(x, y, z, color)。

>>> z = np.random.normal(0, 0.2, 500)
>>> fig = plt.figure()
>>> ax = plt.axes(projection='3d')
>>> ax.scatter3D(x, y, z, color='blue')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x000000000C00A1F0>
>>> plt.show()

最後我们会得到一个3D散点图,其介面是可以按滑鼠左键拖曳旋转的呦!
读者可以自己尝试看看~
https://ithelp.ithome.com.tw/upload/images/20201007/20119871SWV9C25a5X.jpg

其他其实还有相当多的内容,有兴趣的话可以看看官方文件的说明。
像是各种不同种类的图形、标记方式、标签等等,
如果使用者想更进一步的话,可以试试看找一些如绘制股票线形的教学范例,
跟着操作看看,相信会更有收获!

那麽,我们就明天见罗!


<<:  [Day 27] RecyclerView 下 - itmetouchhelper

>>:  Day23 - 什麽是智能合约?

Day.24 Binary Search Tree II

今天来实作二元树~ 首先来定义一下资料结构 type Node struct { Left *Nod...

android studio 30天学习笔记-day 16-databinding Recyclerview

今天会使用databinding的方式去实作一个Recyclerview。 建立model publ...

Day 12 docker 安装 nginx 後的细部设定

昨天的进度虽说是安装好了 nginx 容器,但若你直接在网址列输入主机 IP 位置,那麽便会看见 n...

【day2】突然想吃樱桃鸭握寿司之典华烤鸭

前阵子突然很想念樱桃鸭握寿司 因为疫情关系又不方便呼朋引伴到礁溪吃一顿 意外的在天母地区发现典华系列...

[Day14] 第十四章-使用JWT token来验证user跟登出api

前言 昨天我们完成了登入 接者今天我们来看看token可以做什麽用吧! 前端跟後端沟通时 我们就像拿...