Tengo un conjunto de puntos de datos X, Y (aproximadamente 10k) que son fáciles de trazar como un diagrama de dispersión pero que me gustaría representar como un mapa de calor.
Miré a través de los ejemplos en MatPlotLib y parece que todos ya comienzan con valores de celdas de mapa de calor para generar la imagen.
¿Existe algún método que convierta un grupo de x, y, todos diferentes, en un mapa de calor (donde las zonas con mayor frecuencia de x, y serían "más cálidas")?
python
matplotlib
heatmap
histogram2d
greye
fuente
fuente
Respuestas:
Si no quieres hexágonos, puedes usar la
histogram2d
función de numpy :Esto hace un mapa de calor de 50x50. Si quiere, digamos, 512x384, puede
bins=(512, 384)
llamarhistogram2d
.Ejemplo:
fuente
axes
instancia normal , donde puedo agregar un título, etiquetas de eje, etc. y luego hacer lo normalsavefig()
como lo haría para cualquier otro gráfico de matplotlib típico.plt.savefig('filename.png')
funciona? Si desea obtener una instancia de ejes, use la interfaz orientada a objetos de Matplotlib:fig = plt.figure()
ax = fig.gca()
ax.imshow(...)
fig.savefig(...)
imshow()
está en la misma categoría de funciones quescatter()
. Honestamente, no entiendo por quéimshow()
convierte una matriz 2D de flotadores en bloques de color apropiado, mientras que sí entiendo lo quescatter()
se supone que debe hacer con dicha matriz.plt.imshow(heatmap.T, extent=extent, origin = 'lower')
from matplotlib.colors import LogNorm
plt.imshow(heatmap, norm=LogNorm())
plt.colorbar()
En el léxico Matplotlib , creo que quieres un diagrama de hexbin .
Si no está familiarizado con este tipo de diagrama, es solo un histograma bivariado en el que el plano xy está teselado por una cuadrícula regular de hexágonos.
Entonces, desde un histograma, puede contar el número de puntos que caen en cada hexágono, discretizar la región de trazado como un conjunto de ventanas , asignar cada punto a una de estas ventanas; finalmente, asigne las ventanas a una matriz de colores y obtendrá un diagrama hexbin.
Aunque se usa con menos frecuencia que, por ejemplo, círculos o cuadrados, los hexágonos son una mejor opción para la geometría del contenedor binning es intuitivo:
los hexágonos tienen simetría del vecino más cercano (por ejemplo, los contenedores cuadrados no, por ejemplo, la distancia desde un punto en el borde de un cuadrado hasta un punto dentro de ese cuadrado no es igual en todas partes)
El hexágono es el n-polígono más alto que proporciona la teselación del plano regular (es decir, puede modelar de manera segura el piso de su cocina con mosaicos de forma hexagonal porque no tendrá ningún espacio vacío entre los mosaicos cuando haya terminado, lo cual no es cierto para todos los demás superiores-n, n> = 7, polígonos).
( Matplotlib usa el término gráfico de hexbin ; también lo hacen (AFAIK) todas las bibliotecas de trazado para R ; todavía no sé si este es el término generalmente aceptado para gráficos de este tipo, aunque sospecho que es probable dado que hexbin es corto para el agrupamiento hexagonal , que describe el paso esencial para preparar los datos para su visualización).
fuente
gridsize=
parámetro? Me gustaría elegirlo así, para que los hexágonos se toquen sin superponerse. Noté quegridsize=100
produciría hexágonos más pequeños, pero ¿cómo elegir el valor adecuado?Editar: Para una mejor aproximación de la respuesta de Alejandro, vea a continuación.
Sé que esta es una vieja pregunta, pero quería agregar algo al comentario de Alejandro: si desea una buena imagen suavizada sin usar py-sphviewer, puede usar
np.histogram2d
y aplicar un filtro gaussiano (desdescipy.ndimage.filters
) al mapa de calor:Produce:
El diagrama de dispersión ys = 16 trazados uno encima del otro para Agape Gal'lo (haga clic para ver mejor):
Una diferencia que noté con mi enfoque de filtro gaussiano y el enfoque de Alejandro fue que su método muestra estructuras locales mucho mejores que las mías. Por lo tanto, implementé un método vecino más cercano simple a nivel de píxel. Este método calcula para cada píxel la suma inversa de las distancias del
n
puntos más cercanos en los datos. Este método tiene una alta resolución bastante costoso computacionalmente y creo que hay una forma más rápida, así que avíseme si tiene alguna mejora.Actualización: como sospechaba, hay un método mucho más rápido con Scipy's
scipy.cKDTree
. Vea la respuesta de Gabriel para la implementación.De todos modos, aquí está mi código:
Resultado:
fuente
myplot
función, añadir elrange
parámetro anp.histogram2d
:np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])
y en el bucle para establecer la x e y lim del eje:ax.set_xlim([-5, 5])
ax.set_ylim([-3, 4])
. Además, de forma predeterminada,imshow
mantiene la relación de aspecto idéntica a la relación de sus ejes (en mi ejemplo, una relación de 10: 7), pero si desea que coincida con su ventana de trazado, agregue el parámetroaspect='auto'
aimshow
.En lugar de usar np.hist2d, que en general produce histogramas bastante feos, me gustaría reciclar py-sphviewer , un paquete de python para representar simulaciones de partículas utilizando un núcleo de suavizado adaptativo y que se puede instalar fácilmente desde pip (consulte la documentación de la página web). Considere el siguiente código, que se basa en el ejemplo:
que produce la siguiente imagen:
Como puede ver, las imágenes se ven muy bien y podemos identificar diferentes subestructuras en ellas. Estas imágenes se construyen distribuyendo un peso dado para cada punto dentro de un determinado dominio, definido por la longitud de suavizado, que a su vez viene dada por la distancia al vecino nb más cercano (he elegido 16, 32 y 64 para los ejemplos). Por lo tanto, las regiones de mayor densidad generalmente se extienden sobre regiones más pequeñas en comparación con las regiones de menor densidad.
La función myplot es solo una función muy simple que he escrito para dar los datos x, y a py-sphviewer para hacer la magia.
fuente
Si está utilizando 1.2.x
fuente
Seaborn ahora tiene la función plot conjunta que debería funcionar bien aquí:
fuente
fig = plt.figure(figsize=(12, 12))
, luego obtenga el eje actual conax=plt.gca()
, luego agregue el argumentoax=ax
a lajointplot
función.y la pregunta inicial fue ... ¿cómo convertir los valores de dispersión en valores de cuadrícula, ¿verdad?
histogram2d
sí cuenta la frecuencia por celda, sin embargo, si tiene otros datos por celda además de la frecuencia, necesitará un trabajo adicional para hacer.Entonces, tengo un conjunto de datos con resultados Z para las coordenadas X e Y. Sin embargo, estaba calculando algunos puntos fuera del área de interés (grandes brechas) y montones de puntos en una pequeña área de interés.
Sí, aquí se vuelve más difícil pero también más divertido. Algunas bibliotecas (lo siento):
Pyplot es mi motor gráfico hoy, cm es una gama de mapas de colores con algunas opciones interesantes. numpy para los cálculos y datos de cuadrícula para adjuntar valores a una cuadrícula fija.
El último es importante, especialmente porque la frecuencia de los puntos xy no se distribuye por igual en mis datos. Primero, comencemos con algunos límites que se ajustan a mis datos y un tamaño de cuadrícula arbitrario. Los datos originales tienen puntos de datos también fuera de esos límites x e y.
Así que hemos definido una cuadrícula con 500 píxeles entre los valores mínimo y máximo de x e y.
En mis datos, hay muchos más de los 500 valores disponibles en el área de alto interés; Considerando que en el área de bajo interés, ni siquiera hay 200 valores en la cuadrícula total; entre los límites gráficos de
x_min
yx_max
hay aún menos.Entonces, para obtener una buena imagen, la tarea es obtener un promedio de los valores de alto interés y llenar los vacíos en otros lugares.
Defino mi grilla ahora. Para cada par xx-yy, quiero tener un color.
¿Por qué la forma extraña? scipy.griddata quiere una forma de (n, D).
Griddata calcula un valor por punto en la cuadrícula, por un método predefinido. Elijo "más cercano": los puntos de cuadrícula vacíos se rellenarán con valores del vecino más cercano. Esto parece que las áreas con menos información tienen celdas más grandes (incluso si no es el caso). Se podría elegir interpolar "lineal", luego las áreas con menos información se ven menos nítidas. Cuestión de gustos, de verdad.
Y saltamos, pasamos a matplotlib para mostrar la trama
Alrededor de la parte puntiaguda de la forma de V, ves que hice muchos cálculos durante mi búsqueda del punto óptimo, mientras que las partes menos interesantes en casi todos los demás tienen una resolución más baja.
fuente
Aquí está el enfoque de vecino más cercano de Jurgy, pero implementado usando scipy.cKDTree . En mis pruebas es aproximadamente 100 veces más rápido.
fuente
Haga una matriz bidimensional que corresponda a las celdas en su imagen final, llamada say
heatmap_cells
y ejemplifique como todos los ceros.Elija dos factores de escala que definan la diferencia entre cada elemento de la matriz en unidades reales, para cada dimensión, digamos
x_scale
yy_scale
. Elija estos de modo que todos sus puntos de datos se encuentren dentro de los límites de la matriz de mapas de calor.Para cada punto de datos sin procesar con
x_value
yy_value
:heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1
fuente
Aquí hay uno que hice en un conjunto de 1 millón de puntos con 3 categorías (color rojo, verde y azul). Aquí hay un enlace al repositorio si desea probar la función. Repo de Github
fuente
Muy similar a la respuesta de @ Piti , pero usando 1 llamada en lugar de 2 para generar los puntos:
Salida:
fuente
Me temo que llego un poco tarde a la fiesta, pero tuve una pregunta similar hace un tiempo. La respuesta aceptada (por @ptomato) me ayudó, pero también me gustaría publicar esto en caso de que sea útil para alguien.
Aquí está el resultado.
fuente