Updating (redraw) basemap after panning through Navigation Toolbar Python - python

I get some problems about basemap, where when I want to try panning or zooming map, then the map will be redrawed. Anyone who can give me some clues or methods in this case? Here is some code I included. thanks
(I'm sorry about my bad english)
main.py
from toolbar import tool_bar
from mapping import CanvasFrame
class MainWindow(object):
def __init__(self):
....
self.create_basemap()
def create_basemap(self):
self.canvas = CanvasFrame()
....
self.toolbar = tool_bar(self.canvas, self.window)
self.vbox1 = gtk.VBox(False, 2)
self.button1 = gtk.ToggleButton("zoom")
self.button1.connect("toggled", self.get_zoom)
self.button2 = gtk.ToggleButton("pan")
self.button2.connect("toggled", self.get_pan)
self.button3 = gtk.Button("restore")
self.button3.connect("clicked", self.get_restore)
self.vbox1.pack_start(self.button1)
self.vbox1.pack_start(self.button2)
self.vbox1.pack_start(self.button3)
....
def get_zoom(self, button):
if self.button1.get_active():
self.button2.set_active(False)
self.toolbar._zoom()
def get_pan(self, button):
if self.button2.get_active():
self.button1.set_active(False)
self.toolbar._pan()
def get_restore(self, button):
self.toolbar._restore()
....
mapping.py
from matplotlib.figure import Figure
from mpl_toolkits.basemap import Basemap
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
....
class CanvasFrame(FigureCanvas):
def __init__(self):
self.figure = Figure(dpi=80)
FigureCanvas.__init__(self, self.figure)
self.ax = self.figure.add_subplot(111)
self.plot_map()
def plot_map(self):
self.map = Basemap(projection = 'mill', resolution = 'i', llcrnrlon = 103.5,
llcrnrlat= -6.25,urcrnrlon = 107, urcrnrlat = -3.7, ax = self.ax)
....
toolbar.py
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg
class tool_bar(NavigationToolbar2GTKAgg):
def __init__(self, canvas, window):
super(NavigationToolbar2GTKAgg, self).__init__(canvas, window)
def _zoom(self):
self.zoom()
def _pan(self):
self.pan()
def _restore(self):
self.home()

Related

Updating an embeded matplotlib image in PyQt5

I have a matplotlib image embedded in PyQt:
But am now having trouble updating it.
The UI and the initial embedding is set up as follows:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# Ui_MainWindow is a python class converted from .ui file
def __init__(self, *args, obj=None, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.imageDisp = ImageDisplay() # Class definition below
layoutImage = self.Image_Area.layout() # Image_Area is a Qt Group Box
if layoutImage is None:
layoutImage = QVBoxLayout(self.Image_Area)
ax_img = self.imageDisp.displayImage()
canvas_image = FigureCanvas(ax_img.figure)
layoutImage.addWidget(canvas_image)
self.NextImageButton.clicked.connect(self.inc)
def inc(self):
self.imageDisp.nextImage()
layoutImage = self.Image_Area.layout()
if layoutImage is None:
layoutImage = QVBoxLayout(self.Image_Area)
ax_img = self.imageDisp.UpdateImage()
canvas_image = FigureCanvas(ax_img.figure)
self.imageDisp.draw()
layoutImage.addWidget(canvas_image)
And the ImageDisplay class is defined as follows:
class ImageDisplay(FigureCanvas): # FigureCanvas is matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg
def __init__(self):
# Other attributes
fig = Figure()
self.fig = fig
self.axes = fig.add_subplot(111)
def nextImage(self):
# Do something here
self.UpdateImage()
def UpdateImage(self):
self.axes.imshow(np.asarray(IMAGE))
return self.axes
def displayImage(self):
self.fig = Figure()
self.axes = self.fig.add_subplot(111)
self.axes.imshow(np.asarray(IMAGE))
return self.axes
This does not update the image, but addWidget would create a new widget on top of it, resulting in a stacked plot:
I tried to find ways to remove the widget but to no avail so far. Is there a way I can properly remove this widget and make a new one for the updated image? Or is there another way to display and update an image embedded in PyQt?
try this instead
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
import numpy as np
from matplotlib import image
import matplotlib.pyplot as plt
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, obj=None, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.imageDisp = ImageDisplay(self, width=5, height=4, dpi=100)
self.imageDisp.displayImage()
self.NextImageButton=QtWidgets.QPushButton('next image',self)
self.NextImageButton.clicked.connect(self.inc)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.imageDisp)
layout.addWidget(self.NextImageButton)
widget = QtWidgets.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.show()
def inc(self):
self.imageDisp.nextImage()
class ImageDisplay(FigureCanvas): # FigureCanvas is matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg
def __init__(self, parent=None, width=5, height=4, dpi=100):
self.start=0
self.files=['ball.png','image.jpg']
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.fig.clear()
self.axes = self.fig.add_subplot(111)
self.axes.clear()
self.axes.axis('off')
plt.draw()
super(ImageDisplay, self).__init__(self.fig)
def nextImage(self):
# Do something here
self.IMAGE = image.imread(self.files[self.start%2])
self.UpdateImage()
def UpdateImage(self):
self.start+=1
self.axes.clear()
self.axes.axis('off')
self.axes.imshow(np.asarray(self.IMAGE))
self.draw()
def displayImage(self):
self.IMAGE = image.imread(self.files[self.start%2])
self.start+=1
self.axes.clear()
self.axes.axis('off')
self.axes.imshow(np.asarray(self.IMAGE))
self.draw()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())

Matplotlib integrated in a QScrollArea isn't refresh curves properly on mac OS

I have an issue with a matplotlib figure that I've embedded in a pyqt5 QScrollArea.
My issue is when I'm scrolling down, it is like only the top of the matplotlib has been updated.
For instance, in the image below, the curves below the curve number 35 are not updated properly.
This only happens with mac OS but it run well on Windows 10.
I don't find the issue in the code.
Update
To me, it looks like the matplotlib figure doesn't match with the QSrollBar. I try to explain more. When I scroll down with the Qsrollbar, the Matplotlib figure is going down but not as fast as the scrollbar. I see that with the number of curve that is increasing when I scroll down. It is like the Qscrollbar go down too fast with respect to the matplotlib figure update.
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
import time
class Viewer(QMainWindow):
def __init__(self, parent=None):
super(Viewer, self).__init__()
self.parent = parent
#######################################
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.mainVBOX_param_scene = QVBoxLayout()
self.mascene = plot(self)
self.paramPlotV = QVBoxLayout()
self.horizontalSliders = QScrollBar(Qt.Horizontal)
self.horizontalSliders.setFocusPolicy(Qt.StrongFocus)
self.horizontalSliders.valueChanged.connect(self.update_plot)
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(1)
self.paramPlot = QHBoxLayout()
l_gain = QLabel('Gain')
self.e_gain = QLineEdit('5')
l_win = QLabel('Window')
self.e_win = QLineEdit('10')
l_spacing = QLabel('vertical spacing')
self.e_spacing = QLineEdit('10')
l_linewidth = QLabel('linewidth')
self.e_linewidth = QLineEdit('1')
self.e_gain.returnPressed.connect(self.update_plot)
self.e_win.returnPressed.connect(self.udpate_plot_plus_slider)
self.e_spacing.returnPressed.connect(self.update_plot)
self.e_linewidth.returnPressed.connect(self.update_plot)
self.paramPlot.addWidget(l_gain)
self.paramPlot.addWidget(self.e_gain)
self.paramPlot.addWidget(l_win)
self.paramPlot.addWidget(self.e_win)
self.paramPlot.addWidget(l_spacing)
self.paramPlot.addWidget(self.e_spacing)
self.paramPlot.addWidget(l_linewidth)
self.paramPlot.addWidget(self.e_linewidth)
self.paramPlotV.addWidget(self.horizontalSliders)
self.paramPlotV.addLayout(self.paramPlot)
self.mainVBOX_param_scene.addWidget(self.mascene)
self.mainVBOX_param_scene.addLayout(self.paramPlotV)
self.centralWidget.setLayout(self.mainVBOX_param_scene)
self.Fs = 1024
self.Sigs_dict = np.random.rand(50,20*self.Fs)
self.t = np.arange(self.Sigs_dict.shape[1])/self.Fs
self.parent.processEvents()
self.update()
def updateslider(self):
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(np.ceil(self.t[-1]/int(self.e_win.text()))-1)
self.horizontalSliders.setPageStep(1)
self.horizontalSliders.update()
def udpate_plot_plus_slider(self):
self.updateslider()
self.mascene.update()
def update_plot(self):
t0 = time.time()
self.mascene.update()
print('time old:', time.time()-t0)
def update(self):
self.updateslider()
self.mascene.modify_sigs()
self.mascene.update()
class plot(QGraphicsView):
def __init__(self, parent=None):
super(plot, self).__init__(parent)
self.parent = parent
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.figure = plt.figure(facecolor='white')#Figure()
self.canvas = FigureCanvas(self.figure)
self.widget = QWidget()
self.widget.setLayout(QVBoxLayout())
self.widget.layout().setContentsMargins(0, 0, 0, 0)
self.widget.layout().setSpacing(0)
self.scroll = QScrollArea(self.widget)
self.scroll.setWidget(self.canvas)
layout = QVBoxLayout()
layout.addWidget(self.scroll)
self.setLayout(layout)
def modify_sigs(self):
self.Sigs_dict = self.parent.Sigs_dict
self.t = self.parent.t
self.Fs= self.parent.Fs
def update(self):
win_num = self.parent.horizontalSliders.value()
self.figure.clear()
plt.figure(self.figure.number)
plt.subplots_adjust(left=0.1, bottom=0.01, right=1, top=1, wspace=0.0 , hspace=0.0 )
self.axes = plt.subplot(1, 1, 1)
gain = float(self.parent.e_gain.text())
win= float(self.parent.e_win.text())
self.spacing = float(self.parent.e_spacing.text())
linewidth = float(self.parent.e_linewidth.text())
ts = int(win*(win_num) * self.Fs)
te = ts + int(win * self.Fs)
if te > len(self.t):
te=len(self.t)
for i in range(self.Sigs_dict.shape[0]):
line, = plt.plot(self.t[ts:te], gain*(self.Sigs_dict[i,ts:te]-np.mean(self.Sigs_dict[i,ts:te]))+i*self.spacing, linewidth=linewidth )
self.axes.autoscale(enable=True, axis='both', tight=True)
self.axes.set_ylim((-self.spacing,(self.Sigs_dict.shape[0]+1)*self.spacing))
self.axes.set_xlim((ts/ self.Fs, ts / self.Fs + win ))
self.axes.set_yticks(np.arange(self.Sigs_dict.shape[0]) * self.spacing)
self.axes.set_yticklabels([str(n) for n in np.arange(self.Sigs_dict.shape[0])])
self.canvas.setGeometry(0, 0, self.parent.width()-100, (self.parent.height()-100)*self.spacing)
self.canvas.draw()
def main():
app = QApplication(sys.argv)
app.setStyle('Windows')
ex = Viewer(app)
ex.showMaximized()
sys.exit(app.exec())
if __name__ == '__main__':
main()
I update the version of my matplotlib module from 3.1.1 to 3.2.0rc1 and it solves the issue.

How to make a line move with mouse inside a plot in a PyQt application

I want to show a given plot inside a PyQt application and show a line that moves along with the mouse cursor. However, the line shows up on the left of the plot and doesn't move at all when moving the cursor. I don't know why this is happening. Here's the code:
import numpy as np
from matplotlib.backends.qt_compat import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
class SnaptoCursor(object):
def __init__(self, ax, x):
self.ax = ax
self.ly = ax.axvline(color='k')
self.x = x
self.txt = ax.text(0.7, 0.9, '', transform=ax.transAxes)
def mouse_move(self, event):
if event.inaxes:
indx = np.searchsorted(self.x, [event.xdata])[0]
x = self.x[indx]
self.ly.set_xdata(x)
self.txt.set_text('x=%1.2f' % x)
self.ax.figure.canvas.draw()
else:
pass
class App(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(App, self).__init__(parent)
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
self.figure = Figure(figsize=(10, 6.9))
self.canvas = FigureCanvas(self.figure)
self.canvas_ax = self.canvas.figure.subplots()
x = np.arange(0,40)
self.canvas_ax.plot(x, np.random.rand(40))
# Layout
layout = QtWidgets.QVBoxLayout(self._main)
layout.addWidget(self.canvas)
self.showMaximized()
##############################################
########## This doesnt seem to work ##########
##############################################
cursor = SnaptoCursor(self.canvas_ax, x)
plt.connect('motion_notify_event', cursor.mouse_move)
##############################################
##############################################
##############################################
if __name__ == '__main__':
app = QtWidgets.QApplication([])
ex = App()
ex.show()
app.exec_()
The two lines in question should be
self.cursor = SnaptoCursor(self.canvas_ax, x)
self.cid = self.canvas.mpl_connect('motion_notify_event', self.cursor.mouse_move)
because else the cursor as well as the callback registration do not exist in memory at the point you would expect them to be used. And also you shouldn't be using pyplot/plt when your figure isn't even created with pyplot.

WXPython with MatPlotLib

I am trying to use MatPlotLib with WXPython. I find a nice example from http://www.cs.colorado.edu/~kena/classes/5448/s11/presentations/pearse.pdf
because it show how to use 2 panels and it is well explained how to embed matplotlib. But I think it is missing some part, because the graphic isn't being initialized.
How can I fix that?
import wx
import numpy
import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent,title=title,size=(500,500))
self.sp = wx.SplitterWindow(self)
self.p1 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
self.p2 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
self.sp.SplitVertically(self.p1,self.p2,100)
self.statusbar = self.CreateStatusBar()
self.statusbar.SetStatusText('Oi')
class p1(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent,-1,size=(50,50))
self.figure = matplotlib.figure.Figure()
self.axes = self.figure.add_subplot(111)
t = numpy.arange(0.0,10,1.0)
s = [0,1,0,1,0,2,1,2,1,0]
self.y_max = 1.0
self.axes,plot(t,s)
self.canvas = FigureCanvas(self,-1,self.figure)
app = wx.App(redirect=False)
frame = TestFrame(None, 'Hello World!')
frame.Show()
app.MainLoop()
Thanks.
You made class p1 with matplot but you didn't use it in TestFrame.
I changed some names to make it more clear
import wx
import numpy
import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent,title=title,size=(500,500))
self.sp = wx.SplitterWindow(self)
self.p1 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
self.p2 = MatplotPanel(self.sp)
self.sp.SplitVertically(self.p1,self.p2,100)
self.statusbar = self.CreateStatusBar()
self.statusbar.SetStatusText('Oi')
class MatplotPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent,-1,size=(50,50))
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
t = numpy.arange(0.0,10,1.0)
s = [0,1,0,1,0,2,1,2,1,0]
self.y_max = 1.0
self.axes.plot(t,s)
self.canvas = FigureCanvas(self,-1,self.figure)
app = wx.App(redirect=False)
frame = TestFrame(None, 'Hello World!')
frame.Show()
app.MainLoop()
see also (as example) my answer to how to combine wxPython, matplotlib and Pyopengl
EDIT:
MatplotPanel with NavigationToolbar and wx.Button to change plot.
EDIT: 2022.01.03
As #Samuel said in comment: newer matplotlib needs NavigationToolbar2WxAgg instead of NavigationToolbar2Wx. See also matplotlib doc: Embedding in wx #2
# older matplotlib
#from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as NavigationToolbar
# newer matplotlib
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
class MatplotPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent,-1,size=(50,50))
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.sizer)
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self, -1, self.figure)
self.toolbar = NavigationToolbar(self.canvas)
self.button = wx.Button(self, -1, "Change plot")
self.button.Bind(wx.EVT_BUTTON, self.changePlot)
self.sizer.Add(self.toolbar, 0, wx.EXPAND)
self.sizer.Add(self.button, 0, wx.EXPAND)
self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.drawSin()
self.current_draw = 'sin'
# self.drawLines()
def changePlot(self, event):
if self.current_draw == 'sin' :
self.drawLines()
self.current_draw = 'lines'
else:
self.drawSin()
self.current_draw = 'sin'
self.Layout()
def drawLines(self):
x = numpy.arange(0.0,10,1.0)
y = [0,1,0,1,0,2,1,2,1,0]
self.axes.clear()
self.axes.plot(x, y)
def drawSin(self):
x = numpy.arange(0.0,10,0.1)
y = numpy.sin(x)
self.axes.clear()
self.axes.plot(x, y)

How can I draw a cross which follows my mouse cursor?

I want draw a cross in my paintEvent() which moves with the mouse. I'm using python via pyqt.
I'm using the code below, but the result isn't good.
from __future__ import division
import sys
import platform
# Qt4 bindings for core Qt functionalities (non-GUI)
import PyQt4.QtCore as QtCore
# Python Qt4 bindings for GUI objects
import PyQt4.QtGui as QtGui
from PyQt4.QtGui import *
from PyQt4.QtCore import *
# import the Qt4Agg FigureCanvas object, that binds Figure to
# Qt4Agg backend. It also inherits from QWidget
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
# Matplotlib Figure object
from matplotlib.figure import Figure
class C_MplCanvas(FigureCanvas):
def __init__(self):
# setup Matplotlib Figure and Axis
self.fig = Figure()
#self.cursor = Cursor()
self.fig.set_facecolor('black')
self.fig.set_edgecolor('black')
#self.ax = self.fig.add_subplot(111)
#self.ax.patch.set_facecolor('black')
# initialization of the canvas
FigureCanvas.__init__(self, self.fig)
#super(FigureCanvas, self).__init__(self.fig)
# we define the widget as expandable
FigureCanvas.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
# notify the system of updated policy
FigureCanvas.updateGeometry(self)
self.xx=0
self.yy=0
self.justDoubleClicked=False
def contextMenuEvent(self, event):
menu = QMenu(self)
oneAction = menu.addAction("&One")
twoAction = menu.addAction("&Two")
self.connect(oneAction, SIGNAL("triggered()"), self.one)
self.connect(twoAction, SIGNAL("triggered()"), self.two)
'''
if not self.message:
menu.addSeparator()
threeAction = menu.addAction("Thre&e")
self.connect(threeAction, SIGNAL("triggered()"),
self.three)
'''
menu.exec_(event.globalPos())
def one(self):
self.message = QString("Menu option One")
self.update()
def two(self):
self.message = QString("Menu option Two")
self.update()
def three(self):
self.message = QString("Menu option Three")
self.update()
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.TextAntialiasing)
#painter.drawText(self.rect(), Qt.AlignCenter, text)
#
#painter.setPen('red')
pen=painter.pen()
painter.setPen(QColor(255, 0, 0))
painter.drawLine(self.xx-100,self.yy,self.xx+100,self.yy)
painter.drawLine(self.xx,self.yy-100,self.xx,self.yy+100)
self.update()
def mouseReleaseEvent(self, event):
if self.justDoubleClicked:
self.justDoubleClicked = False
else:
self.setMouseTracking(not self.hasMouseTracking())
self.update()
def mouseMoveEvent(self, event):
self.xx=event.pos().x()
self.yy=event.pos().y()
self.update()
class C_MPL(QWidget):
def __init__(self, parent = None):
# initialization of Qt MainWindow widget
super(C_MPL, self).__init__(parent)
#QtGui.QWidget.__init__(self, parent)
# instantiate a widget, it will be the main one
#self.main_widget = QtGui.QWidget(self)
#vbl = QtGui.QVBoxLayout(self.main_widget)
# set the canvas to the Matplotlib widget
self.canvas = C_MplCanvas()
# create a vertical box layout
self.vbl = QtGui.QVBoxLayout()
# add mpl widget to vertical box
self.vbl.addWidget(self.canvas)
# set the layout to th vertical box
self.setLayout(self.vbl)
if __name__ == "__main__":
import sys
'''
def valueChanged(a, b):
print a, b
'''
app = QApplication(sys.argv)
form = C_MPL()
#form.connect(form, SIGNAL("valueChanged"), valueChanged)
form.setWindowTitle("C_MPL")
#form.move(0, 0)
form.show()
#form.resize(400, 400)
app.exec_()
#bmu: That's great,just like I want.And now there another question:
cid0=self.mpl_connect('axes_enter_event', self.enter_axes)
cid1=self.mpl_connect('button_press_event', self.onpick)
cid2=self.mpl_connect('motion_notify_event', self.onmove)
cid3=self.mpl_connect('draw_event', self.clear)
cid4=self.mpl_connect('key_press_event',self.press)
the strange thing is the 'key_press_event' can't be triggerd but all other events can. there r a case: macosx backend ignores multiple mpl_connect() calls
https://github.com/matplotlib/matplotlib/pull/585,
but i think it's differnt with me.
i got cid0,1,2,3,4 which is different each other
So , any idea can share? I an very crazy now.....
Following is my code,u can test it if u have the same problem:
import sys
import platform
from PyQt4 import QtGui, QtCore
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt4 import NavigationToolbar2QT as NavigationToolbar
import time
from PyQt4.QtCore import *
from PyQt4.QtGui import *
#Just a test
class MplCanvas(FigureCanvas):
def __init__(self):
# initialization of the canvas
self.fig=Figure()
FigureCanvas.__init__(self,self.fig )
self.ax = self.fig.add_axes([.15, .15, .75, .75])
self.canvas = self.ax.figure.canvas
#my added
#self.ax = self.fig.add_axes([.15, .15, .75, .75])
#cursor = C_Cursor(self.LvsT, useblit=True, color='red', linewidth=2 )
x=np.arange(0,20,0.1)
self.ax.plot(x,x*x,'o')
self.ax.set_xlim(-2,2)
self.ax.set_ylim(-2,2)
self.visible = True
self.horizOn = True
self.vertOn = True
self.useblit = True
#if self.useblit:
#lineprops['animated'] = True
self.lineh = self.ax.axhline(self.ax.get_ybound()[0], visible=False)
self.linev = self.ax.axvline(self.ax.get_xbound()[0], visible=False)
self.background = None
self.needclear = False
self.count = 0
cid0=self.mpl_connect('axes_enter_event', self.enter_axes)
cid1=self.mpl_connect('button_press_event', self.onpick)
cid2=self.mpl_connect('motion_notify_event', self.onmove)
cid3=self.mpl_connect('draw_event', self.clear)
cid4=self.mpl_connect('key_press_event',self.press)
self.draw()
def clear(self, event):
'clear the cursor'
if self.useblit:
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
self.linev.set_visible(False)
self.lineh.set_visible(False)
def onmove(self, event):
'on mouse motion draw the cursor if visible'
print("move")
if event.inaxes != self.ax:
self.linev.set_visible(False)
self.lineh.set_visible(False)
if self.needclear:
self.canvas.draw()
self.needclear = False
return
self.needclear = True
if not self.visible: return
self.linev.set_xdata((event.xdata, event.xdata))
self.lineh.set_ydata((event.ydata, event.ydata))
self.linev.set_visible(self.visible and self.vertOn)
self.lineh.set_visible(self.visible and self.horizOn)
self._update()
def _update(self):
if self.useblit:
if self.background is not None:
self.canvas.restore_region(self.background)
self.ax.draw_artist(self.linev)
self.ax.draw_artist(self.lineh)
self.canvas.blit(self.ax.bbox)
else:
self.canvas.draw_idle()
return False
#
def enter_axes(self,event):
print "Enter"
def onpick(self,event):
print "click"
print 'you pressed', event.canvas
a = np.arange(10)
print a
print self.count
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(a)
fig.show()
def press(self,event):
print ('press', event.key)
self.fig.canvas.draw()
class MplWidget(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.vbl = QtGui.QVBoxLayout()
self.canvas = MplCanvas()
self.vbl.addWidget(self.canvas)
self.setLayout(self.vbl)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = MplWidget()
form.show()
#form.resize(400, 400)
app.exec_()
#all:Tks all. I resolved this problem after added:
self.canvas.setFocusPolicy( Qt.ClickFocus )
self.canvas.setFocus()
maybe this a little bug bcs i need explicity setfocus on cavans,maybe if not:)
details u can check https://github.com/matplotlib/matplotlib/issues/707
Here is an example using matplotlib event handling (however I am wondering, if it is really useful to have something like a second cursor).
import numpy as np
import matplotlib.pyplot as plt
class MouseCross(object):
def __init__(self, ax, **kwargs):
self.ax = ax
self.line, = self.ax.plot([0], [0], visible=False, **kwargs)
def show_cross(self, event):
if event.inaxes == self.ax:
self.line.set_data([event.xdata], [event.ydata])
self.line.set_visible(True)
else:
self.line.set_visible(False)
plt.draw()
if __name__ == '__main__':
fig, ax = plt.subplots()
ax.plot(np.random.random(100) * 10.0)
# note that not every "normal" matplotlib marker will work
# math symbols work fine
cross = MouseCross(ax, marker=r'$\bigoplus$', markersize=30,
color='red',)
fig.canvas.mpl_connect('motion_notify_event', cross.show_cross)
plt.tight_layout()
plt.show()
Question...are you trying to change what the cursor looks like over your widget? If so, the easiest thing is to do get rid of the paintEvent entirely, and add setCursor to your init method:
class C_MplCanvas(FigureCanva):
def __init__( self ):
# setup code
...
self.setCursor(Qt.CrossCursor)
This will tell Qt to use the Cross Cursor whenever the mouse is over that particular widget. This will actually replace the arrow (which may or may not be what you want). If that isn't what you want, I would recommend doing something where you create a PNG image of what you do want, create a child QLabel, and move the child widget around in your mouseMoveEvent.
If you need more help on that lemme know.

Categories

Resources