如何旋转matplotlib注释以匹配线? [英] How to rotate matplotlib annotation to match a line?

查看:108
本文介绍了如何旋转matplotlib注释以匹配线?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有包含多个具有不同斜率的对角线的图.我想用与行的斜率匹配的文本标签注释这些行.

Have a plot with several diagonal lines with different slopes. I would like to annotate these lines with a text label that matches the slope of the lines.

类似这样的东西:

有健壮的方法吗?

我已经尝试了textannotate的旋转参数,但是这些参数在屏幕坐标中,而不是数据坐标中(即,无论xy范围如何,屏幕上始终为x度).我的x和y范围相差一个数量级,并且明显的视斜率会受到视口大小以及其他变量的影响,因此,固定角度的旋转并不能解决问题.还有其他想法吗?

I've tried both text's and annotate's rotation parameters, but those are in screen coordinates, not data coordinates (i.e. it's always x degrees on the screen no matter the xy ranges). My x and y ranges differ by orders of magnitude, and obviously the apparent slope is affected by viewport size among other variables, so a fixed-degree rotation doesn't do the trick. Any other ideas?

推荐答案

我想出了一些对我有用的东西.请注意灰色虚线:

I came up with something that works for me. Note the grey dashed lines:

必须手动设置旋转,但是必须在draw()或布局之后完成.因此,我的解决方案是将线条与注释相关联,然后遍历它们并执行以下操作:

The rotation must be set manually, but this must be done AFTER draw() or layout. So my solution is to associate lines with annotations, then iterate through them and do this:

  1. 获取行的数据转换(即从数据坐标转换为显示坐标)
  2. 沿直线变换两个点以显示坐标
  3. 找到显示线的斜率
  4. 设置文本旋转以匹配此斜率

这不是完美的,因为matplotlib处理旋转文本是完全错误的.它通过边界框而不是文本基线对齐.

This isn't perfect, because matplotlib's handling of rotated text is all wrong. It aligns by the bounding box and not by the text baseline.

如果您对文本呈现感兴趣,请使用一些字体基础知识: http: //docs.oracle.com/javase/tutorial/2d/text/fontconcepts.html

Some font basics if you're interested about text rendering: http://docs.oracle.com/javase/tutorial/2d/text/fontconcepts.html

此示例显示了matplotlib的功能: http://matplotlib.org/examples/pylab_examples/text_rotation .html

This example shows what matplotlib does: http://matplotlib.org/examples/pylab_examples/text_rotation.html

我发现在该行旁边正确放置标签的唯一方法是在垂直和水平方向上按中心对齐.然后,我将标签向左偏移10点以使其不重叠.对我的应用程序来说足够好了.

The only way I found to have a label properly next to the line is to align by center in both vertical and horizontal. I then offset the label by 10 points to the left to make it not overlap. Good enough for my application.

这是我的代码.我可以根据需要绘制线条,然后绘制注释,然后使用辅助函数将其绑定:

Here is my code. I draw the line however I want, then draw the annotation, then bind them with a helper function:

line, = fig.plot(xdata, ydata, '--', color=color)

# x,y appear on the midpoint of the line

t = fig.annotate("text", xy=(x, y), xytext=(-10, 0), textcoords='offset points', horizontalalignment='left', verticalalignment='bottom', color=color)
text_slope_match_line(t, x, y, line)

然后在布局之后但在savefig之前调用另一个辅助函数(对于交互式图像,我认为您必须注册绘制事件并在处理程序中调用update_text_slopes)

Then call another helper function after layout but before savefig (For interactive images I think you'll have to register for draw events and call update_text_slopes in the handler)

plt.tight_layout()
update_text_slopes()

助手:

rotated_labels = []
def text_slope_match_line(text, x, y, line):
    global rotated_labels

    # find the slope
    xdata, ydata = line.get_data()

    x1 = xdata[0]
    x2 = xdata[-1]
    y1 = ydata[0]
    y2 = ydata[-1]

    rotated_labels.append({"text":text, "line":line, "p1":numpy.array((x1, y1)), "p2":numpy.array((x2, y2))})

def update_text_slopes():
    global rotated_labels

    for label in rotated_labels:
        # slope_degrees is in data coordinates, the text() and annotate() functions need it in screen coordinates
        text, line = label["text"], label["line"]
        p1, p2 = label["p1"], label["p2"]

        # get the line's data transform
        ax = line.get_axes()

        sp1 = ax.transData.transform_point(p1)
        sp2 = ax.transData.transform_point(p2)

        rise = (sp2[1] - sp1[1])
        run = (sp2[0] - sp1[0])

        slope_degrees = math.degrees(math.atan(rise/run))

        text.set_rotation(slope_degrees)

这篇关于如何旋转matplotlib注释以匹配线?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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