2012-01-31 35 views
24

nếu tôi thực hiện một biểu đồ phân tán với matplotlib:matplotlib: làm thế nào để chú thích điểm trên một phân tán tự động đặt mũi tên?

plt.scatter(randn(100),randn(100)) 
# set x, y lims 
plt.xlim([...]) 
plt.ylim([...]) 

Tôi muốn chú thích một điểm nhất định (x, y) với một mũi tên trỏ đến nó và nhãn. Tôi biết điều này có thể được thực hiện với annotate, nhưng tôi muốn mũi tên và nhãn của nó được đặt "tối ưu" theo cách mà nếu có thể (với quy mô/giới hạn trục hiện tại) mà mũi tên và nhãn không chồng chéo với các điểm khác. ví dụ: nếu bạn muốn gắn nhãn một điểm ngoại lệ. Có cách nào để làm việc này không? nó không phải là hoàn hảo, nhưng chỉ là một vị trí thông minh của mũi tên/nhãn, chỉ cho các tọa độ (x,y) của điểm được dán nhãn. cảm ơn.

+6

Trên ghi chú bên, 'phân tán' không dành cho những gì bạn đang làm. Sử dụng nó khi bạn muốn vẽ dữ liệu 3 hoặc 4 chiều bằng cách thay đổi màu sắc và/hoặc kích thước của điểm đánh dấu. Không sử dụng nó khi bạn chỉ muốn điểm. Không có gì sai khi sử dụng nó cho các điểm, nhưng nó sẽ trả về một bộ sưu tập, phức tạp hơn để đối phó với một đối tượng Line2D mà 'plot' trả về. –

Trả lời

33

Về cơ bản, không, không có.

Công cụ bố trí xử lý việc đặt nhãn bản đồ tương tự như thế này phức tạp đáng ngạc nhiên và vượt ra ngoài phạm vi của matplotlib. (Các điểm nút giao nhau thực sự là một cách khá nghèo để quyết định vị trí đặt nhãn. Có gì khi viết một tấn mã cho thứ gì đó sẽ chỉ hoạt động trong một trường hợp trong số 1000?)

Khác hơn, do số lượng văn bản kết xuất phức tạp mà matplotlib thực hiện (ví dụ: latex), không thể xác định mức độ văn bản mà không hoàn toàn hiển thị văn bản đầu tiên (điều này khá chậm).

Tuy nhiên, trong nhiều trường hợp, bạn sẽ thấy rằng việc sử dụng hộp trong suốt phía sau nhãn được đặt bằng chú thích là cách giải quyết phù hợp.

Ví dụ:

import numpy as np 
import matplotlib.pyplot as plt 

np.random.seed(1) 
x, y = np.random.random((2,500)) 

fig, ax = plt.subplots() 
ax.plot(x, y, 'bo') 

# The key option here is `bbox`. I'm just going a bit crazy with it. 
ax.annotate('Something', xy=(x[0], y[0]), xytext=(-20,20), 
      textcoords='offset points', ha='center', va='bottom', 
      bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3), 
      arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0.5', 
          color='red')) 

plt.show() 

enter image description here

+2

Tôi thích ví dụ của bạn. Người ta cũng có thể đặt chú thích bên ngoài khung, sử dụng "phân số trục" ví dụ cho 'textcoords'. Bản chất tự động của vị trí có thể được bao bọc thành một phương pháp nhỏ để tạo chú thích. Nếu điểm gần với trung tâm dưới cùng, đặt nó bên dưới trục x; nếu nó gần với cạnh phải, đặt nó ở đó, thậm chí có thể tự động xoay nó .... Vẫn vị trí sẽ yêu cầu một chút khéo léo bởi vì nó có thể ẩn các nhãn tick, hoặc bị cắt bởi các cạnh của hình, vv ... – Yann

+0

@Joe: Làm thế nào để bạn quyết định giá trị nào cho 'xytext' (trong trường hợp này là' (-20,20) ')? – user248237dfsf

+1

@ user248273 - Đó là khoản chênh lệch điểm. Đó là tùy ý, nhưng nó sẽ không phụ thuộc vào phạm vi dữ liệu của bạn. Lưu ý kwarg 'textcoords = 'offset points''. Việc chuyển các giá trị khác cho 'textcoords' sẽ điều khiển cách các số trong' xytext' được diễn giải. –

2

Sử dụng adjustText (full tiết lộ, tôi đã viết nó).

Hãy gắn nhãn 10 điểm đầu tiên. Thông số duy nhất tôi thay đổi đã giảm lực đẩy lùi khỏi các điểm, vì có quá nhiều điểm và chúng tôi muốn thuật toán mất nhiều thời gian hơn và đặt chú thích cẩn thận hơn.

import numpy as np 
import matplotlib.pyplot as plt 
from adjustText import adjust_text 
np.random.seed(1) 
x, y = np.random.random((2,500)) 

fig, ax = plt.subplots() 
ax.plot(x, y, 'bo') 
ts = [] 
for i in range(10): 
    ts.append(plt.text(x[i], y[i], 'Something'+str(i))) 
adjust_text(ts, x=x, y=y, force_points=0.1, arrowprops=dict(arrowstyle='->', 
color='red')) 
plt.show() 

enter image description here Đó không phải là lý tưởng, nhưng những điểm thực sự dày đặc ở đây và đôi khi không có cách nào để đặt các văn bản gần mục tiêu của mình mà không chồng chéo bất kỳ trong số họ. Nhưng tất cả đều tự động và dễ sử dụng và cũng không cho phép các nhãn chồng lên nhau.

PS Nó sử dụng giao lộ hộp giới hạn, nhưng đúng hơn tôi muốn nói!

Các vấn đề liên quan