how to show the cursor coordinates in wxPython when using wx.SplitterWindow - matplotlib

I'm trying to do something similar to that shown in this link to draw a cursor and report the data coordinates in the status bar. However, my code is a little bit different since I need to use wx.SplitterWindow to separate buttons and plots. Basically, in the main frame module I create the status bar, but the plot is generated in a separated module. See below my current code:
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar, \
wxc as wxc
import pylab
import wx
from numpy import arange, sin, pi
class data:
def __init__(self):
self.t = []
self.s = []
class Plot_Panel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# create some sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
checkSizer = wx.BoxSizer(wx.HORIZONTAL)
# create figrue
self.fig = Figure()
self.canvas = FigCanvas(self, -1, self.fig)
self.axes = self.fig.add_subplot(111)
# create the widgets
self.toggleMarker = wx.CheckBox(self, label="Show Marker")
# layout the widgets
mainSizer.Add(self.canvas, 1, wx.EXPAND)
checkSizer.Add(self.toggleMarker, 0, wx.ALL, 5)
mainSizer.Add(checkSizer)
self.SetSizer(mainSizer)
def draw_plot(self, data):
# Clear the previous figure
self.fig.clear()
# Redraw figure
self.axes = self.fig.add_subplot(111)
# Define data to plot
self.plot_data= self.axes.plot(data.t, data.s, linewidth=3, color='y',)[0]
# Draw Cursor or not
if self.toggleMarker.IsChecked():
# Note that event is a MplEvent
self.canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar)
self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor)
self.canvas.draw()
def ChangeCursor(self, event):
self.canvas.SetCursor(wxc.StockCursor(wx.CURSOR_BULLSEYE))
def UpdateStatusBar(self, event):
if event.inaxes:
x, y = event.xdata, event.ydata
# self.statusBar.SetStatusText(("x= "+str(Pos.x)+" y="+str(Pos.y)))
class Button_Panel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# create the widgets
self.toggleStart = wx.Button(self, id=wx.ID_ANY, label="Plot data")
class ProportionalSplitter(wx.SplitterWindow):
def __init__(self,parent, id = -1, proportion=0.66, size = wx.DefaultSize, **kwargs):
wx.SplitterWindow.__init__(self,parent,id,wx.Point(0, 0),size, **kwargs)
self.SetMinimumPaneSize(50) #the minimum size of a pane.
self.proportion = proportion
if not 0 < self.proportion < 1:
raise ValueError, "proportion value for ProportionalSplitter must be between 0 and 1."
self.ResetSash()
self.Bind(wx.EVT_SIZE, self.OnReSize)
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged, id=id)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.firstpaint = True
def SplitHorizontally(self, win1, win2):
if self.GetParent() is None: return False
return wx.SplitterWindow.SplitHorizontally(self, win1, win2,
int(round(self.GetParent().GetSize().GetHeight() * self.proportion)))
def SplitVertically(self, win1, win2):
if self.GetParent() is None: return False
return wx.SplitterWindow.SplitVertically(self, win1, win2,
int(round(self.GetParent().GetSize().GetWidth() * self.proportion)))
def GetExpectedSashPosition(self):
if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
else:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
return int(round(tot * self.proportion))
def ResetSash(self):
self.SetSashPosition(self.GetExpectedSashPosition())
def OnReSize(self, event):
"Window has been resized, so we need to adjust the sash based on self.proportion."
self.ResetSash()
event.Skip()
def OnSashChanged(self, event):
"We'll change self.proportion now based on where user dragged the sash."
pos = float(self.GetSashPosition())
if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
else:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
self.proportion = pos / tot
event.Skip()
def OnPaint(self, event):
if self.firstpaint:
if self.GetSashPosition() != self.GetExpectedSashPosition():
self.ResetSash()
self.firstpaint = False
event.Skip()
class Main_Window(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title = title)
# Create a StatusBar at the bottom of the window
self.statusBar = wx.StatusBar(self, -1)
self.SetStatusBar(self.statusBar)
# Set plot panel
self.splitter = ProportionalSplitter(self,-1, 0.85)
self.ppanel = Plot_Panel(self.splitter)
self.ppanel.SetBackgroundColour('#ffffff')
# Set button panel
self.bpanel = Button_Panel(self.splitter)
# Set frame
self.splitter.SplitVertically(self.ppanel, self.bpanel)
self.Show(True)
self.Maximize(True)
# bind the widgets
self.ppanel.toggleMarker.Bind(wx.EVT_CHECKBOX, self.onToggleMarker)
self.bpanel.toggleStart.Bind(wx.EVT_BUTTON, self.onToggleStart)
# Set classes
self.data = data()
def onToggleMarker(self, event):
self.ppanel.draw_plot(self.data)
def onToggleStart(self, event):
self.data.t = arange(0.0, 1.0, 0.01)
self.data.s = sin(2*2*pi*self.data.t)
# plot data
self.ppanel.draw_plot(self.data)
def main():
app = wx.App(False)
frame = Main_Window(None, "GUI")
frame.Show()
app.MainLoop()
if __name__ == "__main__" :
main()
The plot is shown when the button "Plot data" is pressed. What I would like to do is to show the x and y position in the status bar when the checkbox "Show Marker" is checked (in a similar way as it is done in the code posted in the link), and stop when it is unchecked. But I'm not sure if it is possible to do it in my code due to having the definitions of the status bar and the plot in different modules. Any hint will be welcome.

What a joy to get a full, working example program with the question.
You just need to pass the base module as a parameter to self.ppanel
i.e.
self.ppanel = Plot_Panel(self.splitter, self)
then refer to that when updating the status bar, see below for references to base
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar, \
wxc as wxc
import pylab
import wx
from numpy import arange, sin, pi
class data:
def __init__(self):
self.t = []
self.s = []
class Plot_Panel(wx.Panel):
def __init__(self, parent, base):
wx.Panel.__init__(self, parent)
self.base = base
# create some sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
checkSizer = wx.BoxSizer(wx.HORIZONTAL)
# create figrue
self.fig = Figure()
self.canvas = FigCanvas(self, -1, self.fig)
self.axes = self.fig.add_subplot(111)
# create the widgets
self.toggleMarker = wx.CheckBox(self, label="Show Marker")
# layout the widgets
mainSizer.Add(self.canvas, 1, wx.EXPAND)
checkSizer.Add(self.toggleMarker, 0, wx.ALL, 5)
mainSizer.Add(checkSizer)
self.SetSizer(mainSizer)
def draw_plot(self, data):
# Clear the previous figure
self.fig.clear()
# Redraw figure
self.axes = self.fig.add_subplot(111)
# Define data to plot
self.plot_data= self.axes.plot(data.t, data.s, linewidth=3, color='y',)[0]
# Draw Cursor or not
if self.toggleMarker.IsChecked():
# Note that event is a MplEvent
self.canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar)
self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor)
self.canvas.draw()
def ChangeCursor(self, event):
self.canvas.SetCursor(wxc.StockCursor(wx.CURSOR_BULLSEYE))
def UpdateStatusBar(self, event):
if event.inaxes:
x, y = event.xdata, event.ydata
self.base.statusBar.SetStatusText(("x= "+str(x)+" y="+str(y)))
class Button_Panel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# create the widgets
self.toggleStart = wx.Button(self, id=wx.ID_ANY, label="Plot data")
class ProportionalSplitter(wx.SplitterWindow):
def __init__(self,parent, id = -1, proportion=0.66, size = wx.DefaultSize, **kwargs):
wx.SplitterWindow.__init__(self,parent,id,wx.Point(0, 0),size, **kwargs)
self.SetMinimumPaneSize(50) #the minimum size of a pane.
self.proportion = proportion
if not 0 < self.proportion < 1:
raise ValueError, "proportion value for ProportionalSplitter must be between 0 and 1."
self.ResetSash()
self.Bind(wx.EVT_SIZE, self.OnReSize)
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged, id=id)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.firstpaint = True
def SplitHorizontally(self, win1, win2):
if self.GetParent() is None: return False
return wx.SplitterWindow.SplitHorizontally(self, win1, win2,
int(round(self.GetParent().GetSize().GetHeight() * self.proportion)))
def SplitVertically(self, win1, win2):
if self.GetParent() is None: return False
return wx.SplitterWindow.SplitVertically(self, win1, win2,
int(round(self.GetParent().GetSize().GetWidth() * self.proportion)))
def GetExpectedSashPosition(self):
if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
else:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
return int(round(tot * self.proportion))
def ResetSash(self):
self.SetSashPosition(self.GetExpectedSashPosition())
def OnReSize(self, event):
"Window has been resized, so we need to adjust the sash based on self.proportion."
self.ResetSash()
event.Skip()
def OnSashChanged(self, event):
"We'll change self.proportion now based on where user dragged the sash."
pos = float(self.GetSashPosition())
if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
else:
tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
self.proportion = pos / tot
event.Skip()
def OnPaint(self, event):
if self.firstpaint:
if self.GetSashPosition() != self.GetExpectedSashPosition():
self.ResetSash()
self.firstpaint = False
event.Skip()
class Main_Window(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title = title)
# Create a StatusBar at the bottom of the window
self.statusBar = wx.StatusBar(self, -1)
self.SetStatusBar(self.statusBar)
# Set plot panel
self.splitter = ProportionalSplitter(self,-1, 0.85)
self.ppanel = Plot_Panel(self.splitter, self)
self.ppanel.SetBackgroundColour('#ffffff')
# Set button panel
self.bpanel = Button_Panel(self.splitter)
# Set frame
self.splitter.SplitVertically(self.ppanel, self.bpanel)
self.Show(True)
self.Maximize(True)
# bind the widgets
self.ppanel.toggleMarker.Bind(wx.EVT_CHECKBOX, self.onToggleMarker)
self.bpanel.toggleStart.Bind(wx.EVT_BUTTON, self.onToggleStart)
# Set classes
self.data = data()
def onToggleMarker(self, event):
self.ppanel.draw_plot(self.data)
def onToggleStart(self, event):
self.data.t = arange(0.0, 1.0, 0.01)
self.data.s = sin(2*2*pi*self.data.t)
# plot data
self.ppanel.draw_plot(self.data)
def main():
app = wx.App(False)
frame = Main_Window(None, "GUI")
frame.Show()
app.MainLoop()
if __name__ == "__main__" :
main()

Related

Selecting an area for OCR returns a distorted image and Tesseract cant Decode it

import sys
import pytesseract
from PyQt5.QtGui import QPainter, QPen, QImage, QPixmap, QCursor
from PyQt5.QtCore import Qt, QPoint, QRect, QSize
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QAction, QMenu, QSystemTrayIcon, QStyle, QRubberBand
from PIL import ImageGrab, Image, ImageFilter, ImageOps
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# Create the UI elements
self.label = QLabel(self)
self.setCentralWidget(self.label)
# Add the menu items
self.menu = QMenu(self)
self.ocr_action = QAction("Perform OCR", self)
self.ocr_action.triggered.connect(self.perform_ocr)
self.menu.addAction(self.ocr_action)
# Set the window to be transparent
self.setWindowOpacity(0.1)
# Create the system tray icon
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))
self.tray_icon.setContextMenu(self.menu)
self.tray_icon.show()
# Create a rubber band for selecting the area
self.rubber_band = QRubberBand(QRubberBand.Rectangle, self.label)
self.rubber_band.setMouseTracking(True)
self.rubber_band.hide()
# Reset the window position and size to full screen
self.reset_position()
def reset_position(self):
screen_size = QApplication.desktop().screenGeometry()
self.setGeometry(screen_size)
self.move(0, 0)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.start_pos = event.pos()
self.rubber_band.setGeometry(QRect(self.start_pos, QSize()))
self.rubber_band.show()
def mouseMoveEvent(self, event):
if self.rubber_band.isVisible():
self.rubber_band.setGeometry(QRect(self.start_pos, event.pos()).normalized())
# Do not move the window while selecting the area for OCR
event.accept()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
# Hide the previous rubber band
if self.rubber_band.isVisible():
self.rubber_band.hide()
# Get the selected rectangle
x1 = min(self.start_pos.x(), event.pos().x())
y1 = min(self.start_pos.y(), event.pos().y())
x2 = max(self.start_pos.x(), event.pos().x())
y2 = max(self.start_pos.y(), event.pos().y())
# Grab the selected area as an image
img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
# Convert the image to a QImage and display it
qimg = QImage(img.tobytes(), img.width, img.height, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(qimg)
self.label.setPixmap(pixmap)
# Show the OCR menu item
self.ocr_action.setVisible(True)
# Show the rubber band
self.rubber_band.setGeometry(QRect(self.start_pos, QSize()))
self.rubber_band.show()
# Perform OCR on the selected area
self.perform_ocr()
def paintEvent(self, event):
painter = QPainter(self)
painter.setPen(Qt.red)
painter.drawRect(self.rubber_band.geometry())
def perform_ocr(self):
# Get the selected area as an image
pixmap = self.label.pixmap()
if pixmap is None:
return
# Convert the pixmap to a PIL image
qimage = pixmap.toImage()
buffer = qimage.constBits()
buffer.setsize(qimage.byteCount())
pil_image = Image.frombuffer(
'RGB', (qimage.width(), qimage.height()), buffer, 'raw', 'RGB', 0, 1)
# Perform OCR on the selected area of the image
text = pytesseract.image_to_string(pil_image, lang='eng', config='--psm 6')
# Copy the recognized text to the clipboard
clipboard = QApplication.clipboard()
clipboard.setText(text)
# Hide the window and reset the label
self.hide()
self.label.setPixmap(QPixmap())
# Hide the OCR menu item
self.ocr_action.setVisible(False)
# Hide the rubber band and reset start_pos
self.rubber_band.hide()
self.start_pos = None
def hideEvent(self, event):
super().hideEvent(event)
self.reset_position()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry

Pyqt5. How to clear QVBoxLayout by a Signal?

I try to clear QVBoxLayout with self.vbox.takeAt(0), but previous vboxes clog up the QWidget and would not go away. New appear on top of the old ones.
Whole code https://pastebin.com/n43BH1R0
class Worker(QObject):
CLEAR_VBOX = pyqtSignal()
intReady = pyqtSignal(int)
#pyqtSlot()
def procCounter(self):
for i in range(1, 100):
self.CLEAR_VBOX.emit()
self.intReady.emit(i)
time.sleep(1)
class Form(QWidget):
..
..
def initUI(self):
self.vbox = QVBoxLayout()
self.setLayout(self.vbox)
self.setGeometry(333, 333, 222, 222)
self.show()
def clearvbox(self):
while self.vbox.count():
# ~ # break
self.vbox.takeAt(0)
def onIntReady(self, i):
hbox = QHBoxLayout()
for ii in range(i):
ll = QLabel(str(random.randint(1,9)))
hbox.addWidget(ll)
self.vbox.addLayout(hbox)
def clearvbox(self, L = False):
if not L:
L = self.vbox
if L is not None:
while L.count():
item = L.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
else:
self.clearvbox(item.layout())

Include matplotlib in pyqt5 with hover labels

I have a plot from matplotlib for which I would like to display labels on the marker points when hover over with the mouse.
I found this very helpful working example on SO and I was trying to integrate the exact same plot into a pyqt5 application.
Unfortunately when having the plot in the application the hovering doesn't work anymore.
Here is a full working example based on the mentioned SO post:
import matplotlib.pyplot as plt
import scipy.spatial as spatial
import numpy as np
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import sys
pi = np.pi
cos = np.cos
def fmt(x, y):
return 'x: {x:0.2f}\ny: {y:0.2f}'.format(x=x, y=y)
class FollowDotCursor(object):
"""Display the x,y location of the nearest data point.
https://stackoverflow.com/a/4674445/190597 (Joe Kington)
https://stackoverflow.com/a/13306887/190597 (unutbu)
https://stackoverflow.com/a/15454427/190597 (unutbu)
"""
def __init__(self, ax, x, y, tolerance=5, formatter=fmt, offsets=(-20, 20)):
try:
x = np.asarray(x, dtype='float')
except (TypeError, ValueError):
x = np.asarray(mdates.date2num(x), dtype='float')
y = np.asarray(y, dtype='float')
mask = ~(np.isnan(x) | np.isnan(y))
x = x[mask]
y = y[mask]
self._points = np.column_stack((x, y))
self.offsets = offsets
y = y[np.abs(y-y.mean()) <= 3*y.std()]
self.scale = x.ptp()
self.scale = y.ptp() / self.scale if self.scale else 1
self.tree = spatial.cKDTree(self.scaled(self._points))
self.formatter = formatter
self.tolerance = tolerance
self.ax = ax
self.fig = ax.figure
self.ax.xaxis.set_label_position('top')
self.dot = ax.scatter(
[x.min()], [y.min()], s=130, color='green', alpha=0.7)
self.annotation = self.setup_annotation()
plt.connect('motion_notify_event', self)
def scaled(self, points):
points = np.asarray(points)
return points * (self.scale, 1)
def __call__(self, event):
ax = self.ax
# event.inaxes is always the current axis. If you use twinx, ax could be
# a different axis.
if event.inaxes == ax:
x, y = event.xdata, event.ydata
elif event.inaxes is None:
return
else:
inv = ax.transData.inverted()
x, y = inv.transform([(event.x, event.y)]).ravel()
annotation = self.annotation
x, y = self.snap(x, y)
annotation.xy = x, y
annotation.set_text(self.formatter(x, y))
self.dot.set_offsets((x, y))
bbox = ax.viewLim
event.canvas.draw()
def setup_annotation(self):
"""Draw and hide the annotation box."""
annotation = self.ax.annotate(
'', xy=(0, 0), ha = 'right',
xytext = self.offsets, textcoords = 'offset points', va = 'bottom',
bbox = dict(
boxstyle='round,pad=0.5', fc='yellow', alpha=0.75),
arrowprops = dict(
arrowstyle='->', connectionstyle='arc3,rad=0'))
return annotation
def snap(self, x, y):
"""Return the value in self.tree closest to x, y."""
dist, idx = self.tree.query(self.scaled((x, y)), k=1, p=1)
try:
return self._points[idx]
except IndexError:
# IndexError: index out of bounds
return self._points[0]
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.width = 1000
self.height = 800
self.setGeometry(0, 0, self.width, self.height)
canvas = self.get_canvas()
w = QWidget()
w.layout = QHBoxLayout()
w.layout.addWidget(canvas)
w.setLayout(w.layout)
self.setCentralWidget(w)
self.show()
def get_canvas(self):
fig, ax = plt.subplots()
x = np.linspace(0.1, 2*pi, 10)
y = cos(x)
markerline, stemlines, baseline = ax.stem(x, y, '-.')
plt.setp(markerline, 'markerfacecolor', 'b')
plt.setp(baseline, 'color','r', 'linewidth', 2)
cursor = FollowDotCursor(ax, x, y, tolerance=20)
canvas = FigureCanvas(fig)
return canvas
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())
What would I have to do to make the labels also show when hovering over in the pyqt application?
The first problem may be that you don't keep a reference to the FollowDotCursor.
So to make sure the FollowDotCursor stays alive, you can make it a class variable
self.cursor = FollowDotCursor(ax, x, y, tolerance=20)
instead of cursor = ....
Next make sure you instatiate the Cursor class after giving the figure a canvas.
canvas = FigureCanvas(fig)
self.cursor = FollowDotCursor(ax, x, y, tolerance=20)
Finally, keep a reference to the callback inside the FollowDotCursor and don't use plt.connect but the canvas itself:
self.cid = self.fig.canvas.mpl_connect('motion_notify_event', self)

How to access from parent method to child object in PyQt5?

I have a button in widget widget which is a central widget of MyApp class, which inherits from QMainWindow. I have connected widget's button to MyApp's method called logic. This is fine, because if I write a method in my main class MyApp(QMainWindow):
def logic(self):
sender = self.sender()
print(sender)
... and click the button I get a message:
PyQt5.QtWidgets.QPushButton object at 0x7ff92e19eaf8
My question is how can I from MyApp's method called logic access to its child object like MyApp.widget.saltLine which is a QLineEdit object? I need to read that line.
class MyApp(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.initui()
def initui(self):
self.setMinimumSize(500, 150)
# create central widget
widget = QWidget()
# lines for entering data
widget.saltLabel = QLabel("Salt:")
widget.hashSunkenLabel = QLabel()
widget.passwordLine = QLineEdit()
widget.resultButton = QPushButton("&Calculate", self)
# set layout
grid = QGridLayout()
grid.addWidget(widget.saltLabel, 0, 0)
grid.addWidget(widget.passwordLine, 1, 0)
grid.addWidget(widget.hashSunkenLabel, 2, 0)
grid.addWidget(widget.resultButton, 2, 1)
# set widget a grid layout and set widget
# as central widget of QMainWindows
widget.setLayout(grid)
self.setCentralWidget(widget)
# don't know how should this look like
widget.resultButton.clicked.connect(self.logic)
def logic(self):
salt = self.saltLine.text()
password = self.passwordLine.text()
resulting_hash = crypt.crypt(password, salt)
self.hashSunkenLabel.setText(resulting_hash)
Or am I definig centralwidget widget wrong? If I do it without a central widget it works fine:
#!/usr/bin/env python3
import sys
import crypt
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QMainWindow, QLabel, QLineEdit, QPushButton,
QWidget, QApplication, QSystemTrayIcon, QFrame, QGridLayout)
class MyApp(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.saltLabel = QLabel("Salt:")
self.saltLine = QLineEdit()
self.saltLine.setPlaceholderText("e.g. $6$xxxxxxxx")
self.passwordLabel = QLabel("Password:")
self.passwordLine = QLineEdit()
self.hashLabel = QLabel("Hash:")
self.hashSunkenLabel = QLabel()
# widget.hashSunkenLabel.setFrameStyle(QFrame.Box | QFrame.Sunken)
self.hashSunkenLabel.setFrameShadow(QFrame.Sunken)
self.resultButton = QPushButton("&Calculate", self)
self.resultButton.setMaximumSize(100, 50)
self.initui()
def initui(self):
# main window size, title and icon
self.setGeometry(300, 300, 500, 150)
self.setWindowTitle("Password hash calculator | Linux")
# set layout
grid = QGridLayout()
grid.addWidget(self.passwordLabel, 0, 0)
grid.addWidget(self.passwordLine, 0, 1)
grid.addWidget(self.saltLabel, 1, 0)
grid.addWidget(self.saltLine, 1, 1)
grid.addWidget(self.resultButton, 2, 1)
grid.addWidget(self.hashLabel, 3, 0)
grid.addWidget(self.hashSunkenLabel, 3, 1)
self.setLayout(grid)
self.resultButton.clicked.connect(self.logic)
def logic(self):
"""
Calculates hash from salt and password
"""
salt = self.saltLine.text()
password = self.passwordLine.text()
resulting_hash = crypt.crypt(password, salt)
self.hashSunkenLabel.setText(resulting_hash)
# sender = self.sender()
# print(sender)
# print(dir(MyApp))
def main():
app = QApplication(sys.argv)
instance = MyApp()
instance.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

how to refresh pyplots in wx.auinotebook

In following code, when the button is clicked, I insert the plots into the tabs of an auinotebook in another frame.
for example, When I have multiple plots in the plt window, I can drag a notebook tab into the bottom (that results in displaying two plots). Later on when I delete the bottom tab, and try to go into other plots, I see a flicker like the closed tab is still there.
I guess the issue is with my on_nb_tab_close. Because, without that I was not able to notice any such problem.
I appreciate help. Code samples will be very useful. (wxpython version 2.812)
import wx
import wx.lib.agw.aui as aui
import matplotlib as mpl
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as mplCanvas
def create_plotter(self):
try:
self.plotter.Show()
except AttributeError:
self.plotter =PlotFrame(self, 500, 500)
self.plotter.Show()
return self.plotter
class PlotFrame(wx.Frame):
def __init__(self, parent, height, width):
wx.Frame.__init__(self, None, size=(height,width), title="plts")
self.parent=parent
self.nb = aui.AuiNotebook(self)
self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_nb_tab_close, self.nb)
def AddPlotTab(self,name="plot"):
page = Plot(self.nb)
self.nb.AddPage(page,name)
return page
def on_nb_tab_close(self, evt):
print "tab close fired"
s=self.nb.GetSelection()
v=self.nb.RemovePage(s)
if not self.nb.GetPageCount():
self.on_Close(evt)
evt.Veto()
class Plot(wx.Panel):
def __init__(self, parent, id = -1, dpi = None, **kwargs):
wx.Panel.__init__(self, parent, id=id, **kwargs)
self.figure = mpl.figure.Figure(dpi=dpi)
self.canvas = mplCanvas(self, -1, self.figure) # wxPanel object containing plot
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas,1,wx.EXPAND)
self.SetSizer(sizer)
class MainFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, title="Plotting test", size=(300, 300))
self.btn1 = wx.Button(self, -1, "Print 1")
self.Bind(wx.EVT_BUTTON, self.OnBtn1, self.btn1)
def OnBtn1(self, evt):
plotter=create_plotter(self)
page1 = plotter.AddPlotTab("case 1: first_plot")
page1.figure.gca().plot(range(10),range(10),'+')
page1.figure.gca().plot(range(10),range(10),'-',color='red')
page1.figure.canvas.draw()
if __name__ == '__main__':
APP = wx.App(False)
FRAME = MainFrame(None)
FRAME.Show()
APP.MainLoop()