2013-09-29 4 views
20

내 그래프에서 겹쳐지는 주석 텍스트를 중지하려고합니다. Matplotlib overlapping annotations에 대한 대답에서 제안 된 방법은 막대 그래프에 대해서는 매우 유망 해 보입니다. 나는 "축"방법을 내가하고 싶은대로 넘기는 데 어려움을 겪고 있으며, 텍스트가 어떻게 정렬되어 있는지 이해하지 못한다.Matplotlib 겹침 주석/텍스트

import sys 
import matplotlib.pyplot as plt 


# start new plot 
plt.clf() 
plt.xlabel("Proportional Euclidean Distance") 
plt.ylabel("Percentage Timewindows Attended") 
plt.title("Test plot") 

together = [(0, 1.0, 0.4), (25, 1.0127692669427917, 0.41), (50, 1.016404709797609, 0.41), (75, 1.1043426359673716, 0.42), (100, 1.1610446924342996, 0.44), (125, 1.1685687930691457, 0.43), (150, 1.3486407784550272, 0.45), (250, 1.4013999168008104, 0.45)] 
together.sort() 

for x,y,z in together: 
    plt.annotate(str(x), xy=(y, z), size=8) 

eucs = [y for (x,y,z) in together] 
covers = [z for (x,y,z) in together] 

p1 = plt.plot(eucs,covers,color="black", alpha=0.5) 

plt.savefig("test.png") 

이미지 (이 작동하는 경우) 찾을 수 있습니다 here (코드) :

image1

here (더 복잡) : 많은

image2

+0

참조 http://stackoverflow.com/questions/14938541/how-to-improve-the-label-placement-for-matplotlib-scatter-chart-code- 알고리즘/15859652 # 15859652 – tacaswell

답변

40

난 그냥 여기에 다른 해결책을 게시하고 싶었, 작은 도서관 나는 사물의 종류를 구현하기 위해 썼다 : 당신은 완벽한 그림을 원하는 경우에

import matplotlib.pyplot as plt 
from adjustText import adjust_text 
import numpy as np 
together = [(0, 1.0, 0.4), (25, 1.0127692669427917, 0.41), (50, 1.016404709797609, 0.41), (75, 1.1043426359673716, 0.42), (100, 1.1610446924342996, 0.44), (125, 1.1685687930691457, 0.43), (150, 1.3486407784550272, 0.45), (250, 1.4013999168008104, 0.45)] 
together.sort() 

text = [x for (x,y,z) in together] 
eucs = [y for (x,y,z) in together] 
covers = [z for (x,y,z) in together] 

p1 = plt.plot(eucs,covers,color="black", alpha=0.5) 
texts = [] 
for x, y, s in zip(eucs, covers, text): 
    texts.append(plt.text(x, y, s)) 

plt.xlabel("Proportional Euclidean Distance") 
plt.ylabel("Percentage Timewindows Attended") 
plt.title("Test plot") 
adjust_text(texts, only_move='y', arrowprops=dict(arrowstyle="->", color='r', lw=0.5)) 
plt.show() 

enter image description here

, 당신은 주변에 바이올린 수 있습니다 조금. 먼저, 텍스트를 repel로 만들어 봅시다. scipy.interpolate.interp1d를 사용하여 많은 가상 포인트를 만듭니다.

레이블을 X 축을 따라 이동하지 않으려합니다. 왜냐하면 설명을 위해 레이블을 이동하지 않는 것이 좋습니다. 이를 위해 only_move={'points':'y', 'text':'y'} 매개 변수를 사용합니다. 텍스트와 겹치는 경우에만 x 축을 따라 이동하려면 move_only={'points':'y', 'text':'xy'}을 사용하십시오. 또한 처음에는 함수가 원래 점에 상대적인 텍스트의 최적 정렬을 선택하므로 y 축을 따라 텍스트를 원한다. 따라서 autoalign='y'. 우리는 또한 인위적인 회선 회피로 인해 텍스트가 너무 멀리 날아 가지 않도록 지점에서 반발력을 줄입니다. 모두 함께 :

from scipy import interpolate 
p1 = plt.plot(eucs,covers,color="black", alpha=0.5) 
texts = [] 
for x, y, s in zip(eucs, covers, text): 
    texts.append(plt.text(x, y, s)) 

f = interpolate.interp1d(eucs, covers) 
x = np.arange(min(eucs), max(eucs), 0.0005) 
y = f(x)  

plt.xlabel("Proportional Euclidean Distance") 
plt.ylabel("Percentage Timewindows Attended") 
plt.title("Test plot") 
adjust_text(texts, x=x, y=y, autoalign='y', 
      only_move={'points':'y', 'text':'y'}, force_points=0.15, 
      arrowprops=dict(arrowstyle="->", color='r', lw=0.5)) 
plt.show() 

enter image description here

+0

멋진 일 Phlya! 당신은 아마 또한이 답변이나 뭔가를 https://stackoverflow.com/questions/9074996/matplotlib-how-to-annotate-point-on-a-scatter-automatically-placed-arrow에 추가 할 수 있습니다. – naught101

+0

감사합니다, 기꺼이 당신이 좋아! 너무 관련성이있는 몇 가지 다른 질문이 있습니다,하지만 그 하나를 보지 못했어요 ... 나는 그것에 대한 답변을 쓸 시간을 찾으려고 노력하지만, 원한다면 스스로 그렇게 자유롭게 느끼십시오! – Phlya

+0

이것은 정말 대단합니다, 게임 체인저 – dataflow

3

손짓의 안에서, 나는 그것을 이해했다. 다시 원래 솔루션에 대한 크레딧은 Matplotlib overlapping annotations에 대한 대답으로 이동합니다.

그러나 텍스트의 정확한 너비와 높이를 찾는 방법을 모르겠습니다. 누군가 알고있는 경우, 개선 사항을 게시하거나 방법과 함께 의견을 추가하십시오.

import sys 
import matplotlib 
import matplotlib.pyplot as plt 
import numpy as np 

def get_text_positions(text, x_data, y_data, txt_width, txt_height): 
    a = zip(y_data, x_data) 
    text_positions = list(y_data) 
    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*1.01 
       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(text, x_data, y_data, text_positions, txt_width,txt_height): 
    for z,x,y,t in zip(text, x_data, y_data, text_positions): 
     plt.annotate(str(z), xy=(x-txt_width/2, t), size=12) 
     if y != t: 
      plt.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) 

# start new plot 
plt.clf() 
plt.xlabel("Proportional Euclidean Distance") 
plt.ylabel("Percentage Timewindows Attended") 
plt.title("Test plot") 

together = [(0, 1.0, 0.4), (25, 1.0127692669427917, 0.41), (50, 1.016404709797609, 0.41), (75, 1.1043426359673716, 0.42), (100, 1.1610446924342996, 0.44), (125, 1.1685687930691457, 0.43), (150, 1.3486407784550272, 0.45), (250, 1.4013999168008104, 0.45)] 
together.sort() 

text = [x for (x,y,z) in together] 
eucs = [y for (x,y,z) in together] 
covers = [z for (x,y,z) in together] 

p1 = plt.plot(eucs,covers,color="black", alpha=0.5) 

txt_height = 0.0037*(plt.ylim()[1] - plt.ylim()[0]) 
txt_width = 0.018*(plt.xlim()[1] - plt.xlim()[0]) 

text_positions = get_text_positions(text, eucs, covers, txt_width, txt_height) 

text_plotter(text, eucs, covers, text_positions, txt_width, txt_height) 

plt.savefig("test.png") 
plt.show() 

http://i.stack.imgur.com/xiTeU.png enter image description here

더 복잡한 그래프는, 지금도 조금 불확실하지만, 훨씬 더 http://i.stack.imgur.com/KJeYW.png입니다 작성합니다! 여기에서 볼 수있다 https://github.com/Phlya/adjustText 과정의 예 : 여기 enter image description here

는 예를 들어, 이미지 enter image description here

+0

편집을 망쳤지 않은지 확인하십시오. – tacaswell

+0

그리고 답을 수락하면 답안을 수락하십시오. – tacaswell

+0

이고'get_window_extent()'는 – tacaswell