J'ai un ensemble de points de données X, Y (environ 10k) qui sont faciles à tracer sous forme de nuage de points mais que je voudrais représenter sous forme de carte thermique.
J'ai regardé à travers les exemples dans MatPlotLib et ils semblent tous déjà commencer avec des valeurs de cellule de carte thermique pour générer l'image.
Existe-t-il une méthode qui convertit un groupe de x, y, tous différents, en une carte thermique (où les zones avec une fréquence plus élevée de x, y seraient "plus chaudes")?
Réponses:
Si vous ne voulez pas d'hexagones, vous pouvez utiliser la
histogram2d
fonction de numpy :Cela fait une carte thermique 50x50. Si vous voulez, par exemple, 512x384, vous pouvez
bins=(512, 384)
appelerhistogram2d
.Exemple:
la source
axes
instance normale , où je peux ajouter un titre, des étiquettes d'axe, etc. puis faire la normalesavefig()
comme je le ferais pour n'importe quel autre tracé matplotlib typique.plt.savefig('filename.png')
fonctionne pas ? Si vous voulez obtenir une instance d'axes, utilisez l'interface orientée objet de Matplotlib:fig = plt.figure()
ax = fig.gca()
ax.imshow(...)
fig.savefig(...)
imshow()
c'est sur la même catégorie de fonctions quescatter()
. Honnêtement, je ne comprends pas pourquoiimshow()
convertit un tableau 2D de flotteurs en blocs de couleur appropriée, alors que je comprends ce quiscatter()
est censé faire avec un tel tableau.plt.imshow(heatmap.T, extent=extent, origin = 'lower')
from matplotlib.colors import LogNorm
plt.imshow(heatmap, norm=LogNorm())
plt.colorbar()
Dans le lexique Matplotlib , je pense que vous voulez un tracé hexbin .
Si vous n'êtes pas familier avec ce type de tracé, il ne s'agit que d'un histogramme bivarié dans lequel le plan xy est pavé par une grille régulière d'hexagones.
Ainsi, à partir d'un histogramme, vous pouvez simplement compter le nombre de points tombant dans chaque hexagone, discrétiser la région de traçage comme un ensemble de fenêtres , affecter chaque point à l'une de ces fenêtres; enfin, mappez les fenêtres sur un tableau de couleurs , et vous avez un diagramme hexbin.
Bien que moins couramment utilisés que par exemple, les cercles ou les carrés, ces hexagones sont un meilleur choix car la géométrie du conteneur de regroupement est intuitive:
les hexagones ont une symétrie du plus proche voisin (par exemple, les cases carrées ne le font pas, par exemple, la distance entre un point sur la bordure d'un carré et un point à l'intérieur de ce carré n'est pas partout égale) et
hexagone est le n-polygone le plus élevé qui donne une tessellation plane régulière (c'est-à-dire que vous pouvez modéliser en toute sécurité le sol de votre cuisine avec des carreaux de forme hexagonale car vous n'aurez pas d'espace vide entre les carreaux lorsque vous avez terminé - pas vrai pour tous les autres polygones n supérieur, n> = 7).
( Matplotlib utilise le terme hexbin plot; ainsi (AFAIK) toutes les bibliothèques de traçage pour R ; je ne sais toujours pas si c'est le terme généralement accepté pour les parcelles de ce type, même si je soupçonne que c'est probablement étant donné que hexbin est court pour le regroupement hexagonal , qui décrit l'étape essentielle de la préparation des données pour l'affichage.)
la source
gridsize=
paramètre. Je voudrais le choisir tel, de sorte que les hexagones se touchent sans se chevaucher. J'ai remarqué quegridsize=100
cela produirait des hexagones plus petits, mais comment choisir la bonne valeur?Edit: Pour une meilleure approximation de la réponse d'Alejandro, voir ci-dessous.
Je sais que c'est une vieille question, mais je voulais ajouter quelque chose à la réponse d'Alejandro: si vous voulez une belle image lissée sans utiliser py-sphviewer, vous pouvez à la place utiliser
np.histogram2d
et appliquer un filtre gaussien (descipy.ndimage.filters
) à la carte thermique:Produit:
Le nuage de points et s = 16 tracés l'un sur l'autre pour Agape Gal'lo (cliquez pour une meilleure vue):
Une différence que j'ai remarquée avec mon approche du filtre gaussien et celle d'Alejandro était que sa méthode montre bien mieux les structures locales que la mienne. Par conséquent, j'ai implémenté une méthode simple du voisin le plus proche au niveau du pixel. Cette méthode calcule pour chaque pixel la somme inverse des distances du
n
points plus proches dans les données. Cette méthode est à une haute résolution assez coûteuse en calcul et je pense qu'il existe un moyen plus rapide, alors faites-moi savoir si vous avez des améliorations.Mise à jour: Comme je le soupçonnais, il existe une méthode beaucoup plus rapide utilisant Scipy
scipy.cKDTree
. Voir la réponse de Gabriel pour la mise en œuvre.Bref, voici mon code:
Résultat:
la source
myplot
fonction, ajouter lerange
paramètre ànp.histogram2d
:np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])
et dans l'ensemble de la boucle x et y de l'axe lim:ax.set_xlim([-5, 5])
ax.set_ylim([-3, 4])
. De plus, par défaut,imshow
conserve le rapport hauteur / largeur identique au rapport de vos axes (donc dans mon exemple un rapport de 10: 7), mais si vous voulez qu'il corresponde à votre fenêtre de tracé, ajoutez le paramètreaspect='auto'
àimshow
.Au lieu d'utiliser np.hist2d, qui en général produit des histogrammes assez laids, j'aimerais recycler py-sphviewer , un package python pour le rendu de simulations de particules à l'aide d'un noyau de lissage adaptatif et qui peut être facilement installé à partir de pip (voir la documentation de la page Web). Considérez le code suivant, basé sur l'exemple:
qui produit l'image suivante:
Comme vous le voyez, les images sont plutôt jolies et nous pouvons y identifier différentes sous-structures. Ces images sont construites en étalant un poids donné pour chaque point dans un certain domaine, défini par la longueur de lissage, qui à son tour est donnée par la distance au nb voisin le plus proche (j'ai choisi 16, 32 et 64 pour les exemples). Ainsi, les régions à densité plus élevée sont généralement réparties sur des régions plus petites par rapport aux régions à plus faible densité.
La fonction myplot est juste une fonction très simple que j'ai écrite pour donner les données x, y à py-sphviewer pour faire la magie.
la source
Si vous utilisez 1.2.x
la source
Seaborn a maintenant le fonction jointplot qui devrait bien fonctionner ici:
la source
fig = plt.figure(figsize=(12, 12))
, puis obtenez l'axe actuel avecax=plt.gca()
, puis ajoutez l'argumentax=ax
à lajointplot
fonction.et la question initiale était ... comment convertir les valeurs de dispersion en valeurs de grille, non?
histogram2d
compte la fréquence par cellule, cependant, si vous avez d'autres données par cellule que la fréquence, vous aurez besoin d'un travail supplémentaire.Donc, j'ai un jeu de données avec des résultats Z pour les coordonnées X et Y. Cependant, je calculais quelques points en dehors de la zone d'intérêt (grands écarts) et des tas de points dans une petite zone d'intérêt.
Oui ici ça devient plus difficile mais aussi plus amusant. Certaines bibliothèques (désolé):
pyplot est mon moteur graphique aujourd'hui, cm est une gamme de cartes de couleurs avec quelques choix initeresting. numpy pour les calculs et griddata pour attacher des valeurs à une grille fixe.
Le dernier est important surtout parce que la fréquence des points xy n'est pas également distribuée dans mes données. Tout d'abord, commençons par quelques limites adaptées à mes données et une taille de grille arbitraire. Les données d'origine ont des points de données également en dehors de ces limites x et y.
Nous avons donc défini une grille de 500 pixels entre les valeurs min et max de x et y.
Dans mes données, il y a beaucoup plus que les 500 valeurs disponibles dans la zone de grand intérêt; considérant que dans la zone à faible intérêt, il n'y a même pas 200 valeurs dans la grille totale; entre les limites graphiques de
x_min
etx_max
il y en a encore moins.Donc, pour obtenir une belle image, la tâche est d'obtenir une moyenne des valeurs d'intérêt élevé et de combler les lacunes ailleurs.
Je définis ma grille maintenant. Pour chaque paire xx-yy, je veux avoir une couleur.
Pourquoi cette forme étrange? scipy.griddata veut une forme de (n, D).
Griddata calcule une valeur par point de la grille, par une méthode prédéfinie. Je choisis "le plus proche" - les points de grille vides seront remplis avec les valeurs du voisin le plus proche. On dirait que les zones avec moins d'informations ont des cellules plus grandes (même si ce n'est pas le cas). On pourrait choisir d'interpoler "linéaire", alors les zones avec moins d'informations semblent moins nettes. Question de goût, vraiment.
Et hop, on passe à matplotlib pour afficher l'intrigue
Autour de la partie pointue du V-Shape, vous voyez que j'ai fait beaucoup de calculs lors de ma recherche du sweet spot, alors que les parties les moins intéressantes presque partout ailleurs ont une résolution inférieure.
la source
Voici l' approche du grand voisin le plus proche de Jurgy, mais implémentée à l'aide de scipy.cKDTree . Dans mes tests, c'est environ 100 fois plus rapide.
la source
Créez un tableau à 2 dimensions qui correspond aux cellules de votre image finale, appelé par exemple
heatmap_cells
et instanciez-le comme tous les zéros.Choisissez deux facteurs d'échelle qui définissent la différence entre chaque élément du tableau en unités réelles, pour chaque dimension, disons
x_scale
ety_scale
. Choisissez-les de manière à ce que tous vos points de données tombent dans les limites du tableau de heatmap.Pour chaque point de données brut avec
x_value
ety_value
:heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1
la source
En voici un que j'ai fait sur un ensemble de 1 million de points avec 3 catégories (de couleur rouge, vert et bleu). Voici un lien vers le référentiel si vous souhaitez essayer la fonction. Repo Github
la source
Très similaire à la réponse de @ Piti , mais en utilisant 1 appel au lieu de 2 pour générer les points:
Production:
la source
J'ai bien peur d'être un peu en retard à la fête, mais j'avais une question similaire il y a quelque temps. La réponse acceptée (par @ptomato) m'a aidé, mais je voudrais également publier ceci au cas où cela serait utile à quelqu'un.
Voici le résultat
la source