如何使用Matplotlib对齐两个y轴刻度的网格线?

时间:2014-11-05 08:18:48

标签: python matplotlib plot seaborn

我在y轴上绘制了两个不同单位的数据集。有没有办法让刻度线和网格线在两个y轴上对齐?

第一张图片显示了我得到的内容,第二张图片显示了我想要的内容。

这是我用来绘制的代码:

import seaborn as sns
import numpy as np
import pandas as pd

np.random.seed(0)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(pd.Series(np.random.uniform(0, 1, size=10)))
ax2 = ax1.twinx()
ax2.plot(pd.Series(np.random.uniform(10, 20, size=10)), color='r')

Example of unwanted behavior

Example of wanted behavior

8 个答案:

答案 0 :(得分:25)

我不确定这是否是最漂亮的方式,但它确实用一行修复它:

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

np.random.seed(0)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(pd.Series(np.random.uniform(0, 1, size=10)))
ax2 = ax1.twinx()
ax2.plot(pd.Series(np.random.uniform(10, 20, size=10)), color='r')

# ADD THIS LINE
ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())))

plt.show()

答案 1 :(得分:8)

我可以通过停用其中一个网格轴中的ax.grid(None)来解决这个问题:

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

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(pd.Series(np.random.uniform(0, 1, size=10)))
ax2 = ax1.twinx()
ax2.plot(pd.Series(np.random.uniform(10, 20, size=10)), color='r')
ax2.grid(None)

plt.show()

Figure Result

答案 2 :(得分:8)

我写了这个函数,它采用Matplotlib轴对象ax1,ax2和float minresax1 minresax2:

def align_y_axis(ax1, ax2, minresax1, minresax2):
    """ Sets tick marks of twinx axes to line up with 7 total tick marks

    ax1 and ax2 are matplotlib axes
    Spacing between tick marks will be a factor of minresax1 and minresax2"""

    ax1ylims = ax1.get_ybound()
    ax2ylims = ax2.get_ybound()
    ax1factor = minresax1 * 6
    ax2factor = minresax2 * 6
    ax1.set_yticks(np.linspace(ax1ylims[0],
                               ax1ylims[1]+(ax1factor -
                               (ax1ylims[1]-ax1ylims[0]) % ax1factor) %
                               ax1factor,
                               7))
    ax2.set_yticks(np.linspace(ax2ylims[0],
                               ax2ylims[1]+(ax2factor -
                               (ax2ylims[1]-ax2ylims[0]) % ax2factor) %
                               ax2factor,
                               7))

它计算并设置刻度,使得有七个刻度。最低刻度对应于当前最低刻度并增加最高刻度,使得每个刻度之间的间隔是minrexax1或minrexax2的整数倍。

为了使其一般,您可以通过将您看到的所有7更改为刻度总数来设置所需的刻度总数,并将6更改为刻度总数减1

我提出了一个拉请求,将其中的一些内容合并到matplotlib.ticker.LinearLocator中:

https://github.com/matplotlib/matplotlib/issues/6142

将来(也许是Matplotlib 2.0?),试试:

import matplotlib.ticker
nticks = 11
ax1.yaxis.set_major_locator(matplotlib.ticker.LinearLocator(nticks))
ax2.yaxis.set_major_locator(matplotlib.ticker.LinearLocator(nticks))

这应该只是工作并为两个y轴选择方便的刻度。

答案 3 :(得分:1)

此代码将确保来自两个轴的网格彼此对齐,而不必隐藏任一组中的网格线。在此示例中,它允许您匹配任何更精细的网格线。这基于@Leo的想法。希望它有所帮助!

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

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(pd.Series(np.random.uniform(0,1,size=10)))
ax2 = ax1.twinx()
ax2.plot(pd.Series(np.random.uniform(10,20,size=10)),color='r')
ax2.grid(None)

# Determine which plot has finer grid. Set pointers accordingly
l1 = len(ax1.get_yticks())
l2 = len(ax2.get_yticks())
if l1 > l2:
  a = ax1
  b = ax2
  l = l1
else:
  a = ax2
  b = ax1
  l = l2

# Respace grid of 'b' axis to match 'a' axis
b_ticks = np.linspace(b.get_yticks()[0],b.get_yticks()[-1],l)
b.set_yticks(b_ticks)

plt.show()

答案 4 :(得分:1)

这已经在一段时间前得到正确回答: trouble aligning ticks for matplotlib twinx axes

(这里给出的答案对于一般情况根本不起作用)

答案 5 :(得分:0)

如果你正在使用轴标签,由于刻度中数字的精确度,Leo的解决方案可以push them off the side

所以除了像Leo的解决方案(这里重复)之外,

ax2.set_yticks(np.linspace(ax2.get_yticks()[0],ax2.get_yticks()[-1],len(ax1.get_yticks())))

您可以使用this answer中提到的autolayout设置;例如,在您的脚本中,您可以更新rcParams

from matplotlib import rcParams
rcParams.update({'figure.autolayout': True})

在一些测试用例中,这似乎产生了预期的结果,输出中完全包含了排列的标记和标签。

答案 6 :(得分:0)

我有同样的问题,除了这是辅助x轴。我通过将辅助x轴设置为等于我的主轴的限制来解决。下面的示例没有将第二轴的限制设置为等于第一轴:ax2 = ax.twiny() enter image description here

一旦我将第二轴的极限设置为等于第一个ax2.set_xlim(ax.get_xlim()),这是我的结果: enter image description here

答案 7 :(得分:0)

我创建了一种方法来对齐多个y轴的刻度线(可能大于2个),并且在不同的轴上刻度可能不同。

下面是一个示例图: enter image description here

有3个y轴,左边是一个蓝色,右边是绿色和红色。将3条曲线以相应的颜色绘制到y轴上。请注意,它们的数量级都非常不同。

  • 左图:未对齐。
  • 中间图:对齐(大约)每个y轴的下限。
  • 右图:按指定值对齐:@Test public void splitByMultiple() { String input = "aa|bb cc"; final List<String> asList = Arrays.asList(input.split("[ |]")); assertThat(asList, contains("aa", "bb", "cc")); } 表示蓝色,0表示红色,2.2*1e8表示绿色。那些是任意选择的。

我正在做的是将每个y数组缩放到1-100的范围内,然后将所有缩放后的y值合并到一个数组中,并使用{{1} }。然后,使用相应的缩放比例来缩放这组新的滴答声,以获取每个轴的新滴答声。如果需要某些特定的对齐方式,则y数组在缩放之前会先移位,然后再移位回去。

在此处完成代码(关键功能是44):

MaxNLocator