2015-07-20 2 views
6

wissenschaftliche Grenzen matplotlib Einstellung, wenn ich matplotlib y-Achse ticklabels wissenschaftlichen Modus es mir einen Exponenten an der Spitze der y-Achse des Formulars 1e-5einstellt Exponenten Text nach Zur Zeit Achse

gibt würde Ich mag Um dies zu ändern, lesen Sie r'$\mathregular{10^{-5}}$', so dass es gut ausdruckt.

Hier ist mein Beispielcode:

# Create a figure and axis 
fig, ax = plt.subplots() 

# Plot 100 random points 
# the y values of which are very small 
ax.scatter(np.random.rand(100), np.random.rand(100)/100000.0) 

# Set the y limits appropriately 
ax.set_ylim(0, 1/100000.0) 

# Change the y ticklabel format to scientific format 
ax.ticklabel_format(axis='y', style='sci', scilimits=(-2, 2)) 

# Get the offset value 
offset = ax.yaxis.get_offset_text() 

# Print it out 
print '1st offset printout: {}'.format(offset) 

# Run plt.tight_layout() 
plt.tight_layout() 

# Print out offset again - you can see the value now! 
print '2nd offset printout: {}'.format(offset) 

# Change it to latex format 
offset.set_text(r'$\mathregular{10^{-5}}$') 

# Print it out 
print '3rd offset printout: {}'.format(offset) 

# Add some text to the middle of the figure just to 
# check that it isn't the latex format that's the problem 
ax.text(0.5, 0.5/100000.0, r'$\mathregular{10^{-2}}$') 

# And show the figure 
plt.show() 

Meine Ausgabe wie folgt aussieht:

1st offset printout: Text(0,0.5,u'') 
2nd offset printout: Text(0,636.933,u'1e\u22125') 
3rd offset printout: Text(0,636.933,u'$\\mathregular{10^{-5}}$') 

enter image description here

Sie können den Code und Ausbringungs here finden.

Es gibt zwei Kuriositäten: Eine ist, dass ich nicht die 1e-5 an der Spitze der y-Achse (was das Ziel ist) überschreiben, und die andere ist, dass ich plt.tight_layout() ausführen muss, um sogar zu sehen dieser Unicode-Wert als Offset.

Kann mir jemand sagen, wo ich falsch liege?

Danke

EDIT: Die ursprüngliche Frage nicht klar gemacht hat, dass ich die Exponenten automatisch möchte ermitteln, wie sie derzeit von ticklabel_format berechnet wird. Anstatt also eine festgelegte Zeichenfolge an den Offset-Text zu übergeben, sollte dieser Wert automatisch erkannt und die Latex-Zeichenfolge entsprechend angepasst werden.

Antwort

3

Aufbauend auf @ edsmiths Antwort eine mögliche Arbeit, die tut, was ich möchte, ist zu bekommen der Offset-Text, wandeln Sie es in eine Latex-Zeichenfolge um, deaktivieren Sie den Offset und d fügt diese Zeichenfolge an der Spitze der Achse hinzu.

def format_exponent(ax, axis='y'): 

    # Change the ticklabel format to scientific format 
    ax.ticklabel_format(axis=axis, style='sci', scilimits=(-2, 2)) 

    # Get the appropriate axis 
    if axis == 'y': 
     ax_axis = ax.yaxis 
     x_pos = 0.0 
     y_pos = 1.0 
     horizontalalignment='left' 
     verticalalignment='bottom' 
    else: 
     ax_axis = ax.xaxis 
     x_pos = 1.0 
     y_pos = -0.05 
     horizontalalignment='right' 
     verticalalignment='top' 

    # Run plt.tight_layout() because otherwise the offset text doesn't update 
    plt.tight_layout() 
    ##### THIS IS A BUG 
    ##### Well, at least it's sub-optimal because you might not 
    ##### want to use tight_layout(). If anyone has a better way of 
    ##### ensuring the offset text is updated appropriately 
    ##### please comment! 

    # Get the offset value 
    offset = ax_axis.get_offset_text().get_text() 

    if len(offset) > 0: 
     # Get that exponent value and change it into latex format 
     minus_sign = u'\u2212' 
     expo = np.float(offset.replace(minus_sign, '-').split('e')[-1]) 
     offset_text = r'x$\mathregular{10^{%d}}$' %expo 

     # Turn off the offset text that's calculated automatically 
     ax_axis.offsetText.set_visible(False) 

     # Add in a text box at the top of the y axis 
     ax.text(x_pos, y_pos, offset_text, transform=ax.transAxes, 
       horizontalalignment=horizontalalignment, 
       verticalalignment=verticalalignment) 
    return ax 

Beachten Sie, dass Sie sollten die Position des Offset-Text durch den Aufruf pos = ax_axis.get_offset_text().get_position() aber diese Werte sind nicht in Achseneinheiten (sie sind wahrscheinlich Pixeleinheiten - dank @EdSmith - und damit nicht sehr hilfreich) verwenden können, . Deshalb habe ich einfach die x_pos und y_pos Werte entsprechend der Achse eingestellt, die wir betrachten.

Ich schrieb auch eine kleine Funktion, um automatisch geeignete x- und y-Grenzen zu erkennen (obwohl ich weiß, dass Matplotlib viele raffinierte Möglichkeiten hat, dies zu tun).

def get_min_max(x, pad=0.05): 
    ''' 
    Find min and max values such that 
    all the data lies within 90% of 
    of the axis range 
    ''' 
    r = np.max(x) - np.min(x) 
    x_min = np.min(x) - pad * r 
    x_max = np.max(x) + pad * r 
    return x_min, x_max 

So, mein Beispiel von der Frage zu aktualisieren (mit einer geringfügigen Änderung beide Achsen den Exponenten müssen machen):

import matplotlib.pylab as plt 
import numpy as np 

# Create a figure and axis 
fig, ax = plt.subplots() 

# Plot 100 random points that are very small 
x = np.random.rand(100)/100000.0 
y = np.random.rand(100)/100000.0 
ax.scatter(x, y) 

# Set the x and y limits 
x_min, x_max = get_min_max(x) 
ax.set_xlim(x_min, x_max) 
y_min, y_max = get_min_max(y)  
ax.set_ylim(y_min, y_max) 

# Format the exponents nicely 
ax = format_exponent(ax, axis='x') 
ax = format_exponent(ax, axis='y') 

# And show the figure 
plt.show() 

enter image description here

Ein Kern mit einem ipython Notebook die zeigt, Ausgabe des Codes ist verfügbar here.

Ich hoffe, dass hilft!

+0

Sehr ordentlich. Ich nehme an, das ist ein Fehler in Matplotlib, da Sie die Zeichenfolge 'Offsettext' direkt ersetzen können. Ihre Beschreibung ist etwas verwirrend - Sie fügen diese Zeichenfolge nicht hinzu, sondern deaktivieren den Offsettext und fügen die Latexbeschriftung an derselben Stelle ein. Im Idealfall würde der Ersetzungstext auf der Position von ax_axis.get_offset_text(). Get_position() 'basieren. Ich konnte keinen Weg finden, dies zu tun, da "pos" in Pixeleinheiten ist (glaube ich), oder? –

+0

Sie haben Recht - ich bearbeite jetzt meinen Bezug auf 'pos' in der Antwort. Ich konnte nicht herausfinden, was ich mit diesen Zahlen anfangen sollte (tatsächlich kam mir nicht in den Sinn, dass es sich um Pixelkoordinaten handelte - gut geraten!). Haben Sie Vorschläge, wie Sie die Werte aktualisieren können, ohne plt.tight_layout() auszuführen? – KirstieJane

2

Sie erhalten offset und setzen den Textwert, aber es scheint keine Möglichkeit zu geben, dies tatsächlich auf die Achse anzuwenden ... Selbst der Aufruf von ax.yaxis.offsetText.set_text(offset) aktualisiert den angezeigten Offset nicht. Eine Arbeit um den Offset-Text zu entfernen und mit Klammern auf der Achsenbeschriftung,

ax.yaxis.offsetText.set_visible(False) 
ax.set_ylabel("datalabel " + r'$\left(\mathregular{10^{-5}}\right)$') 

oder ersetzen Sie sie mit einem manuellen Textfeld als Minimal Beispiel

import matplotlib as mpl 
import matplotlib.pyplot as plt 
import numpy as np 

# Create a figure and axis 
fig, ax = plt.subplots() 
mpl.rc('text', usetex = True) 

# Plot 100 random points 
# the y values of which are very small 
large = 100000.0 
x = np.random.rand(100) 
y = np.random.rand(100)/large 

ax.scatter(x,y) 

# Set the y limits appropriately 
ax.set_ylim(0, 1/large) 

# Change the y ticklabel format to scientific format 
ax.ticklabel_format(axis='y', style='sci', scilimits=(-2, 2)) 

#print(ax.yaxis.offsetText.get_position()) 
ax.yaxis.offsetText.set_visible(False) 
ax.text(-0.21, 1.01/large, r'$\mathregular{10^{-2}}$') 

# And show the figure 
plt.show() 

Ich kenne diese isn ersetzen 't ideal, aber es kann sein, dass Offset-Text nicht manuell geändert werden kann oder nur mit den numerischen Werten konsistent sein kann ...

+0

Vielen Dank für Ihre Antwort - es gibt etwas sehr ähnliches in diesem [Blogpost] (https://alexpearce.me/2014/04/exponent-label-in-matplotlib). Es ist ein Work around, aber es verpasst die Tatsache, dass die 'ticklabel_format' Methode den Exponenten für Sie ermittelt und ich denke, das sollte etwas sein, was ich von 'offsetText' bekommen kann. Ich werde meine Frage anpassen, um das klarer zu machen. – KirstieJane

0

Fügen Sie zwei Zeilen im Code

import matplotlib.ticker as ptick 
ax.yaxis.set_major_formatter(ptick.ScalarFormatter(useMathText=True)) 
2

Es scheint, dass plt.ticklabel_format nicht richtig funktioniert. Allerdings, wenn Sie die ScalarFormatter selbst und setzen die Grenzen für die wissenschaftliche Schreibweise an die Formatierer definieren, können Sie wie so den Offset automatisch im mathtext Format erhalten:

import matplotlib.pyplot as plt 
import numpy as np 
import matplotlib.ticker 

x = np.linspace(3,5) 
y = np.sin(np.linspace(0,6*np.pi))*1e5 

plt.plot(x,y) 

mf = matplotlib.ticker.ScalarFormatter(useMathText=True) 
mf.set_powerlimits((-2,2)) 
plt.gca().yaxis.set_major_formatter(mf) 

plt.show() 

enter image description here

Verwandte Themen