web-dev-qa-db-fra.com

Carte thermique dans matplotlib avec pcolor?

Je voudrais faire un heatmap comme ceci (montré sur FlowingData ): heatmap

Les données source sont ici , mais des données aléatoires et des libellés peuvent être utilisés, c.-à-d.

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

Faire la carte thermique est assez facile dans matplotlib:

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

Et j'ai même trouvé un palette de couleurs arguments qui ont l'air correct: heatmap = plt.pcolor(data, cmap=matplotlib.cm.Blues)

Mais au-delà de cela, je ne peux pas comprendre comment afficher les étiquettes des colonnes et des lignes et afficher les données dans la bonne orientation (Origin en haut à gauche au lieu de en bas à gauche).

Les tentatives de manipulation de heatmap.axes (par exemple heatmap.axes.set_xticklabels = column_labels) ont toutes échoué. Qu'est-ce que j'oublie ici?

100
Jason Sundram

C’est tard, mais voici ma python mise en œuvre de la carte thermique NBA de flowingdata.

mis à jour le 1/4/2014 : merci à tous

# -*- 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

La sortie ressemble à ceci: flowingdata-like nba heatmap

Il y a un cahier ipython avec tout ce code ici . J'ai beaucoup appris de 'débordement alors j'espère que quelqu'un trouvera cela utile.

122
joelotz

Le module python seaborn est basé sur matplotlib et produit une carte thermique très agréable.

Vous trouverez ci-dessous une implémentation avec seaborn, conçue pour le 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")

La sortie ressemble à ceci: seaborn nba heatmap J'ai utilisé la carte de couleurs blues de matplotlib, mais personnellement, je trouve les couleurs par défaut assez belles. J'ai utilisé matplotlib pour faire pivoter les étiquettes de l'axe des x, car je ne pouvais pas trouver la syntaxe Seaborn. Comme indiqué par grexor, il était nécessaire de spécifier les dimensions (fig.set_size_inches) par essais et erreurs, ce que j'ai trouvé un peu frustrant.

Comme l'a noté Paul H, vous pouvez facilement ajouter les valeurs aux cartes thermiques (annot = True), mais dans ce cas, je ne pensais pas que cela améliorait le chiffre. Plusieurs extraits de code ont été tirés de l'excellente réponse de joelotz.

12
Mark Teese

Le problème principal est que vous devez d’abord définir l’emplacement de vos ticks x et y. En outre, il est utile d’utiliser l’interface plus orientée objet de matplotlib. À savoir, interagissez directement avec l'objet axes.

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()

J'espère que ça t'as aidé.

11
Paul H

Quelqu'un a modifié cette question pour supprimer le code que j'ai utilisé. J'ai donc été obligé de l'ajouter comme réponse. Merci à tous ceux qui ont participé à répondre à cette question! Je pense que la plupart des autres réponses sont meilleures que ce code, je le laisse ici pour référence.

Grâce à Paul H , et nutb (qui a répondu cette question ), j'ai une jolie sortie d'assez jolie apparence:

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()

Et voici la sortie:

Matplotlib HeatMap

3
Jason Sundram