matplotlib:更新补丁的位置(或:set_xy为圆圈) [英] matplotlib: update position of patches (or: set_xy for circles)

查看:150
本文介绍了matplotlib:更新补丁的位置(或:set_xy为圆圈)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

受到此示例的启发,我尝试写一点matplotlib程序,允许用户动态拖放散点图中的数据点.与使用条形图(从而允许拖动矩形)的示例形成对比,我的目标是与其他补丁(例如圆形)(与矩形相比,散点图兼容的任何补丁)都可以达到相同的效果).但是,我被困在更新补丁位置的时候.尽管Rectangle提供了功能set_xy,但我找不到CirlceEllipse的直接模拟.获取圆的位置也比获取矩形的位置简单,但是可以通过获取边界框来获取.现在缺少的部分是寻找一种更新补丁位置的方法.关于如何实现这一目标的任何提示都将很棒!当前的最小工作示例如下所示:

Inspired by this example I'm trying to write a little matplotlib program that allows the user to drag and drop datapoints in a scatter plot dynamically. In contrast to the example which uses a bar plot (and thus allows dragging of rectangles) my goal was to achieve the same with other patches, like for instance a circle (any patch that is more scatter-plot-compatible than a rectangle would do). However I'm stuck at the point of updating the position of my patch. While a Rectangle provides a function set_xy I cannot find a direct analog for Cirlce or Ellipse. Obtaining the position of a circle is also less straightforward that for a rectangle, but is possible via obtaining the bounding box. The missing piece now is to find a way to update the position of my patch. Any hint on how to achieve this would be great! The current minimal working example would look like this:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches

class DraggablePatch:

  def __init__(self, patch):
    self.patch = patch
    self.storedPosition = None
    self.connect()

  def getPosOfPatch(self, marker):
    ext = marker.get_extents().get_points()
    x0 = ext[0,0]
    y0 = ext[0,1]
    x1 = ext[1,0]
    y1 = ext[1,1]
    return 0.5*(x0+x1), 0.5*(y0+y1)

  def connect(self):
    'connect to all the events we need'
    self.cidpress  = self.patch.figure.canvas.mpl_connect('button_press_event',  self.onPress)
    self.cidmotion = self.patch.figure.canvas.mpl_connect('motion_notify_event', self.onMove)

  def onPress(self, event):
    'on button press we will see if the mouse is over us and store some data'
    contains, attrd = self.patch.contains(event)
    if contains:
      self.storedPosition = self.getPosOfPatch(self.patch), event.xdata, event.ydata

  def onMove(self, event):
    'how to update an circle?!'
    contains, attrd = self.patch.contains(event)
    if contains and self.storedPosition is not None:
      oldPos, oldEventXData, oldEventYData = self.storedPosition
      dx = event.xdata - oldEventXData
      dy = event.ydata - oldEventYData
      newX = oldPos[0] + dx
      newY = oldPos[1] + dy
      print "now I would like to move my patch to", newX, newY


def myPatch(x,y): 
  return patches.Circle((x,y), radius=.05, alpha=0.5)

N = 10
x = np.random.random(N)
y = np.random.random(N)
patches = [myPatch(x[i], y[i]) for i in range(N)]

fig = plt.figure()
ax = fig.add_subplot(111)
drs = []
for patch in patches:
  ax.add_patch(patch)
  dr = DraggablePatch(patch)
  drs.append(dr)

plt.show()

推荐答案

有点矛盾,但是要更新圆的位置,请设置circ.center = new_x, new_y.

It's a bit annoying that it's inconsistent, but to update the position of a circle, set circ.center = new_x, new_y.

作为一个简单的(不可拖动的)示例:

As a simple (non-draggable) example:

import matplotlib.pyplot as plt
from matplotlib.patches import Circle

class InteractiveCircle(object):
    def __init__(self):
        self.fig, self.ax = plt.subplots()
        self.ax.axis('equal')

        self.circ = Circle((0.5, 0.5), 0.1)
        self.ax.add_artist(self.circ)
        self.ax.set_title('Click to move the circle')

        self.fig.canvas.mpl_connect('button_press_event', self.on_click)

    def on_click(self, event):
        if event.inaxes is None:
            return
        self.circ.center = event.xdata, event.ydata
        self.fig.canvas.draw()

    def show(self):
        plt.show()


InteractiveCircle().show()

这篇关于matplotlib:更新补丁的位置(或:set_xy为圆圈)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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