Come posso tracciare Pandas DataFrame separati come sottotrame?


129

Ho alcuni Pandas DataFrame che condividono la stessa scala di valori, ma con colonne e indici diversi. Quando invoco df.plot(), ottengo immagini di trama separate. quello che voglio veramente è averli tutti nella stessa trama delle sottotrame, ma sfortunatamente non riesco a trovare una soluzione a come e apprezzerei molto un aiuto.

Risposte:


252

È possibile creare manualmente le sottotrame con matplotlib, quindi tracciare i dataframe su una sottotrama specifica utilizzando la axparola chiave. Ad esempio per 4 sottotrame (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])
...

Ecco axesun array che contiene i diversi assi della sottotrama e puoi accedervi semplicemente indicizzando axes.
Se desideri un asse x condiviso, puoi fornire sharex=Truea plt.subplots.


33
Nota che, fastidiosamente, .subplots()restituisce diversi sistemi di coordinate a seconda delle dimensioni della matrice di sottotrame che stai creando. Quindi, se restituisci sottotrame in cui, ad esempio, nrows=2, ncols=1dovrai indicizzare gli assi come axes[0]e axes[1]. Vedere stackoverflow.com/a/21967899/1569221
canary_in_the_data_mine

3
@canary_in_the_data_mine Grazie, è davvero fastidioso ... il tuo commento mi ha salvato un po 'di tempo :) non riuscivo a capire perché stavo ricevendoIndexError: too many indices for array
snd

9
@canary_in_the_data_mine Questo è fastidioso solo se .subplot()vengono utilizzati gli argomenti predefiniti per . Impostare squeeze=Falseper forzare la .subplot()restituzione sempre di un ndarrayin ogni caso di righe e colonne.
Martin,

73

Puoi vedere ad es. nella documentazione che mostra la risposta di joris. Sempre dalla documentazione, potresti anche impostare subplots=Truee layout=(,)all'interno della plotfunzione panda :

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

Puoi anche usare fig.add_subplot()che accetta parametri della griglia di sottotrama come 221, 222, 223, 224, ecc. Come descritto nel post qui . Simpatici esempi di trama su frame di dati panda, comprese le sottotrame, possono essere visti in questo notebook ipython .


2
sebbene la risposta di joris sia ottima per l'utilizzo generale di matplotlib, questo è eccellente per chiunque desideri utilizzare i panda per una rapida visualizzazione dei dati. Inoltre si adatta un po 'meglio alla domanda.
Little Bobby Tables

Tieni presente che subplotse layoutkwargs genereranno più grafici SOLO per un singolo dataframe. Questo è correlato, ma non una soluzione, alla questione di OP di tracciare più dataframe in un unico grafico.
Austin A

1
Questa è la risposta migliore per l'uso puro dei Panda. Ciò non richiede l'importazione diretta di matplotlib (anche se normalmente dovresti comunque) e non richiede il ciclo per forme arbitrarie (puoi usare layout=(df.shape[1], 1), ad esempio).
Anatoly Makarevich

20

Puoi usare il familiare stile Matplotlib chiamando un figuree subplot, ma devi semplicemente specificare l'asse corrente usando plt.gca(). Un esempio:

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())

eccetera...


7

È possibile tracciare più sottotrame di più frame di dati panda utilizzando matplotlib con un semplice trucco di creare un elenco di tutti i frame di dati. Quindi utilizzare il ciclo for per tracciare sottotrame.

Codice di lavoro:

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

inserisci qui la descrizione dell'immagine

Usando questo codice puoi tracciare sottotrame in qualsiasi configurazione. Devi solo definire il numero di righe nrowe il numero di colonne ncol. Inoltre, è necessario creare un elenco di frame di dati df_listche si desidera tracciare.


2
presta attenzione all'errore di battitura nell'ultima riga: non è count =+1macount +=1
PEBKAC

4

Puoi usare questo:

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

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

plt.show()

3

Potrebbe non essere necessario utilizzare i Panda. Ecco un grafico matplotlib delle frequenze dei gatti:

inserisci qui la descrizione dell'immagine

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()

1

Basandosi sulla risposta @joris sopra, se hai già stabilito un riferimento alla sottotrama, puoi usare anche il riferimento. Per esempio,

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

df.plot.barh(ax=ax1, stacked=True)

0

Come creare più grafici da un dizionario di dataframe con dati lunghi (ordinati)

  • ipotesi

    • C'è un dizionario di più dataframe di dati ordinati
      • Creato leggendo da file
      • Creato separando un singolo dataframe in più dataframe
    • Le categorie cat,, possono essere sovrapposte, ma tutti i dataframe potrebbero non contenere tutti i valori dicat
    • hue='cat'
  • Poiché i dataframe vengono iterati, non è garantito che i colori vengano mappati allo stesso modo per ogni grafico

    • È necessario creare una mappa dei colori personalizzata dai 'cat'valori univoci per tutti i dataframe
    • Poiché i colori saranno gli stessi, posiziona una legenda a lato delle trame, invece di una legenda in ogni trama

Importazioni e dati sintetici

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

Crea mappature di colore e trama

# 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()

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.