domarm-comat / pglive

Live pyqtgraph plot
MIT License
80 stars 14 forks source link

Roll on tick #31

Open slartz42 opened 1 year ago

slartz42 commented 1 year ago

Hello,

I spoke too soon before, it looks like there are still some issues with roll_on_tick. This time however, I took the time to write some code for you to reproduce the error, I made this program as similar as I could to how my data acquisition program actually functions.

When the sampling rate is increased higher than the plot rate, the roll on tick stops working properly. I believe this is because the appended array size is getting larger and larger and ticks are not getting counted properly.

When self.sampling_rate is set to 15 Hz, everything works as it should. When self.sampling_rate is increased to 200 Hz or over, it starts to noticeably lag:

import sys
import time
import threading
import numpy as np
from pglive.sources.data_connector import DataConnector
from pglive.sources.live_axis_range import LiveAxisRange
from pglive.sources.live_plot import LiveLinePlot
from pglive.sources.live_plot_widget import LivePlotWidget
from PySide6.QtWidgets import QApplication
import pyqtgraph as pg

class Window(pg.LayoutWidget):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.plot_rate = 15  # sets the plot rate in Hz
        self.sampling_rate = 15  # sets the sampling rate in hz

        self.packet_size = 16  # sets the packet size in number of samples
        self.packet_time = self.packet_size / self.sampling_rate # sets the time between packets in seconds
        self.plot_slice_width = self.sampling_rate / self.plot_rate  # sets the length of the data array to be plotted

        self.connector_points = 100  # sets the connector size in number of points
        self.roll_on_tick = self.connector_points  # sets the roll on tick value

        self.time_list, self.amplitude_list = [], []  # initialize lists use to collect data
        self.time, self.amplitude = 0, 0  # initialize variables
        self.running = False

        plot_widget = LivePlotWidget(x_range_controller=LiveAxisRange(roll_on_tick=self.roll_on_tick))
        self.addWidget(plot_widget)
        plot_curve = LiveLinePlot()
        plot_widget.addItem(plot_curve)
        self.data_connector = DataConnector(plot_curve, max_points=self.connector_points, plot_rate=self.plot_rate)

    def generate_data(self):
        generation_loop = 0  # data generation loop counter
        while self.running:
            time.sleep(self.packet_time)

            if generation_loop == 0:
                self.time, step = np.linspace(0, generation_loop+1, self.packet_size, retstep=True)
            else:
                self.time, step = np.linspace(self.time[-1] + step, generation_loop+1, self.packet_size, retstep=True)

            self.amplitude = np.sin(self.time)

            self.time_list.extend(self.time)
            self.amplitude_list.extend(self.amplitude)

            generation_loop += 1

    def plot_data(self):
        plot_loop = 0  # plot loop counter
        while self.running:
            time.sleep(1/self.plot_rate)  # sleep at the same frequency as the plot rate
            if len(self.time_list) > plot_loop+1 * self.plot_slice_width:
                slice_start = int(plot_loop * self.plot_slice_width)
                slice_end = int((plot_loop + 1) * self.plot_slice_width)

                time_data = self.time_list[slice_start:slice_end]
                amplitude_data = self.amplitude_list[slice_start:slice_end]

                self.data_connector.cb_append_data_array(amplitude_data, time_data)

                plot_loop += 1

    def start_app(self):
        self.running = True
        threading.Thread(target=self.generate_data).start()
        threading.Thread(target=self.plot_data).start()

# Start application
app = QApplication(sys.argv)
window = Window()
window.show()
window.start_app()
app.exec()

Let me know if this sample code doesn't work for you and I can adjust it as needed

slartz42 commented 1 year ago

Actually now that I look at this closer, there might be some kind of division error somewhere causing this. With a sampling rate of 300 Hz and a connector width of 1000 points, everything works fine. When I change the sampling rate to 301 Hz, it stops working properly. If I force the slice width to be an integer, it works again.

Hopefully this isn't an issue with my code, but that's also very possible

domarm-comat commented 1 year ago

Thanks for your input again. I briefly tested it. There is definetly something wrong. Most likely LiveAxis display region calculation. I set sampling rate to 401 and plot rate to 1Hz. I didn't see any line. Then I zoomed out and saw plot progressing correctly at 1Hz, but autorange was not properly working. Therefore there was nothing plotted. Right now, I'm quite busy with othert stuff. But hopefully will find some time soon to debug and fix this issue.

optio50 commented 1 year ago

Roll on tick seems to be an issue for me as well. I can see a single vertical line that appears top be massively zoomed out (this includes the X axis timeline as well). It takes a lot of zooming in to see the trace as it is sampled.

Auro-93 commented 10 months ago

Hello,

I hope this issue's topic suits my question. I would kindly request clarification on the functionality of the 'roll_on_tick' parameter. I'm currently working on developing a Python GUI for multi-channel live plotting (displaying multiple line charts) of real-time acquired data.

For these charts, I'm able to set the following parameters:

I'm encountering issues while setting this temporal window on the chart, particularly when manipulating the 'roll_on_tick' parameter, resulting in inconsistent outcomes. This might be due to my limited experience in PyQt and live plotting.

Hence, I have a theoretical rather than technical question: What exactly does 'roll_on_tick' entail? How is this parameter correlated with others such as 'update_rate,' 'bin_width,' and 'time_span'?

For a more detailed overview of the problem I'm facing, I've elaborated on Stack Overflow at: link.

Thank you very much.