Создание категориальной или сгруппированной гистограммы с вторичной линейной диаграммой оси - PullRequest
2 голосов
/ 02 апреля 2019

Мне нужно сравнить различные наборы ежедневных данных между 4 сменами (категориальные / групповые), используя гистограммы и линейные графики.Я искал повсюду и не нашел рабочего решения для этого, которое не включает в себя создание новых пивотов и т. Д.

Я использовал оба, matplotlib и seaborn, и хотя я могу сделать одно или другое (разные цветные полосы / линии для каждой смены), когда я включаю другой, либо один исчезает, либо возникают другие аномалии, как показывает только одна точка графика.Я просмотрел все, и есть решения для представления одной серии данных на обоих типах диаграмм, но ни одно из них не относится к нескольким категориям или группируется для обоих.

Пример данных:

report_date wh_id   shift   Head_Count  UTL_R
3/17/19     55  A   72  25%
3/18/19     55  A   71  10%
3/19/19     55  A   76  20%
3/20/19     55  A   59  33%
3/21/19     55  A   65  10%
3/22/19     55  A   54  20%
3/23/19     55  A   66  14%
3/17/19     55  1   11  10%
3/17/19     55  2   27  13%
3/17/19     55  3   18  25%
3/18/19     55  1   23  100%
3/18/19     55  2   16  25%
3/18/19     55  3   12  50%
3/19/19     55  1   28  10%
3/19/19     55  2   23  50%
3/19/19     55  3   14  33%
3/20/19     55  1   29  25%
3/20/19     55  2   29  25%
3/20/19     55  3   10  50%
3/21/19     55  1   17  20%
3/21/19     55  2   29  14%
3/21/19     55  3   30  17%
3/22/19     55  1   12  14%
3/22/19     55  2   10  100%
3/22/19     55  3   17  14%
3/23/19     55  1   16  10%
3/23/19     55  2   11  100%
3/23/19     55  3   13  10%
tm_daily_df = pd.read_csv('fg_TM_Daily.csv')
tm_daily_df = tm_daily_df.set_index('report_date')
fig2, ax2 = plt.subplots(figsize=(12,8))
ax3 = ax2.twinx()
group_obj = tm_daily_df.groupby('shift')
g = group_obj['Head_Count'].plot(kind='bar', x='report_date',  y='Head_Count',ax=ax2,stacked=False,alpha = .2)
g = group_obj['UTL_R'].plot(kind='line',x='report_date', y='UTL_R', ax=ax3,marker='d', markersize=12)
plt.legend(tm_daily_df['shift'].unique())

Этот код сделал меня самым близким, что я смог получить.Обратите внимание, что даже с stacked = False они все еще сложены.Я изменил настройку на True, и ничего не изменилось.

Все, что мне нужно, это чтобы столбцы находились рядом друг с другом с одинаковой цветовой схемой, представляющей сдвиг

График:

graph

Ответы [ 2 ]

1 голос
/ 02 апреля 2019

Вот два решения (с накоплением и без накопления). На основании ваших вопросов мы:

  • график Head_Count по левой оси y и UTL_R по правой оси y.
  • report_date будет нашей осью х
  • shift будет представлять оттенок нашего графика.

В составной версии используется pandas функция построения графиков по умолчанию, а в неструктурированной версии используется seaborn.

EDIT
По вашему запросу я добавил стопроцентный график. Хотя это не совсем то, что вы спрашивали в комментарии, тип графика, который вы спрашивали, может создать некоторую путаницу при чтении (значения основаны на верхней строке стека или ширине стека). Альтернативным решением может быть использование 100% -ного стекового графика.

Stacked

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

dfg = df.set_index(['report_date', 'shift']).sort_index(level=[0,1])

fig, ax = plt.subplots(figsize=(12,6))

ax2  = ax.twinx()

dfg['Head_Count'].unstack().plot.bar(stacked=True, ax=ax, alpha=0.6)
dfg['UTL_R'].unstack().plot(kind='line', ax=ax2, marker='o', legend=None)

ax.set_title('My Graph')
plt.show()

enter image description here

С накоплением 100%

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

dfg = df.set_index(['report_date', 'shift']).sort_index(level=[0,1])

# Create `Head_Count_Pct` column
for date in dfg.index.get_level_values('report_date').unique():
    for shift in dfg.loc[date, :].index.get_level_values('shift').unique():
        dfg.loc[(date, shift), 'Head_Count_Pct'] = dfg.loc[(date, shift), 'Head_Count'].sum() / dfg.loc[(date, 'A'), 'Head_Count'].sum()

fig, ax = plt.subplots(figsize=(12,6))

ax2  = ax.twinx()
pal = sns.color_palette("Set1")

dfg[dfg.index.get_level_values('shift').isin(['1','2','3'])]['Head_Count_Pct'].unstack().plot.bar(stacked=True, ax=ax, alpha=0.5, color=pal)
dfg['UTL_R'].unstack().plot(kind='line', ax=ax2, marker='o', legend=None, color=pal)

ax.set_title('My Graph')
plt.show()

enter image description here

штабель

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

dfg = df.set_index(['report_date', 'shift']).sort_index(level=[0,1])

fig, ax = plt.subplots(figsize=(15,6))

ax2  = ax.twinx()

sns.barplot(x=dfg.index.get_level_values('report_date'),
            y=dfg.Head_Count,
           hue=dfg.index.get_level_values('shift'), ax=ax, alpha=0.7)

sns.lineplot(x=dfg.index.get_level_values('report_date'),
            y=dfg.UTL_R,
           hue=dfg.index.get_level_values('shift'), ax=ax2, marker='o', legend=None)

ax.set_title('My Graph')
plt.show()

enter image description here


РЕДАКТИРОВАТЬ # 2

Вот график, который вы запросили во второй раз (сложен, но стек n + 1 не начинается там, где заканчивается стек n).

Это немного сложнее, так как мы должны сделать несколько вещей: - нам нужно вручную назначить наш цвет нашему shift в нашей df - как только мы назначим наши цвета, мы будем перебирать каждый диапазон дат и 1) сортировать или Head_Count значения по убыванию (чтобы наш самый большой мешок находился сзади, когда мы строим график), и 2) наносить данные и назначать цвет для каждой сцены - Затем мы можем создать нашу вторую ось Y и построить наши значения UTL_R - Затем нам нужно назначить правильный цвет для наших ярлыков легенды

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

def assignColor(shift):
    if shift == 'A':
        return 'R'
    if shift == '1':
        return 'B'
    if shift == '2':
        return 'G'
    if shift == '3':
        return 'Y'

# map a color to a shift
df['color'] = df['shift'].apply(assignColor)

fig, ax = plt.subplots(figsize=(15,6))

# plot our Head_Count values
for date in df.report_date.unique():
    d = df[df.report_date == date].sort_values(by='Head_Count', ascending=False)
    y = d.Head_Count.values
    x = date
    color = d.color
    b = plt.bar(x,y, color=color)

# Plot our UTL_R values
ax2 = ax.twinx()    

sns.lineplot(x=df.report_date, y=df.UTL_R, hue=df['shift'], marker='o', legend=None)

# Assign the color label color to our legend
leg = ax.legend(labels=df['shift'].unique(), loc=1)

legend_maping = dict()

for shift in df['shift'].unique():
    legend_maping[shift] = df[df['shift'] == shift].color.unique()[0]

i = 0
for leg_lab in leg.texts:
    leg.legendHandles[i].set_color(legend_maping[leg_lab.get_text()])
    i += 1

enter image description here

1 голос
/ 02 апреля 2019

Как насчет этого?

tm_daily_df['UTL_R'] = tm_daily_df['UTL_R'].str.replace('%', '').astype('float') / 100
pivoted = tm_daily_df.pivot_table(values=['Head_Count', 'UTL_R'], 
                                  index='report_date', 
                                  columns='shift')
pivoted

#             Head_Count             UTL_R
# shift                1   2   3   A     1     2     3     A
# report_date
# 3/17/19             11  27  18  72  0.10  0.13  0.25  0.25
# 3/18/19             23  16  12  71  1.00  0.25  0.50  0.10
# 3/19/19             28  23  14  76  0.10  0.50  0.33  0.20
# 3/20/19             29  29  10  59  0.25  0.25  0.50  0.33
# 3/21/19             17  29  30  65  0.20  0.14  0.17  0.10
# 3/22/19             12  10  17  54  0.14  1.00  0.14  0.20
# 3/23/19             16  11  13  66  0.10  1.00  0.10  0.14

fig, ax = plt.subplots()
pivoted['Head_Count'].plot.bar(ax=ax)
pivoted['UTL_R'].plot.line(ax=ax, legend=False, secondary_y=True, marker='D')
ax.legend(loc='upper left', title='shift')

...