注释自动放置(matploylib.pyplot)-或列出注释

发布于 2021-01-29 16:17:54

我有可以轻松自动地处理颜色和绘制多个图的代码(对我来说)。我想使注释更容易:

目标: 如果注释xy与前一个注释发生冲突,请上移-说上-直到与其他注释没有冲突为止。

  1. 如果有一个已经可以实现梦想的功能,我找不到它。

  2. 否则,列出注释并在坐标系中获取其边界框的最佳方法是什么?

我有一个自动着色的代码,如下所示:

if chain:
    children = []
    for child in Iplot.axes.get_children():
        if (type(child) is not matplotlib.collections.PathCollection and
            type(child) is not matplotlib.lines.Line2D):
            continue
        children.append(child)
    col_step = 1.0/(len(children)+len(args))
    for child in children:
        child.set_color([Iplot.col,0,1-Iplot.col])
        Iplot.col += col_step

我可以对注解执行类似的操作(更改if语句和第二个循环的主体),但是1)我不喜欢这段代码2)我希望存在更优雅的方法。

谢谢

关注者
0
被浏览
42
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    这是我想避免的解决方案。我在问题评论中链接的旧问题中看到有人提到这是一个np完全问题,但我想指出的是这并不重要。我测试了多达26个注释,这花费了几秒钟,但没有更多。任何实际情节都不会包含1000个注释。

    注意事项:

    1. 如前所述,这不是超快的。 具体来说,我希望可以避免使用draw()。 现在可以,只画两次。
    2. 此代码允许仅在特定的正交(左/右/上/下)方向上添加任何新注释,但是可以对其进行扩展。
    3. 箭头的位置 取决于窗口 。这意味着 确保 注释后(带有箭头) 窗口大小或轴不会改变 。如果调整大小,请重新注释。
    4. 不是动态的,请参阅第3点。

    背景:

    1. Iplot 是一个帮助器类,我必须处理多图图形,处理着色,调整大小和现在进行注释。
    2. pltmatplotlib.pyplot
    3. 此方法处理多个注释(或单个注释),现在可以解决冲突。
    4. 您可能已经猜到了,Iplot.axes握住我的斧头数字。

    编辑
    我删除了我的班级代码,以使其更可粘贴。应该给该函数指定轴,并且kwargs接受现有的box关键字以考虑先前的注释,该注释已在适当位置进行了编辑。注意我使用一个类来封装它。如果是第一次调用,该函数还必须返回要使用的框。

    编辑2

    过一会儿加快速度-无需绘制太多图像,最好循环两次,然后在两者之间更新渲染器。

    编码:

    def annotate(axes,boxes,labels,data,**kwargs):
        #slide should be relevant edge of bbox - e.g. (0,0) for left, (0,1) for bottom ...
        try: slide = kwargs.pop("slide")
        except KeyError: slide = None
        try: 
            xytexts = kwargs.pop("xytexts")
            xytext  = xytexts
        except KeyError: 
            xytext = (0,2)
            xytexts = None
        try: boxes = kwargs.pop("boxes")
        except KeyError: boxes = list()
        pixel_diff = 1
                                                                                      newlabs = []              
        for i in range(len(labels)):
            try: 
                len(xytexts[i])
                xytext = xytexts[i]
            except TypeError: pass
    
            a = axes.annotate(labels[i],xy=data[i],textcoords='offset pixels',
                                        xytext=xytext,**kwargs)
            newlabs.append(a)
        plt.draw()
        for i in range(len(labels)):
            cbox = a.get_window_extent()
            if slide is not None:
                direct  = int((slide[0] - 0.5)*2)
                current = -direct*float("inf")
                arrow = False
                while True:
                    overlaps = False
                    count = 0
                    for box in boxes:
                        if cbox.overlaps(box):
                            if direct*box.get_points()[slide] > direct*current:
                                overlaps = True
                                current =  box.get_points()[slide] 
                                shift   = direct*(current - cbox.get_points()[1-slide[0],slide[1]])
                    if not overlaps: break
                    arrow = True
                    position = array(a.get_position())
                    position[slide[1]] += shift * direct * pixel_diff
                    a.set_position(position)
                    plt.draw()
                    cbox = a.get_window_extent()
                    x,y =  axes.transData.inverted().transform(cbox)[0]
                if arrow:
                    axes.arrow(x,y,data[i][0]-x,data[i][1]-y,head_length=0,head_width=0)
            boxes.append(cbox)
        plt.draw()
        return boxes
    

    任何改进的建议 都会受到热烈欢迎。非常感谢!



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看