该类绘制曲线。但是,输入目前在main()
中设置。我想将它们设置为用户驱动的鼠标交互。其中一些是可能的,并且在Matplotlib文档中(参见下面引用的网站),但它仍然没有真正将它设置为“点击和绘图”。因此,理想情况下,用户可以单击按钮来设置P
,然后他们下次单击的任何点(在曲线上,必须在曲线上)将是新的P
。与Q
相同。我敢肯定,对于任何使用过Matplotlib的人来说,这是一个非常简单的问题,但我现在正在自学它,但是可能只需要几分钟的入门级开发来做一些我无处可去的事情。
代码:
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()
我一直在浏览Matplotlib中的文档,scipy cookbook以及相关问题,但仍然没有看到如何做到这一点:
http://matplotlib.org/users/event_handling.html
http://matplotlib.org/1.3.1/api/widgets_api.html#matplotlib.widgets.Button.on_clicked
Cursors for data selection in matplotlib
How can I create a frontend for matplotlib?
http://wiki.scipy.org/Cookbook/Matplotlib
到目前为止,当我点击它时,我的红色x会变得很小,而且它们甚至不在曲线内。
答案 0 :(得分:3)
我稍微修改了你的代码,这样你就可以设置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()