【问题标题】:Sharing Y-Axis Range for Multiple Horizontal Bar Issue为多个单杠问题共享 Y 轴范围
【发布时间】:2021-09-18 01:32:41
【问题描述】:

我在绘制多个水平条形图的总 y 轴范围以使所有值相互对齐并仅使最左侧图上的 y 标签可见时遇到问题。 我有下面的数据框(数据),在开始创建图形和轴之前,我使用 pd.Grouper 函数按时间间隔分组。由于我使用数据框,我为我创建的每个轴分配了一个图。该代码未正确绘制值。如果我删除了 sharey=y,那么每个图都会正确显示,但当然不会与一个共同的 y 轴对齐。

import pandas as pd
import matplotlib.pyplot as plt

#group by time interval
data_gb = data.groupby([pd.Grouper(freq='1min')])
#create and set y-axis range limits from original dataframe
custom_ylim = (data.price.min(), data.price.max())
#number of plots based on number of intervals
numplot = len(data_gb)
# create a tuple of axe names seems like a hack 
axes =  tuple(['ax'+str(n) for n in range(1, numplot+1)])
f, axes = plt.subplots(1, numplot, sharey= True, sharex=True)
#iterate and assign plot to each axes
for (t, prices), ax in zip(data_gb, axes):
    ax.set_ylim(custom_ylim) #this doesn't seem to do anything
    prices.plot.barh('price', stacked=True, ax=ax)
    ax.legend_ = None   
plt.show()


timestamp                  price     colA      colB     colC     colD
2021-09-08 13:30:00+00:00  11.00      0.0  140037.0      0.0      0.0
2021-09-08 13:30:00+00:00  11.01  21963.0   34732.0   2961.0   1190.0
2021-09-08 13:30:00+00:00  11.02  17578.0   15434.0  12309.0      2.0
2021-09-08 13:30:00+00:00  11.03   2493.0   12393.0  11229.0    907.0
2021-09-08 13:30:00+00:00  11.04  17240.0   16406.0   1479.0    100.0
...                          ...      ...       ...      ...      ...
2021-09-08 13:31:00+00:00  11.01   8520.0   22579.0   4031.0    248.0
2021-09-08 13:31:00+00:00  11.02  64626.0   10330.0  11340.0   3862.0
2021-09-08 13:31:00+00:00  11.03  10967.0    5144.0   2621.0    640.0
2021-09-08 13:31:00+00:00  11.04  15168.0    2907.0      0.0      4.0
2021-09-08 13:31:00+00:00  11.05   1279.0       0.0      0.0      0.0

绘图不正确。

绘制的个体不共享 y 轴。您可以看到第一个图表在上一个图中缺少值。

【问题讨论】:

  • 是的,我已经删除了它并离开了 sharey,但它仍然无法正常工作。如果我删除 sharey,它们只会变成一系列独立的情节。我希望为所有图对齐 y 标签。
  • 当我删除 ax.set_ylim(custom_ylim) 和 sharey = False 时,它​​看起来就像我发布的第二张图片。我正在使用 python 3.7 和 matplotlib 3.4..3
  • 使用 sharey=True 并通过遍历轴来单独分配 ax.set_ylim(custom_ylim) 会完全搞砸。我正在使用熊猫 1.1.2。
  • 您认为我还应该添加哪些信息来帮助解决问题?如果您愿意,我们可以将其移至聊天?
  • 根据我发布的帖子,看起来第二个包含所有数据,但我想要一个包含整个价格高低的通用 y 轴,并且每个柱对齐. .

标签: python pandas matplotlib


【解决方案1】:

Pandas 条形图并不总是直观的。这使得共享轴相当复杂。一个问题是条形图既没有数字也没有纯粹的分类刻度位置。相反,条形图编号为 0,1,2,...,然后刻度线得到它们的标签。

另一个问题是数值列的条形可能会奇怪地转换为字符串(例如,值 12.34 可能会因为某些浮点怪异而显示为 12.340000001)。在您的绘图中可以看到一些奇怪之处,例如显示 7.4 而不是 7.40

我建议的解决方法:

  • 将价格列转换为精确到 2 位小数的字符串
  • 绘图时,将价格设置为索引并重新索引到全价格范围;这使得所有子图都具有相同的范围
  • 烦人的是,在将列转换为字符串之前需要计算完整的价格范围,然后范围也需要转换为字符串
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np

# create some test data
times = np.repeat(pd.date_range('2021-09-08 13:30', '2021-09-08 13:34', freq='1min'), 20)
data = pd.DataFrame({'timestamp': times,
                     'price': np.round(np.arange(1100, 1200) / 100 - np.repeat([0, 0.25, 0.5, 0.55, 0.9], 20), 2),
                     'colA': np.random.randint(1000, 5000, 100),
                     'colB': np.random.randint(1000, 5000, 100),
                     'colC': np.random.randint(1000, 5000, 100),
                     'colD': np.random.randint(1000, 5000, 100)}).set_index('timestamp')
# calculate the full price range, first numeric, then convert to string
full_price_range = [f'{x:.2f}' for x in np.arange(data['price'].min(), data['price'].max() + 0.0001, 0.01)]
# now convert the price column to strings
data['price'] = data['price'].apply(lambda x: f'{x:.2f}')

data_gb = data.groupby([pd.Grouper(freq='1min')])

numplot = len(data_gb)
fig, axes = plt.subplots(1, numplot, sharey=True, sharex=True, figsize=(12, 4))
for (t, prices), ax in zip(data_gb, axes):
    prices.set_index('price').reindex(full_price_range).plot.barh(stacked=True, legend=False, ax=ax)
    ax.set_title(t)
fig.tight_layout()
plt.show()

请注意,原代码中的axes = tuple(....) 行无效,因为在下一行中名为axes 的变量获得了一个新值。

【讨论】:

  • 感谢您的解释和解决方法,但是当我运行代码时它不起作用,该图形弹出了 5 个空图,y 轴和 x 轴具有 0 - 1 值。我会看看我能用你提供的信息做什么。再次感谢。
  • 好的,所以我被剪切并粘贴错了,所以我让你举例来工作,所以我将整合我的数据,看看会发生什么,并在我运行后选择你的答案。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-12
  • 2013-02-16
  • 1970-01-01
  • 2020-04-05
  • 2016-05-21
  • 2017-01-17
相关资源
最近更新 更多