Plotting with python
-
Hello everyone,
This is my first time here, I am quite new to Qt. I am working on a project where I need to plot data from a csv file in a ChartView object. I have created the ui.qml file in QT design studio.
Following are the codes that I am using:Screen01.ui.qml file:
/* This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only. It is supposed to be strictly declarative and only uses a subset of QML. If you edit this file manually, you might introduce QML code that is not supported by Qt Design Studio. Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files. */ import QtQuick import QtQuick.Controls import './imports/Plot_Test' import QtCharts 2.14 Rectangle { id: rectangle width: 1296 height: 730 color: "#6e9ccc" ChartView { id: spline_view anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom anchors.bottomMargin: 20 anchors.topMargin: 20 anchors.rightMargin: 20 anchors.leftMargin: 20 SplineSeries { id: serie name: "Series" axisX: ValuesAxis { color: "#1c2b95" gridLineColor: "#6e9ccc" min: 0 max: 10 tickCount: 6 } axisY: ValuesAxis { color: "#1c2b95" gridLineColor: "#6e9ccc" min: 0 max: 30000 tickCount: 6 } Component.Component.onCompleted: { var series = spline_view.createSeries(ChartView.SeriesTypeSpline,"Random",axisX,axisY) helper.serie() } } } }
data_plot.py file
import pandas as pd from PySide6.QtCore import QPointF, Qt, QObject from PySide6.QtCharts import QChart, QChartView, QSplineSeries, QValueAxis, QXYSeries from PySide6 import QtCore class Helper(QtCore.QObject): serieChanged = QtCore.Signal() def __init__(self, parent=None): super(Helper, self).__init__(parent) self._serie = None def serie(self): return self._serie def setSerie(self, serie): if self._serie == serie: return self._serie = serie self.serieChanged.emit() serie = QtCore.Property(QSplineSeries, fget=serie, fset=setSerie, notify=serieChanged) @QtCore.Slot(list) def replace_points(self, points): if self._serie is not None: self._serie.replace(points) class Provider(QtCore.QObject): pointsChanged = QtCore.Signal(list) # def __init__(self, parent=None): # super(Provider, self).__init__(parent) # timer = QtCore.QTimer( # self, # interval=100, # timeout=self.generate_points # ) # timer.start() @QtCore.Slot() def generate_points(self): points = [] df = pd.read_csv('NK_Heavy.csv') x = df['x'] for i in range(len(x)): point = QtCore.QPointF(i, x) points.append(point) self.pointsChanged.emit(points)
main.py file:
# This Python file uses the following encoding: utf-8 import os from pathlib import Path import sys from PySide6.QtCore import QCoreApplication, Qt, QUrl from PySide6.QtWidgets import QApplication from PySide6.QtQml import QQmlApplicationEngine import data_plot CURRENT_DIRECTORY = Path(__file__).resolve().parent def main(): app = QApplication(sys.argv) helper = data_plot.Helper() provider = data_plot.Provider() provider.pointsChanged.connect(helper.replace_points) engine = QQmlApplicationEngine() engine.rootContext().setContextProperty('helper', helper) filename = os.fspath(CURRENT_DIRECTORY / "main.qml") url = QUrl.fromLocalFile(filename) def handle_object_created(obj, obj_url): if obj is None and url == obj_url: QCoreApplication.exit(-1) engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection) engine.load(url) sys.exit(app.exec()) if __name__ == "__main__": main()
On running the following code, I am not able to get the plot and it shows the error as:
QMetaProperty::read: Unable to handle unregistered datatype 'QSplineSeries*' for property 'Helper::serie'
-
Thank you @SGaist I was able to remove the error, but still I am not able to see anything on my plot. It gives a blank chart. Can you help me with a link to a sample code, where I can understand how to send my .csv file data from python to QML?
-
I do not see anywhere in your code a line where you're adding series to the plot.
-
That's where I am confused, I tried adding it through qml file. I am following the example mentioned in this link I just removed the timer part, as I don't want an updating plot.
link: https://stackoverflow.com/questions/55257134/how-can-i-change-all-the-points-in-an-xyseries-in-qml-or-pyside2 -
You need to trigger the timer once otherwise no data will be generated.
-
@SGaist Thank you for your response, I was able to plot the data using following changes to my code:
main.qml:
Component.onCompleted: { console.log("This is main.QML") var plot = spline_view.createSeries(ChartView.SeriesTypeSpline,"Random",axisX,axisY) plotter.fill_serie(plot) // console.log(plotter.fill_serie(plot)) var ymax = plotter.max_yaxis(axisY) var ymin = plotter.min_yaxis(axisY) var xmax = plotter.max_xaxis(axisX) var xmin = plotter.min_xaxis(axisX) }
data_plot.py:
class DataModel(QObject): @Slot(QSplineSeries) def fill_serie(self, plot): self.df = pd.read_csv('gvk_normal_minus_ambient.csv') x = self.df['x'] count = 0 l = [] for i in range(0,len(x)): point = QPointF(count, x[i]) # point = x[i] plot.append(point) count += 1 # https://doc.qt.io/qt-5/qml-qtcharts-scatterseries.html#borderColor-prop # plot.setProperty("borderColor", QtGui.QColor("salmon")) # https://doc.qt.io/qt-5/qml-qtcharts-scatterseries.html#brush-prop plot.setProperty("color", QtGui.QBrush(QtGui.QColor("red"))) # https://doc.qt.io/qt-5/qml-qtcharts-scatterseries.html#borderColor-prop plot.setProperty("borderWidth", 4.0) @Slot(QValueAxis) def min_yaxis(self, yaxis): yaxis.setProperty('min', min(self.df['x'])) @Slot(QValueAxis) def max_yaxis(self, yaxis): yaxis.setProperty('max', max(self.df['x'])) @Slot(QValueAxis) def min_xaxis(self, xaxis): xaxis.setProperty('min', 0) xaxis.setProperty('tickCount', 6) xaxis.setProperty('tickType', 'TicksDynamic') @Slot(QValueAxis) def max_xaxis(self, xaxis): xaxis.setProperty('max', len(self.df['x']))
But the problem is:
The sampling frequency of the data is 10hz. So when I plot all the data, as shown indata_plot.py
. I get following graph:As you can see, the tick values for x-axis are 0-300, but I want to make it from 0-30. I searched all over the internet to set custom labels for x-ticks but I didn't find any solution.
-
This is a different issue that should have it's own thread as it's not related to the problem at hand.
You should also mark this thread as solved.