简体   繁体   English

Python —鼠标绘制的Matplotlib用户输入

[英]Python — Matplotlib user input from mouse for plotting

This class plots a curve. 此类绘制曲线。 However, the inputs are currently set in main() . 但是,输入当前设置在main() I'd like to set them as user-driven from mouse interaction. 我想将它们设置为用户通过鼠标交互驱动。 Some of this is possible and in the Matplotlib docs (see referenced sites below) but it's still not really setting it up to be a 'click and plot'. Matplotlib文档(参见下面的参考网站)中的某些方法是可行的,但实际上仍未将其设置为“单击并绘制”。 So, ideally the user would click a button to set the P and then whatever point (on the curve, has to be on the curve) they clicked next would be the new P . 因此,理想情况下,用户将单击按钮来设置P ,然后他们接下来单击的任何点(在曲线上,必须在曲线上)将是新的P Same with Q . Q相同。 I'm sure this is a very simple question for anyone who's used Matplotlib but I'm teaching myself it right now, but it would probably take an entry-level dev just a few minutes to do something that I'm getting nowhere with. 对于使用Matplotlib的任何人,我相信这是一个非常简单的问题,但是我现在正在自学,但是入门级开发人员可能只需要几分钟就可以完成我无能为力的事情。

Code: 码:

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid.axislines import SubplotZero
from math import sqrt



class ECC123(object):

    def __init__(self,a,b,px,qx,qy):
        self.a = a
        self.b = b
        self.pxlam = px
        self.qxlam = qx
        self.invertQy = qy
        self.fig = plt.figure(1)
        self.ax = SubplotZero(self.fig, 111)

    def drawAxis(self):
        #fig = plt.figure(1)
        #ax = SubplotZero(fig, 111)
        self.fig.add_subplot(self.ax)
        for direction in ["xzero", "yzero"]:
            self.ax.axis[direction].set_axisline_style("->")
            self.ax.axis[direction].set_visible(True)

    def plotGraph(self):
        self.drawAxis()
        y, x = np.ogrid[-10:10:100j, -10:10:100j]  # range grid  [from : to : how_many_points]
        xlist = x.ravel(); ylist = y.ravel()
        plt.contour(xlist, ylist, self.elliptic_curve(x,y), [0])
        pylam = self.ecclambda(self.pxlam,self.a,self.b)  # calculate P from pxlam
        qylam = self.ecclambda(self.qxlam,self.a,self.b)  # calculate Q from qxlam
        if self.invertQy == 1:  qylam = -qylam # optional, inverts qy to negative on the plot
        plt.plot([self.pxlam,self.qxlam], [pylam,qylam], color = "c", linewidth=1)
        plt.plot([self.pxlam], [pylam], "mo"); plt.plot([self.qxlam], [qylam], "mo")
        plt.text(self.pxlam-0.25,pylam+0.5, '$P$'); plt.text(self.qxlam-0.25,self.qxlam+0.5, '$Q$')
        s = (pylam - qylam)/(self.pxlam - self.qxlam)  # calculate s slope
        xr = s**2 - self.pxlam - self.qxlam  # x-value of R
        yr = pylam + s*(xr - self.pxlam)  # y-value of -R; -y is R (inverted across x-axis)
        plt.plot([xr],[yr],"mo")
        plt.plot([xr],[-yr],"co")
        plt.plot([self.qxlam,xr], [qylam,yr], color = "c", linewidth=1)
        plt.plot([xr,xr], [yr,-yr], "x--")
        plt.text(xr+0.25,yr, '$-R$'); plt.text(xr+0.25,-yr, '$R$')

        plt.grid(True)
        plt.show()

I've been going over the docs in Matplotlib, the scipy cookbook, and related questions here on SO and still not seeing exactly how to do this: 我一直在仔细阅读Matplotlib中的文档,scipy食谱以及有关SO的相关问题,但仍然没有确切地知道如何执行此操作:

http://matplotlib.org/users/event_handling.html http://matplotlib.org/users/event_handling.html

http://matplotlib.org/1.3.1/api/widgets_api.html#matplotlib.widgets.Button.on_clicked http://matplotlib.org/1.3.1/api/widgets_api.html#matplotlib.widgets.Button.on_clicked

Cursors for data selection in matplotlib matplotlib中用于数据选择的游标

How can I create a frontend for matplotlib? 如何为matplotlib创建前端?

http://wiki.scipy.org/Cookbook/Matplotlib http://wiki.scipy.org/Cookbook/Matplotlib

So far, I'm getting little red x's all over when I click and they don't even fall within the curve. 到目前为止,单击时我几乎看不到红色的x,它们甚至都没有落在曲线内。

I modified your code a little, so that you can set location of P & Q by left & right click, I didn't accomplish all the graph data updates, the rest is left for you: 我对代码进行了一些修改,以便您可以通过左右单击来设置P&Q的位置,但是我并没有完成所有图形数据的更新,其余的留给您了:

from mpl_toolkits.axes_grid.axislines import SubplotZero
import numpy as np
import matplotlib.pyplot as plt
from math import sqrt



class ECC(object):
    """
    class to implement elliptic curve and find P+Q=R on the plot
    """

    def __init__(self,a,b,px,qx,qy):
        """
        initialize input variables
        """
        self.a = a
        self.b = b
        self.pxlam = px
        self.qxlam = qx
        self.invertQy = qy
        self.fig = plt.figure(1)
        self.ax = SubplotZero(self.fig, 111)

    def drawAxis(self):
        """
        draw main x,y axis
        """
        #fig = plt.figure(1)
        #ax = SubplotZero(fig, 111)
        self.fig.add_subplot(self.ax)
        for direction in ["xzero", "yzero"]:
            self.ax.axis[direction].set_axisline_style("->")
            self.ax.axis[direction].set_visible(True)

    def ecclambda(self,xl,a,b):
        """
        returns points elliptic curve for P and Q
        y**2 = x**3 + a*x + b
        """
        return sqrt(xl**3 + a*xl + b)

    def elliptic_curve(self,x,y):
        """
        takes in x,y as set of points, returns the elliptic curve
        y**2 = x**3 + a*x + b
        """
        return pow(y, 2) - pow(x, 3) - x * self.a - self.b

    def onclick(self, event):
        x = event.xdata
        if event.button == 1:
            self.pxlam = x
        if event.button == 3:
            self.qxlam = x

        self.update()

    def update(self):
        pylam = self.ecclambda(self.pxlam,self.a,self.b)  # calculate P from pxlam
        qylam = self.ecclambda(self.qxlam,self.a,self.b)  # calculate Q from qxlam
        self.p.set_data([self.pxlam], [pylam])
        self.q.set_data([self.qxlam], [qylam])
        self.pt.set_x(self.pxlam-0.25)
        self.pt.set_y(pylam+0.5)
        self.qt.set_x(self.qxlam-0.25)
        self.qt.set_y(qylam+0.5)
        plt.gcf().canvas.draw()

    def plotGraph(self):
        """
        main plotting of elliptic curve and points/line for P+Q=R
        P+Q=R --->>>  -R is plotted (xr,yr), R is plotted (xr, -yr)
        conditional with invertQy allows inversion of Q across x-axis; set option in main()
        """
        self.drawAxis()
        y, x = np.ogrid[-10:10:100j, -10:10:100j]  # range grid  [from : to : how_many_points]
        xlist = x.ravel(); ylist = y.ravel()
        plt.contour(xlist, ylist, self.elliptic_curve(x,y), [0])
        pylam = self.ecclambda(self.pxlam,self.a,self.b)  # calculate P from pxlam
        qylam = self.ecclambda(self.qxlam,self.a,self.b)  # calculate Q from qxlam
        if self.invertQy == 1:  qylam = -qylam # optional, inverts qy to negative on the plot
        plt.plot([self.pxlam,self.qxlam], [pylam,qylam], color = "c", linewidth=1)
        self.p = plt.plot([self.pxlam], [pylam], "mo")[0]
        self.q = plt.plot([self.qxlam], [qylam], "mo")[0]
        self.pt = plt.text(self.pxlam-0.25,pylam+0.5, '$P$')
        self.qt = plt.text(self.qxlam-0.25,self.qxlam+0.5, '$Q$')
        s = (pylam - qylam)/(self.pxlam - self.qxlam)  # calculate s slope
        xr = s**2 - self.pxlam - self.qxlam  # x-value of R
        yr = pylam + s*(xr - self.pxlam)  # y-value of -R; -y is R (inverted across x-axis)
        plt.plot([xr],[yr],"mo")
        plt.plot([xr],[-yr],"co")
        plt.plot([self.qxlam,xr], [qylam,yr], color = "c", linewidth=1)
        plt.plot([xr,xr], [yr,-yr], "x--")
        plt.text(xr+0.25,yr, '$-R$'); plt.text(xr+0.25,-yr, '$R$')
        plt.text(-9,6,' P: (%s ,%s) \n Q: (%s ,%s) \n R: (%s ,%s) \n a: %s \n b: %s '
                %(self.pxlam,pylam,self.qxlam,qylam,xr,-yr,self.a,self.b),
                fontsize=10, color = 'blue',bbox=dict(facecolor='tan', alpha=0.5))
        plt.title(r"Elliptic Curve Implementation $y^{2} = x^{3} + a*x + b$", fontsize = 16, color = 'b')
        self.fig.canvas.mpl_connect('button_press_event', self.onclick)
        #[xi,yi] = plt.ginput(0)
        ##print "ginput ",xi,yi
        plt.grid(True)
        plt.show()




def main():

    a = -2; b = 1; px = -1.55; qx = -0.1
    invertQy = 0 # set to 1 if q should be inverted to negative along its y axis
    ec = ECC(a,b,px,qx,invertQy)
    ec.plotGraph()


if __name__ == '__main__':
    main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM