使用pyplot分段条在数据框中绘制枚举值

时间:2018-05-15 19:21:38

标签: pandas matplotlib

我有一系列(时间戳,枚举值)描述系统何时处于给定状态;该状态由枚举描述。

Time | State
--------------
  0  |   A
  3  |   B
  4  |   A
  7  |   C
  9  |   D

我希望通过将每个状态向前填充到下一个时间戳来显示条形图中的状态更改,并为每个枚举值使用不同的颜色:

|
|__________________________________________
|     A     | B |     A     |   C   |  D  |
|___________|___|___________|_______|_____|
|
---------------------------------------------
0   1   2   3   4   5   6   7   8   9   10   

有什么建议吗?我查看了Line Collection和水平条,但是线条集合看起来很笨重,而hbar似乎是标量值。我希望找到一个优雅的惯用解决方案。

2 个答案:

答案 0 :(得分:1)

您可以创建指定左起点和宽度的条形图:

color = {'A': 'red', 'B': 'green', 'C': 'blue', 'D': 'yellow'}
for s, t, c in list(zip(df.State, df.Time.shift(-1) - df.Time, df.Time))[: -1]:
    bar(left=c, height=0.8, width=t, bottom=0, color=color[s], orientation="horizontal", label=s)
    print(c, t)
legend();

enter image description here

您也可以致电

get_yaxis().set_visible(False)

使用更好的颜色,并使这个数字不那么难看(很难让它变得更多丑陋)。

答案 1 :(得分:0)

我想出了一个使用LineCollection的解决方案。我对它的不满是LineCollection元素看起来是尺度不变的(无论y轴刻度如何,它们看起来都是相同的宽度),这使得它很难操纵。由于这个缺点,我认为我更喜欢吧解决方案。

Horizontal bar plot with states represented as colors, and lengths of bars representing the duration that state was valid for.

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.patches as mpatches
import pandas as pd

df = pd.DataFrame(zip([0, 3, 4, 7, 9, 12], ['A', 'B', 'A', 'C', 'D', 'A']), 
                  columns=['Time', 'State'])

df['Duration'] = df['Time'].shift(-1) - df['Time']

# Showing how we can use HTML color names
state_to_color_map = {
    'A': 'LightBlue',
    'B': 'gray',
    'C': 'LightPink',
    'D': 'MediumSeaGreen'
}
fig = plt.figure(figsize=(8, 4))
ax = fig.gca()

plot_height = 0  # Can loop this to plot multiple bars

for state, state_color in state_to_color_map.iteritems():
  segments = [[(start, plot_height), (start + duration, plot_height)] for 
              (start, duration) in 
              df[df['State'] == state][['Time', 'Duration']].values]
  plot_segments = mpl.collections.LineCollection(
      segments=segments,
      # In matplotlib 2.2.2, this code is `mcolors.to_rgba(...)`
      # Use this code for matplotlib 1.5.3.
      colors=[mcolors.colorConverter.to_rgba(state_color)] * len(segments),
      linewidths=50)
  ax.add_collection(plot_segments)

ax.set_ylim(-1, 1)
ax.set_xlim(0, 12)

# Legend
patches = []
for state, color in sorted(state_to_color_map.iteritems()):
  patches.append(mpatches.Patch(color=color, label=state))
ax.legend(handles=patches, bbox_to_anchor=(1.10, 0.5), loc='center', 
          borderaxespad=0.)