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')
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()
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.
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()
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.)
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()
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.
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()
Sobald ich die Grenze der zweiten Achse gleich der ersten ax2.set_xlim(ax.get_xlim())
gesetzt habe, ist hier mein Ergebnis: