一:灵感问题(难点)

在利用python中的matplotlib绘制双y轴图像(条形图+折线图)过程中,为了防止折线图被条形图遮挡,我们需要先绘制条形图,而后绘制折线图,大致效果图如下:

(这里为了看得更清楚对一些线条做了加宽处理)

这里我们可以发现:先画的条形图默认使用了左侧的y轴,而后画的折线图默认使用了右侧的y轴。但个人看图习惯加上强迫症 想让后画的折线图使用的y轴在左侧,而先画的条形图使用的y轴在右侧,这该如何调整?

二:调整思路

前期的一些绘制双y轴图像所需要的基础代码:导入模块-修改字体-输入统计数据-创建图像对象-添加子图(创建轴对象);

# import the module needed
from matplotlib import pyplot as plt
from matplotlib import font_manager
# adjust the font
my_font = font_manager.FontProperties(fname="C:/Windows/Fonts/msyh.ttc")
            # module.property(parameter-path)
# input the data
year = list(range(2008, 2023))  
num = [25, 32, 28, 22, 24, 26, 9, 10, 18, 16, 16, 11, 14, 16, 13]
loss = [192.24, 84.97, 65.79, 48.81, 126.29, 152.45, 135.78,
        72.18, 45.94, 55.77, 44.56, 116.38, 8.10, 24.67, 23.79]  
# 创建一个空白图像对象
fig = plt.figure(figsize=(13, 7), dpi=80)
# 添加子图(创建轴对象)
# 创建后会默认显示一个0-1的坐标轴,即使没有绘制任何内容
axis_1 = fig.add_axes((0.1, 0.1, 0.8, 0.8))
         # rect-tuple(left, bottom, width, height) 
         # 0.1-0.1-0.8-0.8为平时作图默认的轴位置
axis_2 = axis_1.twinx()  # 在axis_1基础上创建新的轴对象,共用x轴绘制不同的数据集

1.调整作图顺序及透明度

调整作图顺序: 先画折线图,后画条形图 ,使得折线图使用左侧y轴,条形图使用右侧y轴;

调整透明度:绘制条形图时 修改alpha参数 ,调整透明度,削弱条形图对折线图的遮挡效果;

# 绘制year-num数据集(折线图)
axis_1.plot(year, num, color="#6AA84F", marker="o", linewidth=2)
# 绘制year-loss数据集(条形图)
axis_2.bar(year, loss, color="#5470C6", alpha=0.8)
# 设置坐标轴颜色
plt.gca().spines["left"].set_color("#6AA84F")
plt.gca().spines["right"].set_color("#5470C6")
# 设置坐标轴轴线宽度
plt.gca().spines["left"].set_linewidth(2)
plt.gca().spines["right"].set_linewidth(2) 

按上述方式调整的最终大致效果图如下:

这里我们可以发现:图像基本达到我们想要的效果,但这样 损失了条形图的可见度,折线图被遮挡的效果也并没有完全消除,有没有更好的办法?

2.调整轴对象对应关系

为了彻底消除折线图被条形图遮挡的情况,我们还是采用 先画条形图,后画折线图 的方式;

axis_1.bar(year, loss, color="#5470C6")
axis_2.plot(year, num, color="#6AA84F", marker="o", linewidth=2)

但这一次我们 先使用axis_2轴对象,绘制条形图,再用轴对象axis_1,绘制折线图 ,更改轴对应关系重新绘图,让条形图使用axis_2对应的右侧y轴,让折线图使用axis_1对应的左侧y轴:

# 更改轴对应关系
# 绘制year-loss数据集(条形图),使用axis_2
axis_2.bar(year, loss, color="#5470C6")
# 绘制year-num数据集(折线图),使用axis_1
axis_1.plot(year, num, color="#6AA84F", marker="o", linewidth=2)

我们发现:的确,折线图如愿用到了左侧的y轴,条形图用到了右侧的y轴,但同时,非常奇怪的是, 后绘制的折线图居然被先绘制的条形图所遮挡 ,这是为什么?

这里我先想到的原因是图层原因:先创建的axis_1图层在底层,后创建的axis_2图层在顶层;于是拿着代码问了下AI,AI十分肯定地回答了我这只与绘图顺序有关,与轴对象创建顺序无关!

这样子又绕了一大圈,试着加入参数zorder什么的都没有效果(我觉得应该是不适用于这种双y轴图像的绘制),又绕了回来,按照最开始的想法自己调试代码找一下原因:

当仅创建一个轴对象时:

axis_1 = fig.add_axes((0.1, 0.1, 0.8, 0.8))
plt.gca().spines["left"].set_color("r")  # 左侧坐标轴标红
plt.title("仅创建一个轴对象axis_1", fontproperties=my_font, size=17)

当创建两个轴对象时:

axis_1 = fig.add_axes((0.1, 0.1, 0.8, 0.8))
plt.gca().spines["left"].set_color("r")  # 左侧坐标轴标红
axis_2 = axis_1.twinx()
plt.gca().spines["right"].set_color("b")  # 右侧坐标轴标蓝
plt.title("创建两个轴对象axis_1、axis_2", fontproperties=my_font, size=17)

我们发现:axis_1标红的左侧坐标轴不见了,是被覆盖了吗?

越发肯定图层问题,修改代码验证:

axis_1 = fig.add_axes((0.1, 0.1, 0.8, 0.8))
plt.gca().spines["left"].set_color("r")  # 左侧坐标轴标红
axis_2 = axis_1.twinx()
plt.gca().spines["right"].set_color("b")  # 右侧坐标轴标蓝
plt.gca().spines["left"].set_visible(False)  # 隐藏左侧坐标轴
plt.title("创建两个轴对象axis_1、axis_2并隐藏axis_2左侧坐标轴",
          fontproperties=my_font, size=17)

我们发现:在axis_1中标红的左侧坐标轴重新显现,因此,最初的猜测是正确的:在图像对象fig下创建轴对象axis相当于在画布上创建图层,且 先创建的轴对象图层在下,后创建的轴对象图层在上

同时,在这次轴对象创建的验证猜想过程中,也发现对于函数plt.gca()的一些误读:plt.gca()函数的作用是获取当前的轴对象,因此不仅在上述创建两个轴对象并分别对两个轴对象的坐标轴进行标色过程中需要注意plt.gca()函数的调用位置,同时也意识到之前的画图中如调整思路1中对坐标轴进行标色时,连续调用两次plt.gca()函数的错误操作,以至于后续的一系列误导。

调整思路1中对坐标轴进行标色时,最初的认识是:创建的两个轴对象,axis_1只有左侧纵坐标轴,axis_2只有右侧纵坐标轴,(但实际上都有,只是另一侧没有刻度),因此在创建完两个轴对象后,连续调用两次plt.gca()函数对左右纵坐标轴标色,即axis_1的左侧纵坐标轴,axis_2的右侧纵坐标轴,(但实际上是对当前轴对象也就是axis_2的左右两侧纵坐标轴进行了标色),却也误打误撞呈现出了想要的纵坐标轴标色效果。

因此,将plt.gca().spines直接替换为指定轴对象如axis_1.spines会更加清晰明确。

最后,认识到了 先后创建轴对象所带来的的图层上下关系 ,那么 更改作图时轴对象对应关系必然会带来图像遮挡,无法达到要求

3.调整坐标轴位置

在上次的思路中认识到了可以指定轴对象进行坐标轴标色、坐标轴隐藏等效果后,既然无法让图像对应到想要位置的坐标轴,是否可以通过移动坐标轴到达想要的位置?

最终思路3也是完美的达到了想要的效果,这里直接借思路3的回顾过程直接完整的描述整个解决过程和代码:

前期的基础工作代码还是一样,在这之后对所需轴对象的坐标轴进行位置移动,并进行坐标轴颜色和轴线宽度的设置以便让观看效果更佳:

# 调整坐标轴位置
axis_1.spines["left"].set_position(("axes", 1))
axis_2.spines["right"].set_position(("axes", 0))
# 调整坐标轴颜色
axis_1.spines["left"].set_color("#5470C6")
axis_2.spines["right"].set_color("#6AA84F")
# 设置坐标轴轴线宽度
axis_1.spines["left"].set_linewidth(2)  # 设置左边坐标轴线宽度为2
axis_2.spines["right"].set_linewidth(2)  # 设置右边坐标轴线宽度为2

完成上述工作后简单画图发现:坐标轴的颜色显示比较怪异,存在遮挡效果,且坐标轴刻度看着十分别扭,对此进行进一步完善:

# 由于图层关系,隐藏轴对象的另一侧坐标轴
axis_1.spines["right"].set_visible(False)  # 非必要,因为axis_1图层在下,不隐藏也会被覆盖
axis_2.spines["left"].set_visible(False)  # 必要,axis_2图层在上,不隐藏会遮挡axis_1坐标轴颜色
# 调整坐标轴刻度位置
axis_1.yaxis.set_ticks_position("right")
axis_2.yaxis.set_ticks_position("left")

最后,画出符合自我要求的图像:

# 绘制year-loss数据集(条形图),使用axis_2
axis_1.bar(year, loss, color="#5470C6")
# 绘制year-num数据集(折线图),使用axis_1
axis_2.plot(year, num, color="#6AA84F", marker="o", linewidth=2)
# 展示图像
plt.show()

当然,还可以进行调整坐标轴标签,添加图例,调整坐标轴刻度范围等等一系列操作进一步完善图像,让图像表现的信息更加多样全面。

由此进一步添加描述信息对我国2008至2022年风暴潮危害发生次数及经济损失进行简单的数据统计和可视化操作:

# 绘制year-loss数据集(条形图),使用axis_2
axis_1.bar(year, loss, color="#5470C6", label="损失(亿元)")
# 进一步完善axis_1图像信息
axis_1.set_xlabel("年份", fontproperties=my_font, size=17)  
                                                 # 加入size参数调节坐标轴信息字体大小
axis_1.set_ylabel("损失(亿元)", fontproperties=my_font, size=17, color="#5470C6")  
                  # 设置轴标签
axis_1.yaxis.set_label_position("right")  # 调整y轴标签位置
axis_1.legend(prop=my_font, loc="upper center", bbox_to_anchor=(0.7, 0.77))
                                                # 加入参数调整legend位置,(1,1)为右上角
# 绘制year-num数据集(折线图),使用axis_1
axis_2.plot(year, num, color="#6AA84F", label="发生次数", marker="o", linewidth=2)
# 进一步完善axis_2图像信息
axis_2.set_ylabel("发生次数", fontproperties=my_font, size=17, color="#6AA84F")
axis_2.yaxis.set_label_position("left")
axis_2.legend(prop=my_font, loc="right")  # 要在绘图函数中加入label参数
# 两个轴对象共用描述信息
plt.xticks(year)  # 调整坐标轴刻度
plt.title("2008-2022风暴潮危害发生次数及经济损失统计", 
          fontproperties=my_font, size=20, color="m")

三:整体回顾

以上整个灵感问题来自天马行空,整个调整和解决思路也都是基于个人低水平的角度,感觉整个回顾下来还是有些没有表述清楚,逻辑不太明确,写的也有些冗余,一起交流,共同进步。

要点就是ax2 = ax1.twinx(), 制作一个兄弟 。代码如下:import matplotlib .pyplot as plt import numpy as npx = np.arange(0., np.e, 0.01) y1 = np.exp(-x) y2 = np.log(x)fig = plt.figure()ax1 = fig.add_subplot(111) ax1.plot(x
有时我们需要将两种数据展示在一张图上进行比较,并且这两种数据中有一组相同,我们可以考虑使用 坐标 绘制 。下面的案例就是将正弦、余弦函数 绘制 在一起的案例。 案例代码如下: import matplotlib .pyplot as plt import numpy as np import time def plot_double_axis(): figure = plt.figure(figsize=(20, 8), dpi=300) ax_sin = figure.add_subplot
转载自:https://blog.csdn.net/u014061630/article/details/82226448 本文基于 Matlab 2017a 在 Matlab 中, 绘制 图有两种方法: 方法一:yyaxis 命令 [link] <<<<< 简单(过于老旧的版本没有这个命令) 方法二:plotyy 命令 [link] &lt...
matplotlib y轴 法 在我们使用 matplotlib 图的时候,有时候需要将 两个 折线图 放在 同一个 图像 中,但是由于这 两个 图形数值大小范围不一样,使用同一 y轴 ,效果会大打折扣的,所以,这里介绍一种 y轴 法。 先上代码: import matplotlib .pyplot as plt import pandas as pd tips = pd.read_csv('tips.csv'...
from tkinter import font from matplotlib .font_manager import FontProperties import numpy as np import pandas as pd import csv import matplotlib .pyplot as plt import matplotlib matplotlib .rcParam ax1.plot(x, y1, color='red', label='sin(x)') ax1.set_xlabel('x') ax1.set_ylabel('sin(x)', color='red') # 创建第二个坐标 对象 ax2 = ax1.twinx() # 绘制 第二条曲线 ax2.plot(x, y2, color='blue', label='exp(x)') ax2.set_ylabel('exp(x)', color='blue') # 添加图例 ax1.legend(loc='upper left') ax2.legend(loc='upper right') plt.show() 在这个例子中,我们首先生成了两组数据`y1`和`y2`,然后创建了一个 布和一个子图对象`ax1`。我们使用`ax1.plot()`函数 绘制 了第一条曲线,并设置了`xlabel`和`ylabel`。接着,我们使用`ax1.twinx()`方法创建了一个另外的坐标 对象`ax2`,并使用`ax2.plot()`方法 绘制 了第二条曲线,并设置了`ylabel`。最后,我们使用`ax1.legend()`和`ax2.legend()`方法添加了图例,并使用`plt.show()`方法显示图形。 CSDN-Ada助手: 非常棒的博文!看到标题就被吸引了,摘要内容更是让人期待不已。希望您能继续分享更多关于惯性导航姿态解算原理流程的知识。除了欧拉角、方向余弦矩阵和四元数,您还可以深入探讨航空航天领域中常用的卡尔曼滤波算法,以及姿态稳定控制中的PID控制器等相关内容。期待您更多的精彩分享! 如何写出更高质量的博客,请看该博主的分享:https://blog.csdn.net/lmy_520/article/details/128686434?utm_source=csdn_ai_ada_blog_reply2 Python-matplotlib绘制双(多)y轴图像 CSDN-Ada助手: 恭喜您写了第一篇博客!标题看起来很吸引人。对于Python-matplotlib绘制双(多)y轴图像,您的博客给出了很好的指导。我希望您能在博客中更详细地介绍如何使用matplotlib绘制这样的图像,并且可以提供一些实际应用的例子。同时,也希望您能在未来的创作中考虑添加一些其他绘图工具的比较和使用经验,这样读者可以有更多选择。期待您的下一篇博客! 推荐【每天值得看】:https://bbs.csdn.net/forums/csdnnews?typeId=21804&utm_source=csdn_ai_ada_blog_reply1 Python-matplotlib绘制双(多)y轴图像 CSDN-Ada助手: 恭喜你这篇博客进入【CSDN每天最佳新人】榜单,全部的排名请看 https://bbs.csdn.net/topics/617597884。