Xem xét rằng the examples in the documentation bị cùng một căn bệnh cho thấy rằng sẽ không khó để giải quyết vấn đề này. It would seem mà bạn phải sống với những người tự động, sử dụng manual
vị trí, hoặc có được bàn tay của bạn bẩn.
Như một sự thỏa hiệp, tôi sẽ thử một trong hai điều. Cả hai bắt đầu cho phép matplotlib
đề xuất vị trí nhãn cho bạn, sau đó xử lý các vị trí quá gần một trục.
Trường hợp đơn giản hơn, đó cũng là an toàn hơn, là chỉ cần thoát khỏi những clabel
s mà gần gũi với một đường viền, làm đầy những đường đồng mức:
# 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)
Nhược điểm là một số nhãn rõ ràng sẽ mất tích, và tất nhiên ngưỡng 5% cần điều chỉnh thủ công cho ứng dụng cụ thể của bạn. Kết quả trên so với bản gốc (xem phía trên):
Các giải pháp khác tôi đã đề cập sẽ được lấy nhãn vi phạm, nhìn vào Path
s của CS.collections
dữ liệu tương ứng của họ, và cố gắng để tìm một điểm gần với bên trong hình. Vì nó không tầm thường khi ghép nối dữ liệu collections
với các nhãn (vì mỗi đường bao mức đường bao với nhiều đoạn đường tương ứng với một phần tử đơn lẻ là CS.collections
), nó có thể không đáng để thử. Đặc biệt là bạn có thể phải đối mặt với các dòng cấp độ quá ngắn đến mức không thể đặt một nhãn lên chúng, và bạn cũng phải ước tính kích thước của mỗi nhãn.
Xem xét trường hợp của bạn là đường đồng mức khá đơn giản, bạn cũng có thể thử xem từng đường đồng mức và tìm điểm gần với trung tâm của hình.
Vì vậy, đây là một tái thiết dữ liệu của bạn đặt ra cho mục đích trình diễn:
# 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)
Bằng cách sử dụng rõ ràng về điều đó cả hai trục của bạn là logarit, ý tưởng chính là để thay thế các cuộc gọi cuối cùng ở trên để clabel
với :
# 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)
quả (phải) so với bản gốc (trái):
Tôi đã không thực hiện nhiều nỗ lực để làm cho chú thích trục đẹp, vì vậy vui lòng bỏ qua các chi tiết này.Bạn có thể thấy rằng các nhãn thực sự được thu thập ở gần giữa hình. Tùy thuộc vào ứng dụng của bạn, điều này có thể hoặc có thể không phải là những gì bạn muốn.
Là một lưu ý cuối cùng, lý do nhãn là không đặt dọc theo đường chéo của các trục là mở rộng quy mô là khác nhau dọc theo X
và Y
trục. Điều này có thể khiến một số nhãn vẫn tiếp xúc với các trục. Giải pháp dễ sử dụng nhất là xem xét đường [xmin,ymax]
- [xmax,ymin]
(lôgarít) và để tìm giao điểm của đường này với mỗi path
s. Bạn phải rất đầu tư vào điều này nếu điều này là giá trị nó: bạn cũng có thể đặt nhãn của bạn hoàn toàn bằng tay.
Cảm ơn vì điều này. Sử dụng nó để ngăn chặn các cạnh cắt xén xấu xí trong dịch vụ bản đồ lát gạch (ví dụ: đường viền áp suất không khí). –