I have a QAbstractListModel (SitesModel) that has two roles (x_test, y_test). Each contains a list of values (e.g., [1, 2, 3], [0.1, 0.7, 0.3]). My implementation of the QAbstractListModel works well and populates a ListView QML-side.
I then have a QSortFilterProxyModel (SiteFilter) which takes the SitesModel as source. This is there to allow users to see one sitesModel row at a time (i.e., it filters the last row). This also works nicely.
Now I want to chart the x_test, y_test list values of the SiteFilter row in a ChartView on the QML end. I have come across VXYModelMapper, which seems ideal - however, it only accepts table columns as input.
After some reading I came across a thread suggesting a QIdentityProxyModel could be used to transform the roles into columns for use in VXYModelMapper. The actual solution is never provided, though.
I have attempted to implement QIdentityProxyModel but I'm a bit lost on how to use it. Particularly, I'm not sure how to actually do the role - column transformation. Should I be implementing mapFromSource to convert the x_test, y_test lists to columns?
My full implementation (with some minor code omitted) so far is below (PySide6).
app.py
def main():
...
sites_model = core.SitesModel()
site_filter = core.SiteFilter()
site_filter.setSourceModel(sites_model)
site_chart = core.SiteChart()
site_chart.setSourceModel(site_filter)
engine.rootContext().setContextProperty("sitesModel", sites_model)
engine.rootContext().setContextProperty("siteFilterModel", site_filter)
engine.rootContext().setContextProperty("siteChartModel", site_chart)
...
core.py
class Site:
# class for a single site
def __init__(self, **kwargs):
props_defaults = {
'x_test': [],
'y_test': []
}
for (prop, default) in props_defaults.items():
setattr(self, prop, kwargs.get(prop, default))
class SitesModel(QtCore.QAbstractListModel):
# core list model containing n sites
XTestRole = QtCore.Qt.UserRole + 1
YTestRole = QtCore.Qt.UserRole + 2
def __init__(self, parent=None):
super(SitesModel, self).__init__(parent)
self._sites = []
self.testing() # populates a few rows of class Site for testing
# roleNames ...
# data ...
# setData ...
# rowCount ...
# etc...
# testing ...
class SiteFilter(QtCore.QSortFilterProxyModel):
# filters SitesModel to last row
def __init__(self, parent=None):
super(SiteFilter, self).__init__(parent)
self.row_filter_id = None
def clearFilter(self):
self.row_filter_id = None
self.invalidateFilter()
def filterAcceptsRow(self, source_row, source_parent):
if self.row_filter_id:
if source_row == self.row_filter_id:
return True
return False
@QtCore.Slot()
def setFilterToLastRow(self):
sites = self.sourceModel()._sites
if sites:
last_id = max([site.id for site in sites])
self.row_filter_id = last_id
self.invalidateFilter()
class SiteChart(QtCore.QIdentityProxyModel):
def __init__(self, parent=None):
super(SiteChart, self).__init__(parent)
# need to access x_test, y_test values here and place in 2 columns.
# these columns will then be read in qml shown below
NewSite.qml
ChartView {
anchors.fill: parent
LineSeries {
VXYModelMapper {
model: siteChartModel
xColumn: 0 //x_test
yColumn: 1 //y_test
}
}
}