前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >气象绘图——折线图

气象绘图——折线图

作者头像
自学气象人
发布2023-06-21 15:56:32
3300
发布2023-06-21 15:56:32
举报
文章被收录于专栏:自学气象人自学气象人

本节提要:不满意最开始那一版的折线图教程,所以进行了这一强化版的撰写。主要针对matplotlib中的折线图,对关键字指令升级梳理,希望能帮助新入门的小伙伴。



一、简要谈谈折线图

折线图是科学或者商业图表中最为基础的一种了,其主要展示时间序列的变化情况,能够使读者了然数据的大小、升降、正负关系,还能展示各种折线数据的相对关系,但对整体——局部的表现力较差,参与有地图的绘制也比较困难。

折线图非常实用,过往期刊杂志由于黑色印刷,为区分各个值的折线,要求用标记符号、线条样式等方式用于区分;matplotlib作为python的祖母级绘图库,提供了丰富的关键字指令用以美化、修饰图表。下面就让我们来一睹plot绘图函数的风采吧!

二、plot( )绘图函数的基础运作

使用过excel的小伙伴应该能理解折线图的绘制原理,其本质是针对横轴和纵轴坐标点的链接,实际上这些点和scatter命令是一致的,只是plot命令能够使其连接成线。

不管你在前面是否划分了子图,plt.plot()都是可以使用的,进一步的,库包提供了ax.plot()在子图内部调用。

plot()命令是在内部传入x轴、y轴数据,两者的数据不能长度不一,然后电脑自动在笛卡尔坐标系中按顺序连接这些点。

A、横纵轴数据直接的传入

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(4,4),dpi=500)#添加画布
plt.plot([1],[1],marker='*')#列表单独一个点
plt.plot(1,1,marker='*')#数值单独一个点
plt.plot((1),(1),marker='*')#元组单独一个点
plt.show()

可以看出,列表、元组、数值都可以直接传入plot并成功绘制,原则上是没有问题的。这种传入方式只能用来做实验讲明原理,在上手实际数据时完全受到限制。

B、横纵轴数据间接的传入

这种数据传入方式才是实用的,通过一个参数符号,连接plot与外部数据:

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(3,3),dpi=500)#添加画布
x=[1,2,3,4,5]
y=[1,2,3,4,5]
plt.plot(x,y)

通过参数x和y,我们实现了内外数据的连接。当然,在这种方式下,元组数据也能传入并正常绘图。

C、横轴纵轴数据必须长度一致

x、y在传入时,长度必须一致,否则报错。

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(3,3),dpi=500)#添加画布
x=[1,2,3,4,5]
y=[1,2,3,4]
plt.plot(x,y)
代码语言:javascript
复制
ValueError: x and y must have same first dimension, but have shapes (5,) and (4,)

三、plot( )函数的常用关键字参数

接下来,就是plot函数的最重要部分了——关键字参数。关键字参数相当于战士的武器、巫师的拐杖、道士的法宝,没有关键字参与,plot()函数和咸鱼没什么区别。

(点击右侧小图可查看大图)

plot( )函数常用关键字参数

xy

x,y即最为关键的数据部分,请注意顺序。

color或c

指定折线的颜色

linestyle或ls

指定折线的样式

linewidth或lw

指定折线宽度

fmt

混合命令,同时指定线条颜色和样式

marker

指定折线图的标记样式

markeredgecolor

指定标记的边缘颜色

markerfacecolor

指定标记内部填充颜色

markeredgewidth

指定标记边缘宽度

markersize

指定标记直径大小

fillstyle

指定标记内部的填充方式

label

指定折线的图例名称

zorder

指定绘图层次(高层次会盖住低层次)

visible

是否显示该线条(True or False)

四、折线图实用命令

A、堆积折线图

严格来说这个函数不属于plot( ),但是为了方便,也放在这里讲,堆积折线图可以实现不同折线之间的填色样式,该图主要依赖stackplot( )命令。

代码语言:javascript
复制
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(3,3),dpi=500)#添加画布
x=[1,2,3,4,5]
y1=[1,2,3,4,5]
y2=[1,2,3,4,5]
y3=[1,2,3,4,5]
colors=['tab:blue','tab:green','tab:orange']#指定填充颜色,从低到高
plt.stackplot(x,y1,y2,y3,colors=colors)

B、折线图与坐标轴之间进行填色

这也是一种常规的折线数值比较方式,通过plt.fill( )命令绘制:

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(3,3),dpi=500)
x=[1,2,3,4,5,6,7,8,9,10,11]
y=[1,2,3,4,5,2,-1,-5,-7,-2,1]
plt.plot(x,y,c='tab:blue',marker='o',markersize=3)
plt.fill(x,y,color='tab:green',alpha=0.5)

C、使用fill_between( )命令完成B类型填充

fill_between( )表示填充传递进去的的列表相夹的部分,比如下面子图1,仅传入(x,y1)那么就会将x与y1的相夹部分填充;子图2,传入(x,y1,1),多了一个限定值1,那么就会绘制y1与x=1相夹部分;子图3,传入(x,y1,y2),就会绘制y1与y2相夹部分。

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
x = np.arange(0.0, 2, 0.01)
y1 = np.sin(2 * np.pi * x)
y2 = 0.8 * np.sin(4 * np.pi * x)

fig, (ax1, ax2, ax3) = plt.subplots(3, 1, sharex=True, figsize=(6, 6),dpi=500)

ax1.fill_between(x, y1)
ax1.set_title('fill between y1 and 0')

ax2.fill_between(x, y1, 1)
ax2.set_title('fill between y1 and 1')

ax3.fill_between(x, y1, y2)
ax3.set_title('fill between y1 and y2')
ax3.set_xlabel('x')
fig.tight_layout()
plt.savefig('a',bbox_inches='tight')

D、折线图之间分类填色

某些时候,需要比较两根折线的相对大小,或者比较其大小的差值,可以使用在折线图之间填色的方法,该方法仍然用到C中的fill_between( )函数。

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(3,3),dpi=500)
ax=fig.add_axes([0,0,1,1])
x=np.array([1,2,3,4,5,6,7,8,9,10,11])
y1=np.array([1,2,3,4,5,2,-1,-5,-7,-2,1])
y2=np.array([3,4,5,3,1,-1,-4,-6,-3,2,1])
ax.plot(x,y1,ls=':',c='k',marker='o',fillstyle='none')
ax.plot(x,y2,ls='-.',c='k')
ax.fill_between(x,y1,y2,where=(y1>y2),interpolate=True,
               facecolor='tab:orange',alpha=0.8)
ax.fill_between(x,y1,y2,where=(y2>y1),interpolate=True,
               facecolor='tab:blue',alpha=0.8)

在fill_between( )中多了一个where命令,判定填充条件。

E、interpolate=True 或者False

这个参数是干什么的呢?官网给出了解释:

以上图为例,蓝线和橙线在x=1.5这个地方是有交点,如果不开启interpolate,则填色时默认不填充这个交叉区域。一般来说,建议将其设置为True。

五、折线图的多坐标轴

在进行科研分析时,时常遇到两个值的量级相差悬殊,如果直接在一张表上绘制,量级小的值将会被压缩,失去图示意义,在这个时候,一般引入多坐标轴解决问题。

以下面三个值为例,他们之间相差2-3个量级。

代码语言:javascript
复制
x=np.array([1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20])
y1=np.array([1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1])
y2=np.array([950,960,970,980,990,1000,1107,1108,1109,
             1110,1109,1108,1107,1106,1200,1000,980,960,940])
y3=np.array([0.11,0.22,0.43,0.4,0.5,0.6,0.7,0.8,0.9,1.0,0.9,
             0.8,0.7,0.6,0.5,0.4,0.3,0.2,1])
ax.plot(x,y1,ls=':')
ax.plot(x,y2,ls='-.')
ax.plot(x,y3,ls='--')

如果直接在同一张子图的同一个y坐标轴进行绘图,那么就会出现下面这种情况:

除了橙线量级较大勉强能看出发展形势,另外两个量级小的被压在地平线上了。这时,就需要引入第二个坐标轴给量值差异最大的橙线,以将另外两根线从地板解放出来。

代码语言:javascript
复制
ax.plot(x,y1,c='tab:blue',ls=':',marker='o')
ax.plot(x,y3,c='tab:green',ls='--',marker='^')
ax2=ax.twinx()
ax2.plot(x,y2,c='tab:red',ls='--',marker='*')

twinx顾名思义,就是使两个子图共享x轴,但是y轴各用各的:

这时,三根线都能在图上比较正常的显示出来了,我们可以添加一个图例,来分清楚哪根线用哪边的y轴:

代码语言:javascript
复制
line1,=ax.plot(x,y1,c='tab:blue',ls=':',marker='o')
line3,=ax.plot(x,y3,c='tab:green',ls='--',marker='^')
ax2=ax.twinx()
line2,=ax2.plot(x,y2,c='tab:red',ls='--',marker='*')
ax.legend([line1,line2,line3],['介于1-10','介于900-1200','介于0.1-1'],loc='upper left')

当然,如果需要更多的坐标轴,就需要参考官网的例子了(这仅是其中一种方法,更多的方式可以参考下面的官网实例链接):

代码语言:javascript
复制
from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA
fig=plt.figure(figsize=(3,3),dpi=500)
host = host_subplot(111, axes_class=AA.Axes)
plt.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

offset = 60
new_fixed_axis = par2.get_grid_helper().new_fixed_axis
par2.axis["right"] = new_fixed_axis(loc="right",
                                    axes=par2,
                                    offset=(offset, 0))

par1.axis["right"].toggle(all=True)
par2.axis["right"].toggle(all=True)

host.set_xlim(0, 2)
host.set_ylim(0, 2)

host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity")

par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

host.legend()

host.axis["left"].label.set_color(p1.get_color())
par1.axis["right"].label.set_color(p2.get_color())
par2.axis["right"].label.set_color(p3.get_color())
plt.show()

我的建议是共享坐标轴不要超过4根,再多的话就看不清楚图了。

参考链接:

折线图填充:https://matplotlib.org/gallery/lines_bars_and_markers/fill_between_demo.html#sphx-glr-gallery-lines-bars-and-markers-fill-between-demo-py

多坐标轴:https://matplotlib.org/gallery/axisartist/demo_parasite_axes.html#sphx-glr-gallery-axisartist-demo-parasite-axes-py

https://matplotlib.org/gallery/axisartist/demo_parasite_axes2.html#sphx-glr-gallery-axisartist-demo-parasite-axes2-py

https://matplotlib.org/gallery/ticks_and_spines/multiple_yaxis_with_spines.html#sphx-glr-gallery-ticks-and-spines-multiple-yaxis-with-spines-py

刘大成:《matplotlib实践》,电子工业出版社,2018.张杰:《Python数据可视化之美》,电子工业出版社,2020.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-05-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 自学气象人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档