Änderung der Notation im Contour plot

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
lpterritory
User
Beiträge: 4
Registriert: Mittwoch 27. April 2016, 20:50

Hallöchen liebes Python-Forum,

also ich habe erst vor kurzem begonnen mich mit Python zu beschäftigen und stehe nun vor einem kleinen Problem, das doch ein wenig größer zu sein scheint. Ich habe von den Aufenthaltsorten eines Teilchens zu verschiedenen Zeitpunkten, die Aufenthaltswahrscheinlichkeitsdichte mittels KDE berechnet. Diese Werte sind so gering, dass sie nicht signifikant durch 4 Nullstellen dargestellt werden können, was aber der Standard beim Contour plot zu sein scheint. Ich würde daher gerne irgendwie die Anzeige der Zahlen so modifizieren, dass ich eine wissenschaftliche Notation verwenden kann, also 4,56 * 10^(-6) zum Beispiel.
Ich habe es schon mit der Option

Code: Alles auswählen

fmt = ticker.LogFormatterMathtext()
probiert, aber dann werden merkwürdigerweise überhaupt keine Zahlen mehr angezeigt. Eine andere Idee wäre möglicherweise, die berechneten Werte aus dem KDE mit 1000 zu multiplizieren und dann die Zahl "10^(-3)" anzuhängen. Ist das vielleicht möglich?

Hier einmal mein Ausgangscode:

Code: Alles auswählen

import numpy as np
import matplotlib.pyplot as pl
import scipy.stats as st
from matplotlib.patches import Ellipse
import matplotlib.ticker as ticker

data = np.loadtxt(filename)
x = data[:, 0]
y = data[:, 1]
xmin, xmax = 265, 675
ymin, ymax = 45,450

# Set Parameters from Autotracking
a1 = 277
a2 = 664
b1 = 51
b2 = 437
a = (a2-a1)
b = (b2-b1)
xm = a1+(a/2)
ym = b1+(b/2)

# Peform the kernel density estimate
xx, yy = np.mgrid[xmin:xmax:200j, ymin:ymax:200j]
positions = np.vstack([xx.ravel(), yy.ravel()])
values = np.vstack([x, y])
kernel = st.gaussian_kde(values)
f = np.reshape(kernel(positions).T, xx.shape)

fig = pl.figure()
ax = fig.gca()
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
# Contourf plot
cfset = ax.contourf(xx, yy, f, cmap='Blues')
cset = ax.contour(xx, yy, f, colors='k')
# Label plot
ax.clabel(cset, inline=1, fontsize=10)
ax.set_xlabel('Bewegung in $x$-Richtung [px]')
ax.set_ylabel('Bewegung in $y$-Richtung [px]')
# Plot ellipse as border of system
ellipse = Ellipse(xy=(xm, ym), width=a, height=b, 
                        edgecolor='black', fc='None', lw=1.5)
pl.gca().add_patch(ellipse)
pl.gca().set_aspect('equal', adjustable='box')
pl.show()
Ich hatte diese Frage auch schon in folgendem Forum gestellt, aber dort konnte mir niemand so wirklich weiterhelfen: http://stackoverflow.com/questions/3689 ... 7_36900258
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@lpterritory: ich verstehe nicht ganz, was Du möchtest. Suchst Du einfach die Formatierungsangabe bei Labels?

Code: Alles auswählen

ax.clabel(cset, inline=1, fontsize=10, fmt="%e")
Oder dass man mit `levels´ individuelle Stufen vorgeben kann?

PS: Hilfreich für den Leser wäre es, wenn das Beispiel auch ohne zusätzliche Daten lauffähig wäre.
lpterritory
User
Beiträge: 4
Registriert: Mittwoch 27. April 2016, 20:50

Hallo Sirius3 und vielen Dank für deine Antwort!

Also ja im Prinzip suche ich diese Option schon, allerdings hat diese Darstellungsform ziemlich viele Nachkommastellen (schön fände ich 2-3) und es taucht diese unschöne "e-Potenz"-Schreibweise auf, die man auch aus Excel kennt. Ich hätte da gerne einfach 10^(-3) oder sowas stehen. Ist das denn möglich? ich könnte bei Interesse und falls das hilft mal eine Datendatei anhängen.

Vielen Dank schonmal!

Liebe Grüße
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@lpterritory: Du kannst als Format auch jede andere Formatierung angeben, oder eine beliebige Funktion, oder eine Formatierungsinstanz:

Code: Alles auswählen

fmt = matplotlib.ticker.ScalarFormatter(useMathText=True)
ax.clabel(cset, inline=1, fontsize=10, fmt=fmt)
Am besten, Du schaust Dir mal die Beispiele in der Dokumentation an.
lpterritory
User
Beiträge: 4
Registriert: Mittwoch 27. April 2016, 20:50

Hallöchen,

also diesen Befehl habe ich schon mal ausprobiert, aber merkwürdigerweise funktioniert der ausgerechnet nicht bzw. es werden irgendwie keine Werte auf den Konturlinien angezeigt. Im anderen Forum hieß es, dass das evtl. mit dem Auslesen von xx, yy oder f zu tun hat, also die Werte sollen dadurch verschoben werden. Als ich die mal geändert habe, hat das aber auch nichts gebracht.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@lpterritory: wie schon geschrieben, kannst Du ja auch alles selbst hinformatieren:

Code: Alles auswählen

def format_number(value):
    num,exp = ('%.3e' % value).split('e')
    return r'$%s\cdot10^{%s}$' % (num, exp)
ax.clabel(cset, inline=1, fontsize=10, fmt=format_number)
lpterritory
User
Beiträge: 4
Registriert: Mittwoch 27. April 2016, 20:50

Ahhh super,

mir war ehrlich gesagt, gar nicht so sehr bewusst, dass man das so leicht definieren kann, aber jetzt ist es deutlich. Ich danke dir auf jeden Fall vielmals! :)
Antworten