Plotting with pyqtgraph without displaying - python

I am trying to move from matplotlib to plotting with pyqtgraph because of its touted capabilities to render and save images faster. In my attempts to do this on a cluster with multiprocessors, I run into the following trouble:
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to
'/tmp/runtime-user' qt.qpa.screen: QXcbConnection: Could not connect
to display Could not connect to any X display.
How do I obviate displaying a plot, and save it directly to file? Here's my attempt at the code:
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import pyqtgraph.exporters
#app = QtGui.QApplication([])
#view = pg.GraphicsView()
l = pg.GraphicsWindow()
#view.setCentralItem(l)
#view.show()
#view.setWindowTitle('GraphicsLayout')
#view.resize(1000,1600)
def plotlayout(lines):
p_res={}
p_data={}
for rows in rows:
p_res[row]={}
p_data[row]={}
for col in cols:
l2=l.addLayout()
p_res[row][col]=l2.addPlot()
p_res[row][col].hideAxis('bottom')
l2.nextRow()
p_data[row][col]=l2.addPlot()
l.nextColumn()
l.nextRow()
return p_res, p_data
pl = plotlayout(lines)
pl[0].plot([1,3,5,9,7,8],[2,3,3,5,6,8])
pl[1].plot([1,3,5,9,7,8],[2,22,3,45,6,8])
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
QtGui.QApplication.exit()
QtGui.QApplication.quit()
QtGui.QApplication.quitOnLastWindowClosed()
QtGui.QApplication.closeAllWindows()
exporter = pg.exporters.ImageExporter(l.scene())
exporter.export('fits.ps')
I have tested this on my personal laptop and it works fine.

If you want to run a GUI without using desktop environment/window manager a possible solution is to use Xvfb.

Related

PyQt5. Script runs when monitor is attached, but errors without monitor [duplicate]

I am trying to move from matplotlib to plotting with pyqtgraph because of its touted capabilities to render and save images faster. In my attempts to do this on a cluster with multiprocessors, I run into the following trouble:
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to
'/tmp/runtime-user' qt.qpa.screen: QXcbConnection: Could not connect
to display Could not connect to any X display.
How do I obviate displaying a plot, and save it directly to file? Here's my attempt at the code:
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import pyqtgraph.exporters
#app = QtGui.QApplication([])
#view = pg.GraphicsView()
l = pg.GraphicsWindow()
#view.setCentralItem(l)
#view.show()
#view.setWindowTitle('GraphicsLayout')
#view.resize(1000,1600)
def plotlayout(lines):
p_res={}
p_data={}
for rows in rows:
p_res[row]={}
p_data[row]={}
for col in cols:
l2=l.addLayout()
p_res[row][col]=l2.addPlot()
p_res[row][col].hideAxis('bottom')
l2.nextRow()
p_data[row][col]=l2.addPlot()
l.nextColumn()
l.nextRow()
return p_res, p_data
pl = plotlayout(lines)
pl[0].plot([1,3,5,9,7,8],[2,3,3,5,6,8])
pl[1].plot([1,3,5,9,7,8],[2,22,3,45,6,8])
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
QtGui.QApplication.exit()
QtGui.QApplication.quit()
QtGui.QApplication.quitOnLastWindowClosed()
QtGui.QApplication.closeAllWindows()
exporter = pg.exporters.ImageExporter(l.scene())
exporter.export('fits.ps')
I have tested this on my personal laptop and it works fine.
If you want to run a GUI without using desktop environment/window manager a possible solution is to use Xvfb.

pyqtgraph live data from a CMOS camera

I am trying to plot live data that is streamed from a CMOS camera in python. As a little side note: I want to use this to stabilize the pointing of a laser in the lab.
I am using ImageItem from the pyqtgraph module and my script is basically a modification of the ImageItem example (see below).
However when I execute the script I immediately get a delay of about 3 seconds and the RAM memory increases until the process gets killed. The resolution of the camera is 3672x5496 pixel which is quiet high and it seems like the pictures are queuing up until it is out of memory (my interpretation of the problem).
I tried to clear the ImageItem module every time when it gets updated but it does not change anything.
What am I doing wrong? Is it even possible to get this working live and without running out of memory with this resolution? I am already happy with about 1-2 frames per seconds.
## Add path to library (just for examples; you do not need this)
#import initExample
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import pyqtgraph as pg
import pyqtgraph.ptime as ptime
import gxipy as gx
import sys
## Check for connected devices
device_manager = gx.DeviceManager()
dev_num, dev_info_list = device_manager.update_device_list()
if dev_num == 0:
sys.exit(1)
## Connect to the camera
strSN = dev_info_list[0].get("sn")
cam = device_manager.open_device_by_sn(strSN)
## start the data stream
cam.stream_on()
app = QtGui.QApplication([])
## Create window with GraphicsView widget
win = pg.GraphicsLayoutWidget()
win.show() ## show widget alone in its own window
win.setWindowTitle('pyqtgraph example: ImageItem')
view = win.addViewBox()
## lock the aspect ratio so pixels are always square
view.setAspectLocked(True)
## Create image item
img = pg.ImageItem(border='w')
view.addItem(img)
## Set initial view bounds
view.setRange(QtCore.QRectF(0, 0, 3672, 5496))
## Create random image
updateTime = ptime.time()
def updateData():
global img, i, updateTime
## Get a new image from the camera
raw_image = cam.data_stream[0].get_image()
data = raw_image.get_numpy_array()
if data is None:
sys.exit(1)
## Display the image
img.setImage(data)
QtCore.QTimer.singleShot(1, updateData)
updateData()
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
cam.stream_off()
cam.close_device()

In PyQt5, matplotlib's FigureCanvasQTAgg in QScrollArea is not working fine

I'm creating an application with PyQt5.
I want to add a chart with long width, so I tried to add the graph into a QScrollArea.
I wrote the code below using FigureCanvasQTAgg of matplotlib
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QScrollArea
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Qt5Agg')
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = QWidget()
widget.resize(400, 300)
fig, ax = plt.subplots(1)
fig.set_size_inches(30, 1)
figure_canvas = FigureCanvas(fig)
scroll = QScrollArea(widget)
scroll.setWidget(figure_canvas)
widget.show()
sys.exit(app.exec_())
But when I scroll it, it is not working fine.
The gif shows the situation when I scroll to right.
Is there any advice for the code?
My python is python 3.6.0
And I am using matplotlib 3.0.3, and PyQt5 5.12.2
My computer is MacBook Pro 15-inch Mid 2014,
and the os is Mojave 10.14.3
Can you try to update your version of my matplotlib module >3.2.0rc1.
This version contains a correction for that issue https://github.com/matplotlib/matplotlib/issues/14160.
I tested it on my computer and it works well.

PyQtGraph 0.10.0: auto range of PlotItem tries to scale TextItem and crashes

Since version 0.10.0 of PyQtGraph I have problems with TextItems in plots:
I have a diagram (PlotItem) with enabled auto-scaling and a TextItem. Under some circumstances the auto-scaling tries to scale the TextItem which is not scalable. The diagram is rescaled again and again.
This happens when:
the plotted curve has no height or
the window height is reduced until the text does not fit anymore.
For my opinion this issue was not there in version 0.9.10 of PyQtGraph.
Example for case 1:
import PySide
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
app = QtGui.QApplication([])
win = pg.GraphicsWindow(title="auto scaling bug when having a TextItem")
win.resize(1000,500)
win.setWindowTitle("auto scaling bug when having a TextItem")
p1 = win.addPlot(title="Plot with TextItem", y=np.zeros(10))
#p1.plot(y=[100]*10)
ti = pg.TextItem(text="My TextItem", color='r', anchor=(0.0, 1.0), angle=90)
p1.addItem(ti)
ti.setPos(0, 0)
p1.enableAutoRange('y', True)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
Example for case 2:
import PySide
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
app = QtGui.QApplication([])
win = pg.GraphicsWindow(title="auto scaling bug when having a TextItem")
win.resize(1000,150)
win.setWindowTitle("auto scaling bug when having a TextItem")
p1 = win.addPlot(title="Plot with TextItem", y=np.zeros(10))
p1.plot(y=[100]*10)
ti = pg.TextItem(text="My TextItem", color='r', anchor=(0.0, 1.0), angle=90)
p1.addItem(ti)
ti.setPos(0, 0)
p1.enableAutoRange('y', True)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
Has anyone an idea (except going back to version 0.9.10)?
Thank you in advance!
Oh, I found a solution by myself:
The addItem method allows an option ignoreBounds. When I add the TextItem and set this option to True then the autoscale works:
p1.addItem(ti, ignoreBounds = True)
Sorry for asking before debugging.

How to update a plot event driven?

How can I update a matplotlib plot event driven?
Background:
I wanna program a tool that displays me measured values I receive via a serial port.
These values will be send by a serial connected device when it has measured values and not when the host requests.
Current State:
It seems there is no way to update a plot manually.
When I call the plot()-function more than one time the new plots will be added. Similar to MATLAB or Octave, when you use the "hold on"-Option.
This ends after about 10 calls. Then it is freezed.
When I clear the figures before update, the whole plot disappears.
At least, when the plot is embedded in a window.
Neither draw() nor show() provide a remedy.
When I use a single plot figure, there is no easy way to update, because after the call of show(), the program flow sticks at this line, until the Window is closed. So the update has to be done in a separate thread.
Both problems will be solved, when I use an animation:
import sys
from PyQt4.QtGui import QApplication, QMainWindow, QDockWidget, QVBoxLayout,QTabWidget, QWidget
from PyQt4.QtCore import Qt
from matplotlib import pyplot, animation
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from random import randint
a = QApplication(sys.argv)
w = QMainWindow()
t = QTabWidget(w)
Tab1 = QWidget()
t.addTab(Tab1, '1st Plot')
t.resize(1280, 300)
x = [1, 2, 3]
Fig1 = pyplot.Figure();
Plot = Fig1.add_subplot(111);
Plot.plot(x)
Plot.grid();
layout = QVBoxLayout();
layout.addWidget(FigureCanvasQTAgg(Fig1));
Tab1.setLayout(layout);
def UpdateFunction(i):
x.append(randint(0, 10));
Plot.clear();
Plot.plot(x);
Plot.grid();
Anim = animation.FuncAnimation(Fig1, UpdateFunction, interval=500)
w.showMaximized()
sys.exit(a.exec_())
But such an animation is time triggered.
Is there any solution to update event triggered?
The event should be a finished UART read in.
Thank you very much.
Fabian
#tcaswell
Thank you!
This is my actual code:
import sys
from PyQt4.QtGui import QApplication, QMainWindow, QVBoxLayout,QTabWidget, QWidget
from PyQt4.QtCore import SIGNAL
from matplotlib import pyplot
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from random import randint
import time
from threading import Thread
a = QApplication(sys.argv)
w = QMainWindow()
t = QTabWidget(w)
Tab1 = QWidget()
t.addTab(Tab1, '1st Plot')
t.resize(1280, 300)
x = [];
x.append(randint(0, 10));
x.append(randint(0, 10));
x.append(randint(0, 10));
Fig1 = pyplot.Figure();
Plot = Fig1.add_subplot(111);
Line, = Plot.plot(x)
Plot.grid();
layout = QVBoxLayout();
layout.addWidget(FigureCanvasQTAgg(Fig1));
Tab1.setLayout(layout);
def triggerUpdate():
while True:
a.emit(SIGNAL('updatePlot()'));
time.sleep(2);
print('update triggered!\n')
def updateFunction():
x.append(randint(0, 10));
#Plot.clear();
Line.set_data(range(len(x)), x);
Fig1.canvas.draw_idle();
print('update done!\n')
a.connect(a, SIGNAL('updatePlot()'), updateFunction)
t = Thread(target=triggerUpdate);
t.start();
w.showMaximized()
sys.exit(a.exec_())
It seems to run, but the content of the plot gets not updated.
The Plot has no canvas. (Although it should have one, otherwise I don't now on what it is plotting when I command it.)
To be honest, I did not understand already the concept of the GUI and plot foo. The missing canvas is covered by its parenting figure. I really don't got it. When there is a figure, what can handle more than one plots, should't each plot have its own canvas?
But I think, here is the problem.
Thank you very much.

Categories

Resources