【问题标题】:How to create a historical timeline with Python如何使用 Python 创建历史时间线
【发布时间】:2018-11-25 17:46:23
【问题描述】:

所以我在这里看到了一些有帮助的答案,但我的数据集比之前回答的要大。要了解我正在使用什么,here's a link to the full dataset。我附上了一张尝试过的解决方案的图片,可以在link 找到: 。

问题在于 1. 这很难阅读 2. 我不知道如何将其展平以使其看起来像传统的时间线。当我尝试处理更大的段时,这个问题变得更加明显,比如这个基本上是不可读的: 这是我用来生成这两个的代码(我只是修改了包含的代码以更改使用了整个数据集的哪个部分)。

event = Xia['EnglishName']
begin = Xia['Start']
end = Xia['Finish']
length = Xia['Length']

plt.figure(figsize=(12,6))
plt.barh(range(len(begin)), (end-begin), .3, left=begin)
plt.tick_params(axis='both', which='major', labelsize=15)
plt.tick_params(axis='both', which='minor', labelsize=20)
plt.title('Xia Dynasty', fontsize = '25')
plt.xlabel('Year', fontsize = '20')
plt.yticks(range(len(begin)), "")
plt.xlim(-2250, -1750)
plt.ylim(-1,18)
for i in range(18):
    plt.text(begin.iloc[i] + length.iloc[i]/2, i+.25, event.iloc[i], ha='center', fontsize = '12') 

此代码半有效,但如果条形更靠近或颜色不同并且都在相同的 y 值上,我会更喜欢。我感谢任何和所有的帮助。我已经尝试解决这个问题大约两周了,但我遇到了难题。

【问题讨论】:

  • 你能详细介绍一下'Xia'吗?
  • 夏是一个特别的朝代。基本上,它是一个包含 18 行的切片 pandas 数据框,每行都有 EnglishName、Start 和 Finish(至少与我在这里所做的有关)。长度仅仅是结束减去开始。开始和结束是数字。一行的一个例子是大禹 | -2207 | -2197 | 10,按顺序包含 EnglishName、Start、Finish 和 Length。
  • 我认为@Braca 指的是变量。是否有任何代码可以粘贴并在本地机器上运行以复制您的结果并提供一些帮助?您的问题已经充满了任务,“您还必须复制我的数据”是一个额外的负担。有关于在 pandas 中制作可复制代码的好链接,但没有人阅读它们。
  • Xia = pd.DataFrame([[大禹, -2207, -2197], [齐, -2197, -2188], [泰康, -2188, -2159]], columns= ['EnglishName', 'Start', 'Finish'])

标签: python matplotlib data-science


【解决方案1】:

我不知道你是否已经解决了这个问题,但是,从我迄今为止从你的代码中看到的以及(也从 Evgeny 的代码中借用的)你的需求来看,你有不同级别的水平的唯一原因条,因为您已将 matplotlib (matplotlib.pyplot.barh(y, width, height=0.8, left=None, *, align='center', **kwargs) 的 barh 的标量 y 定义为一个范围。因此,每个连续堆叠的条都列在单独的级别上。

所以,我冒昧地下载了您的数据集并稍微修改了一下代码。

我从 google 数据集创建了一个数据框,并为每个 Dynasty(Dynasty_col 列)和 Age(Age_col 列)分配了 matplotlib CSS 颜色(这不是必需的,但是我发现这更易于管理可视化):

然后为了复制您的夏朝表示,我只是创建了一个子集:

在此之后,我主要保留了您/Evgeny 的代码已经显示的内容,并进行了一些小的更改:

event = data_set_xia['EnglishName']
begin = data_set_xia['Start']
end = data_set_xia['Finish']
length =  data_set_xia['Length']

这里我添加了一个用垂直线命名的级别(您可以延长或缩短数组 [-2, 2, -1, 1] 以获得不同级别的标签):

levels = np.tile([-2, 2, -1, 1],
                 int(np.ceil(len(begin)/4)))[:len(begin)]

import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.figure(figsize=(12,6))

在这里,我基本上将所有朝代添加到同一个 y 标量(列为 0)上,该行的其余部分已修改为对应于条形的颜色并给出边缘颜色。

plt.barh(0, (end-begin), color=data_set_xia.loc[:,"Dynasty_col"], height =0.3 ,left=begin, edgecolor = "black")
plt.tick_params(axis='both', which='major', labelsize=15)
plt.tick_params(axis='both', which='minor', labelsize=20)
plt.title('Xia Dynasty', fontsize = '25')
plt.xlabel('Year', fontsize = '20')
# plt.yticks(range(len(begin)), "")
ax = plt.gca()
ax.axes.yaxis.set_visible(False)
plt.xlim(-2250, -1700)
plt.ylim(-5,5)

我在标签的垂直线上玩了一下,标签与级别相关联以创建情节。

plt.vlines(begin+length/2, 0, levels, color="tab:red")
for i in range(18):
    plt.text(begin.iloc[i] + length.iloc[i]/2, 
             levels[i]*1.3, event.iloc[i], 
             ha='center', fontsize = '12')

plt.tight_layout()
plt.show()

这导致了夏朝的以下图表:

使用更大的子集,我也可以生成另一个图表:

现在显然,条目数越长,图表就越繁忙和混乱,它开始看起来有点难看,但仍然清晰可见。另外,代码不是“完美”的,我会稍微清理一下并更改一些命令选项,例如 barh 参数中的 color,但它现在可以工作。

对于另一种表示,我添加了不同朝代按时间交错表示的代码,因为一些朝代相互重叠:

event = data_set_adj['EnglishName']
begin = data_set_adj['Start']
end = data_set_adj['Finish']
length =  data_set_adj['Length']
dynasty = data_set_adj['Dynasty']
dynasty_col = data_set_adj['Dynasty_col']

dict_dynasty = dict(zip(dynasty.unique(), range(0,4*len(dynasty.unique()),4)))

levels = np.tile([-1.2,1.2, -0.8, 0.8, -0.4, 0.4],
                 int(np.ceil(len(begin)/6)))[:len(begin)]

import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.figure(figsize=(20,10))

for x in range(len(dynasty)):   
    plt.vlines(begin.iloc[x]+length.iloc[x]/2, dict_dynasty[dynasty.iloc[x]], dict_dynasty[dynasty.iloc[x]]+levels[x], color="tab:red")
    plt.barh(dict_dynasty[dynasty.iloc[x]], (end.iloc[x]-begin.iloc[x]), color=dynasty_col.iloc[x], height =0.3 ,left=begin.iloc[x], edgecolor = "black", alpha = 0.5)
    if x%2==0:
        plt.text(begin.iloc[x] + length.iloc[x]/2, 
                 dict_dynasty[dynasty.iloc[x]]+1.6*levels[x], event.iloc[x], 
                 ha='center', fontsize = '8')
    else:
        plt.text(begin.iloc[x] + length.iloc[x]/2, 
                 dict_dynasty[dynasty.iloc[x]]+1.25*levels[x], event.iloc[x], 
                 ha='center', fontsize = '8')
plt.tick_params(axis='both', which='major', labelsize=15)
plt.tick_params(axis='both', which='minor', labelsize=20)
plt.title('Chinese Dynasties', fontsize = '25')
plt.xlabel('Year', fontsize = '20')
ax = plt.gca()
ax.axes.yaxis.set_visible(False)
plt.xlim(900, 1915)
plt.ylim(-4,28)


plt.tight_layout()
plt.show()

这最后一部分是匆忙完成的,所以代码不是最整洁的,但我在这里唯一更改的是根据数据子集中的朝代更新 barh 的 y 标量我正在考虑。我已经修改了级别和字体大小以提高可读性,您可以使用数字和代码来获得适当的表示。

这导致以下表示:

此外,当我添加 Age_col 列时,您可以将整个事物分类为前帝国和帝国(红色或蓝色)。我暂时没有附上任何图表,但如果你在朝代周围添加一块具有不同“zorder”的该颜色的补丁,那就可以了。

对于可缩放和可平移的图形,我想使用 bokeh 或其他类似的库进行绘图会更好,这样,您可以保持它整洁并专注于有意义的部分?

【讨论】:

    【解决方案2】:

    我为一个小情景喜剧继任图做了类似的图表。代码有点幼稚(placed on github),但是在遇到您的问题时,我很惊讶这对于进行类似可视化的人来说仍然是一个问题。我希望可能有专门的历史图表库。

    【讨论】:

    【解决方案3】:

    这里是复制原始图的代码,问题中预计会出现这样的情况,这样可以有更多时间来回答问题(而不是重新创建它)。

    import pandas as pd
    import matplotlib.pyplot as plt
    
    xia = pd.DataFrame([['Da Yu', -2207, -2197], 
                        ['Qi', -2197, -2188], 
                        ['Tai Kang', -2188, -2159]], 
                        columns=['EnglishName', 'Start', 'Finish']) 
    event = xia['EnglishName']
    begin = xia['Start']
    end = xia['Finish']
    length =  xia['Finish'] - xia['Start']
    
    
    plt.figure(figsize=(12,6))
    plt.barh(range(len(begin)), (end-begin), .3, left=begin)
    plt.tick_params(axis='both', which='major', labelsize=15)
    plt.tick_params(axis='both', which='minor', labelsize=20)
    plt.title('Xia Dynasty', fontsize = '25')
    plt.xlabel('Year', fontsize = '20')
    plt.yticks(range(len(begin)), "")
    plt.xlim(-2250, -1750)
    plt.ylim(-1,18)
    for i in range(3):
        plt.text(begin.iloc[i] + length.iloc[i]/2, 
                 i+.25, event.iloc[i], 
                 ha='center', fontsize = '12')
    

    申诉(解决接下来要做什么):

    问题是 1.这很难阅读和 2. 我不知道如何把它弄平,使它看起来像一个传统的时间线。当我尝试使用更大的细分市场时,这个问题变得更加明显

    如果条形更靠近或颜色不同并且都在相同的 y 值上,我会更喜欢。

    这些设计很难用语言来具体说明。如果你放在一行上(例如使用这个plt.barh([1 for _ in begin], (end-begin)-0.5, .3, left=begin)),文本会重叠,甚至更难以阅读。

    这是一个重现水平时间线的小代码:

    plt.figure(figsize=(4,2))
    plt.ylim(0.5, 1.5)
    plt.yticks(range(len(begin)), "")
    # 0.25 is a stub, it controls for white separator
    plt.barh([1 for _ in begin], (end-begin)-0.25, .3, left=begin)
    

    但是你希望把名字放在哪里?

    如果你想要不同的颜色,需要一些关于颜色的规则。程序员会说你需要一个更好的任务规范。

    【讨论】:

      猜你喜欢
      • 2021-11-25
      • 2012-08-26
      • 2018-08-02
      • 1970-01-01
      • 2022-01-13
      • 2013-04-08
      • 1970-01-01
      • 2011-08-30
      • 2012-06-20
      相关资源
      最近更新 更多