Python 尽管尽了最大努力,Matplotlib 仍显示 x-tick 标签重叠

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26700598/
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:53:52  来源:igfitidea点击:

Matplotlib showing x-tick labels overlapping despite best efforts

pythonpandasmatplotlib

提问by 8one6

Have a look at the graph below: enter image description here

看看下面的图表: 在此处输入图片说明

It's a subplot of this larger figure: enter image description here

这是这个大图的一个子图: 在此处输入图片说明

I see two problems with it. First, the x-axis labels overlap with one another (this is my major issue). Second. the location of the x-axis minor gridlines seems a bit wonky. On the left of the graph, they look properly spaced. But on the right, they seem to be crowding the major gridlines...as if the major gridline locations aren't proper multiples of the minor tick locations.

我看到它有两个问题。首先,x 轴标签彼此重叠(这是我的主要问题)。第二。x 轴次要网格线的位置似乎有点不稳定。在图表的左侧,它们看起来间隔适当。但在右侧,它们似乎挤满了主要网格线……好像主要网格线位置不是次要刻度线位置的正确倍数。

My setup is that I have a DataFrame called dfwhich has a DatetimeIndexon the rows and a column called valuewhich contains floats. I can provide an example of the dfcontents in a gist if necessary. A dozen or so lines of dfare at the bottom of this post for reference.

我的设置是我有一个名为 DataFrame 的数据帧df,它在行上有一个DatetimeIndex,而在一个列上有一个value包含浮点数的列。df如有必要,我可以在要点中提供内容示例。df这篇文章的底部有十多行供参考。

Here's the code that produces the figure:

这是生成图形的代码:

now = dt.datetime.now()

fig, axes = plt.subplots(2, 2, figsize=(15, 8), dpi=200)
for i, d in enumerate([360, 30, 7, 1]):
    ax = axes.flatten()[i]
    earlycut = now - relativedelta(days=d)
    data = df.loc[df.index>=earlycut, :]
    ax.plot(data.index, data['value'])
    ax.xaxis_date()

    ax.get_xaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())
    ax.get_yaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())

    ax.grid(b=True, which='major', color='w', linewidth=1.5)
    ax.grid(b=True, which='minor', color='w', linewidth=0.75)

What is my best option here to get the x-axis labels to stop overlapping each other (in each of the four subplots)? Also, separately (but less urgently), what's up with the minor tick issue in the top-left subplot?

我在这里让 x 轴标签停止相互重叠的最佳选择是什么(在四个子图中的每一个中)?另外,单独(但不太紧急),左上角子图中的小刻度问题是怎么回事?

I am on Pandas 0.13.1, numpy 1.8.0, and matplotlib 1.4.x.

我在 Pandas 0.13.1、numpy 1.8.0 和 matplotlib 1.4.x 上。

Here's a small snippet of dffor reference:

这里有一个小片段df供参考:

                                    id scale  tempseries_id    value
timestamp                                                           
2014-11-02 14:45:10.302204+00:00  7564     F              1  68.0000
2014-11-02 14:25:13.532391+00:00  7563     F              1  68.5616
2014-11-02 14:15:12.102229+00:00  7562     F              1  68.9000
2014-11-02 14:05:13.252371+00:00  7561     F              1  69.0116
2014-11-02 13:55:11.792191+00:00  7560     F              1  68.7866
2014-11-02 13:45:10.782227+00:00  7559     F              1  68.6750
2014-11-02 13:35:10.972248+00:00  7558     F              1  68.4500
2014-11-02 13:25:10.362213+00:00  7557     F              1  68.1116
2014-11-02 13:15:10.822247+00:00  7556     F              1  68.2250
2014-11-02 13:05:10.102200+00:00  7555     F              1  68.5616
2014-11-02 12:55:10.292217+00:00  7554     F              1  69.0116
2014-11-02 12:45:10.382226+00:00  7553     F              1  69.3500
2014-11-02 12:35:10.642245+00:00  7552     F              1  69.2366
2014-11-02 12:25:12.642255+00:00  7551     F              1  69.1250
2014-11-02 12:15:11.122382+00:00  7550     F              1  68.7866
2014-11-02 12:05:11.332224+00:00  7549     F              1  68.5616
2014-11-02 11:55:11.662311+00:00  7548     F              1  68.2250
2014-11-02 11:45:11.122193+00:00  7547     F              1  68.4500
2014-11-02 11:35:11.162271+00:00  7546     F              1  68.7866
2014-11-02 11:25:12.102211+00:00  7545     F              1  69.2366
2014-11-02 11:15:10.422226+00:00  7544     F              1  69.4616
2014-11-02 11:05:11.412216+00:00  7543     F              1  69.3500
2014-11-02 10:55:10.772212+00:00  7542     F              1  69.1250
2014-11-02 10:45:11.332220+00:00  7541     F              1  68.7866
2014-11-02 10:35:11.332232+00:00  7540     F              1  68.5616
2014-11-02 10:25:11.202411+00:00  7539     F              1  68.2250
2014-11-02 10:15:11.932326+00:00  7538     F              1  68.5616
2014-11-02 10:05:10.922229+00:00  7537     F              1  68.9000
2014-11-02 09:55:11.602357+00:00  7536     F              1  69.3500

Edit: Trying fig.autofmt_xdate(): I don't think this going to do the trick. This seems to use the same x-tick labels for both graphs on the left and also for both graphs on the right. Which is not correct given my data. Please see the problematic output below:

编辑:尝试fig.autofmt_xdate():我认为这不会奏效。这似乎对左侧的两个图和右侧的两个图使用相同的 x-tick 标签。鉴于我的数据,这是不正确的。请查看下面有问题的输出:

enter image description here

在此处输入图片说明

采纳答案by 8one6

Ok, finally got it working. The trick was to use plt.setpto manually rotate the tick labels. Using fig.autofmt_xdate()did not work as it does some unexpected things when you have multiple subplots in your figure. Here's the working code with its output:

好的,终于可以运行了。诀窍是用来plt.setp手动旋转刻度标签。使用fig.autofmt_xdate()不起作用,因为当您的图中有多个子图时,它会做一些意想不到的事情。这是带有输出的工作代码:

for i, d in enumerate([360, 30, 7, 1]):
    ax = axes.flatten()[i]
    earlycut = now - relativedelta(days=d)
    data = df.loc[df.index>=earlycut, :]
    ax.plot(data.index, data['value'])

    ax.get_xaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())
    ax.get_yaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())

    ax.grid(b=True, which='major', color='w', linewidth=1.5)
    ax.grid(b=True, which='minor', color='w', linewidth=0.75)

    plt.setp(ax.get_xticklabels(), rotation=30, horizontalalignment='right')

fig.tight_layout()

enter image description here

在此处输入图片说明

By the way, the comment earlier about some matplotlib things taking forever is very interesting here. I'm using a raspberry pi to act as a weather station at a remote location. It's collecting the data and serving the results via the web. And boy oh boy, it's really wheezing trying to put out these graphics.

顺便说一下,之前关于一些 matplotlib 的东西永远需要的评论在这里非常有趣。我正在使用树莓派作为远程位置的气象站。它正在收集数据并通过网络提供结果。天哪,天哪,试图推出这些图形真的让人喘不过气来。

回答by Joe Kington

Due to the way text rendering is handled in matplotlib, auto-detecting overlapping text really slows things down. (The space that text takes up can't be accurately calculated until after it's been drawn.) For that reason, matplotlib doesn't try to do this automatically.

由于在 matplotlib 中处理文本渲染的方式,自动检测重叠文本确实会减慢速度。(文本占用的空间在绘制之后才能准确计算。)因此,matplotlib 不会尝试自动执行此操作。

Therefore, it's best to rotate long tick labels. Because dates most commonly have this problem, there's a figure method fig.autofmt_xdate()that will (among other things) rotate the tick labels to make them a bit more readable. (Note: If you're using a pandas plotmethod, it returns an axes object, so you'll need to use ax.figure.autofmt_xdate().)

因此,最好旋转长刻度标签。因为日期最常有这个问题,所以有一种 figure 方法fig.autofmt_xdate()可以(除其他外)旋转刻度标签,使它们更具可读性。(注意:如果您使用的是 pandasplot方法,它会返回一个轴对象,因此您需要使用ax.figure.autofmt_xdate().)

As a quick example:

举个简单的例子:

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

time = pd.date_range('01/01/2014', '4/01/2014', freq='H')
values = np.random.normal(0, 1, time.size).cumsum()

fig, ax = plt.subplots()
ax.plot_date(time, values, marker='', linestyle='-')

fig.autofmt_xdate()
plt.show()

If we were to leave fig.autofmt_xdate()out:

如果我们要离开fig.autofmt_xdate()

enter image description here

在此处输入图片说明

And if we use fig.autofmt_xdate():

如果我们使用fig.autofmt_xdate()

enter image description here

在此处输入图片说明