Jak mogę wykreślić oddzielne ramki danych Pandas jako podploty?

129

Mam kilka ramek Pandas DataFrames, które mają tę samą skalę wartości, ale mają różne kolumny i indeksy. Podczas wywoływania df.plot()otrzymuję oddzielne obrazy fabuły. to, czego naprawdę chcę, to mieć je wszystkie na tej samej działce co wątki poboczne, ale niestety nie udaje mi się znaleźć rozwiązania, jak i byłbym bardzo wdzięczny za pomoc.

Jimmy C.
źródło

Odpowiedzi:

252

Możesz ręcznie utworzyć wykresy podrzędne za pomocą matplotlib, a następnie wykreślić ramki danych na określonym wykresie podrzędnym za pomocą axsłowa kluczowego. Na przykład dla 4 poletek (2x2):

import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=2, ncols=2)

df1.plot(ax=axes[0,0])
df2.plot(ax=axes[0,1])
...

Oto axestablica, która zawiera różne osie wykresów pomocniczych, do której można uzyskać dostęp po prostu przez indeksowanie axes.
Jeśli chcesz mieć współdzieloną oś X, możesz to sharex=Truezrobić plt.subplots.

joris
źródło
33
Zwróć uwagę, że irytująco .subplots()zwraca różne układy współrzędnych w zależności od wymiarów tablicy tworzonych wykresów podrzędnych. Więc jeśli zwrócisz działki podrzędne, w których, powiedzmy, nrows=2, ncols=1będziesz musiał zindeksować osie jako axes[0]i axes[1]. Zobacz stackoverflow.com/a/21967899/1569221
canary_in_the_data_mine
3
@canary_in_the_data_mine Dzięki, to naprawdę denerwujące ... Twój komentarz zaoszczędził mi trochę czasu :) nie mogłem zrozumieć, dlaczego dostajęIndexError: too many indices for array
snd
9
@canary_in_the_data_mine To jest denerwujące tylko wtedy, gdy .subplot()używane są domyślne argumenty dla . Ustaw squeeze=Falsetak, .subplot()aby zawsze zwracać an ndarrayw każdym przypadku wierszy i kolumn.
Martin
73

Możesz zobaczyć np. w dokumentacji demonstrującej odpowiedź Jorisa. Również z dokumentacji można było ustawić subplots=Trueiw layout=(,)ramach plotfunkcji pandy :

df.plot(subplots=True, layout=(1,2))

Możesz także użyć, fig.add_subplot()który przyjmuje parametry siatki podplotu, takie jak 221, 222, 223, 224 itp., Jak opisano w poście tutaj . Ładne przykłady wykresów na ramce danych pandy, w tym wątki poboczne , można zobaczyć w tym notatniku ipython .

sedeh
źródło
2
chociaż odpowiedź jorisa jest świetna do ogólnego użycia matplotlib, jest to doskonała dla każdego, kto chce używać pand do szybkiej wizualizacji danych. To też trochę lepiej wpisuje się w pytanie.
Little Bobby Tables
Należy pamiętać, że subplotsi layoutkwargs wygenerują wiele wykresów TYLKO dla jednej ramki danych. Jest to związane, ale nie rozwiązuje problemu OP, polegającego na wykreślaniu wielu ramek danych na jednym wykresie.
Austin A
1
To jest lepsza odpowiedź na użycie czystych pand. Nie wymaga to bezpośredniego importowania matplotlib (chociaż normalnie i tak powinieneś) i nie wymaga zapętlania dla dowolnych kształtów (można użyć layout=(df.shape[1], 1)na przykład).
Anatoly Makarevich
20

Możesz użyć znanego stylu Matplotlib, wywołując a figurei subplot, ale wystarczy określić bieżącą oś za pomocą plt.gca(). Przykład:

plt.figure(1)
plt.subplot(2,2,1)
df.A.plot() #no need to specify for first axis
plt.subplot(2,2,2)
df.B.plot(ax=plt.gca())
plt.subplot(2,2,3)
df.C.plot(ax=plt.gca())

itp...

Q-man
źródło
7

Możesz wykreślić wiele podplotów wielu ramek danych pandy za pomocą matplotlib z prostą sztuczką tworzenia listy wszystkich ramek danych. Następnie użyj pętli for do kreślenia wykresów podrzędnych.

Kod roboczy:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# dataframe sample data
df1 = pd.DataFrame(np.random.rand(10,2)*100, columns=['A', 'B'])
df2 = pd.DataFrame(np.random.rand(10,2)*100, columns=['A', 'B'])
df3 = pd.DataFrame(np.random.rand(10,2)*100, columns=['A', 'B'])
df4 = pd.DataFrame(np.random.rand(10,2)*100, columns=['A', 'B'])
df5 = pd.DataFrame(np.random.rand(10,2)*100, columns=['A', 'B'])
df6 = pd.DataFrame(np.random.rand(10,2)*100, columns=['A', 'B'])
#define number of rows and columns for subplots
nrow=3
ncol=2
# make a list of all dataframes 
df_list = [df1 ,df2, df3, df4, df5, df6]
fig, axes = plt.subplots(nrow, ncol)
# plot counter
count=0
for r in range(nrow):
    for c in range(ncol):
        df_list[count].plot(ax=axes[r,c])
        count=+1

wprowadź opis obrazu tutaj

Za pomocą tego kodu można wykreślić podploty w dowolnej konfiguracji. Musisz tylko zdefiniować liczbę wierszy nrowi liczbę kolumn ncol. Musisz także zrobić listę ramek danych, df_listktóre chciałeś wykreślić.

Dr Arslan
źródło
2
zwrócić uwagę na literówki w ostatnim rzędzie: to nie jest count =+1jednakcount +=1
PEBKAC
4

Możesz użyć tego:

fig = plt.figure()
ax = fig.add_subplot(221)
plt.plot(x,y)

ax = fig.add_subplot(222)
plt.plot(x,z)
...

plt.show()
Joe
źródło
3

Być może w ogóle nie będziesz musiał używać Pand. Oto wykres matplotlib częstotliwości kotów:

wprowadź opis obrazu tutaj

x = np.linspace(0, 2*np.pi, 400)
y = np.sin(x**2)

f, axes = plt.subplots(2, 1)
for c, i in enumerate(axes):
  axes[c].plot(x, y)
  axes[c].set_title('cats')
plt.tight_layout()
duhaime
źródło
1

Opierając się na powyższej odpowiedzi @joris, jeśli już ustanowiłeś odniesienie do polplotu, możesz również użyć odniesienia. Na przykład,

ax1 = plt.subplot2grid((50,100), (0, 0), colspan=20, rowspan=10)
...

df.plot.barh(ax=ax1, stacked=True)
DaveL17
źródło
0

Jak utworzyć wiele wykresów ze słownika ramek danych z długimi (uporządkowanymi) danymi

  • Założenia

    • Istnieje słownik wielu ramek uporządkowanych danych
      • Utworzone przez wczytanie z plików
      • Tworzone przez rozdzielenie pojedynczej ramki danych na wiele ramek danych
    • Kategorie cat,, mogą się na siebie nakładać, ale nie wszystkie ramki danych mogą zawierać wszystkie wartościcat
    • hue='cat'
  • Ponieważ ramki danych są iterowane, nie ma gwarancji, że kolory zostaną odwzorowane tak samo dla każdego wykresu

    • Należy utworzyć niestandardową mapę kolorów z unikalnych 'cat'wartości dla wszystkich ramek danych
    • Ponieważ kolory będą takie same, umieść jedną legendę z boku działek zamiast legendy na każdym wykresie

Importy i dane syntetyczne

import pandas as pd
import numpy as np  # used for random data
import random  # used for random data
import matplotlib.pyplot as plt
from matplotlib.patches import Patch  # for custom legend
import seaborn as sns
import math import ceil  # determine correct number of subplot


# synthetic data
df_dict = dict()
for i in range(1, 7):
    np.random.seed(i)
    random.seed(i)
    data_length = 100
    data = {'cat': [random.choice(['A', 'B', 'C']) for _ in range(data_length)],
            'x': np.random.rand(data_length),
            'y': np.random.rand(data_length)}
    df_dict[i] = pd.DataFrame(data)


# display(df_dict[1].head())

  cat         x         y
0   A  0.417022  0.326645
1   C  0.720324  0.527058
2   A  0.000114  0.885942
3   B  0.302333  0.357270
4   A  0.146756  0.908535

Utwórz odwzorowania kolorów i wydrukuj

# create color mapping based on all unique values of cat
unique_cat = {cat for v in df_dict.values() for cat in v.cat.unique()}  # get unique cats
colors = sns.color_palette('husl', n_colors=len(unique_cat))  # get a number of colors
cmap = dict(zip(unique_cat, colors))  # zip values to colors

# iterate through dictionary and plot
col_nums = 3  # how many plots per row
row_nums = math.ceil(len(df_dict) / col_nums)  # how many rows of plots
plt.figure(figsize=(10, 5))  # change the figure size as needed
for i, (k, v) in enumerate(df_dict.items(), 1):
    plt.subplot(row_nums, col_nums, i)  # create subplots
    p = sns.scatterplot(data=v, x='x', y='y', hue='cat', palette=cmap)
    p.legend_.remove()  # remove the individual plot legends
    plt.title(f'DataFrame: {k}')

plt.tight_layout()
# create legend from cmap
patches = [Patch(color=v, label=k) for k, v in cmap.items()]
# place legend outside of plot; change the right bbox value to move the legend up or down
plt.legend(handles=patches, bbox_to_anchor=(1.06, 1.2), loc='center left', borderaxespad=0)
plt.show()

wprowadź opis obrazu tutaj

Trenton McKinney
źródło