python - matplotlib: líneas de dibujo entre puntos que ignoran datos faltantes
plt title python (5)
Tengo un conjunto de datos que quiero trazar como un gráfico de líneas. Para cada serie, faltan algunos datos (pero diferentes para cada serie). Actualmente, matplotlib no dibuja líneas que omitan datos faltantes: por ejemplo
import matplotlib.pyplot as plt
xs = range(8)
series1 = [1, 3, 3, None, None, 5, 8, 9]
series2 = [2, None, 5, None, 4, None, 3, 2]
plt.plot(xs, series1, linestyle=''-'', marker=''o'')
plt.plot(xs, series2, linestyle=''-'', marker=''o'')
plt.show()
da como resultado una trama con espacios en las líneas. ¿Cómo puedo decirle a matplotlib que dibuje líneas a través de los huecos? (Prefiero no tener que interpolar los datos).
Por lo que pueda valer, después de algunas pruebas y errores, me gustaría agregar una aclaración a la solución de Thorsten. Con suerte, se ahorra tiempo a los usuarios que buscaron en otro lado después de haber probado este enfoque.
No pude tener éxito con un problema idéntico mientras usaba
from pyplot import *
e intentando trazar con
plot(abscissa[mask],ordinate[mask])
Parecía que se requería usar import matplotlib.pyplot as plt
para obtener el manejo adecuado de NaNs, aunque no puedo decir por qué.
Puede enmascarar los valores NaN de esta manera:
import numpy as np
import matplotlib.pyplot as plt
xs = np.arange(8)
series1 = np.array([1, 3, 3, None, None, 5, 8, 9]).astype(np.double)
s1mask = np.isfinite(series1)
series2 = np.array([2, None, 5, None, 4, None, 3, 2]).astype(np.double)
s2mask = np.isfinite(series2)
plt.plot(xs[s1mask], series1[s1mask], linestyle=''-'', marker=''o'')
plt.plot(xs[s2mask], series2[s2mask], linestyle=''-'', marker=''o'')
plt.show()
Esto lleva a
Qouting @Rutger Kassies ( link ):
Matplotlib solo dibuja una línea entre puntos de datos consecutivos (válidos) y deja un espacio en los valores de NaN.
Una solución si estás usando Pandas,:
#pd.Series
s.dropna().plot() #masking (as @Thorsten Kranz suggestion)
#pd.DataFrame
df[''a_col_ffill''] = df[''a_col''].ffill(method=''ffill'')
df[''b_col_ffill''] = df[''b_col''].ffill(method=''ffill'') # changed from a to b
df[[''a_col_ffill'',''b_col_ffill'']].plot()
Sin interpolación, deberá eliminar los Ninguno de los datos. Esto también significa que deberá eliminar los valores X correspondientes a ninguno en la serie. Aquí hay un (un feo) trazador de líneas para hacer eso:
x1Clean,series1Clean = zip(* filter( lambda x: x[1] is not None , zip(xs,series1) ))
La función lambda devuelve False for None values, filtrando los pares x, series de la lista, luego vuelve a volver a comprimir los datos en su forma original.
Tal vez no entendí el punto, pero creo que Pandas ahora lo hace de forma automática . El siguiente ejemplo es un poco complicado y requiere acceso a Internet, pero la línea para China tiene muchas lagunas en los primeros años, de ahí los segmentos de línea recta.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# read data from Maddison project
url = ''http://www.ggdc.net/maddison/maddison-project/data/mpd_2013-01.xlsx''
mpd = pd.read_excel(url, skiprows=2, index_col=0, na_values=['' ''])
mpd.columns = map(str.rstrip, mpd.columns)
# select countries
countries = [''England/GB/UK'', ''USA'', ''Japan'', ''China'', ''India'', ''Argentina'']
mpd = mpd[countries].dropna()
mpd = mpd.rename(columns={''England/GB/UK'': ''UK''})
mpd = np.log(mpd)/np.log(2) # convert to log2
# plots
ax = mpd.plot(lw=2)
ax.set_title(''GDP per person'', fontsize=14, loc=''left'')
ax.set_ylabel(''GDP Per Capita (1990 USD, log2 scale)'')
ax.legend(loc=''upper left'', fontsize=10, handlelength=2, labelspacing=0.15)
fig = ax.get_figure()
fig.show()