Heatmap in Matplotlib mit Farbe?

100

Ich möchte eine Heatmap wie diese erstellen (auf FlowingData gezeigt ): Heatmap

Die Quelldaten sind hier , aber zufällige Daten und Beschriftungen wären in Ordnung zu verwenden, dh

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

Das Erstellen der Heatmap ist in matplotlib ganz einfach:

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

Und ich habe sogar Colormap- Argumente gefunden, die ungefähr richtig aussehen:heatmap = plt.pcolor(data, cmap=matplotlib.cm.Blues)

Darüber hinaus kann ich nicht herausfinden, wie Beschriftungen für die Spalten und Zeilen angezeigt und die Daten in der richtigen Ausrichtung angezeigt werden (Ursprung oben links statt unten links).

Manipulationsversuche heatmap.axes(z. B. heatmap.axes.set_xticklabels = column_labels) sind fehlgeschlagen. Was fehlt mir hier?

Jason Sundram
quelle
Es gibt viele Überschneidungen mit dieser Heatmap-Frage - könnte dort einige gute Informationen für Sie sein.
John Lyon
Die Etikettentechniken aus diesem Beitrag könnten dazu beitragen, stackoverflow.com/questions/6352740/matplotlib-label-each-bin
tacaswell

Antworten:

123

Dies ist spät, aber hier ist meine Python-Implementierung der NBA-Heatmap für fließende Daten.

aktualisiert: 04.01.2014 : Danke an alle

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

Die Ausgabe sieht folgendermaßen aus: Fließende Daten-ähnliche NBA-Heatmap

Es gibt ein ipython Notebook mit all diesen Code hier . Ich habe viel aus dem Überlauf gelernt, also wird dies hoffentlich jemand nützlich finden.

BubbleGuppies
quelle
1
Der obige Code wurde in iPythnon Notebook nicht ausgeführt. Ich hatte einige geringfügige Änderungen vorgenommen und nba_sort = nba_norm.sort ('PTS', aufsteigend = wahr, inplace = wahr) in nba_sort = nba_norm.copy () geändert. Nba_sort.sort ('PTS', aufsteigend = wahr, inplace = wahr) da die Sortierung nach Nebeneffekt funktioniert, nicht nach Funktionsrückgabe! Danke für das wundervolle Conceret-Beispiel!
Yu Shen
1
Hmmm ... du scheinst richtig zu sein. Ich bin mir nicht sicher, worum es geht. Ich werde den Code korrigieren. Vielen Dank!
BubbleGuppies
Was wäre der einfachste Weg, eine Grafik wie diese zu erstellen, aber den Wert der Statistik in der Tabelle anzuzeigen. Dh ich möchte so etwas machen, pcoloraber das zeigt auch numerische Werte. ODER: Ich möchte eine Matplotlib erstellen table, die ihre Zellen färbt. Ich habe Lösungen für das andere Problem gesehen und sie sind ästhetisch hässlich. Das sieht gut aus, wenn ich nur wüsste, wie man die Zahlen überlagert.
8one6
Ja. Ich stolperte darüber, als ich die Frage eines anderen beantwortete: stackoverflow.com/a/21167108/2501018
8one6
@joelotz Würdest du bereit sein, eine (modifizierte) Version davon zu den matplotlib-Dokumenten beizutragen? Wenn ja, öffnen Sie entweder einfach eine PR oder pingen Sie mich per E-Mail (siehe mein Profil).
Tacaswell
12

Das Python Seaborn-Modul basiert auf Matplotlib und erstellt eine sehr schöne Heatmap.

Unten finden Sie eine Implementierung mit seaborn, die für das ipython / jupyter-Notebook entwickelt wurde.

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

Die Ausgabe sieht folgendermaßen aus: Seaborn NBA Heatmap Ich habe die Matplotlib Blues-Farbkarte verwendet, finde aber die Standardfarben persönlich sehr schön. Ich habe matplotlib verwendet, um die Beschriftungen der x-Achse zu drehen, da ich die Seaborn-Syntax nicht finden konnte. Wie von grexor festgestellt, war es notwendig, die Abmessungen (fig.set_size_inches) durch Ausprobieren anzugeben, was ich etwas frustrierend fand.

Wie von Paul H bemerkt, können Sie die Werte leicht zu Heatmaps hinzufügen (annot = True), aber in diesem Fall habe ich nicht gedacht, dass dies die Zahl verbessert. Aus der hervorragenden Antwort von joelotz wurden mehrere Codefragmente entnommen.

Mark Teese
quelle
11

Hauptproblem ist, dass Sie zuerst die Position Ihrer x- und y-Ticks festlegen müssen. Außerdem ist es hilfreich, die objektorientiertere Schnittstelle zu matplotlib zu verwenden. Interagiere nämlich axesdirekt mit dem Objekt.

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

Hoffentlich hilft das.

Paul H.
quelle
Danke, @Paul H, das funktioniert wunderbar. Ich habe die heatmap.axesImmobilie benutzt, die aus irgendeinem Grund nichts tut.
Jason Sundram
Wissen Sie, wie Sie die Beschriftungen der x-Achse nach oben verschieben können? Ich versuchte das Offensichtliche ax.xaxis.set_label_position('top')ohne Erfolg.
Jason Sundram
@JasonSundram Sie sollten eine neue Frage zum Verschieben der Etikettenpositionierung öffnen, da dies funktionieren sollte und es seltsam ist, dass dies nicht der Fall ist.
Tacaswell
1
@tcaswell, guter Punkt. Neue Frage hier: stackoverflow.com/questions/14406214/…
Jason Sundram
1
@ Tgsmith61591 Ich würde die Heatmap-Funktion von Seaborn verwenden und annot=Truebeim Aufruf festlegen ( stanford.edu/~mwaskom/software/seaborn/generated/… )
Paul H
3

Jemand hat diese Frage bearbeitet, um den von mir verwendeten Code zu entfernen, sodass ich gezwungen war, ihn als Antwort hinzuzufügen. Vielen Dank an alle, die an der Beantwortung dieser Frage teilgenommen haben! Ich denke, die meisten anderen Antworten sind besser als dieser Code. Ich lasse dies hier nur zu Referenzzwecken.

Dank Paul H und Unutbu (der diese Frage beantwortet hat ) habe ich eine ziemlich gut aussehende Ausgabe:

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

Und hier ist die Ausgabe:

Matplotlib HeatMap

Jason Sundram
quelle