matplotlib 中的日期刻度和旋转
Posted
技术标签:
【中文标题】matplotlib 中的日期刻度和旋转【英文标题】:Date ticks and rotation in matplotlib 【发布时间】:2012-07-01 03:31:05 【问题描述】:我在尝试让我的日期刻度在 matplotlib 中旋转时遇到问题。下面是一个小示例程序。如果我尝试在最后旋转刻度,则刻度不会旋转。如果我尝试旋转注释“崩溃”下显示的刻度,则 matplot lib 崩溃。
仅当 x 值为日期时才会发生这种情况。如果我在对avail_plot
的调用中将变量dates
替换为变量t
,那么xticks(rotation=70)
调用在avail_plot
中就可以正常工作。
有什么想法吗?
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
def avail_plot(ax, x, y, label, lcolor):
ax.plot(x,y,'b')
ax.set_ylabel(label, rotation='horizontal', color=lcolor)
ax.get_yaxis().set_ticks([])
#crashes
#plt.xticks(rotation=70)
ax2 = ax.twinx()
ax2.plot(x, [1 for a in y], 'b')
ax2.get_yaxis().set_ticks([])
ax2.set_ylabel('testing')
f, axs = plt.subplots(2, sharex=True, sharey=True)
t = np.arange(0.01, 5, 1)
s1 = np.exp(t)
start = dt.datetime.now()
dates=[]
for val in t:
next_val = start + dt.timedelta(0,val)
dates.append(next_val)
start = next_val
avail_plot(axs[0], dates, s1, 'testing', 'green')
avail_plot(axs[1], dates, s1, 'testing2', 'red')
plt.subplots_adjust(hspace=0, bottom=0.3)
plt.yticks([0.5,],("",""))
#doesn't crash, but does not rotate the xticks
#plt.xticks(rotation=70)
plt.show()
【问题讨论】:
在 x 轴上创建带有日期的绘图是一项常见的任务 - 可惜没有更完整的示例。 我想知道这是否与 ***.com/questions/10998621/… 重复 【参考方案1】:如果您更喜欢非面向对象的方法,请将plt.xticks(rotation=70)
移动到右侧在两个avail_plot
调用之前,例如
plt.xticks(rotation=70)
avail_plot(axs[0], dates, s1, 'testing', 'green')
avail_plot(axs[1], dates, s1, 'testing2', 'red')
这会在设置标签之前设置旋转属性。由于您在这里有两个轴,plt.xticks
在您制作了这两个图后会感到困惑。当plt.xticks
不做任何事情时,plt.gca()
确实 not 为您提供要修改的轴,因此作用于当前轴的 plt.xticks
不会执行上班。
对于不使用plt.xticks
的面向对象方法,您可以使用
plt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70 )
在两个avail_plot
调用之后。这会专门设置正确轴上的旋转。
【讨论】:
另一件方便的事情:当您调用plt.setp
时,您可以通过将多个参数指定为附加关键字参数来设置它们。 horizontalalignment
kwarg 在您旋转刻度标签时特别有用:plt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70, horizontalalignment='right' )
我不喜欢这个解决方案,因为它混合了 pyplot 和面向对象的方法。您可以在任何地方拨打ax.tick_params(axis='x', rotation=70)
。
@TedPetrou 这里的“混合”是什么意思? plt.setp
解决方案完全面向对象。如果您不喜欢其中有一些plt
,请改用from matplotlib.artist import setp; setp(ax.get_xticklabels(), rotation=90)
。
@ImportanceOfBeingErnest 第一行代码使用plt.xticks
,即pyplot。文档本身说不要混合样式。 plt.setp
更冗长,但也不是典型的面向对象风格。你的答案绝对是这里最好的。基本上,任何具有函数的东西都不是面向对象的。是否导入setp
都没关系。
大部分问题的代码都使用了pyplot,比如yticks
,而且代码在avail_plot
之外根本没有定义ax...【参考方案2】:
将horizontalalignment
和rotation
应用于每个刻度标签的另一种方法是对要更改的刻度标签执行for
循环:
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
now = dt.datetime.now()
hours = [now + dt.timedelta(minutes=x) for x in range(0,24*60,10)]
days = [now + dt.timedelta(days=x) for x in np.arange(0,30,1/4.)]
hours_value = np.random.random(len(hours))
days_value = np.random.random(len(days))
fig, axs = plt.subplots(2)
fig.subplots_adjust(hspace=0.75)
axs[0].plot(hours,hours_value)
axs[1].plot(days,days_value)
for label in axs[0].get_xmajorticklabels() + axs[1].get_xmajorticklabels():
label.set_rotation(30)
label.set_horizontalalignment("right")
如果你想控制主要和次要刻度的位置,这里有一个例子:
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
fig, axs = plt.subplots(2)
fig.subplots_adjust(hspace=0.75)
now = dt.datetime.now()
hours = [now + dt.timedelta(minutes=x) for x in range(0,24*60,10)]
days = [now + dt.timedelta(days=x) for x in np.arange(0,30,1/4.)]
axs[0].plot(hours,np.random.random(len(hours)))
x_major_lct = mpl.dates.AutoDateLocator(minticks=2,maxticks=10, interval_multiples=True)
x_minor_lct = matplotlib.dates.HourLocator(byhour = range(0,25,1))
x_fmt = matplotlib.dates.AutoDateFormatter(x_major_lct)
axs[0].xaxis.set_major_locator(x_major_lct)
axs[0].xaxis.set_minor_locator(x_minor_lct)
axs[0].xaxis.set_major_formatter(x_fmt)
axs[0].set_xlabel("minor ticks set to every hour, major ticks start with 00:00")
axs[1].plot(days,np.random.random(len(days)))
x_major_lct = mpl.dates.AutoDateLocator(minticks=2,maxticks=10, interval_multiples=True)
x_minor_lct = matplotlib.dates.DayLocator(bymonthday = range(0,32,1))
x_fmt = matplotlib.dates.AutoDateFormatter(x_major_lct)
axs[1].xaxis.set_major_locator(x_major_lct)
axs[1].xaxis.set_minor_locator(x_minor_lct)
axs[1].xaxis.set_major_formatter(x_fmt)
axs[1].set_xlabel("minor ticks set to every day, major ticks show first day of month")
for label in axs[0].get_xmajorticklabels() + axs[1].get_xmajorticklabels():
label.set_rotation(30)
label.set_horizontalalignment("right")
【讨论】:
这在 matplotlib v1.5.1 上对我有用(我在工作中被困在 matplotlib 的旧版本上,不要问为什么) 我刚刚用 python3.6 和 matplotlib v2.2.2 测试过,它也可以。【参考方案3】:避免在ticklabes上循环的简单解决方案是使用
fig.autofmt_xdate()
此命令会自动旋转 xaxis 标签并调整它们的位置。默认值为 30° 旋转角度和水平对齐“右”。但是可以在函数调用中改变它们
fig.autofmt_xdate(bottom=0.2, rotation=30, ha='right')
额外的bottom
参数等效于设置plt.subplots_adjust(bottom=bottom)
,它允许将底部轴填充设置为更大的值以承载旋转的刻度标签。
所以基本上在这里,您可以在一个命令中拥有一个漂亮的日期轴所需的所有设置。
good example 可以在 matplotlib 页面上找到。
【讨论】:
很好的答案!谢谢! 可以通过这个函数控制'rotation_mode'参数吗? @TheoryX 否。如果您需要rotation_mode,您需要使用plt.setp
方法,或者在刻度上循环(基本上相同)。
是的,只有当 x 轴出现在图表底部时,它才是一个简单的解决方案。但是,当 x 轴位于图表顶部或存在两个 x 轴 (twinx
) 时,它会打乱刻度和刻度标签之间的对齐方式。在这种情况下,Ted Petrou 的解决方案会更好。
@Śubham 正确。这主要是针对最常见情况的所有其他解决方案的捷径。【参考方案4】:
解决方案适用于 matplotlib 2.1+
有一个坐标轴方法tick_params
可以更改刻度属性。它也作为轴方法存在,如set_tick_params
ax.tick_params(axis='x', rotation=45)
或者
ax.xaxis.set_tick_params(rotation=45)
附带说明一下,当前解决方案通过使用命令plt.xticks(rotation=70)
将有状态接口(使用 pyplot)与面向对象接口混合。由于问题中的代码使用面向对象的方法,因此最好始终坚持这种方法。该解决方案确实提供了一个很好的明确解决方案,plt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70 )
【讨论】:
是否可以更改所有绘图的默认旋转?我想我需要在我制作的每一个情节上都改变这一点。 这里似乎是最OOP的方法。【参考方案5】:简单使用
ax.set_xticklabels(label_list, rotation=45)
【讨论】:
【参考方案6】:我显然迟到了,但有一个官方示例使用
plt.setp(ax.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor")
旋转标签,同时保持它们与刻度线正确对齐,既干净又容易。
参考:https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html
【讨论】:
以上是关于matplotlib 中的日期刻度和旋转的主要内容,如果未能解决你的问题,请参考以下文章
python使用matplotlib可视化为X轴添加自定义文本轴刻度标签并旋转轴刻度标签(rotate custom text tick labels in matplotlib)
如何在 matplotlib 条形图上旋转 x 轴刻度标签?尝试了几种方法,都没有奏效
如何在 matplotlib 条形图上旋转 x 轴刻度标签?尝试了几种方法,都没有奏效
python matplotlib刻度(含日期刻度处理),标签,网格
python使用matplotlib可视化自定义Y轴轴标签刻度旋转的角度(customize degree rotating axis tick labels in matplotlib)