pandas DataFrame 图 - 无法为 timedelta 值设置 xtick 间隔
pandas DataFrame plot - impossible to set xtick intervals for timedelta values
我试图在绘制 DataFrame 时指定 x 轴间隔。我有几个数据文件,例如
0:0:0 29
0:5:0 85
0:10:0 141
0:15:0 198
0:20:0 251
0:25:0 308
0:30:0 363
0:35:0 413
第一列是 %H:%M:%S 格式的时间,但小时数超过 24 小时(直到 48 小时)。
当我读取如下文件并绘图时,它看起来不错,但我想将 xticks 间隔设置为 8 小时。
df0 = pd.read_csv(fil, names=['Time', 'Count'], delim_whitespace=True, parse_dates=['Time'])
df0 = df0.set_index('Time')
ax = matplotlib.pyplot.gca()
mkfunc = lambda x, pos: '%1.1fM' % (x * 1e-6) if x >= 1e6 else '%1.1fK' % (x * 1e-3) if x >= 1e3 else '%1.1f' % x
mkformatter = matplotlib.ticker.FuncFormatter(mkfunc)
ax.yaxis.set_major_formatter(mkformatter)
ax.xaxis.set_major_locator(mdates.HourLocator(interval=8))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H'))
df0.plot(ax=ax, x_compat=True, color='blue')
plt.grid()
plt.savefig('figure2.pdf',dpi=300, bbox_inches = "tight")
我尝试了这里许多答案指定的上述方法,但导致了以下警告,
Locator attempting to generate 1874 ticks ([-28.208333333333332, ..., 596.125]), which exceeds Locator.MAXTICKS (1000).
图中还出现了很多竖线。
我尝试将我的时间列专门转换为 timedelta,但仍然没有帮助。
我如下转换为 timedelta。
custom_date_parser = lambda x: pd.to_timedelta(x.split('.')[0])
df0 = pd.read_csv(fil, names=['Time', 'Count'], delim_whitespace=True, parse_dates=['Time']), date_parser=custom_date_parser)
你能帮我找出问题并正确设置 xticks 间隔吗?
这里的问题是 a) matplotlib/pandas 对 timedelta 对象没有太多支持,b) 您不能将 HourLocator 用于您的数据,因为在转换为 datetime 对象后,您的轴将被标记0, 8, 16, 0, 8, 16...
相反,我们可以将您的转换器导入的 timedelta 转换为小时并绘制数值:
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
import numpy as np
custom_date_parser = lambda x: pd.to_timedelta(x.split('.')[0])
df0 = pd.read_csv("test.txt", names=['Time', 'Count'], delim_whitespace=True, parse_dates=['Time'], date_parser=custom_date_parser)
#conversion into numerical hour value
df0["Time"] /= np.timedelta64(1, "h")
df0 = df0.set_index('Time')
ax = matplotlib.pyplot.gca()
df0.plot(ax=ax, x_compat=True, color='blue')
mkfunc = lambda x, pos: '%1.1fM' % (x * 1e-6) if x >= 1e6 else '%1.1fK' % (x * 1e-3) if x >= 1e3 else '%1.1f' % x
mkformatter = matplotlib.ticker.FuncFormatter(mkfunc)
ax.yaxis.set_major_formatter(mkformatter)
#set locator at regular hour intervals
ax.xaxis.set_major_locator(MultipleLocator(8))
ax.set_xlabel("Time (in h)")
plt.grid()
plt.show()
示例输出:
如果出于未知原因您确实需要 datetime 对象,您可以使用任意偏移量转换 timedelta 值,因为您打算忽略日期值:
df0["Time"] += pd.to_datetime("2000-01-01 00:00:00 UTC")
但我怀疑这对你的情况是否有利。
顺便说一句 - 对于调试,不使用规则间隔的测试数据很有用。在您的示例中,您可能没有注意到图表是根据索引 (0, 1, 2...) 绘制的,然后用字符串重新标记,模仿规则间隔的日期时间对象。下面的测试数据一下子就暴露了问题
0:0:0 29
0:5:0 85
0:10:0 141
3:15:0 98
5:20:0 251
17:25:0 308
27:30:0 63
35:35:0 413
我试图在绘制 DataFrame 时指定 x 轴间隔。我有几个数据文件,例如
0:0:0 29
0:5:0 85
0:10:0 141
0:15:0 198
0:20:0 251
0:25:0 308
0:30:0 363
0:35:0 413
第一列是 %H:%M:%S 格式的时间,但小时数超过 24 小时(直到 48 小时)。
当我读取如下文件并绘图时,它看起来不错,但我想将 xticks 间隔设置为 8 小时。
df0 = pd.read_csv(fil, names=['Time', 'Count'], delim_whitespace=True, parse_dates=['Time'])
df0 = df0.set_index('Time')
ax = matplotlib.pyplot.gca()
mkfunc = lambda x, pos: '%1.1fM' % (x * 1e-6) if x >= 1e6 else '%1.1fK' % (x * 1e-3) if x >= 1e3 else '%1.1f' % x
mkformatter = matplotlib.ticker.FuncFormatter(mkfunc)
ax.yaxis.set_major_formatter(mkformatter)
ax.xaxis.set_major_locator(mdates.HourLocator(interval=8))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H'))
df0.plot(ax=ax, x_compat=True, color='blue')
plt.grid()
plt.savefig('figure2.pdf',dpi=300, bbox_inches = "tight")
我尝试了这里许多答案指定的上述方法,但导致了以下警告,
Locator attempting to generate 1874 ticks ([-28.208333333333332, ..., 596.125]), which exceeds Locator.MAXTICKS (1000).
图中还出现了很多竖线。 我尝试将我的时间列专门转换为 timedelta,但仍然没有帮助。 我如下转换为 timedelta。
custom_date_parser = lambda x: pd.to_timedelta(x.split('.')[0])
df0 = pd.read_csv(fil, names=['Time', 'Count'], delim_whitespace=True, parse_dates=['Time']), date_parser=custom_date_parser)
你能帮我找出问题并正确设置 xticks 间隔吗?
这里的问题是 a) matplotlib/pandas 对 timedelta 对象没有太多支持,b) 您不能将 HourLocator 用于您的数据,因为在转换为 datetime 对象后,您的轴将被标记0, 8, 16, 0, 8, 16...
相反,我们可以将您的转换器导入的 timedelta 转换为小时并绘制数值:
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
import numpy as np
custom_date_parser = lambda x: pd.to_timedelta(x.split('.')[0])
df0 = pd.read_csv("test.txt", names=['Time', 'Count'], delim_whitespace=True, parse_dates=['Time'], date_parser=custom_date_parser)
#conversion into numerical hour value
df0["Time"] /= np.timedelta64(1, "h")
df0 = df0.set_index('Time')
ax = matplotlib.pyplot.gca()
df0.plot(ax=ax, x_compat=True, color='blue')
mkfunc = lambda x, pos: '%1.1fM' % (x * 1e-6) if x >= 1e6 else '%1.1fK' % (x * 1e-3) if x >= 1e3 else '%1.1f' % x
mkformatter = matplotlib.ticker.FuncFormatter(mkfunc)
ax.yaxis.set_major_formatter(mkformatter)
#set locator at regular hour intervals
ax.xaxis.set_major_locator(MultipleLocator(8))
ax.set_xlabel("Time (in h)")
plt.grid()
plt.show()
示例输出:
如果出于未知原因您确实需要 datetime 对象,您可以使用任意偏移量转换 timedelta 值,因为您打算忽略日期值:
df0["Time"] += pd.to_datetime("2000-01-01 00:00:00 UTC")
但我怀疑这对你的情况是否有利。
顺便说一句 - 对于调试,不使用规则间隔的测试数据很有用。在您的示例中,您可能没有注意到图表是根据索引 (0, 1, 2...) 绘制的,然后用字符串重新标记,模仿规则间隔的日期时间对象。下面的测试数据一下子就暴露了问题
0:0:0 29
0:5:0 85
0:10:0 141
3:15:0 98
5:20:0 251
17:25:0 308
27:30:0 63
35:35:0 413