在 x 轴上创建 pandas 数据框的分面图,其中月份为月份

Create facet plot of pandas dataframe with month of year on x-axis

我有一个数据系列,其中包含各个会计年度的月销售额。我正在使用 pandas 数据框来存储数据。每个财政年度从三月的第一天开始,到次年二月的最后一天结束。我正在使用 plotly 分面图来显示一年中的月份垂直对齐,因此 2021 年 3 月低于 2020 年 3 月,依此类推。

尽管对 x 轴使用分类变量,但顺序略有偏差。我曾尝试使用具有唯一值的 'yearmon' 变量进行排序,但这也不起作用。具体来说,在下图中,2018 年 1 月和 2 月的值是空白的,2021 年 1 月和 2 月的值也不合适。在没有这些问题的情况下,我怎样才能让 facet 显示连续的数据? 编辑:我感觉它与类别的顺序有关,但还没有设法确定它。

import pandas as pd
import numpy as np
import plotly.express as px
import chart_studio.plotly as py

rng = np.random.default_rng(12345)
df = pd.DataFrame(rng.integers(80, 100, size=(36, 1)), columns=list('A'))
df.index = pd.date_range("2018-03-01", periods=36, freq="M")
df['year'] = df.index.strftime('%Y')
df['month'] = df.index.strftime('%b')
df['monthindex'] = df.index.strftime('%m')
df['yearmon'] = df['year']+df['monthindex']

month_categories = ['Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec','Jan','Feb']
df["month"] = pd.Categorical(df["month"], categories = month_categories)
df = df.sort_values(by = "yearmon")

fig = px.bar(df, x = 'month', y = 'A', facet_col='year', facet_col_wrap=1)
py.image.save_as(fig, 'plotly.png', width=1000, height=500)

更新

使用下面@vestland 的代码作为基础,我根据下面的评论调整了开始日期和财政年度分配,因为财政年度通常与日历年不一致。此外,数据系列的长度是任意的——可能是几个月,也可能是十年——开始和结束月份也是如此。最后,我希望 x 轴以财政年度的第一个月和最后一个月开始和结束,所以在这种情况下(三月和二月)'Mar' 应该是左边的第一个刻度线,并且 'Feb'右边最后一个。如果这还不够清楚,我深表歉意。

import pandas as pd
import numpy as np
import plotly.express as px
import chart_studio.plotly as py

rng = np.random.default_rng(12345)
df = pd.DataFrame(rng.integers(80, 100, size=(36, 1)), columns=list('A'))
df.index = pd.date_range("2018-01-01", periods=36, freq="M")
df['year'] = df.index.strftime('%Y')
df['month'] = df.index.strftime('%b')
df['monthindex'] = df.index.strftime('%m')
df['yearmon'] = df['year']+df['monthindex']

month_categories = ['Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec','Jan','Feb']
df["month"] = pd.Categorical(df["month"], categories = month_categories)
df = df.sort_values(by = "yearmon")

df['fiscal_year'] = [2017]*2+[2018]*12+[2019]*12+[2020]*10
fig = px.bar(df, x = 'month', y = 'A', facet_col='fiscal_year', facet_col_wrap=1)
fig.show()

这似乎给出了以下内容:

如果我没理解错的话,那么你似乎除了一个小细节外,其他所有事情都做对了。这有点令人惊讶,所以我很有可能误解了你问题的前提。无论如何...

Specifically, in the plot below the values for Jan and Feb in 2018 are blank

那是因为 df.head()

中不存在这样的日期
             A  year month monthindex yearmon
2018-03-31  93  2018   Mar         03  201803
2018-04-30  84  2018   Apr         04  201804
2018-05-31  95  2018   May         05  201805
2018-06-30  86  2018   Jun         06  201806
2018-07-31  84  2018   Jul         07  201807

如果我正确理解您的意图,您实际上希望将 january and february of 2019 与第一个 x 轴相关联。尽管你付出了巨大的努力,但还没有建立这样的联系。我不太确定你会怎么做,但如果你确定要设置这样的东西:

df['fiscal_year'] = [2018]*12+[2019]*12+[2020]*12

并得到:

那你可以运行

fig = px.bar(df, x = 'month', y = 'A', facet_col='fiscal_year',facet_col_wrap=1)

并得到:

如您所见,January and february of 2019 现在出现在 2018 年的 x 轴上。其余年份依此类推。我希望这就是您要找的。如果没有,请随时告诉我。

完整代码:

import pandas as pd
import numpy as np
import plotly.express as px
import chart_studio.plotly as py

rng = np.random.default_rng(12345)
df = pd.DataFrame(rng.integers(80, 100, size=(36, 1)), columns=list('A'))
df.index = pd.date_range("2018-03-01", periods=36, freq="M")
df['year'] = df.index.strftime('%Y')
df['month'] = df.index.strftime('%b')
df['monthindex'] = df.index.strftime('%m')
df['yearmon'] = df['year']+df['monthindex']

month_categories = ['Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec','Jan','Feb']
df["month"] = pd.Categorical(df["month"], categories = month_categories)
df = df.sort_values(by = "yearmon")

df['fiscal_year'] = [2018]*12+[2019]*12+[2020]*12
fig = px.bar(df, x = 'month', y = 'A', facet_col='fiscal_year', facet_col_wrap=1)
fig.show()

这种情况下的问题似乎是 plotly 不遵守用于 x 轴的 pandas 数据系列中类别的顺序,除非特别指示这样做,如plotly 论坛 here, and documented here。在 px.bar 调用中使用 category_orders 允许我们覆盖默认的 plotly 假设并创建一个从指定财政年度的第一个月到财政年度最后一个月的 x 轴。

import pandas as pd
import numpy as np
import plotly.express as px
import chart_studio.plotly as py

rng = np.random.default_rng(12345)
df = pd.DataFrame(rng.integers(80, 100, size=(36, 1)), columns=list('A'))
df.index = pd.date_range("2018-01-01", periods=36, freq="M")
df['year'] = df.index.strftime('%Y')
df['month'] = df.index.strftime('%b')
df['monthindex'] = df.index.strftime('%m')
df['yearmon'] = df['year']+df['monthindex']

month_categories = ['Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec','Jan','Feb']
df["month"] = pd.Categorical(df["month"], categories = month_categories)
df = df.sort_values(by = "yearmon")

df['fiscal_year'] = [2017]*2+[2018]*12+[2019]*12+[2020]*10

fig = px.bar(df, x = 'month', y = 'A', 
              facet_col='fiscal_year',
              facet_col_wrap=1,
              category_orders={ # replaces default order by column name
                "month": ['Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec','Jan','Feb']
            })       
fig.show()