मैं एक त्वरित समाधान है, जो सभी अन्य एनोटेशन के लिए डिफ़ॉल्ट बाउंडिंग बॉक्स के खिलाफ प्रत्येक एनोटेशन स्थिति की जाँच करता है लिखा है। यदि कोई टकराव होता है तो यह अपनी स्थिति को अगले उपलब्ध टकराव मुक्त स्थान पर बदल देता है। यह भी अच्छे तीरों में डालता है।
इसके बजाय इस बात का
:
एक काफी चरम उदाहरण के लिए, यह इस (संख्या में से कोई भी ओवरलैप) का उत्पादन करेगा
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import *
def get_text_positions(x_data, y_data, txt_width, txt_height):
a = zip(y_data, x_data)
text_positions = y_data.copy()
for index, (y, x) in enumerate(a):
local_text_positions = [i for i in a if i[0] > (y - txt_height)
and (abs(i[1] - x) < txt_width * 2) and i != (y,x)]
if local_text_positions:
sorted_ltp = sorted(local_text_positions)
if abs(sorted_ltp[0][0] - y) < txt_height: #True == collision
differ = np.diff(sorted_ltp, axis=0)
a[index] = (sorted_ltp[-1][0] + txt_height, a[index][1])
text_positions[index] = sorted_ltp[-1][0] + txt_height
for k, (j, m) in enumerate(differ):
#j is the vertical distance between words
if j > txt_height * 2: #if True then room to fit a word in
a[index] = (sorted_ltp[k][0] + txt_height, a[index][1])
text_positions[index] = sorted_ltp[k][0] + txt_height
break
return text_positions
def text_plotter(x_data, y_data, text_positions, axis,txt_width,txt_height):
for x,y,t in zip(x_data, y_data, text_positions):
axis.text(x - txt_width, 1.01*t, '%d'%int(y),rotation=0, color='blue')
if y != t:
axis.arrow(x, t,0,y-t, color='red',alpha=0.3, width=txt_width*0.1,
head_width=txt_width, head_length=txt_height*0.5,
zorder=0,length_includes_head=True)
:
यहाँ कोड है यहाँ कोड इन भूखंडों का निर्माण किया जाता है, उपयोग दिखा रहा है:
#random test data:
x_data = random_sample(100)
y_data = random_integers(10,50,(100))
#GOOD PLOT:
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.bar(x_data, y_data,width=0.00001)
#set the bbox for the text. Increase txt_width for wider text.
txt_height = 0.04*(plt.ylim()[1] - plt.ylim()[0])
txt_width = 0.02*(plt.xlim()[1] - plt.xlim()[0])
#Get the corrected text positions, then write the text.
text_positions = get_text_positions(x_data, y_data, txt_width, txt_height)
text_plotter(x_data, y_data, text_positions, ax2, txt_width, txt_height)
plt.ylim(0,max(text_positions)+2*txt_height)
plt.xlim(-0.1,1.1)
#BAD PLOT:
fig = plt.figure()
ax = fig.add_subplot(111)
ax.bar(x_data, y_data, width=0.0001)
#write the text:
for x,y in zip(x_data, y_data):
ax.text(x - txt_width, 1.01*y, '%d'%int(y),rotation=0)
plt.ylim(0,max(text_positions)+2*txt_height)
plt.xlim(-0.1,1.1)
plt.show()
काफी अच्छा है। क्या गैर-बार ग्राफिक्स पर इसे सामान्यीकृत करने का कोई तरीका है? मैं एक स्कैटरप्लॉट को एनोटेट करने की कोशिश कर रहा हूं, और स्वाभाविक रूप से यह अच्छा होगा अगर तीरों की दूरी को भी कम किया जाए। संख्याओं के माध्यम से जाने वाले तीरों की मात्रा को कम करना भी संभव है? – tarrasch
@tarrasch - इस सिद्धांत को किसी भी प्रकार की साजिश के लिए ठीक काम करना चाहिए। उम्मीद है कि मेरे पास अगले कुछ दिनों में कोड को अधिक आकर्षक आकार में दस्तक देने का समय होगा (जैसा कि मैंने उल्लेख किया है, इसे सामान्यीकृत करने की आवश्यकता है)। तीरों की दूरी को थोड़ा कम किया जा सकता है ('2 * एल' से 'एल' में बदलें), लेकिन तीरों को कभी-कभी संख्याओं के माध्यम से जाना पड़ता है (हालांकि इससे बचने के लिए यह बहुत जटिल हो जाएगा), हालांकि यदि आप तीर 'अल्फा' सेटिंग को 'अल्फा = 0.3' में बदलते हैं, और पाठ' रंग 'को नीले रंग में बदलते हैं, तो साजिश और भी बेहतर दिखने लगती है। – fraxel
अच्छा! मैं आज दोपहर इसे आजमाउंगा :) – tarrasch