【问题标题】:Matplot line graph of pandas dataframe with double y axis scale and datetime on x axis具有双 y 轴刻度和 x 轴日期时间的 pandas 数据框的 Matplotlib 线图
【发布时间】:2020-04-27 04:37:17
【问题描述】:

我有一个描述我家 ADSL 速度的日志。 日志条目的格式如下,其中字段为 datetime;level;down​​speed;upspeed;testhost:

2020-01-06 18:09:45;INFO;211.5;29.1;0;host:spd-pub-rm-01-01.fastwebnet.it
2020-01-06 18:14:39;WARNING;209.9;28.1;0;host:spd-pub-rm-01-01.fastwebnet.it
2020-01-08 10:51:27;INFO;211.6;29.4;0;host:spd-pub-rm-01-01.fastwebnet.it

(获取完整示例文件 -> https://www.dropbox.com/s/tfmj9ozxe5millx/test.log?dl=0 供您下载以下代码)

我希望在左轴上绘制一个 matplot 图形,其中下载速度、上传速度(值的范围越来越小)并且在 x 刻度线下可能有 45 度角的缩短日期时间。

"""Plots the adsl-log generated log."""
import matplotlib.pyplot as plt
# import matplotlib.dates as mdates
import pandas as pd

# set field delimiter and set column names which will also cause reading from row 1
data = pd.read_csv("test.log", sep=';', names=[
                   'datetime', 'severity', 'down', 'up', 'loss', 'server'])

#  we need to filter out ERROR records (with 0 speeds)
indexNames = data[data['severity'] == 'ERROR'].index
data.drop(indexNames, inplace=True)

# convert datetime pandas objecti to datetime64
data['datetime'] = pd.to_datetime(data['datetime'])

# use a dataframe with just the data I need; cleaner
speeds_df = data[['datetime', 'down', 'up']]
speeds_df.info() # this shows datetime column is really a datetime64 value now
# now let's plot
fig, ax = plt.subplots()
y1 = speeds_df.plot(ax=ax, x='datetime', y='down', grid=True, label="DL", legend=True, linewidth=2,ylim=(100,225))
y2 = speeds_df.plot(ax=ax, x='datetime', y='up', secondary_y=True, label="UL", legend=True, linewidth=2, ylim=(100,225))

plt.show()

我现在正在获取我需要的绘图,但希望能对上述代码中的 ax、y1 和 y2 轴的作用进行一些澄清。

【问题讨论】:

  • 幸运的中风 ;) 通过在我的地块之前添加一个 fig, ax = plt.subplots() 行并在两者中使用 ax=ax 参数,设法几乎到达那里。仍然对我的代码生成的 ax 和 y1、y2 的语义感到困惑。

标签: python pandas datetime matplotlib


【解决方案1】:

首先,分配 y1y2 对象是不必要的,因为您以后将永远不会使用它们。此外,legend=True 是默认值。

因此,您首先初始化一个轴对象数组(默认为一个项目,nrow=1nrow=2),然后根据熊猫图分配它/它们。现在,通常情况下,您会覆盖使用ax=ax 对 ax 的分配,但由于您使用辅助 y 轴,因此绘图会相互重叠:

# INITIALIZE FIG DIMENSION AND AXES OBJECTS
fig, axs = plt.subplots(figsize=(8,4))

# ASSIGN AXES OBJECTS ACCORDINGLY
speeds_df.plot(ax=axs, x='datetime', y='down', grid=True, label="DL", linewidth=2, ylim=(100,225))
speeds_df.plot(ax=axs, x='datetime', y='up', secondary_y=True, label="UL", linewidth=2, ylim=(100,225))

plt.show()


为了说明坐标区对象可以如何扩展,请参见下面的多个(非重叠)图。

使用nrows=2的多个子图示例:

# INITIALIZE FIG DIMENSION AND AXES OBJECTS
fig, axs = plt.subplots(nrows=2, figsize=(8,4))

# ASSIGN AXES OBJECTS WITH INDEXING AND NO Y LIMITS
speeds_df.plot(ax=axs[0], x='datetime', y='down', grid=True, label="DL", linewidth=2)
plt.subplots_adjust(hspace = 1)
speeds_df.plot(ax=axs[1], x='datetime', y='up', label="UL", linewidth=2)

plt.show()


使用ncols=2的多个绘图示例:

# INITIALIZE FIG DIMENSION AND AXES OBJECTS
fig, axs = plt.subplots(ncols=2, figsize=(12,4))

# ASSIGN AXES OBJECTS WITH INDEXING AND NO Y LIMITS
speeds_df.plot(ax=axs[0], x='datetime', y='down', grid=True, label="DL", linewidth=2)
speeds_df.plot(ax=axs[1], x='datetime', y='up', label="UL", linewidth=2)

plt.show()


您甚至可以在将日期/时间字段设置为索引后使用subplots=True

# INITIALIZE FIG DIMENSION AND AXES OBJECTS
fig, axs = plt.subplots(figsize=(8,4))

# ASSIGN AXES OBJECT PLOTTING ALL COLUMNS
speeds_df.set_index('datetime').plot(ax=axs, subplots=True, grid=True, label="DL", linewidth=2)

plt.show()

【讨论】:

  • 谢谢。在您的第一个代码示例中,我不明白的是 df.plot ylim 参数的使用。他们似乎定义了左轴限制,但是当您在两个图上使用相同的数字时,您如何指定正确的值?
  • Pandas 的subplots=True(如下图所示)和secondary_y=True 都是方便快捷的方式,可能用于更简单的绘图,而 matplotlib 对这两个功能都有自己的方式。见dual axes。如您所见,它不允许指定您必须手动处理的第二个 y 限制轴。
【解决方案2】:

感谢@Parfait,我希望我理解正确。这里的工作代码:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
###### Prepare the data to plot
# set field delimiter and set column names which will also cause reading from row 1
data = pd.read_csv('test.log', sep=';', names=[
                   'datetime', 'severity', 'down', 'up', 'loss', 'server'])
#  we need to filter out ERROR records (with 0 speeds)
indexNames = data[data['severity'] == 'ERROR'].index
data.drop(indexNames, inplace=True)
# convert datetime pandas object to datetime64
data['datetime'] = pd.to_datetime(data['datetime'])
# use a dataframe with just the data I need; cleaner
speeds_df = data[['datetime', 'down', 'up']]

# now plot the graph
fig, ax = plt.subplots()

color = 'tab:green'
ax.set_xlabel('thislabeldoesnotworkbutcolordoes', color=color)
ax.tick_params(axis='x', labelcolor=color)

color = 'tab:red'
speeds_df.plot(ax=ax, x='datetime', y='down', label="DL", legend=True, linewidth=2, color=color)
ax.set_ylabel('DL', color=color)
ax.tick_params(axis='y', labelcolor=color)

color = 'tab:blue'
ax2 = speeds_df.plot(ax=ax, x='datetime', y='up', secondary_y=True, label="UL", legend=True, linewidth=2, color=color)
ax2.set_ylabel('UL', color=color)
ax2.tick_params(axis='y', labelcolor=color)
# using ylim in the plot command params does not work the same
# cannot show a grid since the two scales are different
ax.set_ylim(10, 225)
ax2.set_ylim(15, 50)

plt.show()

这给出了:

我仍然没有得到的是: a)为什么x轴标签似乎只尊重颜色而不是字符串值:( b) 为什么 df 图中的 ylim=(n,m) 参数不能正常工作,我必须改用 ax.set_ylim 构造

【讨论】:

  • 对于 (a) pandas 可能没有选择辅助 y 轴限制的功能。对于 (b) 你的 pandas plot 覆盖 x 标签 thislabeldoesnotworkbutcolordoes。所以在熊猫绘图后移动它,它应该会渲染。
  • @Parfait 感谢您帮助我实现的清晰度。情况就是这样,现在一切正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-01
  • 1970-01-01
  • 2019-01-05
  • 2016-06-25
  • 1970-01-01
  • 2012-03-14
  • 2013-01-04
相关资源
最近更新 更多