【问题标题】:How to make a bump chart如何制作凹凸图
【发布时间】:2021-06-23 07:31:14
【问题描述】:

我有一张排名数据表,我想将其可视化为凹凸图或斜率图,例如

我知道如何绘制一个,但如果我学到了关于 pandas 的一件事,那就是通常有一些融化、合并、起泡和摆弄的组合可以在一个班轮中完成这项工作。又名优雅的熊猫,而不是打乱的熊猫。

数据看起来有点像这样:(much more data here)

ed_name source
2562 edition_3 gq
2956 edition_8 warontherocks
10168 edition_12 aeon.co
1137 edition_14 hbr.org
4573 edition_13 thesmartnik
7143 edition_16 vijayboyapati.medium
9674 edition_15 medium
5555 edition_9 smh.au
8831 edition_11 salon
8215 edition_14 thegospelcoalition.org

以此类推,其中每一行是一篇文章,来源是该文章的来源。目标是找出每个版本中哪些来源贡献的文章最多。

这是我笨拙地将其转换为不良凹凸图的尝试:

all_sources = set(sources)
source_rankings = {}
for s in all_sources:
    source_rankings[s]={}

for ed in printed.groupby("ed_name"):
    df = ed[1]
    vc = df.source.value_counts()
    for i, x in enumerate(vc.index):
        source_rankings[x][ed[0]] = i+1
ranks = pd.DataFrame(source_rankings)

cols_to_drop = []
for name, values in ranks.iteritems():
    interesting = any([x>30 for x in list(values) if not math.isnan(x)])
    # print(name, interesting)
    if interesting:
        cols_to_drop.append(name)
only_interesting = ranks.drop(labels=cols_to_drop, axis='columns')

only_interesting.sort_index(
    axis=0, inplace=True, 
    key=lambda col: [int(x.split("_")[1]) for x in col],
    ascending=False
    )

linestyles = ['-', '--', '-.', ':']

plt.plot(only_interesting, alpha=0.8, linewidth=1)
plt.ylim(25, 0)
plt.gca().invert_xaxis()
plt.xticks(rotation=70)
plt.title("Popularity of publisher by edition")

editions_that_rank_threshold = 10
for name, values in only_interesting.iteritems():
    if len(values[values.isna() == False]) > editions_that_rank_threshold: 
        for i, x in values.iteritems():
            if not math.isnan(x):
                # print(name, i, x)
                plt.annotate(xy=(i,x), text=name)
                plt.plot(values, linewidth=5, linestyle=sample(linestyles,1)[0])
                break

plt.xlabel("Edition")
plt.ylabel("Cardinal Rank (1 at the top)")
plt.close()

这给出了类似的东西:

至少可以说,还有很多不足之处。很多问题都可以通过使用标准的 matplotlib 东西来解决,但我很犹豫,因为它感觉不优雅,而且我可能缺少一个内置的 bumpchart 方法。

This question 提出了类似的问题,但the answer 将其作为斜率图解决。它们看起来很棒,但这是一种不同类型的图表。

有没有更优雅的方法来做到这一点?

【问题讨论】:

  • mplsoccer 库中有一个函数可以绘制bump chart。我希望这会有所帮助。

标签: python pandas matplotlib


【解决方案1】:

我不认为您缺少某些内置方法。我不确定您的数据是否适合凹凸图,因为版本之间的差异似乎很大,并且几个来源似乎具有相同的等级,但这是我的一些尝试。

读取/排列数据

import pandas as pd

data_source = (
    "https://gist.githubusercontent.com/"
    "notionparallax/7ada7b733216001962dbaa789e246a67/raw/"
    "6d306b5d928b04a5a2395469694acdd8af3cbafb/example.csv"
)

df = (
    pd.read_csv(data_source, index_col=0)
    .assign(ed_name=lambda x: x["ed_name"].str.extract(r"(\d+)").astype(int))
    .value_counts(["ed_name", "source"])
    .groupby("ed_name")
    .rank("first", ascending=False)
    .rename("rank")
    .sort_index()
    .reset_index()
    .query("ed_name < 17")
)

在这里我选择了“第一”排名,因为这将给我们排他的排名,而不是重叠的排名。它使情节看起来稍微好一点,但可能不是你想要的。如果您想要重叠排名,请使用“min”而不是 first。

获取上一版排名前 n 位(用于标注)

n_top_ranked = 10
top_sources = df[df["ed_name"] == df["ed_name"].max()].nsmallest(n_top_ranked, "rank")

简单的情节

import matplotlib.pyplot as plt
for i, j in df.groupby("source"):
    plt.plot("ed_name", "rank", "o-", data=j, mfc="w")
plt.ylim(0.5, 0.5 + n_top_ranked)
plt.gca().invert_yaxis()

这里的结果图不是很好,但制作起来很简单。

让剧情更精彩

import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FixedFormatter, FixedLocator

fig, ax = plt.subplots(figsize=(8, 5), subplot_kw=dict(ylim=(0.5, 0.5 + n_top_ranked)))

ax.xaxis.set_major_locator(MultipleLocator(1))
ax.yaxis.set_major_locator(MultipleLocator(1))

yax2 = ax.secondary_yaxis("right")
yax2.yaxis.set_major_locator(FixedLocator(top_sources["rank"].to_list()))
yax2.yaxis.set_major_formatter(FixedFormatter(top_sources["source"].to_list()))

for i, j in df.groupby("source"):
    ax.plot("ed_name", "rank", "o-", data=j, mfc="w")

ax.invert_yaxis()
ax.set(xlabel="Edition", ylabel="Rank", title="Popularity of publisher by edition")
ax.grid(axis="x")
plt.tight_layout()

它为您提供以下内容

这里仍然需要做一些工作才能让这个看起来非常好(例如颜色需要排序),但希望这个答案能让你更接近你的目标。

【讨论】:

    【解决方案2】:

    还有一个非常有用的GitHub仓库https://github.com/kartikay-bagla/bump-plot-python

    它基本上是一类允许您从pd.DataFrame 绘制凹凸图。

    data = {"A":[1,2,1,3],"B":[2,1,3,2],"C":[3,3,2,1]}
    df = pd.DataFrame(data, index=['step_1','step_2','step_3','step_4'])
    
    plt.figure(figsize=(10, 5))
    bumpchart(df, show_rank_axis= True, scatter= True, holes= False,
              line_args= {"linewidth": 5, "alpha": 0.5}, scatter_args= {"s": 100, "alpha": 0.8}) ## bump chart class with nice examples can be found on github
    plt.show()
    

    免责声明。我不是存储库的创建者,但我发现这很有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-30
      • 2011-10-05
      • 2016-10-21
      • 1970-01-01
      相关资源
      最近更新 更多