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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26752464/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:58:37  来源:igfitidea点击:

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

pythonmatplotlibplotseaborn

提问by Artturi Bj?rk

I'm plotting two datasets with different units on the y-axis. Is there a way to make the ticks and gridlines aligned on both y-axes?

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

The first image shows what I get, and the second image shows what I would like to get.

第一张图显示了我得到的东西,第二张图显示了我想要得到的东西。

This is the code I'm using to plot:

这是我用来绘制的代码:

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

通缉行为示例

采纳答案by Leo

I am not sure if this is the prettiest way to do it, but it does fix it with one line:

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

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()

回答by arnaldo

I could solve it by deactivating ax.grid(None)in one of the grid`s axes:

我可以通过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

图结果

回答by Scott Howard

I wrote this function that takes Matplotlib axes objects ax1, ax2, and floats minresax1 minresax2:

我编写了这个函数,它接受 Matplotlib 轴对象 ax1、ax2 和浮动 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))

It calculates and sets the ticks such that there are seven ticks. The lowest tick corresponds to the current lowest tick and increases the highest tick such that the separation between each tick is integer multiples of minrexax1 or minrexax2.

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

To make it general, you can set the total number of ticks you want by changing ever 7you see to the total number of ticks, and change 6to the total number of ticks minus 1.

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

I put a pull request in to incorporate some this into matplotlib.ticker.LinearLocator:

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

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

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

In the future (Matplotlib 2.0 perhaps?), try:

将来(也许是 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))

That should just work and choose convenient ticks for both y-axes.

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

回答by Jonathan W.

If you're using axis labels, Leo's solution can push them off the side, due to the precision of the numbers in the ticks.

如果您使用轴标签,由于刻度中数字的精度,Leo 的解决方案可以将它们推离一边

So in addition to something like Leo's solution (repeated here),

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

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

you can use the autolayoutsetting, as mentioned in this answer; e.g., earlier in your script you can update rcParams:

您可以使用此答案中autolayout提到的设置;例如,在您的脚本的早期,您可以更新:rcParams

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

In a few test cases, this appears to produce the expected result, with both lined-up ticks and labels fully contained in the output.

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

回答by John

This code will ensure that grids from both axes align to each other, without having to hide gridlines from either set. In this example, it allows you to match whichever has the finer grid lines. This builds off of the idea from @Leo. Hope it helps!

此代码将确保来自两个轴的网格彼此对齐,而不必隐藏任一组的网格线。在此示例中,它允许您匹配具有更细网格线的任何一个。这是建立在@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()

回答by Hugo Alain Oliva

I had the same issue except this was for a secondary x axis. I solved by setting my secondary x axis equal to the limit of my primary axis.The example below is without setting the limit of the second axis equal to the first:ax2 = ax.twiny()enter image description here

我有同样的问题,但这是针对辅助 x 轴的。我通过将第二个 x 轴设置为等于我的主轴的限制来解决。下面的示例没有将第二个轴的限制设置为等于第一个:ax2 = ax.twiny()在此处输入图片说明

Once I set the limit of the second axis equal to the first ax2.set_xlim(ax.get_xlim())here is my result: enter image description here

一旦我将第二个轴的限制设置为等于第一个,ax2.set_xlim(ax.get_xlim())这是我的结果: 在此处输入图片说明

回答by raphael

this has already been properly answered a while ago: trouble aligning ticks for matplotlib twinx axes

这已经在不久前得到了正确的回答: 在 matplotlib twinx 轴上对齐刻度的问题

(the answer given in here is not at all working for a general case)

(此处给出的答案根本不适用于一般情况)