Discussion:
[pyqtgraph] Generate Export Pictures Does not Work for First Loop Execution
GR
2018-09-17 20:24:18 UTC
Permalink
Hi,

I am using the following code to generate png files with PyQtGraph.

The code works quite well, but unfortunately, the first loop / picture
("0exported_image.png", that is: runner = 0) does not have any data in the
output picture (respectively: has only default values in the exported
graph).
I additionally set a manual breakpoint in "update_data" and looked at the
attributes of the class instance for runner = 0 and runner >0. It strikes
that at several parts of the object tree the "picture" is set for runner
"picture": {
"py/object": "PyQt5.QtGui.QPicture"
},



This is the code I use. Does anybody have an idea what could be the reason
for this?

Thanks in advance.

import numpy as np
from PyQt5 import QtWidgets
from PyQt5.QtCore import pyqtSignal, pyqtSlot
import pyqtgraph as pg
import pyqtgraph.exporters
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph import GraphicsLayoutWidget
from threading import Thread, Event
import time


# Routine to acquire and serve data
# This might be a camera driver, notifying when a new frame is available
def generate_data(callback, threadkill):
# while not threadkill.is_set():
# width = 1600
# data = np.zeros(width)
# runner = int(np.random.random()*5)
# data.fill(runner)
# callback(data, runner)
# time.sleep(0.01)
for runner in range(5):
width = 1600
data = np.zeros(width)
data.fill(runner)
my_var = callback(data, runner)
time.sleep(0.01)
print("callback called")

# threadkill.set()
# # sys.exit(1)


class PyQtGraphTest(GraphicsLayoutWidget):
# Signal to indicate new data acquisition
# Note: signals need to be defined inside a QObject class/subclass
data_acquired = pyqtSignal(np.ndarray, int)

def __init__(self):
super().__init__()
self.exporter = None

self.setWindowTitle('Test pyqtgraph paint signals')
self.resize(640, 400)
self.plot = self.addPlot()
self.spectrum = self.plot.plot()
self.plot.enableAutoRange(pg.ViewBox.XYAxes)

# Connect the signal
self.data_acquired.connect(self.update_data)

# Make and start the background thread to acquire data
# Pass it the signal.emit as the callback function
self.threadkill = Event()
self.thread = Thread(target=generate_data, args=(self.data_acquired.emit, self.threadkill))
self.thread.start()

self.thread.join()
# my_var = self.thread.isAlive()
# print("my_var:", my_var)
# self.threadkill.set()
# print("fin")

# Kill our data acquisition thread when shutting down
def closeEvent(self, close_event):
self.threadkill.set()

# Slot to receive acquired data and update plot
@pyqtSlot(np.ndarray, int)
def update_data(self, data, runner):
if not self.exporter:
# Here we are passing the exporter the GraphicsLayout object that is
# the central item (ci) inside this GraphicsLayoutWidget. That in
# turn contains the two PlotItem objects.
self.exporter = pg.exporters.ImageExporter(self.ci)
self.exporter.parameters()['width'] = 640

self.spectrum.setData(data)
self.exporter.export(str(runner) + 'exported_image.png')
print("exported image")


if __name__ == '__main__':
import sys

app = QtWidgets.QApplication(sys.argv)
window = PyQtGraphTest()
window.show()
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
sys.exit(app.exec_())

print("fin2")
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/51672517-fe3b-4266-9b14-ae336d7dd547%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Patrick
2018-09-18 02:40:18 UTC
Permalink
Hi,

I think there is a bug somewhere, where the first call to setData() doesn't
result in the view range being updated. Your code is working fine, the plot
is being updated with the correct data, but the axes scales aren't correct
on the first call.

Without spending time tracing through why the ranges aren't being updated,
a simple workaround would be to manually trigger the update by inserting
"self.plot.autoRange()" after your self.spectrum.setData(data) line. Not
ideal, but seems to work.

Patrick
Post by GR
Hi,
I am using the following code to generate png files with PyQtGraph.
The code works quite well, but unfortunately, the first loop / picture
("0exported_image.png", that is: runner = 0) does not have any data in the
output picture (respectively: has only default values in the exported
graph).
I additionally set a manual breakpoint in "update_data" and looked at the
attributes of the class instance for runner = 0 and runner >0. It strikes
that at several parts of the object tree the "picture" is set for runner
"picture": {
"py/object": "PyQt5.QtGui.QPicture"
},
This is the code I use. Does anybody have an idea what could be the reason
for this?
Thanks in advance.
import numpy as np
from PyQt5 import QtWidgets
from PyQt5.QtCore import pyqtSignal, pyqtSlot
import pyqtgraph as pg
import pyqtgraph.exporters
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph import GraphicsLayoutWidget
from threading import Thread, Event
import time
# Routine to acquire and serve data
# This might be a camera driver, notifying when a new frame is available
# width = 1600
# data = np.zeros(width)
# runner = int(np.random.random()*5)
# data.fill(runner)
# callback(data, runner)
# time.sleep(0.01)
width = 1600
data = np.zeros(width)
data.fill(runner)
my_var = callback(data, runner)
time.sleep(0.01)
print("callback called")
# threadkill.set()
# # sys.exit(1)
# Signal to indicate new data acquisition
# Note: signals need to be defined inside a QObject class/subclass
data_acquired = pyqtSignal(np.ndarray, int)
super().__init__()
self.exporter = None
self.setWindowTitle('Test pyqtgraph paint signals')
self.resize(640, 400)
self.plot = self.addPlot()
self.spectrum = self.plot.plot()
self.plot.enableAutoRange(pg.ViewBox.XYAxes)
# Connect the signal
self.data_acquired.connect(self.update_data)
# Make and start the background thread to acquire data
# Pass it the signal.emit as the callback function
self.threadkill = Event()
self.thread = Thread(target=generate_data, args=(self.data_acquired.emit, self.threadkill))
self.thread.start()
self.thread.join()
# my_var = self.thread.isAlive()
# print("my_var:", my_var)
# self.threadkill.set()
# print("fin")
# Kill our data acquisition thread when shutting down
self.threadkill.set()
# Slot to receive acquired data and update plot
@pyqtSlot(np.ndarray, int)
# Here we are passing the exporter the GraphicsLayout object that is
# the central item (ci) inside this GraphicsLayoutWidget. That in
# turn contains the two PlotItem objects.
self.exporter = pg.exporters.ImageExporter(self.ci)
self.exporter.parameters()['width'] = 640
self.spectrum.setData(data)
self.exporter.export(str(runner) + 'exported_image.png')
print("exported image")
import sys
app = QtWidgets.QApplication(sys.argv)
window = PyQtGraphTest()
window.show()
sys.exit(app.exec_())
print("fin2")
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/bcdf99a4-5288-4c3b-a922-7e9b82c8dde3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
GR
2018-09-18 05:48:16 UTC
Permalink
Hi Patrick,

thanks a lot! I will use that.

Wonderful - again!
Post by Patrick
Hi,
I think there is a bug somewhere, where the first call to setData()
doesn't result in the view range being updated. Your code is working fine,
the plot is being updated with the correct data, but the axes scales aren't
correct on the first call.
Without spending time tracing through why the ranges aren't being updated,
a simple workaround would be to manually trigger the update by inserting
"self.plot.autoRange()" after your self.spectrum.setData(data) line. Not
ideal, but seems to work.
Patrick
Post by GR
Hi,
I am using the following code to generate png files with PyQtGraph.
The code works quite well, but unfortunately, the first loop / picture
("0exported_image.png", that is: runner = 0) does not have any data in the
output picture (respectively: has only default values in the exported
graph).
I additionally set a manual breakpoint in "update_data" and looked at
the attributes of the class instance for runner = 0 and runner >0. It
strikes that at several parts of the object tree the "picture" is set for
"picture": {
"py/object": "PyQt5.QtGui.QPicture"
},
This is the code I use. Does anybody have an idea what could be the
reason for this?
Thanks in advance.
import numpy as np
from PyQt5 import QtWidgets
from PyQt5.QtCore import pyqtSignal, pyqtSlot
import pyqtgraph as pg
import pyqtgraph.exporters
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph import GraphicsLayoutWidget
from threading import Thread, Event
import time
# Routine to acquire and serve data
# This might be a camera driver, notifying when a new frame is available
# width = 1600
# data = np.zeros(width)
# runner = int(np.random.random()*5)
# data.fill(runner)
# callback(data, runner)
# time.sleep(0.01)
width = 1600
data = np.zeros(width)
data.fill(runner)
my_var = callback(data, runner)
time.sleep(0.01)
print("callback called")
# threadkill.set()
# # sys.exit(1)
# Signal to indicate new data acquisition
# Note: signals need to be defined inside a QObject class/subclass
data_acquired = pyqtSignal(np.ndarray, int)
super().__init__()
self.exporter = None
self.setWindowTitle('Test pyqtgraph paint signals')
self.resize(640, 400)
self.plot = self.addPlot()
self.spectrum = self.plot.plot()
self.plot.enableAutoRange(pg.ViewBox.XYAxes)
# Connect the signal
self.data_acquired.connect(self.update_data)
# Make and start the background thread to acquire data
# Pass it the signal.emit as the callback function
self.threadkill = Event()
self.thread = Thread(target=generate_data, args=(self.data_acquired.emit, self.threadkill))
self.thread.start()
self.thread.join()
# my_var = self.thread.isAlive()
# print("my_var:", my_var)
# self.threadkill.set()
# print("fin")
# Kill our data acquisition thread when shutting down
self.threadkill.set()
# Slot to receive acquired data and update plot
@pyqtSlot(np.ndarray, int)
# Here we are passing the exporter the GraphicsLayout object that is
# the central item (ci) inside this GraphicsLayoutWidget. That in
# turn contains the two PlotItem objects.
self.exporter = pg.exporters.ImageExporter(self.ci)
self.exporter.parameters()['width'] = 640
self.spectrum.setData(data)
self.exporter.export(str(runner) + 'exported_image.png')
print("exported image")
import sys
app = QtWidgets.QApplication(sys.argv)
window = PyQtGraphTest()
window.show()
sys.exit(app.exec_())
print("fin2")
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/14056ac8-a80f-4c2c-876b-1162e1157f28%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...