Qt visualization as a function in separate file - qt

I'm newbie in PyQtGraph and Qt. I need to write a function (preferably in separate file) for visualization my data. The short version of my snippet is below. The function and the main code in the same file here:
import numpy as np
from pyqtgraph.Qt import QtGui
import pyqtgraph as pg
def visualizator(image):
app = QtGui.QApplication([])
win = QtGui.QMainWindow()
w = QtGui.QWidget()
win.setCentralWidget(w)
layout = QtGui.QGridLayout()
w.setLayout(layout)
imgView = pg.ImageView()
layout.addWidget(imgView)
imgView.setImage(image)
win.show()
app.exec_()
return
my_image = np.ones((256,256),np.float)
visualizator(my_image)
When I run my code I get Qt crash. What am I doing wrong? What should I return from my function?

You have to be careful with your QApplications. You don't want to start another one in a function. Try removing the app-stuff.

Related

How to update Holoviews plot layout dynamically in Jupyter Notebook?

I would like to work in Jupyter Notebook though the project with one plot. Update it with a new data or new layout, maybe add/delete additional plot nearby it and so on… In Bokeh I could use smth similar to:
target = show(layout, notebook_handle=True)
push_notebook(handle=target)
In Holoviews I found how to feed new data to the existing plot:
pipe = Pipe(data=[])
Image = hv.DynamicMap(hv.Image, streams=[pipe1])
pipe.send(np.random.rand(3,2)) #data change
But is there any solution to manage live layout update in Holoviews? Is it possible to update existed plot by .opts() construction? In this example I will get a new plot:
pipe = Pipe(data=[])
Image = hv.DynamicMap(hv.Image, streams=[pipe])
Image.opts(width=1000,height=1000)
#######new cell in jupyter notebook############
Image.opts(width=100,height=100)
Here is a brilliant answer I have got on my question:
import param
import panel as pn
import numpy as np
import holoviews as hv
from holoviews.streams import Pipe
pn.extension()
pipe = Pipe(data=[])
class Layout(param.Parameterized):
colormap = param.ObjectSelector(default='viridis', objects=['viridis', 'fire'])
width = param.Integer(default=500)
update_data = param.Action(lambda x: x.param.trigger('update_data'), label='Update data!')
#param.depends("update_data", watch=True)
def _update_data(self):
pipe.send(np.random.rand(3,2))
layout = Layout()
Image = hv.DynamicMap(hv.Image, streams=[pipe]).apply.opts(cmap=layout.param.colormap, width=layout.width)
pdmap = pn.panel(Image)
playout = pn.panel(layout)
def update_width(*events):
for event in events:
if event.what == "value":
pdmap.width = event.new
layout.param.watch(update_width, parameter_names=['width'], onlychanged=False)
pn.Row(playout, pdmap)
https://discourse.holoviz.org/t/how-to-update-holoviews-plots-width-height/1947

Current Screen Size in Python3 with PyQt5

Is there an alternative in Qt5 python3 to the following code :
https://askubuntu.com/questions/153549/how-to-detect-a-computers-physical-screen-size-in-gtk
from gi.repository import Gdk
s = Gdk.Screen.get_default()
print(s.get_width(), s.get_height())
You can get the primary screen from the QApplication, which returns a QScreen object giving access to many useful properties:
import sys
from PyQt5 import QtWidgets
app = QtWidgets.QApplication(sys.argv)
screen = app.primaryScreen()
print('Screen: %s' % screen.name())
size = screen.size()
print('Size: %d x %d' % (size.width(), size.height()))
rect = screen.availableGeometry()
print('Available: %d x %d' % (rect.width(), rect.height()))
Note that the primaryScreen method is static, so if you've already created an instance of QApplication elsewhere in your application, can easily get a QScreen object later on like this:
screen = QApplication.primaryScreen()
The following python3 code allows to get screen size but is there an alternative to
QtWidgets.QDesktopWidget().screenGeometry(-1) method :
import sys
from PyQt5 import QtWidgets
def main():
"""
allow you to get size of your current screen
-1 is to precise that it is the current screen
"""
sizeObject = QtWidgets.QDesktopWidget().screenGeometry(-1)
print(" Screen size : " + str(sizeObject.height()) + "x" + str(sizeObject.width()))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main()
sys.exit(app.exec_())
The value for screenGeometry() is the display you take a look at.
0 is the main screen, 1, 2 indicates further monitors installed.
To list all availible displays:
def screen_resolutions():
for displayNr in range(QtWidgets.QDesktopWidget().screenCount()):
sizeObject = QtWidgets.QDesktopWidget().screenGeometry(displayNr)
print("Display: " + str(displayNr) + " Screen size : " + str(sizeObject.height()) + "x" + str(sizeObject.width()))
from PyQt5.QtWidgets import QApplication, QWidget
self.desktop = QApplication.desktop()
self.screenRect = self.desktop.screenGeometry()
self.height = self.screenRect.height()
self.width = self.screenRect.width()
You can see here - https://www.programmersought.com/article/58831562998/
Screen information is available from the QApplication object as noted by ekhumoro. However, there should be only one global instance of QApplication. It is often set in the main script of a PyQt Gui application:
import sys
from PyQt5.QtWidgets import QApplication
def main():
...
app = QApplication(sys.argv)
window = MainWindow()
window.show
sys.exit(app.exec_())
That's probably not where you want to work with screen properties.
As pointed out by Omkar76, to access the global instance from elsewhere (e.g. in MainWindow()) use its instance() function. You can then use its primaryScreen property to get access to the many useful pieces of information available from the QScreen object:
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
# Window dimensions
app = QApplication.instance()
screen = app.primaryScreen()
geometry = screen.availableGeometry()
self.setFixedSize(geometry.width() * 0.8, geometry.height() * 0.7)
QDesktopWidget is obsolete and so should be avoided.
i honestly don't know why it's always such a hustle to find pyqt5 answers,but anyway i think this is what you were looking for .
print(self.frameSize())

pyqt4 - singleapplication - bring up the original window in an attempt to open the app for the second time

I want only one instance of my app to be running at each time. but when the user attempts to open it the second time, I want the first window to be brought to the front (it could be just minimized or minimized to the corner of the taskbar and the user doesn't know how to open it)
I have this code that does the detection job and it doesn't allow the second instance. I have trouble with the part that it has to open the original window. I have commented out some of my attempt.
import sys
from PyQt4 import QtGui, QtCore
import sys
class SingleApplication(QtGui.QApplication):
def __init__(self, argv, key):
QtGui.QApplication.__init__(self, argv)
self._activationWindow=None
self._memory = QtCore.QSharedMemory(self)
self._memory.setKey(key)
if self._memory.attach():
self._running = True
else:
self._running = False
if not self._memory.create(1):
raise RuntimeError(
self._memory.errorString().toLocal8Bit().data())
def isRunning(self):
return self._running
def activationWindow(self):
return self._activationWindow
def setActivationWindow(self, activationWindow):
self._activationWindow = activationWindow
def activateWindow(self):
if not self._activationWindow:
return
self._activationWindow.setWindowState(
self._activationWindow.windowState() & ~QtCore.Qt.WindowMinimized)
self._activationWindow.raise_()
self._activationWindow.activateWindow()
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.label = QtGui.QLabel(self)
self.label.setText("Hello")
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.label)
if __name__ == '__main__':
key = 'random _ text'
app = SingleApplication(sys.argv, key)
if app.isRunning():
#app.activateWindow()
sys.exit(1)
window = Window()
#app.setActivationWindow(window)
#print app.topLevelWidgets()[0].winId()
window.show()
sys.exit(app.exec_())
I've made this work on Windows using the win32 api (I'm not entirely sure, but there are probably equivalent calls on macos/unix).
Add the following import to your application,
import win32gui
set the window title to a fixed name (instead of doing this, you could store its whndl in the shared memory)
window = Window()
window.setWindowTitle('Single Application Example')
window.show()
and then change your activateWindow method to something like the following:
def activateWindow(self):
# needs to look for a named window ...
whndl = win32gui.FindWindowEx(0, 0, None, "Single Application Example")
if whndl is 0:
return #couldn't find the name window ...
#this requests the window to come to the foreground
win32gui.SetForegroundWindow(whndl)
You might be interested by the solutions proposed here
For instance, I would try:
app = SingleApplication(sys.argv, key)
if app.isRunning():
window = app.activationWindow()
window.showNormal()
window.raise()
app.activateWindow()
sys.exit(1)
window = Window()
app.setActivationWindow(window)
window.setWindowFlags(Popup)
window.show()

Controling a matplotlib plot from a separate window

I'm trying to create the simplest example of controlling a plot in one window from buttons and functions in another window. I know I'm going to need more things in the window with the plot, so, I need to create my plot figure withing a QT window.
This is what I have so far:
My control window:
import sys
from PyQt4.QtCore import (QSize, SIGNAL)
from PyQt4.QtGui import (QApplication, QDialog, QPushButton, QVBoxLayout)
import PlotWindow
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.pushButton1 = QPushButton()
self.pushButton1.setMaximumSize(QSize(110, 24))
self.pushButton1.setObjectName("pushButton1")
self.pushButton1.setText("Open Plot")
self.pushButton2 = QPushButton()
self.pushButton2.setMaximumSize(QSize(110, 24))
self.pushButton2.setObjectName("pushButton2")
self.pushButton2.setText("Update Plot")
layout = QVBoxLayout()
layout.addWidget(self.pushButton1)
layout.addWidget(self.pushButton2)
self.setLayout(layout)
self.setWindowTitle("Plot Control")
self.connect(self.pushButton1,SIGNAL("clicked()"),self.plotNew)
def plotNew(self):
print "new plot window"
self.dialog = PlotWindow.PlotWindow()
self.dialog.show()
app = QApplication(sys.argv)
form = Window()
form.open()
app.exec_()
My plot window :
import matplotlib
import numpy as np
from PyQt4 import QtGui
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import matplotlib.animation as animation
class PlotWindow(QtGui.QDialog):
def __init__(self, parent=None):
super(PlotWindow, self).__init__(parent)
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111)
plt.draw()
Obviously my plot window is where I'm having the biggest problems. I've gone through lots of examples, but none of them seem to show how to place a plot within another window.
Thanks
Well, I can answer part of my own question, but I would like comments on whether or not this is the best way to accomplish. The following code shows the changes I've made to bring up a second window with a plot inside.
import sys
from PyQt4 import QtGui
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
class PlotCanvas(FigureCanvas):
def __init__(self, parent):
self.fig = Figure()
self.axes = self.fig.add_subplot(111)
# self.x = np.arange(0.0,0.3,0.01)
# self.y = np.cos(2*np.pi*self.x)
# self.axes.plot(self.x,self.y)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
class PlotWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowTitle("Plot Figure")
self.main_widget = QtGui.QWidget(self)
vbl = QtGui.QVBoxLayout(self.main_widget)
qmc = PlotCanvas(self.main_widget)
ntb = NavigationToolbar(qmc, self.main_widget)
vbl.addWidget(qmc)
vbl.addWidget(ntb)
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
I still need help with setting the data for the plot from the other window.
Thanks

How do I display a PGM file within a QGraphicsView?

I am trying to display a PGM file using the following test application. The code works with a PNG file, but not PGM:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import Image
import ImageQt
class MyView(QGraphicsView):
def __init__(self):
QGraphicsView.__init__(self)
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
img = Image.open('test.pgm') # works with 'test.png'
self.imgQ = ImageQt.ImageQt(img)
pixmap = QPixmap.fromImage(self.imgQ)
self.scene.addPixmap(pixmap)
if __name__ == '__main__':
app = QApplication(sys.argv)
view = MyView()
view.show()
sys.exit(app.exec_())
How can I display a PGM file within the QGraphicsView?
QImage supports reading PGM files. Have you checked that img is loaded correctly?
Perhaps you have abad file, or a typo in the name, or wrong permissions
It looks like you're using PIL to open the image, convert to a QImage and then convert that to a QPixmap.
Is there any reason why you can't just load the PGM directly into a QPixmap and avoid PIL?
Replacing
img = Image.open('test.pgm') # works with 'test.png'
self.imgQ = ImageQt.ImageQt(img)
pixmap = QPixmap.fromImage(self.imgQ)
self.scene.addPixmap(pixmap)
with
pixmap = QPixmap('test.pgm')
self.scene.addPixmap(pixmap)
should work for you.

Resources