¿Cómo puedo trazar los Pandas DataFrames separados como subtramas?

129

Tengo algunos Pandas DataFrames que comparten la misma escala de valores, pero que tienen diferentes columnas e índices. Al invocar df.plot(), obtengo imágenes de trama separadas. lo que realmente quiero es tenerlos a todos en la misma trama que las subtramas, pero desafortunadamente no puedo encontrar una solución a cómo y agradecería mucho alguna ayuda.

Jimmy C
fuente

Respuestas:

250

Puede crear manualmente las subtramas con matplotlib y luego trazar los marcos de datos en una subtrama específica utilizando la axpalabra clave. Por ejemplo para 4 subtramas (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])
...

Aquí axeshay una matriz que contiene los diferentes ejes de subtrama, y ​​puede acceder a uno simplemente indexando axes.
Si quieres un eje x compartida, entonces se puede ofrecer sharex=Truea plt.subplots.

joris
fuente
33
Tenga en cuenta que, molestamente, .subplots()devuelve diferentes sistemas de coordenadas dependiendo de las dimensiones de la matriz de subtramas que está creando. Entonces, si devuelve subtramas donde, por ejemplo, nrows=2, ncols=1deberá indexar los ejes como axes[0]y axes[1]. Ver stackoverflow.com/a/21967899/1569221
canary_in_the_data_mine
3
Gracias @canary_in_the_data_mine, que es realmente molesto ... tu comentario me salvó algún tiempo :) no podía entender por qué me estaba metiendoIndexError: too many indices for array
SND
9
@canary_in_the_data_mine Eso solo es molesto si .subplot()se utilizan argumentos predeterminados para . Establezca squeeze=Falseforzar .subplot()para devolver siempre un ndarrayen cualquier caso de filas y columnas.
Martin
73

Puedes ver e.gs. en la documentación que demuestra la respuesta de joris. También desde la documentación, también puede establecer subplots=Truey layout=(,)dentro de la plotfunción pandas :

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

También puede usar el fig.add_subplot()que toma parámetros de cuadrícula de subtrama como 221, 222, 223, 224, etc. como se describe en la publicación aquí . En este cuaderno de ipython se pueden ver buenos ejemplos de tramas en el marco de datos de pandas, incluidas las subtramas .

sedeh
fuente
2
aunque la respuesta de joris es excelente para el uso general de matplotlib, es excelente para cualquiera que quiera usar pandas para una visualización rápida de datos. También encaja un poco mejor con la pregunta.
Little Bobby Tables
Tenga en cuenta que subplotsy layoutkwargs generarán múltiples gráficos SOLAMENTE para un solo marco de datos. Esto está relacionado, pero no es una solución para la pregunta de OP de trazar múltiples marcos de datos en un solo gráfico.
Austin A
1
Esta es la mejor respuesta para el uso puro de Pandas. Esto no requiere importar matplotlib directamente (aunque normalmente debería hacerlo de todos modos) y no requiere bucle para formas arbitrarias (puede usar layout=(df.shape[1], 1), por ejemplo).
Anatoly Makarevich
20

Puede usar el estilo familiar de Matplotlib llamando a figurey subplot, pero simplemente necesita especificar el eje actual usando plt.gca(). Un ejemplo:

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
fuente
6

Puede trazar múltiples subtramas de múltiples marcos de datos de pandas usando matplotlib con un simple truco de hacer una lista de todos los marcos de datos. Luego, use el bucle for para trazar subtramas.

Código de trabajo:

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

ingrese la descripción de la imagen aquí

Con este código, puede trazar subtramas en cualquier configuración. Solo necesita definir el número de filas nrowy el número de columnas ncol. Además, debe hacer una lista de los marcos de datos df_listque desea trazar.

Dr. Arslan
fuente
2
preste atención al error tipográfico en la última fila: no es count =+1sinocount +=1
PEBKAC
4

Puedes usar esto:

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

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

plt.show()
Joe
fuente
3

Es posible que no necesite usar Pandas en absoluto. Aquí hay una gráfica de matplotlib de frecuencias de gatos:

ingrese la descripción de la imagen aquí

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
fuente
1

Basándose en la respuesta @joris anterior, si ya ha establecido una referencia a la subtrama, también puede usar la referencia. Por ejemplo,

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

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

Cómo crear múltiples gráficos a partir de un diccionario de marcos de datos con datos largos (ordenados)

  • Supuestos

    • Hay un diccionario de múltiples marcos de datos de datos ordenados
      • Creado al leer desde archivos
      • Creado al separar un único marco de datos en múltiples marcos de datos
    • Las categorías, catpueden estar superpuestas, pero todos los marcos de datos pueden no contener todos los valores decat
    • hue='cat'
  • Debido a que los marcos de datos se están iterando, no hay garantía de que los colores se asignen de la misma manera para cada gráfico

    • Se debe crear un mapa de color personalizado a partir de los 'cat'valores únicos para todos los marcos de datos
    • Como los colores serán los mismos, coloque una leyenda al lado de las parcelas, en lugar de una leyenda en cada trama

Importaciones y datos sintéticos

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 mapeos de color y 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()

ingrese la descripción de la imagen aquí

Trenton McKinney
fuente