【问题标题】:Matplotlib EllipseSelector - how to get the path?Matplotlib EllipseSelector - 如何获取路径?
【发布时间】:2021-09-14 15:29:44
【问题描述】:

下面是 matplotlib 小部件EllipseSelector 的基本示例。顾名思义,此小部件用于通过在轴上绘制椭圆来选择数据。
确切地说,用户可以通过在轴上单击和拖动来绘制和修改椭圆。每次释放鼠标按钮时都会调用一个回调函数(例如:onselect)。
示例如下:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import EllipseSelector

class EllipseExample:

    def __init__(self):

        # creating data points
        self.X, self.Y = (0, 1, 2), (0, -1, -2)
        self.XY = np.asarray((self.X, self.Y)).T

        # plotting
        self.fig, self.ax = plt.subplots()
        self.ax.scatter(self.X, self.Y) # just for visualization

        # creating the EllipseSelector
        self.es = EllipseSelector(self.ax, self.onselect,
                                  drawtype='box', interactive=True)

        # bool array about selection status of XY rows.
        self.selection_bool = None # e.g. (False, True, False)
        
        plt.show()

    # selector callback method
    def onselect(self, eclick, erelease):
        print('click: (%f, %f)' % (eclick.xdata, eclick.ydata))
        print('release  : (%f, %f)' % (erelease.xdata, erelease.ydata))
        # how to get the path of the selector's ellipse?
        # path = self.es.??? <--- no clue how to get there
        # self.selection_bool = path.contains_points(self.XY)
        # print('selection:\n', self.selection_bool)

example = EllipseExample()

我使用过其他 matplotlib 选择小部件(PolygonSelector、RectangleSelector、LassoSelector)。这些都以某种方式返回与选择形状对应的选择顶点,可用于直接过滤数据(例如 RectangleSelector 给出矩形范围的 x0、x1、y0、y1 坐标)或创建路径并通过 path.contains_points 进行检查如果数据在选择范围内。
基本上我在问:
如何使用 EllipseSelector 不仅用于绘图和椭圆,还用于选择器部分?如何获取绘制椭圆的路径,以便我可以通过path.contains_points检查我的数据,如上例中的 cmets 中所建议的那样。

【问题讨论】:

    标签: python matplotlib widget


    【解决方案1】:

    似乎没有直接的方法可以通过.contains_points() 检查点是否包含在选择器中。我能找到的最简单的方法是从 EllipseSelector 的属性创建一个椭圆补丁。这些属性继承自 RectangleSelector 顺便说一句。
    通过将所选内容的中心、宽度和高度传递给matplotlib.patches.Ellipse,我们得到一个椭圆补丁,我们可以在其上调用方法contains_points()。该方法返回一个bool ndarray,每个元素对应一个数据点(True:选择包含点,False:选择不包含点)。
    所述布尔数组可用于例如过滤熊猫数据框。
    注意:在任何情况下都不要将此补丁添加到轴上(即不要绘制此补丁),因为它的坐标将被转换,并且如果没有转换步骤,您将无法再检查原始数据。
    这是一个对初学者友好的逐步示例,带有详细的代码注释:

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.widgets import EllipseSelector
    from matplotlib.patches import Ellipse
    
    class EllipseSelectorExample:
    
        def __init__(self):
    
            # creating data points as numpy arrays
            self.X = np.asarray((0, 1, 2, 3, 4, 5, 6))
            self.Y = np.asarray((0, 0, 0, 0, 0, 0, 0))
            
            # plotting
            self.fig, self.ax = plt.subplots()
            self.ax.set_xlim(-1, 7), self.ax.set_ylim(-3, 3)
            self.ax.grid(True)
            self.ax.scatter(self.X, self.Y)
    
            # creating the EllipseSelector and connecting it to onselect
            self.es = EllipseSelector(self.ax, self.onselect,
                                      drawtype='box', interactive=True)
            plt.show()
    
        # selector callback method
        def onselect(self, eclick, erelease):
    
            # 1. Collect ellipse parameters (center, width, height)
    
            # getting the center property of the drawn ellipse
            cx, cy = self.es.center # tuple of floats: (x, y)
    
            # calculating the width and height
            # self.es.extents returns tuple of floats: (xmin, xmax, ymin, ymax)
            xmin, xmax, ymin, ymax = self.es.extents
            width = xmax - xmin
            height = ymax - ymin
            print(f'center=({cx:.2f},{cy:.2f}), '
                  f'width={width:.2f}, height={height:.2f}')
    
            # 2. Create an ellipse patch
            # CAUTION: DO NOT PLOT (==add this patch to ax), as the coordinates will
            # be transformed and you will not be able to directly check your data
            # points.
            ellipse = Ellipse((cx,cy), width, height)
    
            # 3. Check which points are contained in the ellipse by directly calling
            # contains_points on the ellipse.
            # contains_points wants input like ( (x0,y0), (x1,y1), ... )
    
            # X=x0,x1,... Y=y0,y1,...  ->  [ [x0,y0], [x1,y1], [x2,y2], ... ]
            XY = np.asarray((self.X, self.Y)).T
    
            # calling contains_plot and returning our filter ndarray
            filter_array = ellipse.contains_points(XY)
    
            # 4. Apply filter to your data (optional)
            X_filtered = self.X[filter_array]
            Y_filtered = self.Y[filter_array]
    
            # results:
            print(f'\n'
                  f'original data:\nX={self.X}\nY={self.Y}\n'
                  f'filter_array={filter_array}\n'
                  f'resulting data:\nX={X_filtered}\nY={Y_filtered}')
    
    example = EllipseSelectorExample()
    

    这是上面例子的一个简短版本,检查点只有 3 行代码:

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.widgets import EllipseSelector
    from matplotlib.patches import Ellipse
    
    class EllipseSelectorExample:
    
        def __init__(self):
            self.MYDATA = np.array([[0, 1, 2, 3, 4, 5, 6],
                                    [0, 0, 0, 0, 0, 0, 0]])
            self.fig, self.ax = plt.subplots()
            self.ax.set_xlim(-1, 7), self.ax.set_ylim(-3, 3), self.ax.grid(True)
            self.ax.scatter(self.MYDATA[0], self.MYDATA[1])
            self.es = EllipseSelector(self.ax, self.onselect,
                                      drawtype='box', interactive=True)
            plt.show()
    
        # selector callback method
        def onselect(self, eclick, erelease):
            ext = self.es.extents
            ellipse = Ellipse(self.es.center, ext[1]-ext[0], ext[3]-ext[2])
            # result:
            print(ellipse.contains_points(self.MYDATA.T))
    
    example = EllipseSelectorExample()
    

    【讨论】:

      猜你喜欢
      • 2011-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-30
      相关资源
      最近更新 更多