Барная диаграмма pandas multiindex: стек первого уровня [дубликат]

Эта ошибка в основном возникла, когда SQL-служба остановлена. Вам нужно перезапустить службу. Чтобы перейти в это окно, вам необходимо выполнить поиск таких сервисов, как this-

Затем Найдите SQLSERVER (MSSQLSERVER) и перезапустите службу.

Надеюсь, что это сработает.

34
задан jrjc 10 February 2017 в 20:52
поделиться

5 ответов

Итак, я в конце концов нашел трюк (изменить: см. ниже для использования морского и длинного фреймов данных):

Решение с помощью pandas и matplotlib

Здесь приводится более полный пример :

import pandas as pd
import matplotlib.cm as cm
import numpy as np
import matplotlib.pyplot as plt

def plot_clustered_stacked(dfall, labels=None, title="multiple stacked bar plot",  H="/", **kwargs):
    """Given a list of dataframes, with identical columns and index, create a clustered stacked bar plot. 
labels is a list of the names of the dataframe, used for the legend
title is a string for the title of the plot
H is the hatch used for identification of the different dataframe"""

    n_df = len(dfall)
    n_col = len(dfall[0].columns) 
    n_ind = len(dfall[0].index)
    axe = plt.subplot(111)

    for df in dfall : # for each data frame
        axe = df.plot(kind="bar",
                      linewidth=0,
                      stacked=True,
                      ax=axe,
                      legend=False,
                      grid=False,
                      **kwargs)  # make bar plots

    h,l = axe.get_legend_handles_labels() # get the handles we want to modify
    for i in range(0, n_df * n_col, n_col): # len(h) = n_col * n_df
        for j, pa in enumerate(h[i:i+n_col]):
            for rect in pa.patches: # for each index
                rect.set_x(rect.get_x() + 1 / float(n_df + 1) * i / float(n_col))
                rect.set_hatch(H * int(i / n_col)) #edited part     
                rect.set_width(1 / float(n_df + 1))

    axe.set_xticks((np.arange(0, 2 * n_ind, 2) + 1 / float(n_df + 1)) / 2.)
    axe.set_xticklabels(df.index, rotation = 0)
    axe.set_title(title)

    # Add invisible data to add another legend
    n=[]        
    for i in range(n_df):
        n.append(axe.bar(0, 0, color="gray", hatch=H * i))

    l1 = axe.legend(h[:n_col], l[:n_col], loc=[1.01, 0.5])
    if labels is not None:
        l2 = plt.legend(n, labels, loc=[1.01, 0.1]) 
    axe.add_artist(l1)
    return axe

# create fake dataframes
df1 = pd.DataFrame(np.random.rand(4, 5),
                   index=["A", "B", "C", "D"],
                   columns=["I", "J", "K", "L", "M"])
df2 = pd.DataFrame(np.random.rand(4, 5),
                   index=["A", "B", "C", "D"],
                   columns=["I", "J", "K", "L", "M"])
df3 = pd.DataFrame(np.random.rand(4, 5),
                   index=["A", "B", "C", "D"], 
                   columns=["I", "J", "K", "L", "M"])

# Then, just call :
plot_clustered_stacked([df1, df2, df3],["df1", "df2", "df3"])

И это дает следующее:

multiple stacked bar plot [/g3]

Вы можете изменить цвета полосы, передав cmap:

plot_clustered_stacked([df1, df2, df3],
                       ["df1", "df2", "df3"],
                       cmap=plt.cm.viridis)

Решение с морским транспортом:

Учитывая тот же самый df1, df2, df3, я преобразую их в длинной форме:

df1["Name"] = "df1"
df2["Name"] = "df2"
df3["Name"] = "df3"
dfall = pd.concat([pd.melt(i.reset_index(),
                           id_vars=["Name", "index"]) # transform in tidy format each df
                   for i in [df1, df2, df3]],
                   ignore_index=True)

Проблема с морским суннитом заключается в том, что он не складывает бары изначально, поэтому трюк заключается в построении совокупной суммы каждого бара друг над другом:

dfall.set_index(["Name", "index", "variable"], inplace=1)
dfall["vcs"] = dfall.groupby(level=["Name", "index"]).cumsum()
dfall.reset_index(inplace=True) 

>>> dfall.head(6)
  Name index variable     value       vcs
0  df1     A        I  0.717286  0.717286
1  df1     B        I  0.236867  0.236867
2  df1     C        I  0.952557  0.952557
3  df1     D        I  0.487995  0.487995
4  df1     A        J  0.174489  0.891775
5  df1     B        J  0.332001  0.568868

Затем цикл над каждой группой variable и нарисуйте кумулятивную сумму:

c = ["blue", "purple", "red", "green", "pink"]
for i, g in enumerate(dfall.groupby("variable")):
    ax = sns.barplot(data=g[1],
                     x="index",
                     y="vcs",
                     hue="Name",
                     color=c[i],
                     zorder=-i, # so first bars stay on top
                     edgecolor="k")
ax.legend_.remove() # remove the redundant legends 

В нем отсутствует легенда, которую можно легко добавить. Проблема заключается в том, что вместо люков (которые могут быть легко добавлены), чтобы отличать данные, мы имеем градиентность легкости, и это слишком мало для первого, и я действительно не знаю, как изменить это, не меняя каждый прямоугольник один за другим (как в первом решении).

Скажите, если вы что-то не поняли в коде.

Не забудьте повторно использовать этот код, который находится под СС0.

47
ответ дан jrjc 19 August 2018 в 01:40
поделиться
  • 1
    Ницца ! Как это можно построить с помощью mpld3? – ArtDijk 27 April 2014 в 22:06
  • 2
    Я не знаю mpdld3, но из того, что я понял из документа, вам просто нужно отобразить его с помощью mpld3.display(plt.gcf()) или чего-то подобного. – jrjc 28 April 2014 в 10:47
  • 3
    Могли бы вы сделать мне огромную услугу и поставить этот сниппет под BSD / MIT / CC-0? Благодаря :) – Andreas Mueller 26 August 2014 в 09:58
  • 4
    @AndreasMueller: Готово, получайте удовольствие! – jrjc 8 September 2014 в 15:25
  • 5
    Спасибо! Это было очень полезно. – Andreas Mueller 9 September 2014 в 11:07

Ты на правильном пути! Чтобы изменить порядок баров, вы должны изменить порядок в индексе.

In [5]: df_both = pd.concat(dict(df1 = df1, df2 = df2),axis = 0)

In [6]: df_both
Out[6]:
              I         J
df1 A  0.423816  0.094405
    B  0.825094  0.759266
    C  0.654216  0.250606
    D  0.676110  0.495251
df2 A  0.607304  0.336233
    B  0.581771  0.436421
    C  0.233125  0.360291
    D  0.519266  0.199637

[8 rows x 2 columns]

Итак, мы хотим поменять оси, а затем переупорядочить. Вот простой способ сделать это

In [7]: df_both.swaplevel(0,1)
Out[7]:
              I         J
A df1  0.423816  0.094405
B df1  0.825094  0.759266
C df1  0.654216  0.250606
D df1  0.676110  0.495251
A df2  0.607304  0.336233
B df2  0.581771  0.436421
C df2  0.233125  0.360291
D df2  0.519266  0.199637

[8 rows x 2 columns]

In [8]: df_both.swaplevel(0,1).sort_index()
Out[8]:
              I         J
A df1  0.423816  0.094405
  df2  0.607304  0.336233
B df1  0.825094  0.759266
  df2  0.581771  0.436421
C df1  0.654216  0.250606
  df2  0.233125  0.360291
D df1  0.676110  0.495251
  df2  0.519266  0.199637

[8 rows x 2 columns]

Если важно, чтобы ваши горизонтальные метки отображались в старом порядке (df1, A), а не (A, df1), мы можем просто swaplevel s снова, а не sort_index:

In [9]: df_both.swaplevel(0,1).sort_index().swaplevel(0,1)
Out[9]:
              I         J
df1 A  0.423816  0.094405
df2 A  0.607304  0.336233
df1 B  0.825094  0.759266
df2 B  0.581771  0.436421
df1 C  0.654216  0.250606
df2 C  0.233125  0.360291
df1 D  0.676110  0.495251
df2 D  0.519266  0.199637

[8 rows x 2 columns]
1
ответ дан bgschiller 19 August 2018 в 01:40
поделиться
  • 1
    Спасибо, он работает как можно раньше. Я хотел бы иметь что-то визуально ясное, здесь все бары одинаково распределены вдоль оси x, я хотел бы сгруппировать 2 на 2. Извините, я не упоминал об этом в вопросе. (Я отредактирую) – jrjc 1 April 2014 в 14:52

Мне удалось сделать то же самое, используя подзаголовки pandas и matplotlib с базовыми командами.

Вот пример:

fig, axes = plt.subplots(nrows=1, ncols=3)

ax_position = 0
for concept in df.index.get_level_values('concept').unique():
    idx = pd.IndexSlice
    subset = df.loc[idx[[concept], :],
                    ['cmp_tr_neg_p_wrk', 'exp_tr_pos_p_wrk',
                     'cmp_p_spot', 'exp_p_spot']]     
    print(subset.info())
    subset = subset.groupby(
        subset.index.get_level_values('datetime').year).sum()
    subset = subset / 4  # quarter hours
    subset = subset / 100  # installed capacity
    ax = subset.plot(kind="bar", stacked=True, colormap="Blues",
                     ax=axes[ax_position])
    ax.set_title("Concept \"" + concept + "\"", fontsize=30, alpha=1.0)
    ax.set_ylabel("Hours", fontsize=30),
    ax.set_xlabel("Concept \"" + concept + "\"", fontsize=30, alpha=0.0),
    ax.set_ylim(0, 9000)
    ax.set_yticks(range(0, 9000, 1000))
    ax.set_yticklabels(labels=range(0, 9000, 1000), rotation=0,
                       minor=False, fontsize=28)
    ax.set_xticklabels(labels=['2012', '2013', '2014'], rotation=0,
                       minor=False, fontsize=28)
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(['Market A', 'Market B',
               'Market C', 'Market D'],
              loc='upper right', fontsize=28)
    ax_position += 1

# look "three subplots"
#plt.tight_layout(pad=0.0, w_pad=-8.0, h_pad=0.0)

# look "one plot"
plt.tight_layout(pad=0., w_pad=-16.5, h_pad=0.0)
axes[1].set_ylabel("")
axes[2].set_ylabel("")
axes[1].set_yticklabels("")
axes[2].set_yticklabels("")
axes[0].legend().set_visible(False)
axes[1].legend().set_visible(False)
axes[2].legend(['Market A', 'Market B',
                'Market C', 'Market D'],
               loc='upper right', fontsize=28)

Структура данных данных подмножества перед группировкой выглядит например:

<class 'pandas.core.frame.DataFrame'>
MultiIndex: 105216 entries, (D_REC, 2012-01-01 00:00:00) to (D_REC, 2014-12-31 23:45:00)
Data columns (total 4 columns):
cmp_tr_neg_p_wrk    105216 non-null float64
exp_tr_pos_p_wrk    105216 non-null float64
cmp_p_spot          105216 non-null float64
exp_p_spot          105216 non-null float64
dtypes: float64(4)
memory usage: 4.0+ MB

и график следующим образом:

Отформатирован в стиле «ggplot» с следующий заголовок:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
matplotlib.style.use('ggplot')
4
ответ дан Cord Kaldemeyer 19 August 2018 в 01:40
поделиться
  • 1
    Отличный ответ, но сложнее следовать без данных для тиражирования. Можно ли где-то загружать данные? – lincolnfrias 7 May 2017 в 11:36

Это отличное начало, но я думаю, что цвета могут быть немного изменены для ясности. Также будьте осторожны при импорте каждого аргумента в Altair, поскольку это может привести к конфликтам с существующими объектами в вашем пространстве имен. Ниже приведен некоторый реконфигурированный код для отображения правильного цветового отображения при укладке значений:

Импортировать пакеты

import pandas as pd
import numpy as np
import altair as alt

Создать некоторые случайные данные

df1=pd.DataFrame(10*np.random.rand(4,3),index=["A","B","C","D"],columns=["I","J","K"])
df2=pd.DataFrame(10*np.random.rand(4,3),index=["A","B","C","D"],columns=["I","J","K"])
df3=pd.DataFrame(10*np.random.rand(4,3),index=["A","B","C","D"],columns=["I","J","K"])

def prep_df(df, name):
    df = df.stack().reset_index()
    df.columns = ['c1', 'c2', 'values']
    df['DF'] = name
    return df

df1 = prep_df(df1, 'DF1')
df2 = prep_df(df2, 'DF2')
df3 = prep_df(df3, 'DF3')

df = pd.concat([df1, df2, df3])

Данные графика с Altair

alt.Chart(df).mark_bar().encode(

    # tell Altair which field to group columns on
    x=alt.X('c2:N',
        axis=alt.Axis(
            title='')),

    # tell Altair which field to use as Y values and how to calculate
    y=alt.Y('sum(values):Q',
        axis=alt.Axis(
            grid=False,
            title='')),

    # tell Altair which field to use to use as the set of columns to be  represented in each group
    column=alt.Column('c1:N',
                 axis=alt.Axis(
            title='')),

    # tell Altair which field to use for color segmentation 
    color=alt.Color('DF:N',
            scale=alt.Scale(
                # make it look pretty with an enjoyable color pallet
                range=['#96ceb4', '#ffcc5c','#ff6f69'],
            ),
        ))\
    .configure_facet_cell(
    # remove grid lines around column clusters
        strokeWidth=0.0)
1
ответ дан Grant Langseth 19 August 2018 в 01:40
поделиться

Альтаир может быть полезен здесь.

Импорт

import pandas as pd
import numpy as np
from altair import *

Создание набора данных

df1=pd.DataFrame(10*np.random.rand(4,2),index=["A","B","C","D"],columns=["I","J"])
df2=pd.DataFrame(10*np.random.rand(4,2),index=["A","B","C","D"],columns=["I","J"])

Подготовка набора данных

def prep_df(df, name):
    df = df.stack().reset_index()
    df.columns = ['c1', 'c2', 'values']
    df['DF'] = name
    return df

df1 = prep_df(df1, 'DF1')
df2 = prep_df(df2, 'DF2')

df = pd.concat([df1, df2])

Задание Altair

Chart(df).mark_bar().encode(y=Y('values', axis=Axis(grid=False)),
                            x='c2:N', 
                            column=Column('c1:N') ,
                            color='DF:N').configure_facet_cell( strokeWidth=0.0).configure_cell(width=200, height=200)
0
ответ дан Nipun Batra 19 August 2018 в 01:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: