Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Matplotlib重叠注释/文本_Python_Matplotlib_Annotate - Fatal编程技术网

Python Matplotlib重叠注释/文本

Python Matplotlib重叠注释/文本,python,matplotlib,annotate,Python,Matplotlib,Annotate,我正在尝试停止图表中的注释文本重叠。在被接受的答案中建议的方法看起来非常有希望,但是它适用于条形图。我很难将“axis”方法转换为我想做的事情,我不明白文本是如何排列的 import sys import matplotlib.pyplot as plt # start new plot plt.clf() plt.xlabel("Proportional Euclidean Distance") plt.ylabel("Percentage Timewindows Attended") p

我正在尝试停止图表中的注释文本重叠。在被接受的答案中建议的方法看起来非常有希望,但是它适用于条形图。我很难将“axis”方法转换为我想做的事情,我不明白文本是如何排列的

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")
可以找到图像(如果可行)(此代码):

和(更复杂的):


我费了好大劲才弄明白。同样,最初的解决方案的功劳归于解决问题的答案

然而,我不知道如何找到文本的确切宽度和高度。如果有人知道,请发布改进(或使用该方法添加注释)

导入系统 导入matplotlib 将matplotlib.pyplot作为plt导入 将numpy作为np导入 def get_text_位置(文本、x_数据、y_数据、txt_宽度、txt_高度): a=zip(y_数据,x_数据) 文本位置=列表(y数据) 对于枚举(a)中的索引(y,x): 局部文本位置=[i为i,如果i[0]>(y-txt\u高度) 和(abs(i[1]-x)txt_height*2:#如果为真,则有空间容纳一个单词 a[index]=(排序的[u ltp[k][0]+txt\u高度,a[index][1]) 文本位置[索引]=已排序的文本ltp[k][0]+txt\U高度 打破 返回文本位置 def text_绘图仪(文字、x_数据、y_数据、文字位置、文字宽度、文字高度): 对于zip中的z、x、y、t(文本、x_数据、y_数据、文本_位置): plt.annotate(str(z),xy=(x-txt_-width/2,t),size=12) 如果y!=t: plt.箭头(x,t,0,y-t,color='red',alpha=0.3,width=txt_width*0.1, 头部宽度=txt宽度,头部长度=txt高度*0.5, zorder=0,长度_包括_头=真) #开始新的绘图 plt.clf() plt.xlabel(“比例欧几里德距离”) plt.ylabel(“出席的时间窗口百分比”) plt.标题(“测试图”) 加起来=[(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.4013999168004,0.45)] together.sort() text=[x表示(x,y,z)在一起] eucs=[y表示(x,y,z)在一起] 封面=[z表示(x,y,z)在一起] p1=plt.绘图(eucs,封面,颜色=“黑色”,alpha=0.5) txt_height=0.0037*(plt.ylim()[1]-plt.ylim()[0]) txt_width=0.018*(plt.xlim()[1]-plt.xlim()[0]) 文本位置=获取文本位置(文本、eucs、封面、文本宽度、文本高度) 文字绘图仪(文字、eucs、封面、文字位置、文字宽度、文字高度) plt.savefig(“test.png”) plt.show() 创造

现在,更复杂的图形仍然有点模糊,但要好得多!

我只是想在这里发布另一个解决方案,一个我为实现这类功能而编写的小型库: 此处可以看到该过程的一个示例:

以下是示例图像:

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={'points':'y', 'texts':'y'}, arrowprops=dict(arrowstyle="->", color='r', lw=0.5))
plt.show()

如果你想要一个完美的身材,你可以随意摆弄一下。首先,让我们也让文本排斥直线-为此,我们只需使用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()

这里的简单解决方案:(适用于jupyter笔记本电脑)

右键单击点以显示其名称

用鼠标左键单击一个加油站,将其关闭

右键单击并拖动anotation以移动它


另请参见和
get_window_extent()
是您想要旋转的美工函数。get_window_extent()返回Bbox(数组([[349.194625,38.0572],[372.132125,448.0572])。这意味着文本的宽度/高度是什么?即以显示单位表示的文本边界框。看到了吗,这个代码是从哪里来的,对吗我认为应该归功于原作者@Fraxel。在
get\u text\u positions
中,
a[index][2]
似乎应该被
a[index][1]
取代。
a
中的元素看起来确实是大小为2的元组。代码没有与提供的示例冲突,因为相关部分没有执行。干得好,Phlya!你也可以加上这个答案或类似的东西来表示感谢,我很高兴你喜欢它!还有几个其他的问题是相关的,但我还没有看到这个问题。。。我会尽量找时间写一个答案,但是如果你愿意的话,你可以自己写@Phlya:按照你在GitHub的例子,它现在可以工作了,看起来真的很棒!因为其他人可能会第一次看到您的软件包,所以我建议您更新答案和代码。@RuthgerRighart我很高兴它对您有效!谢谢你的建议,我想我会在某个时候这样做……如果有人发现错误
“str”对象没有属性“values”
,请使用
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()
%matplotlib notebook
import mplcursors

plt.plot.scatter(y=YOUR_Y_DATA, x =YOUR_X_DATA)


mplcursors.cursor(multiple = True).connect(
    "add", lambda sel: sel.annotation.set_text(
          YOUR_ANOTATION_LIST[sel.target.index]
))