wake-up-neo.com

Wie stelle ich Rasterlinien für zwei Y-Achsenskalen mit Matplotlib ein?

Ich zeichne zwei Datensätze mit unterschiedlichen Einheiten auf der Y-Achse. Gibt es eine Möglichkeit, die Ticks und Gitternetzlinien auf beiden Y-Achsen auszurichten?

Das erste Bild zeigt, was ich bekomme, und das zweite Bild zeigt, was ich gerne hätte.

Dies ist der Code, den ich zum Zeichnen verwende:

import seaborn as sns
import numpy as np
import pandas as pd

np.random.seed(0)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(pd.Series(np.random.uniform(0, 1, size=10)))
ax2 = ax1.twinx()
ax2.plot(pd.Series(np.random.uniform(10, 20, size=10)), color='r')

Example of unwanted behavior

Example of wanted behavior

26
Artturi Björk

Ich bin nicht sicher, ob dies der schönste Weg ist, aber es korrigiert es mit einer Zeile:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd

np.random.seed(0)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(pd.Series(np.random.uniform(0, 1, size=10)))
ax2 = ax1.twinx()
ax2.plot(pd.Series(np.random.uniform(10, 20, size=10)), color='r')

# ADD THIS LINE
ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())))

plt.show()
24
Leo

Ich habe diese Funktion geschrieben, die die Matplotlib-Achsenobjekte ax1, ax2 und minresax1 schwimmt: minresax2:

def align_y_axis(ax1, ax2, minresax1, minresax2):
    """ Sets tick marks of twinx axes to line up with 7 total tick marks

    ax1 and ax2 are matplotlib axes
    Spacing between tick marks will be a factor of minresax1 and minresax2"""

    ax1ylims = ax1.get_ybound()
    ax2ylims = ax2.get_ybound()
    ax1factor = minresax1 * 6
    ax2factor = minresax2 * 6
    ax1.set_yticks(np.linspace(ax1ylims[0],
                               ax1ylims[1]+(ax1factor -
                               (ax1ylims[1]-ax1ylims[0]) % ax1factor) %
                               ax1factor,
                               7))
    ax2.set_yticks(np.linspace(ax2ylims[0],
                               ax2ylims[1]+(ax2factor -
                               (ax2ylims[1]-ax2ylims[0]) % ax2factor) %
                               ax2factor,
                               7))

Es berechnet und setzt die Ticks so, dass es sieben Ticks gibt. Der niedrigste Tick entspricht dem aktuellen niedrigsten Tick und erhöht den höchsten Tick, sodass der Abstand zwischen jedem Tick ganzzahlige Vielfache von Minrexax1 oder Minrexax2 beträgt.

Um es allgemein zu machen, können Sie die Gesamtanzahl der Ticks festlegen, die Sie möchten, indem Sie 7 in die Gesamtanzahl der Ticks ändern und 6 die Gesamtanzahl der Ticks minus 1 ändern.

Ich habe eine Pull-Anforderung eingefügt, um einige davon in matplotlib.ticker.LinearLocator zu integrieren:

https://github.com/matplotlib/matplotlib/issues/6142

Versuchen Sie in der Zukunft (Matplotlib 2.0?):

import matplotlib.ticker
nticks = 11
ax1.yaxis.set_major_locator(matplotlib.ticker.LinearLocator(nticks))
ax2.yaxis.set_major_locator(matplotlib.ticker.LinearLocator(nticks))

Das sollte einfach funktionieren und für beide Y-Achsen geeignete Häkchen auswählen.

8
Scott Howard

Ich könnte es lösen, indem ich ax.grid(None) in einer der Achsen des Gitters deaktiviere:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(pd.Series(np.random.uniform(0, 1, size=10)))
ax2 = ax1.twinx()
ax2.plot(pd.Series(np.random.uniform(10, 20, size=10)), color='r')
ax2.grid(None)

plt.show()

Figure Result

7
arnaldo

dies wurde bereits vor einiger Zeit richtig beantwortet: Probleme beim Ausrichten von Ticks für Matplotlib-Twinx-Achsen

(Die Antwort, die hier gegeben wird, funktioniert überhaupt nicht für einen allgemeinen Fall.)

1
raphael

Dieser Code stellt sicher, dass die Raster beider Achsen zueinander ausgerichtet sind, ohne dass die Rasterlinien in beiden Sätzen ausgeblendet werden müssen. In diesem Beispiel können Sie denjenigen anpassen, der die feineren Gitterlinien hat. Dies baut auf der Idee von @Leo auf. Ich hoffe es hilft!

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(pd.Series(np.random.uniform(0,1,size=10)))
ax2 = ax1.twinx()
ax2.plot(pd.Series(np.random.uniform(10,20,size=10)),color='r')
ax2.grid(None)

# Determine which plot has finer grid. Set pointers accordingly
l1 = len(ax1.get_yticks())
l2 = len(ax2.get_yticks())
if l1 > l2:
  a = ax1
  b = ax2
  l = l1
else:
  a = ax2
  b = ax1
  l = l2

# Respace grid of 'b' axis to match 'a' axis
b_ticks = np.linspace(b.get_yticks()[0],b.get_yticks()[-1],l)
b.set_yticks(b_ticks)

plt.show()
1
John

Wenn Sie Achsenbeschriftungen verwenden, kann die Lösung von Leo aufgrund der Genauigkeit der Zahlen in den Teilstrichen von der Seite schieben.

Also zusätzlich zu etwas wie Leos Lösung (hier wiederholt),

ax2.set_yticks(np.linspace(ax2.get_yticks()[0],ax2.get_yticks()[-1],len(ax1.get_yticks())))

sie können die Einstellung autolayout verwenden, wie in diese Antwort erwähnt; Beispielsweise können Sie in Ihrem Skript rcParams aktualisieren:

from matplotlib import rcParams
rcParams.update({'figure.autolayout': True})

In einigen Testfällen scheint dies das erwartete Ergebnis zu liefern, wobei sowohl aufgereihte Häkchen als auch Beschriftungen vollständig in der Ausgabe enthalten sind.

0
Jonathan W.

Ich hatte das gleiche Problem, außer dass dies für eine sekundäre x-Achse war. Ich löste mich, indem ich meine sekundäre x-Achse gleich der Grenze meiner primären Achse setzte. Im folgenden Beispiel wird die Grenze der zweiten Achse gleich der ersten gesetzt: ax2 = ax.twiny() enter image description here

Sobald ich die Grenze der zweiten Achse gleich der ersten ax2.set_xlim(ax.get_xlim()) gesetzt habe, ist hier mein Ergebnis:  enter image description here

0