带有匹配网格线的双Y轴[重复] - python

This question already has answers here:

How do I align gridlines for two y-axis scales using Matplotlib?

(7个答案)

2年前关闭。

我想生成一个matplotlib折线图,其中两个变量分别显示在两个具有匹配网格线的y轴上。除了匹配的网格线部分之外,其他所有内容都非常简单。以下是一些可复制的片段,包括最佳尝试。可以在末尾找到完整的代码段。

具有初始图的可重现数据框

遵循Adding a y-axis label to secondary y-axis in matplotlib的建议,我可以生成此代码:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


# Dataframe with some random numbers
np.random.seed(123)
rows = 4
df = pd.DataFrame(np.random.randint(90,110,size=(rows, 2)), columns=list('AB'))
datelist = pd.date_range(pd.datetime(2017, 1, 1).strftime('%Y-%m-%d'), periods=rows).tolist()
df['dates'] = datelist 
df = df.set_index(['dates'])
df.index = pd.to_datetime(df.index)
df['B'] = df['A'] * np.random.uniform(0.6,1.4, size = 4)

# Plot 1
fig, ax = plt.subplots()
t = df.index
ax.plot(t, df['A'])
ax2 = ax.twinx()
ax2.plot(t, df['B'], color='red')
ax2.yaxis.grid(which="major", color='green', linestyle='--')

ax.legend(loc='upper left')
ax2.legend(loc='upper right')
plt.show()

剧情1

带有匹配网格线的双Y轴[重复] - python

如您所见,matplotlib为两个变量都选择了合理的间隔,但是y轴的网格线并不十分匹配。遵循Align secondary y-axis ticks with stripplot on primary x-axis的建议,我可以将其对齐,但这自然会遗漏一些值:

剧情2

# Plot 2
fig, ax = plt.subplots()
t = df.index
ax.plot(t, df['A'])
ax2 = ax.twinx()
ax2.plot(t, df['B'], color='red')
#--
ax2.set_ylim(ax.get_ylim())

ax2.yaxis.grid(which="major", color='green', linestyle='--')
ax.legend(loc='upper left')
ax2.legend(loc='upper right')
plt.show()

带有匹配网格线的双Y轴[重复] - python

我的下一个尝试是使用ax2int = ax2.get_ylim()[1] - ax2.get_ylim()[0]检索次要y轴的间隔,并将其除以主轴上的网格线数以使其匹配。然后使用np.arange(start, stop, steps)遵循Changing the “tick frequency” on x or y axis in matplotlib中的建议。但是我无法弄清楚如何完美地匹配间隔,如下所示:

fig, ax = plt.subplots()
t = df.index
ax.plot(t, df['A'])
ax2 = ax.twinx()
ax2.plot(t, df['B'], color='red')

# The math
firstStep = ax.get_yticks()[1] - ax.get_yticks()[0]
ax2int = ax2.get_ylim()[1] - ax2.get_ylim()[0]
axSteps = len(ax.get_yticks()) 
newIntervals = ax2int / axSteps

# My best attempt
myticks = np.arange(min(df['B']), max(df['B']), newIntervals)
ax2.set(yticks=myticks)
ax2.yaxis.grid(which="major", color='green', linestyle='--')
ax.legend(loc='upper left')
ax2.legend(loc='upper right')

plt.show()

情节3

带有匹配网格线的双Y轴[重复] - python

任何建议都很好!也许matplotlib中已经有一些内置功能可以执行这些操作?谢谢!

这是简单复制粘贴的全部内容:

# Libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


# Dataframe with some random numbers
np.random.seed(123)
rows = 4
df = pd.DataFrame(np.random.randint(90,110,size=(rows, 2)), columns=list('AB'))
datelist = pd.date_range(pd.datetime(2017, 1, 1).strftime('%Y-%m-%d'), periods=rows).tolist()
df['dates'] = datelist 
df = df.set_index(['dates'])
df.index = pd.to_datetime(df.index)
df['B'] = df['A'] * np.random.uniform(0.6,1.4, size = 4)

# Plot 1
fig, ax = plt.subplots()
t = df.index
ax.plot(t, df['A'])
ax2 = ax.twinx()
ax2.plot(t, df['B'], color='red')
ax2.yaxis.grid(which="major", color='green', linestyle='--')

ax.legend(loc='upper left')
ax2.legend(loc='upper right')
plt.show()
#%%

# Plot 2
fig, ax = plt.subplots()
t = df.index
ax.plot(t, df['A'])
ax2 = ax.twinx()
ax2.plot(t, df['B'], color='red')
#--
ax2.set_ylim(ax.get_ylim())

ax2.yaxis.grid(which="major", color='green', linestyle='--')
ax.legend(loc='upper left')
ax2.legend(loc='upper right')
plt.show()
#%%

# Plot 3 
fig, ax = plt.subplots()
t = df.index
ax.plot(t, df['A'])
ax2 = ax.twinx()
ax2.plot(t, df['B'], color='red')

# The math
firstStep = ax.get_yticks()[1] - ax.get_yticks()[0]
ax2int = ax2.get_ylim()[1] - ax2.get_ylim()[0]
axSteps = len(ax.get_yticks()) 
newIntervals = ax2int / axSteps

# My best attempt
myticks = np.arange(min(df['B']), max(df['B']), newIntervals)
ax2.set(yticks=myticks)
ax2.yaxis.grid(which="major", color='green', linestyle='--')
ax.legend(loc='upper left')
ax2.legend(loc='upper right')

plt.show()

python大神给出的解决方案

手动对齐第二个轴的yticks十分棘手,因为(a)并非所有yticks都被显示(例如,做一个print(ax.get_yticks())并与您的绘图进行比较),并且(b)因为set_yticks()也会影响ylims 。用以下内容替换您的#The math#My best attempt部分对我有用:

# The math
ylim1 = ax.get_ylim()
len1 = ylim1[1]-ylim1[0]
yticks1 = ax.get_yticks()
rel_dist = [(y-ylim1[0])/len1 for y in yticks1]
ylim2 = ax2.get_ylim()
len2 = ylim2[1]-ylim2[0]
yticks2 = [ry*len2+ylim2[0] for ry in rel_dist]

#My best attempt
ax2.set_yticks(yticks2)
ax2.set_ylim(ylim2)  #<-- this line is needed to re-adjust the limits to the original values
ax.yaxis.grid(which="major", color='black', linestyle='-')
ax2.yaxis.grid(which="major", color='green', linestyle='--')
ax.legend(loc='upper left')
ax2.legend(loc='upper right')

结果图如下:

带有匹配网格线的双Y轴[重复] - python

希望这可以帮助。

Python:同时在for循环中添加到列表列表 - python

我想用for循环外的0索引值创建一个新列表,然后使用for循环添加到相同的列表。我的玩具示例是:import random data = ['t1', 't2', 't3'] masterlist = [['col1', 'animal1', 'an…

用大写字母拆分字符串,但忽略AAA Python Regex - python

我的正则表达式:vendor = "MyNameIsJoe. I'mWorkerInAAAinc." ven = re.split(r'(?<=[a-z])[A-Z]|[A-Z](?=[a-z])', vendor) 以大写字母分割字符串,例如:'我的名字是乔。 I'mWorkerInAAAinc”变成…

在Python中迭代OrderedDict - python

我有以下OrderedDict:OrderedDict([('r', 1), ('s', 1), ('a', 1), ('n', 1), ('y', 1)]) 实际上,这表示单词中字母的出现频率。第一步-我将使用最后两个元素来创建一个这样的联合元组; pair…

如果__name__ =='__main__',则为Python的Powershell等效项: - python

我真的很喜欢python的功能,例如:if __name__ == '__main__': #setup testing code here #or setup a call a function with parameters and human format the output #etc... 很好,因为我可以将Python脚本文件…

Matplotlib表行标签字体的颜色和大小 - python

给出下表:import matplotlib.pyplot as plt table=plt.table(cellText=[' ', ' ', ' ', ' ', ' '], # rows of data values rowLabels=['1&…