Matplotlib 重叠注释/文本 [英] Matplotlib overlapping annotations / text

查看:42
本文介绍了Matplotlib 重叠注释/文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图阻止注释文本在我的图表中重叠.(更复杂):

解决方案

我只是想在这里发布另一个解决方案,我写的一个小库来实现这种事情:

这是示例图片:

将 matplotlib.pyplot 导入为 plt从 adjustText 导入 adjust_text将 numpy 导入为 np一起= [(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)]一起排序()text = [x for (x,y,z) in together]eucs = [y for (x,y,z) in together]覆盖 = [z for (x,y,z) 在一起]p1 = plt.plot(eucs,covers,color=black", alpha=0.5)文本 = []对于 zip 中的 x、y、s(eucs、covers、text):texts.append(plt.text(x, y, s))plt.xlabel(比例欧几里得距离")plt.ylabel(参与的时间窗口百分比")plt.title(测试图")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 interpolatep1 = plt.plot(eucs,covers,color=black", alpha=0.5)文本 = []对于 zip 中的 x、y、s(eucs、covers、text):texts.append(plt.text(x, y, s))f = interpolate.interp1d(eucs,cover)x = np.arange(min(eucs), max(eucs), 0.0005)y = f(x)plt.xlabel(比例欧几里得距离")plt.ylabel(参与的时间窗口百分比")plt.title(测试图")调整文本(文本,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()

I'm trying to stop annotation text overlapping in my graphs. The method suggested in the accepted answer to Matplotlib overlapping annotations looks extremely promising, however is for bar graphs. I'm having trouble converting the "axis" methods over to what I want to do, and I don't understand how the text lines up.

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

Images (if this works) can be found here (this code):

and here (more complicated):

解决方案

I just wanted to post here another solution, a small library I wrote to implement this kind of things: https://github.com/Phlya/adjustText An example of the process can be seen here:

Here is the example image:

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

If you want a perfect figure, you can fiddle around a little. First, let's also make text repel the lines - for that we just create lots of virtual points along them using scipy.interpolate.interp1d.

We want to avoid moving the labels along the x-axis, because, well, why not do it for illustrative purposes. For that we use the parameter only_move={'points':'y', 'text':'y'}. If we want to move them along x axis only in the case that they are overlapping with text, use move_only={'points':'y', 'text':'xy'}. Also in the beginning the function chooses optimal alignment of texts relative to their original points, so we only want that to happen along the y axis too, hence autoalign='y'. We also reduce the repelling force from points to avoid text flying too far away due to our artificial avoidance of lines. All together:

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 重叠注释/文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆