Comment puis-je tracer des DataFrames Pandas séparés en tant que sous-graphiques?

129

J'ai quelques Pandas DataFrames partageant la même échelle de valeur, mais ayant des colonnes et des indices différents. Lors de l'invocation df.plot(), j'obtiens des images de tracé séparées. ce que je veux vraiment, c'est les avoir tous dans la même intrigue que les sous-intrigues, mais je n'arrive malheureusement pas à trouver une solution à la façon dont et j'apprécierais beaucoup de l'aide.

Jimmy C
la source

Réponses:

252

Vous pouvez créer manuellement les sous-tracés avec matplotlib, puis tracer les dataframes sur un sous-tracé spécifique à l'aide du axmot - clé. Par exemple pour 4 sous-parcelles (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])
...

Voici axesun tableau qui contient les différents axes de sous-tracé, et vous pouvez y accéder simplement par indexation axes.
Si vous voulez un x-axe commun, vous pouvez fournir sharex=Trueà plt.subplots.

joris
la source
33
Notez que, de manière ennuyeuse, .subplots()renvoie différents systèmes de coordonnées en fonction des dimensions du tableau de sous-graphiques que vous créez. Donc, si vous retournez des sous-graphiques où, par exemple, nrows=2, ncols=1vous devrez indexer les axes comme axes[0]et axes[1]. Voir stackoverflow.com/a/21967899/1569221
canary_in_the_data_mine
3
@canary_in_the_data_mine Merci, c'est vraiment ennuyeux ... votre commentaire m'a fait gagner du temps :) je n'ai pas IndexError: too many indices for array
compris
9
@canary_in_the_data_mine Cela n'est gênant que si les arguments par défaut pour .subplot()sont utilisés. Défini squeeze=Falsesur forcer .subplot()pour toujours renvoyer un ndarraydans tous les cas de lignes et de colonnes.
Martin
73

Vous pouvez voir par exemple dans le documentation démontrant la réponse joris. Également à partir de la documentation, vous pouvez également définir subplots=Trueet layout=(,)dans la plotfonction pandas :

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

Vous pouvez également utiliser des fig.add_subplot()paramètres de grille de sous-tracé tels que 221, 222, 223, 224, etc., comme décrit dans l'article ici . De jolis exemples de tracé sur une trame de données pandas, y compris des sous-graphiques, peuvent être vus dans ce cahier ipython .

sedeh
la source
2
bien que la réponse de joris soit excellente pour l'utilisation générale de matplotlib, elle est excellente pour tous ceux qui souhaitent utiliser des pandas pour une visualisation rapide des données. Cela correspond également un peu mieux à la question.
Little Bobby Tables
Gardez à l'esprit que les subplotset layoutkwargs généreront plusieurs graphiques UNIQUEMENT pour une seule trame de données. Ceci est lié à, mais pas une solution à la question d'OP de tracer plusieurs dataframes dans un seul tracé.
Austin A
1
C'est la meilleure réponse pour une utilisation pure des Pandas. Cela ne nécessite pas d'importer directement matplotlib (bien que vous devriez normalement de toute façon) et ne nécessite pas de boucle pour les formes arbitraires (peut utiliser layout=(df.shape[1], 1), par exemple).
Anatoly Makarevich le
20

Vous pouvez utiliser le style familier de Matplotlib en appelant un figureand subplot, mais vous devez simplement spécifier l'axe actuel à l'aide de plt.gca(). Un exemple:

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

etc...

Q-man
la source
7

Vous pouvez tracer plusieurs sous-tracés de plusieurs trames de données pandas à l'aide de matplotlib avec une simple astuce consistant à faire une liste de toutes les trames de données. Ensuite, utilisez la boucle for pour tracer des sous-graphiques.

Code de travail:

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

entrez la description de l'image ici

En utilisant ce code, vous pouvez tracer des sous-graphiques dans n'importe quelle configuration. Vous devez simplement définir le nombre de lignes nrowet le nombre de colonnes ncol. En outre, vous devez créer une liste des blocs de données df_listque vous vouliez tracer.

Dr Arslan
la source
2
faites attention à la faute de frappe dans la dernière rangée: ce n'est pas count =+1maiscount +=1
PEBKAC
4

Vous pouvez utiliser ceci:

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

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

plt.show()
Joe
la source
3

Vous n'aurez peut-être pas du tout besoin d'utiliser Pandas. Voici un graphique matplotlib des fréquences de chat:

entrez la description de l'image ici

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
la source
1

En vous basant sur la réponse @joris ci-dessus, si vous avez déjà établi une référence au sous-tracé, vous pouvez également utiliser la référence. Par exemple,

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

df.plot.barh(ax=ax1, stacked=True)
DaveL17
la source
0

Comment créer plusieurs graphiques à partir d'un dictionnaire de dataframes avec des données longues (rangées)

  • Hypothèses

    • Il existe un dictionnaire de plusieurs dataframes de données ordonnées
      • Créé en lisant des fichiers
      • Créé en séparant une seule dataframe en plusieurs dataframes
    • Les catégories cat,, peuvent se chevaucher, mais toutes les dataframes peuvent ne pas contenir toutes les valeurs decat
    • hue='cat'
  • Étant donné que les dataframes sont itérées, il n'est pas garanti que les couleurs seront mappées de la même manière pour chaque tracé

    • Une carte de couleurs personnalisée doit être créée à partir de l'unique 'cat' valeurs de toutes les dataframes
    • Puisque les couleurs seront les mêmes, placez une légende sur le côté des parcelles, au lieu d'une légende dans chaque parcelle

Importations et données synthétiques

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

Créer des mappages de couleurs et tracer

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

entrez la description de l'image ici

Trenton McKinney
la source