Matplotlib kontur plot etiketten überlappen achsen

Ich mache einige Kontur-Plots mit contour die über clabel beschriftet clabel . Das Problem ist, dass die Kontur-Etiketten dazu neigen, sich mit den Achsen zu überlappen: Bildbeschreibung hier eingeben

(Einige der anderen Etiketten sind unordentlich, ignorieren das). Für die linke Handlung sind 10 ^ -3 und 10 problematisch. Auf der rechten Seite ist 10 ^ 3 das einzige Problem. Hier ist der Code, der eine von ihnen erzeugt:

 fig = plt.figure(figsize=(6,3)) ax = fig.add_subplot(121) ax.set_xscale('log') ax.set_yscale('log') ax.set_xlabel(r'$T_e$ (eV)', fontsize=10) ax.set_ylabel(r'$n_e$ (1/cm$^3$)', fontsize=10) ax.set_xlim(0.1, 1e4) ax.set_ylim(1e16, 1e28) CS = ax.contour(X, Y, Z, V, colors='k') ax.clabel(CS, inline=True, inline_spacing=3, rightside_up=True, colors='k', fontsize=8, fmt=fmt) 

Gibt es irgendeinen Weg, um clabel zu werden, um sich besser über seine Platzierung zu clabel ?

One Solution collect form web for “Matplotlib kontur plot etiketten überlappen achsen”

In Anbetracht der Tatsache, dass die Beispiele in der Dokumentation leiden unter der gleichen Krankheit deutet darauf hin, dass es nicht schmerzlos, dies zu lösen. Es scheint, dass Sie mit den automatischen leben müssen, verwenden Sie manual Platzierung, oder erhalten Sie Ihre Hände schmutzig.

Als Kompromiss würde ich eines von zwei Sachen versuchen. Beide beginnen mit der Vermietung matplotlib vorschlagen Etikettenpositionen für Sie, dann die Handhabung diejenigen, die zu nah an einer Achse sind.

Der einfachere Fall, der auch sicherer ist, ist, diese clabel die sich in der Nähe einer Grenze befinden, einfach loszuwerden und diese Konturlinien zu füllen:

 # based on matplotlib.pyplot.clabel example: import matplotlib import numpy as np import matplotlib.cm as cm import matplotlib.mlab as mlab import matplotlib.pyplot as plt delta = 0.025 x = np.arange(-3.0, 3.0, delta) y = np.arange(-2.0, 2.0, delta) X, Y = np.meshgrid(x, y) Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) # difference of Gaussians Z = 10.0 * (Z2 - Z1) plt.figure() CS = plt.contour(X, Y, Z) CLS = plt.clabel(CS, inline=1, fontsize=10) # now CLS is a list of the labels, we have to find offending ones thresh = 0.05 # ratio in x/y range in border to discard # get limits if they're automatic xmin,xmax,ymin,ymax = plt.axis() Dx = xmax-xmin Dy = ymax-ymin # check which labels are near a border keep_labels = [] for label in CLS: lx,ly = label.get_position() if xmin+thresh*Dx<lx<xmax-thresh*Dx and ymin+thresh*Dy<ly<ymax-thresh*Dy: # inlier, redraw it later keep_labels.append((lx,ly)) # delete the original lines, redraw manually the labels we want to keep # this will leave unlabelled full contour lines instead of overlapping labels for cline in CS.collections: cline.remove() for label in CLS: label.remove() CS = plt.contour(X, Y, Z) CLS = plt.clabel(CS, inline=1, fontsize=10, manual=keep_labels) 

Der Nachteil ist, dass einige Etiketten offensichtlich fehlen werden, und natürlich die 5% Schwelle sollte manuelle Optimierung für Ihre spezifische Anwendung benötigen. Ergebnis der oben im Vergleich zum Original (siehe oben):

Vor nach

Die andere Lösung, die ich erwähnt habe, wäre, die beleidigenden Etiketten zu nehmen, die Path s ihrer jeweiligen CS.collections Daten zu betrachten und versuchen, einen Punkt zu finden, der näher an der Innenseite der Figur liegt. Da es nicht trivial ist, die collections mit den Etiketten zu paaren (da jeder Kontur-Level-Pfad mit seinen mehreren Segmenten einem einzelnen Element von CS.collections ), ist es vielleicht nicht alles der Mühe wert. Vor allem, dass man sich vor Level-Linien so kurz, dass es unmöglich ist, ein Label auf sie zu platzieren, und Sie müssten auch die Größe der einzelnen Etikett zu schätzen.


Wenn man bedenkt, dass in Ihrem Fall die Konturlinien ziemlich einfach sind, können Sie auch versuchen, jede Konturlinie zu betrachten und diesen Punkt zu finden, der dem Zentrum der Figur am nächsten liegt.

Also, hier ist eine Rekonstruktion Ihres Datensatzes für Demonstrationszwecke:

 # guesstimated dummy data X,Y = np.meshgrid(np.logspace(-3,7,200),np.logspace(13,31,200)) Z = X/Y*10**21 Vrange = range(-3,5) V = [10**k for k in Vrange] fmt = {lev: '$10^{%d}$'%k for (k,lev) in zip(Vrange,V)} fig = plt.figure(figsize=(3,3)) ax = fig.add_subplot(111) ax.set_xscale('log') ax.set_yscale('log') ax.set_xlabel(r'$T_e$ (eV)', fontsize=10) ax.set_ylabel(r'$n_e$ (1/cm$^3$)', fontsize=10) ax.set_xlim(0.1, 1e4) ax.set_ylim(1e16, 1e28) CS = ax.contour(X, Y, Z, V, colors='k') ax.clabel(CS, inline=True, inline_spacing=3, rightside_up=True, colors='k', fontsize=8, fmt=fmt) 

Durch die explizite Verwendung dieser beiden Achsen sind logarithmisch, die Hauptidee ist, den letzten Aufruf zu clabel mit zu clabel :

 # get limits if they're automatic xmin,xmax,ymin,ymax = plt.axis() # work with logarithms for loglog scale # middle of the figure: logmid = (np.log10(xmin)+np.log10(xmax))/2, (np.log10(ymin)+np.log10(ymax))/2 label_pos = [] for line in CS.collections: for path in line.get_paths(): logvert = np.log10(path.vertices) # find closest point logdist = np.linalg.norm(logvert-logmid, ord=2, axis=1) min_ind = np.argmin(logdist) label_pos.append(10**logvert[min_ind,:]) # draw labels, hope for the best ax.clabel(CS, inline=True, inline_spacing=3, rightside_up=True, colors='k', fontsize=8, fmt=fmt, manual=label_pos) 

Ergebnis (rechts) im Vergleich zum Original (links):

Vor 2 Nach 2

Ich habe nicht viel Mühe gemacht, die Achsen Anmerkungen schön zu machen, also bitte ignoriere diese Details. Sie können sehen, dass die Etiketten in der Tat gut in der Mitte der Figur versammelt sind. Abhängig von Ihrer Anwendung, könnte dies oder nicht sein, was Sie wollen.

Als endgültige Anmerkung ist der Grund, warum die Etiketten nicht entlang der Diagonale der Achsen platziert sind, dass die Skalierung an den X und Y Achsen unterschiedlich ist. Dies könnte dazu führen, dass einige der Etiketten noch aus den Achsen herauskommen. Die ärgerlichste Lösung wäre, die [xmin,ymax][xmax,ymin] (logarithmische) Linie zu betrachten und den Schnittpunkt dieser Linie mit jedem der path . Sie müssen sehr investiert werden, wenn dies sich lohnt: Sie können auch Ihre Etiketten vollständig manuell platzieren.

  • Die Regressionslinie zu bekommen, um von einer Pandas-Regression zu plotten
  • So erstellen Sie eine Farbkarte von Vertrauensschätzungen für k-Nearest Neighbor Classification
  • Wie kann ich scipy.ndimage.interpolation.affine_transform verwenden, um ein Bild über sein Zentrum zu drehen?
  • Plotten geschwungene Linie in Python Basemap
  • Film aus Python erzeugen, ohne einzelne Bilder in Dateien zu speichern
  • Ändern Sie bestimmte Quadrate in einer abgetrennten Hitzewelle
  • Finden Sie den Bereich zwischen zwei Kurven in Matplotlib (Füllung zwischen Bereich)
  • Matplotlib 3D Scatterplot mit Markerfarbe entsprechend RGB-Werten
  • Pause matplotlib benutzerdefinierte Animation Schleife
  • Plotten verschiedene Farben in Matplotlib
  • Wie ändere ich Schriften in matplotlib (python)?
  • Python ist die beste Programmiersprache der Welt.