python - font - pyplot title
Parcela de coordenadas paralelas en Matplotlib (4)
Los datos bidimensionales y tridimensionales se pueden ver de forma relativamente directa utilizando tipos de gráficos tradicionales. Incluso con datos de cuatro dimensiones, a menudo podemos encontrar una manera de mostrar los datos. Las dimensiones superiores a cuatro, sin embargo, se vuelven cada vez más difíciles de mostrar. Afortunadamente, las gráficas de coordenadas paralelas proporcionan un mecanismo para ver resultados con dimensiones superiores.
Varios paquetes de trazado proporcionan gráficas de coordenadas paralelas, como Matlab , R , VTK tipo 1 y VTK tipo 2 , pero no veo cómo crear una usando Matplotlib.
- ¿Hay un gráfico de coordenadas paralelas incorporado en Matplotlib? Ciertamente no veo uno en la galería .
- Si no hay un tipo incorporado, ¿es posible construir un gráfico de coordenadas paralelas utilizando las características estándar de Matplotlib?
Editar :
En base a la respuesta proporcionada por Zhenya a continuación, desarrollé la siguiente generalización que admite un número arbitrario de ejes. Siguiendo el estilo de trama del ejemplo que publiqué en la pregunta original anterior, cada eje obtiene su propia escala. Lo logré normalizando los datos en cada punto del eje y haciendo que los ejes tengan un rango de 0 a 1. Luego regreso y aplico etiquetas a cada marca que da el valor correcto en esa intersección.
La función funciona al aceptar un conjunto de datos iterable. Cada conjunto de datos se considera un conjunto de puntos donde cada punto se encuentra en un eje diferente. El ejemplo en __main__
toma números aleatorios para cada eje en dos conjuntos de 30 líneas. Las líneas son aleatorias dentro de los rangos que causan la agrupación de líneas; un comportamiento que quería verificar
Esta solución no es tan buena como una solución integrada, ya que tiene un comportamiento extraño en el mouse y falsifico los rangos de datos a través de las etiquetas, pero hasta que Matplotlib agregue una solución integrada, es aceptable.
#!/usr/bin/python
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
def parallel_coordinates(data_sets, style=None):
dims = len(data_sets[0])
x = range(dims)
fig, axes = plt.subplots(1, dims-1, sharey=False)
if style is None:
style = [''r-'']*len(data_sets)
# Calculate the limits on the data
min_max_range = list()
for m in zip(*data_sets):
mn = min(m)
mx = max(m)
if mn == mx:
mn -= 0.5
mx = mn + 1.
r = float(mx - mn)
min_max_range.append((mn, mx, r))
# Normalize the data sets
norm_data_sets = list()
for ds in data_sets:
nds = [(value - min_max_range[dimension][0]) /
min_max_range[dimension][2]
for dimension,value in enumerate(ds)]
norm_data_sets.append(nds)
data_sets = norm_data_sets
# Plot the datasets on all the subplots
for i, ax in enumerate(axes):
for dsi, d in enumerate(data_sets):
ax.plot(x, d, style[dsi])
ax.set_xlim([x[i], x[i+1]])
# Set the x axis ticks
for dimension, (axx,xx) in enumerate(zip(axes, x[:-1])):
axx.xaxis.set_major_locator(ticker.FixedLocator([xx]))
ticks = len(axx.get_yticklabels())
labels = list()
step = min_max_range[dimension][2] / (ticks - 1)
mn = min_max_range[dimension][0]
for i in xrange(ticks):
v = mn + i*step
labels.append(''%4.2f'' % v)
axx.set_yticklabels(labels)
# Move the final axis'' ticks to the right-hand side
axx = plt.twinx(axes[-1])
dimension += 1
axx.xaxis.set_major_locator(ticker.FixedLocator([x[-2], x[-1]]))
ticks = len(axx.get_yticklabels())
step = min_max_range[dimension][2] / (ticks - 1)
mn = min_max_range[dimension][0]
labels = [''%4.2f'' % (mn + i*step) for i in xrange(ticks)]
axx.set_yticklabels(labels)
# Stack the subplots
plt.subplots_adjust(wspace=0)
return plt
if __name__ == ''__main__'':
import random
base = [0, 0, 5, 5, 0]
scale = [1.5, 2., 1.0, 2., 2.]
data = [[base[x] + random.uniform(0., 1.)*scale[x]
for x in xrange(5)] for y in xrange(30)]
colors = [''r''] * 30
base = [3, 6, 0, 1, 3]
scale = [1.5, 2., 2.5, 2., 2.]
data.extend([[base[x] + random.uniform(0., 1.)*scale[x]
for x in xrange(5)] for y in xrange(30)])
colors.extend([''b''] * 30)
parallel_coordinates(data, style=colors).show()
Editar 2:
Aquí hay un ejemplo de lo que sale del código anterior al trazar los datos de Fisher Iris . No es tan bonito como la imagen de referencia de Wikipedia, pero es aceptable si todo lo que tienes es Matplotlib y necesitas tramas multidimensionales.
El mejor ejemplo que he visto hasta ahora es este
https://python.g-node.org/python-summerschool-2013/_media/wiki/datavis/olympics_vis.py
Ver la función normalised_coordinates. No muy rápido, pero funciona con lo que he probado.
normalised_coordinates([''VAL_1'', ''VAL_2'', ''VAL_3''], np.array([[1230.23, 1500000, 12453.03], [930.23, 140000, 12453.03], [130.23, 120000, 1243.03]]), [1, 2, 1])
Estoy seguro de que hay una mejor manera de hacerlo, pero aquí hay uno rápido y sucio (uno muy sucio):
#!/usr/bin/python
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
#vectors to plot: 4D for this example
y1=[1,2.3,8.0,2.5]
y2=[1.5,1.7,2.2,2.9]
x=[1,2,3,8] # spines
fig,(ax,ax2,ax3) = plt.subplots(1, 3, sharey=False)
# plot the same on all the subplots
ax.plot(x,y1,''r-'', x,y2,''b-'')
ax2.plot(x,y1,''r-'', x,y2,''b-'')
ax3.plot(x,y1,''r-'', x,y2,''b-'')
# now zoom in each of the subplots
ax.set_xlim([ x[0],x[1]])
ax2.set_xlim([ x[1],x[2]])
ax3.set_xlim([ x[2],x[3]])
# set the x axis ticks
for axx,xx in zip([ax,ax2,ax3],x[:-1]):
axx.xaxis.set_major_locator(ticker.FixedLocator([xx]))
ax3.xaxis.set_major_locator(ticker.FixedLocator([x[-2],x[-1]])) # the last one
# EDIT: add the labels to the rightmost spine
for tick in ax3.yaxis.get_major_ticks():
tick.label2On=True
# stack the subplots together
plt.subplots_adjust(wspace=0)
plt.show()
Esto se basa esencialmente en una (mucho más agradable) de Joe Kingon, Python / Matplotlib. ¿Hay alguna manera de hacer un eje discontinuo? . También es posible que desee echar un vistazo a la otra respuesta a la misma pregunta.
En este ejemplo, ni siquiera intento escalar las escalas verticales, ya que depende de qué es exactamente lo que estás tratando de lograr.
EDITAR: Aquí está el resultado
Tenga en cuenta: cuando se utilizan pandas (como sugiere theta), no hay forma de escalar los ejes de forma independiente.
La razón por la que no puede encontrar los diferentes ejes verticales es porque no hay ninguno. Nuestras coordenadas paralelas están "falsificando" los otros dos ejes simplemente dibujando una línea vertical y algunas etiquetas.
https://github.com/pydata/pandas/issues/7083#issuecomment-74253671
Lo siento, no puedo añadir esto como comentario directo (reputación <50)
pandas tiene un contenedor de coordenadas paralelas:
import pandas
import matplotlib.pyplot as plt
from pandas.tools.plotting import parallel_coordinates
data = pandas.read_csv(r''C:/Python27/Lib/site-packages/pandas/tests/data/iris.csv'', sep='','')
parallel_coordinates(data, ''Name'')
plt.show()
Código fuente, cómo lo hicieron: plotting.py#L494