Matplotlib重叠注释/文本

我正试图在我的图表中停止注释文本重叠。 在接受的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") 

图片(如果这个工程)可以在这里find(这个代码):

此搜索

这里 (更复杂):

图像2

我只是想在这里发布另一个解决scheme,我写的一个小型库来实现这样的事情: https : //github.com/Phlya/adjustText这个过程的一个例子(从旧版本的库 – 我也是懒得做一个新的)可以在这里看到: 在这里输入图像描述

这是示例图像:

 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() 

在这里输入图像描述

如果你想要一个完美的身材,你可以稍微摆弄一下。 首先,让我们使文本排斥线 – 为此,我们使用scipy.interpolate.interp1d沿着它们创build大量虚拟点。

我们希望避免将标签沿着x轴移动,因为,为什么不为了说明的目的呢? 为此,我们使用参数only_move={'points':'y', 'text':'y'} 。 如果我们只想在它们与文本重叠的情况下沿x轴移动它们,请使用move_only={'points':'y', 'text':'xy'} 。 同样在开始时,函数会select文本相对于原始点的最佳alignment方式,所以我们只希望沿着y轴进行,因此autoalign='y' 。 我们也减less了来自点的排斥力,以避免由于我们人为地避免线条而使文本飞得太远。 全部一起:

 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() 

在这里输入图像描述

有很多的摆弄,我明白了。 原来的解决scheme再次信贷到Matplotlib重叠注释的答案。

我不知道如何find文本的确切宽度和高度。 如果有人知道,请发布一个改进(或添加一个评论的方法)。

 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,yt, 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() 

创buildhttp://i.stack.imgur.com/xiTeU.png 在这里输入图像描述

更复杂的图现在是http://i.stack.imgur.com/KJeYW.png ,还有点不好但是好多了! 在这里输入图像描述