Mappa di calore in matplotlib con pcolor?


100

Vorrei creare una mappa di calore come questa (mostrata su FlowingData ): mappa di calore

I dati di origine sono qui , ma i dati e le etichette casuali andrebbero bene da usare, ad es

import numpy
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = numpy.random.rand(4,4)

Creare la mappa di calore è abbastanza facile in matplotlib:

from matplotlib import pyplot as plt
heatmap = plt.pcolor(data)

E ho anche trovato argomenti della mappa dei colori che sembrano giusti:heatmap = plt.pcolor(data, cmap=matplotlib.cm.Blues)

Ma oltre a ciò, non riesco a capire come visualizzare le etichette per le colonne e le righe e visualizzare i dati con l'orientamento corretto (origine in alto a sinistra invece che in basso a sinistra).

Tutti i tentativi di manipolazione heatmap.axes(ad esempio heatmap.axes.set_xticklabels = column_labels) sono falliti. Cosa mi manca qui?


Ci sono molte sovrapposizioni con questa domanda sulla mappa termica : potrebbero esserci alcune buone informazioni per te.
John Lyon

Le tecniche di etichetta di questo post potrebbe aiutare stackoverflow.com/questions/6352740/matplotlib-label-each-bin
tacaswell

Risposte:


123

Questo è tardi, ma ecco la mia implementazione in python della heatmap NBA flowdata.

aggiornato: 1/4/2014 : grazie a tutti

# -*- coding: utf-8 -*-
# <nbformat>3.0</nbformat>

# ------------------------------------------------------------------------
# Filename   : heatmap.py
# Date       : 2013-04-19
# Updated    : 2014-01-04
# Author     : @LotzJoe >> Joe Lotz
# Description: My attempt at reproducing the FlowingData graphic in Python
# Source     : http://flowingdata.com/2010/01/21/how-to-make-a-heatmap-a-quick-and-easy-solution/
#
# Other Links:
#     http://stackoverflow.com/questions/14391959/heatmap-in-matplotlib-with-pcolor
#
# ------------------------------------------------------------------------

import matplotlib.pyplot as plt
import pandas as pd
from urllib2 import urlopen
import numpy as np
%pylab inline

page = urlopen("http://datasets.flowingdata.com/ppg2008.csv")
nba = pd.read_csv(page, index_col=0)

# Normalize data columns
nba_norm = (nba - nba.mean()) / (nba.max() - nba.min())

# Sort data according to Points, lowest to highest
# This was just a design choice made by Yau
# inplace=False (default) ->thanks SO user d1337
nba_sort = nba_norm.sort('PTS', ascending=True)

nba_sort['PTS'].head(10)

# Plot it out
fig, ax = plt.subplots()
heatmap = ax.pcolor(nba_sort, cmap=plt.cm.Blues, alpha=0.8)

# Format
fig = plt.gcf()
fig.set_size_inches(8, 11)

# turn off the frame
ax.set_frame_on(False)

# put the major ticks at the middle of each cell
ax.set_yticks(np.arange(nba_sort.shape[0]) + 0.5, minor=False)
ax.set_xticks(np.arange(nba_sort.shape[1]) + 0.5, minor=False)

# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()

# Set the labels

# label source:https://en.wikipedia.org/wiki/Basketball_statistics
labels = [
    'Games', 'Minutes', 'Points', 'Field goals made', 'Field goal attempts', 'Field goal percentage', 'Free throws made', 'Free throws attempts', 'Free throws percentage',
    'Three-pointers made', 'Three-point attempt', 'Three-point percentage', 'Offensive rebounds', 'Defensive rebounds', 'Total rebounds', 'Assists', 'Steals', 'Blocks', 'Turnover', 'Personal foul']

# note I could have used nba_sort.columns but made "labels" instead
ax.set_xticklabels(labels, minor=False)
ax.set_yticklabels(nba_sort.index, minor=False)

# rotate the
plt.xticks(rotation=90)

ax.grid(False)

# Turn off all the ticks
ax = plt.gca()

for t in ax.xaxis.get_major_ticks():
    t.tick1On = False
    t.tick2On = False
for t in ax.yaxis.get_major_ticks():
    t.tick1On = False
    t.tick2On = False

L'output è simile a questo: mappa di calore nba simile ai dati

C'è un notebook ipython con tutto questo codice qui . Ho imparato molto dall'overflow, quindi spero che qualcuno lo trovi utile.


1
Il codice sopra non è stato eseguito nel notebook iPythnon. Ho apportato alcune lievi modifiche, cambiando nba_sort = nba_norm.sort ('PTS', ascending = True, inplace = True) in nba_sort = nba_norm.copy () nba_sort.sort ('PTS', ascending = True, inplace = True) poiché l'ordinamento funziona per effetto collaterale non per ritorno di funzione! Grazie per il meraviglioso esempio di conceret!
Yu Shen

1
Hmmm ... sembra che tu abbia ragione. Non sono sicuro di cosa si tratti. Correggerò il codice. Grazie!
BubbleGuppies

Quale sarebbe il modo più semplice per creare un grafico come questo ma visualizzare il valore della statistica nella tabella. Cioè voglio fare un pcolorcome questo ma ha anche valori numerici mostrati. OPPURE: Voglio creare un matplotlib tableche colora le sue celle. Ho visto soluzioni all'altro problema e sono esteticamente brutte. Sembra fantastico, se solo sapessi come sovrapporre i numeri.
8one6

Si. Mi sono imbattuto il mio modo di che nel rispondere qualcun altro domanda: stackoverflow.com/a/21167108/2501018
8one6

@joelotz Saresti disposto a contribuire con una versione (modificata) di questo alla documentazione di matplotlib? In tal caso, apri un PR o inviami un ping tramite e-mail (vedi il mio profilo).
tacaswell

12

Il modulo python seaborn è basato su matplotlib e produce una mappa termica molto carina.

Di seguito è riportata un'implementazione con seaborn, progettata per il notebook ipython / jupyter.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
# import the data directly into a pandas dataframe
nba = pd.read_csv("http://datasets.flowingdata.com/ppg2008.csv", index_col='Name  ')
# remove index title
nba.index.name = ""
# normalize data columns
nba_norm = (nba - nba.mean()) / (nba.max() - nba.min())
# relabel columns
labels = ['Games', 'Minutes', 'Points', 'Field goals made', 'Field goal attempts', 'Field goal percentage', 'Free throws made', 
          'Free throws attempts', 'Free throws percentage','Three-pointers made', 'Three-point attempt', 'Three-point percentage', 
          'Offensive rebounds', 'Defensive rebounds', 'Total rebounds', 'Assists', 'Steals', 'Blocks', 'Turnover', 'Personal foul']
nba_norm.columns = labels
# set appropriate font and dpi
sns.set(font_scale=1.2)
sns.set_style({"savefig.dpi": 100})
# plot it out
ax = sns.heatmap(nba_norm, cmap=plt.cm.Blues, linewidths=.1)
# set the x-axis labels on the top
ax.xaxis.tick_top()
# rotate the x-axis labels
plt.xticks(rotation=90)
# get figure (usually obtained via "fig,ax=plt.subplots()" with matplotlib)
fig = ax.get_figure()
# specify dimensions and save
fig.set_size_inches(15, 20)
fig.savefig("nba.png")

Il risultato è questo: mappa di calore nba seaborn ho usato la mappa dei colori Blues matplotlib, ma personalmente trovo i colori predefiniti piuttosto belli. Ho usato matplotlib per ruotare le etichette dell'asse x, poiché non riuscivo a trovare la sintassi seaborn. Come notato da grexor, è stato necessario specificare le dimensioni (fig.set_size_inches) per tentativi ed errori, cosa che ho trovato un po 'frustrante.

Come notato da Paul H, puoi facilmente aggiungere i valori alle mappe di calore (annot = True), ma in questo caso non pensavo che migliorasse la figura. Diversi frammenti di codice sono stati presi dall'eccellente risposta di joelotz.


11

Il problema principale è che devi prima impostare la posizione dei tuoi tick xey. Inoltre, aiuta a usare l'interfaccia più orientata agli oggetti per matplotlib. Vale a dire, interagisci axesdirettamente con l' oggetto.

import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4,4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data)

# put the major ticks at the middle of each cell, notice "reverse" use of dimension
ax.set_yticks(np.arange(data.shape[0])+0.5, minor=False)
ax.set_xticks(np.arange(data.shape[1])+0.5, minor=False)


ax.set_xticklabels(row_labels, minor=False)
ax.set_yticklabels(column_labels, minor=False)
plt.show()

Spero che aiuti.


Grazie, @Paul H, funziona magnificamente. Stavo usando la heatmap.axesproprietà, che per qualche motivo non fa nulla.
Jason Sundram

Sai come spostare le etichette dell'asse x in modo che siano in alto? Ho provato l'ovvio ax.xaxis.set_label_position('top')senza alcun risultato.
Jason Sundram

@JasonSundram Dovresti aprire una nuova domanda per spostare il posizionamento dell'etichetta, perché dovrebbe funzionare ed è strano che non lo faccia.
tacaswell

1
@tcaswell, buon punto. Nuova domanda qui: stackoverflow.com/questions/14406214/…
Jason Sundram

1
@ Tgsmith61591 Vorrei usare la funzione heatmap di Seaborn, impostando annot=Truequando viene chiamato ( stanford.edu/~mwaskom/software/seaborn/generated/… )
Paul H

3

Qualcuno ha modificato questa domanda per rimuovere il codice che ho usato, quindi sono stato costretto ad aggiungerlo come risposta. Grazie a tutti coloro che hanno partecipato a rispondere a questa domanda! Penso che la maggior parte delle altre risposte siano migliori di questo codice, lo lascio qui solo a scopo di riferimento.

Ringraziando Paul H e unutbu (che ha risposto a questa domanda ), ho un output piuttosto carino:

import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4,4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)

# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[0])+0.5, minor=False)
ax.set_yticks(np.arange(data.shape[1])+0.5, minor=False)

# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()

ax.set_xticklabels(row_labels, minor=False)
ax.set_yticklabels(column_labels, minor=False)
plt.show()

Ed ecco l'output:

Matplotlib HeatMap

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.