Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plotting refactor #2940

Draft
wants to merge 52 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
d944176
initial state for copying from local disk to sasview plot_refactoring…
juliuskarliczek Jun 27, 2024
4d07568
logic for checking if a dataset is a 2d dataset. inside subtabs, a lo…
juliuskarliczek Jun 27, 2024
596bdec
change drop acceptance of plottreewidget: now only the items that can…
juliuskarliczek Jun 27, 2024
9126553
plottreewidget now represents 2d data as supposed to be. plotting fun…
juliuskarliczek Jun 28, 2024
2c87007
implemented 2d plotting logic
juliuskarliczek Jun 28, 2024
f6204f6
add dock widget logic for subtabs
juliuskarliczek Jul 10, 2024
c816b34
added plotting changes: one big plot in the middle and other small pl…
juliuskarliczek Jul 11, 2024
7307146
dropping logic: plotwindow will now show the specific pages that a mo…
juliuskarliczek Jul 12, 2024
4afeb29
add txts from meeting notes and sketches
juliuskarliczek Jul 23, 2024
5967b55
Non logic changing changes for DataCollector.py. Docstrings, changing…
juliuskarliczek Jul 29, 2024
a57b4c2
Rename get_fitpage_fp and get_fitpage_id to get_fitpage_by_fp and get…
juliuskarliczek Jul 29, 2024
b1d2be5
use find_object_by_property in DataCollector.py to iterate over the l…
juliuskarliczek Jul 29, 2024
7871fd9
update datasets to be privite with _datasets and use property decorat…
juliuskarliczek Jul 29, 2024
feda56a
Stop Mainwindow.py from being executed every time it is imported. Wra…
juliuskarliczek Jul 29, 2024
788d85b
update txt
juliuskarliczek Jul 30, 2024
9484ec4
change method header, because main window is already a class variable
juliuskarliczek Aug 1, 2024
9f53141
remove unused commented section from earlier tests in RandomDatasetCr…
juliuskarliczek Aug 1, 2024
62cde3a
add docstrings for RandomDatasetCreator.py
juliuskarliczek Aug 1, 2024
d7b450d
docstring Dataset.py
juliuskarliczek Aug 1, 2024
6c6a320
docstrings and bettercomments for DataViewer.py. Fixed small issue fo…
juliuskarliczek Aug 2, 2024
85c1438
forgot to commit the mainwindow.py one commit earlier
juliuskarliczek Aug 2, 2024
c86cab4
Comments for MainWindow.py. Small change for one method call from onC…
juliuskarliczek Aug 2, 2024
35a3531
make colormaps applicable to 2d plots
juliuskarliczek Aug 5, 2024
d4316bb
delete print statement
juliuskarliczek Aug 5, 2024
1cdf37d
DataTreeWidget: add docstrings and type specifics for method headers
juliuskarliczek Aug 6, 2024
da3f350
Dataset.py: Add type specifics to method parameters. Add return types…
juliuskarliczek Aug 7, 2024
0d0efa5
Add properties to a lot of classes and change the method calling
juliuskarliczek Aug 7, 2024
087ab1b
move Ui files to ui folder and change imports
juliuskarliczek Aug 7, 2024
08dacdb
remove *ui.ui and *ui.py files from main folder
juliuskarliczek Aug 7, 2024
f7d9303
add UI folder and *UI.ui files in there
juliuskarliczek Aug 7, 2024
05ba173
add docstring FitPage.py
juliuskarliczek Aug 7, 2024
ad0daf0
FitPage.py change identifier to be a property
juliuskarliczek Aug 7, 2024
ee03473
update identifier comment FitPage.py
juliuskarliczek Aug 7, 2024
f5eafef
change method parameter type specification and return type specification
juliuskarliczek Aug 7, 2024
5abe666
remove unnecessary imports
juliuskarliczek Aug 7, 2024
56154bc
Docstrings for PlotTreeItems.py and little formatting typo in SubTabs.py
juliuskarliczek Aug 7, 2024
082d5f0
formatting stuff SubTabs.py. remove unused method for returning the f…
juliuskarliczek Aug 8, 2024
921e9a1
Comments and docstrings for SubTabs.py
juliuskarliczek Aug 8, 2024
99f205d
Add gray out on dock out mechanism
juliuskarliczek Aug 9, 2024
061a17f
property call typo correction
juliuskarliczek Aug 9, 2024
aff5ca2
update dataviewer, so that the datatreewidget does not produce double…
juliuskarliczek Aug 16, 2024
ba66be0
implement correct bookkeeping for plottreewidget when closing a tab
juliuskarliczek Aug 16, 2024
b6a7389
update agenda.txt
juliuskarliczek Aug 19, 2024
95d7722
update agenda.txt
juliuskarliczek Aug 20, 2024
f0b4411
update agenda.txt again
juliuskarliczek Aug 20, 2024
0deb9bf
reworked Agenda.txt
juliuskarliczek Sep 10, 2024
38bf454
update the agenda more and delete unnecessary variables in MainWindow.py
juliuskarliczek Sep 23, 2024
2c10a86
add comments regarding type_nums it PlotTreeItems.py
juliuskarliczek Sep 24, 2024
f9360a0
change redrawAll to redraw for appropriate naming
juliuskarliczek Sep 24, 2024
a5f20f0
PlotTreeWidget.py comments
juliuskarliczek Sep 26, 2024
231e92c
PlotTreeWidget.py comment correction
juliuskarliczek Sep 26, 2024
c985f66
Add larger documentation file to plotting_refactor/notes_and_sketches
juliuskarliczek Sep 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions plotting_refactor/DataCollector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
from PySide6 import QtWidgets
import RandomDatasetCreator
from Dataset import Dataset

class DataCollector:
"""
This class keeps track of all generated datasets. When the update_dataset is called through onCalculate
from MainWindow, either a new dataset can be created or the existing dataset is adjusted with respect to
the currently displayed SpinBox Values from the Fitpage.
"""
def __init__(self):
self._datasets: list[Dataset] = []
self.datasetcreator = RandomDatasetCreator.DatasetCreator()

def update_dataset(self, main_window: QtWidgets.QMainWindow, fitpage_index: int,
create_fit: bool, checked_2d: bool):
"""
Search for an existing dataset saved in here. If no dataset for the corresponding fitpage exists: create new
data.
"""

# search for an existing dataset with the right fitpage_index
existing_dataset_index = -1
for i, dataset in enumerate(self._datasets):
if dataset.get_fitpage_index() == fitpage_index:
existing_dataset_index = i

if existing_dataset_index == -1:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add new line between blocks, if you like

# create new dataset in case it does not exist
x_data, y_data, y_fit = self.simulate_data(main_window, create_fit, checked_2d)
plotpage_index = -1

dataset = Dataset(fitpage_index, x_data, y_data, y_fit, checked_2d, plotpage_index)
self._datasets.append(dataset)
else:
# update values for existing dataset with respect to the number boxes in the fitpage
x_data, y_data, y_fit = self.simulate_data(main_window, create_fit, checked_2d)
self._datasets[existing_dataset_index].set_x_data(x_data)
self._datasets[existing_dataset_index].set_y_data(y_data)
self._datasets[existing_dataset_index].set_y_fit(y_fit)
self._datasets[existing_dataset_index].set_2d(checked_2d)

def simulate_data(self, main_window: QtWidgets.QMainWindow, create_fit: bool, checked_2d: bool):
"""
Collect all information from the FitPage from the MainWindow hat is needed to calculate the test data.
Feed this information to the DatasetCreator and return the values.
"""
combobox_index = main_window.fittingTabs.currentWidget().get_combobox_index()
param_scale = main_window.fittingTabs.currentWidget().doubleSpinBox_scale.value()
param_radius = main_window.fittingTabs.currentWidget().doubleSpinBox_radius.value()
param_height = main_window.fittingTabs.currentWidget().doubleSpinBox_height.value()

x_data, y_data, y_fit = self.datasetcreator.createRandomDataset(param_scale, param_radius, param_height,
combobox_index, create_fit, checked_2d)

return x_data, y_data, y_fit

@property
def datasets(self) -> list:
return self._datasets

def find_object_by_property(self, obj_list: list, property_name: str, property_value: int):
for obj in obj_list:
if hasattr(obj, property_name) and getattr(obj, property_name) == property_value:
return obj

return None

def get_data_by_fp(self, fitpage_index: int) -> Dataset:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better name would just be data_by_id

"""
Get the dataset for a certain fitpage
"""
return self.find_object_by_property(self._datasets, "fitpage_index", fitpage_index)

def get_data_by_id(self, data_id: int) -> Dataset:
"""
Get the dataset for certain id
"""
return self.find_object_by_property(self._datasets, "data_id", data_id)

def get_x_data(self, fitpage_index: int) -> list:
"""
Get x data for certain fitpage index
"""
dataset = self.find_object_by_property(self._datasets, "fitpage_index", fitpage_index)
return dataset.get_x_data()

def get_y_data(self, fitpage_index: int) -> list:
"""
Get y data for certain fitpage index
"""
dataset = self.find_object_by_property(self._datasets, "fitpage_index", fitpage_index)
return dataset.get_y_data()

def get_y_fit_data(self, fitpage_index: int) -> list:
"""
Get y fit data for certain fitpage index
"""
dataset = self.find_object_by_property(self._datasets, "fitpage_index", fitpage_index)
return dataset.get_y_fit()

def get_plotpage_index(self, fitpage_index: int) -> int:
"""
Get the plotpage index for a certain fitpage index: Plotpage index refers to the index of the major tabs in
the plotting widget in which the data is displayed.
"""
dataset = self.find_object_by_property(self._datasets, "fitpage_index", fitpage_index)
return dataset.get_plotpage_index()

def set_plot_index(self, fitpage_index: int, plot_index: int):
"""
Set the plotpage index for the dataset for a certain fitpage index. Plotpage index refers to the index of the
major tabs in the plotting widget in which the data is displayed.
"""
dataset = self.find_object_by_property(self._datasets, "fitpage_index", fitpage_index)
dataset.set_plotpage_index(plot_index)

25 changes: 25 additions & 0 deletions plotting_refactor/DataTreeItems.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from PySide6.QtWidgets import QTreeWidgetItem

class PlotPageItem(QTreeWidgetItem):
def __init__(self, parent, name, fitpage_index, data_id):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

types

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring

super().__init__(parent, name)
self.fitpage_index = fitpage_index
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These look like private variables, consider doing self._fitpage_index instead

self.data_id = data_id
super().setData(0, 1, self)

def get_fitpage_index(self):
return self.fitpage_index

def get_data_id(self):
return self.data_id

class DataItem(PlotPageItem):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These do not need to inherit from one another. The DataItem instances should be held within a PlotPageItem instead.

def __init__(self, parent, name, fitpage_index, data_id, type_num):
super().__init__(parent, name, fitpage_index, data_id)
# self.type_num saves if the item is a data item or a fit item in the tree widget
# identifier=1 is for data and identifier=2 is for fit identifier=3 is for residuals
self.type_num = type_num

def get_type_num(self):
return self.type_num

25 changes: 25 additions & 0 deletions plotting_refactor/DataTreeWidget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from PySide6.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView
from PySide6.QtCore import QMimeData, QRect, QByteArray, QDataStream, QIODevice
from PySide6.QtGui import QDrag
from DataTreeItems import DataItem

class DataTreeWidget(QTreeWidget):
def __init__(self, DataViewer, datacollector):
super().__init__(parent=DataViewer)
self.datacollector = datacollector
self.setGeometry(QRect(10, 10, 391, 312))
self.setDragEnabled(True)
self.setColumnCount(1)
self.setHeaderLabels(["Data Name"])

def startDrag(self, supportedActions):
item = self.currentItem()
if item:
if isinstance(item.data(0, 1), DataItem):
drag = QDrag(self)
mimeData = QMimeData()
mimeData.setData('ID', QByteArray(str(item.data(0, 1).get_data_id())))
mimeData.setData('Type', QByteArray(str(item.data(0, 1).get_type_num())))

drag.setMimeData(mimeData)
drag.exec(supportedActions)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you drag these objects to places outside the window, what happens then?

205 changes: 205 additions & 0 deletions plotting_refactor/DataViewer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
from PySide6 import QtWidgets

from DataViewerUI import Ui_DataViewer
from PlotWidget import PlotWidget
from DataTreeWidget import DataTreeWidget
from PlotTreeWidget import PlotTreeWidget
from DataCollector import DataCollector
from DataTreeItems import PlotPageItem, DataItem
from PlotTreeItems import TabItem, SubTabItem, PlotItem, PlottableItem
from PlotModifiers import ModifierLinecolor, ModifierLinestyle, ModifierColormap, PlotModifier


class DataViewer(QtWidgets.QWidget, Ui_DataViewer):
"""
Class for interface between Plotwidget and Datacollector. Processing of signals for plotting,
redrawing of existing plots, adding new plot modifiers ends here.
"""
def __init__(self, main_window):
"""
Main Window is used as a parameter in the constructor to be able to hand it further to the Datacollector which
can then directly read values from checkboxes and spinboxes for new model calculations.

self.dataTreeWidget and self.plotTreeWidget represent data that exists in the DataCollector or existing plots
in the plot widget, respectively.
"""
super(DataViewer, self).__init__()
self.setupUi(self)

self.main_window = main_window
self.datacollector = DataCollector()

self.dataTreeWidget = DataTreeWidget(self, self.datacollector)
self.plotTreeWidget = PlotTreeWidget(self)

self.cmdClose.clicked.connect(self.onShowDataViewer)
self.cmdAddModifier.clicked.connect(self.onAddModifier)
self.plotTreeWidget.dropSignal.connect(self.redrawAll)

self.setupMofifierCombobox()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mofifier?

self.plot_widget = PlotWidget(self.datacollector)

def create_plot(self, fitpage_index):
self.update_plot_tree(fitpage_index)
self.plot_widget.show()
self.plot_widget.activateWindow()

def update_datasets_from_collector(self):
"""
Collects datasets from the datacollector and adds them to the dataTreeWidget. Is called upon a plot or
calculation request from the mainwindow
"""
datasets = self.datacollector.datasets
for i in range(len(datasets)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for i, dataset in enumerate(datasets): - This will give you both the index and indexed dataset. Calling dataset[i] has a time cost everytime it is invoked.

fitpage_index = datasets[i].get_fitpage_index()
name = "Data from Fitpage " + str(fitpage_index)
data_id = datasets[i].get_data_id()
item = PlotPageItem(self.dataTreeWidget, [name], fitpage_index, data_id)
item.setData(0, 1, item)
subitem_data = DataItem(item, ["Data"], fitpage_index, data_id, 1)
subitem_data.setData(0, 1, subitem_data)
if datasets[i].has_y_fit():
subitem_fit = DataItem(item, ["Fit"], fitpage_index, data_id, 2)
subitem_fit.setData(0, 1, subitem_fit)

self.dataTreeWidget.expandAll()

def onShowDataViewer(self):
"""
Function for handling showing and hiding of the data viewer and the button for that in the main window
"""
if self.isVisible():
self.hide()
self.main_window.cmdShowDataViewer.setText("Show Data Viewer")
else:
self.update_datasets_from_collector()
self.show()
self.main_window.cmdShowDataViewer.setText("Hide Data Viewer")

def update_dataset(self, fitpage_index, create_fit, checked_2d):
"""
Updates existing or non-existing datasets in the datacollector for a fitpage in the mainwindow
"""
self.datacollector.update_dataset(self.main_window, fitpage_index, create_fit, checked_2d)

def update_plot_tree(self, fitpage_index):
"""
Function to populate the plotTreeWidget for a certain fitpage. Checks if a plot for the given fitpage already
exists and recreates it if so. Therefore it collects all the data for the given fitpage from the datacollector
and creates the Tabs, Subtabs, Plots, Plottables for the plotTreeWidget. This mechanism also checks, if a
dataitem that comes from the datacollector is 2d. If it is 2d, the type_num for this PlottableItem will be
different (4 instead of 1) and the SubTabs.py can recognize, that only this 2d data can be plotted in one
actual plot.
"""
# check if an item for the fitpage index already exists
# if one is found - remove from tree
for i in range(self.plotTreeWidget.topLevelItemCount()):
if isinstance(self.plotTreeWidget.topLevelItem(i), TabItem):
if fitpage_index == self.plotTreeWidget.topLevelItem(i).data(0, 1).get_fitpage_index():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be all on one line. Python evaluates each part of an if statement individually and from left to right, so there will be no cost or increase in errors by combining these.

if isinstance(self.plotTreeWidget.topLevelItem(i), TabItem) and fitpage_index == self.plotTreeWidget.topLevelItem(i).data(0, 1).get_fitpage_index():

self.plotTreeWidget.takeTopLevelItem(i)

# add tab
tab_name = "Plot for Fitpage " + str(fitpage_index)
tab_item = TabItem(self.plotTreeWidget, [tab_name], fitpage_index)
tab_item.setData(0, 1, tab_item)

# add data child and corresponding plot children in every case
subtab_data = SubTabItem(tab_item, ["Data"], fitpage_index, 0)
subplot_data = PlotItem(subtab_data, ["Data Plot"], fitpage_index, 0, 0,
self.datacollector.get_data_by_fp(fitpage_index).is_2d())
fitpage_id = self.datacollector.get_data_by_fp(fitpage_index).get_data_id()

# create plottables in the plottreewidget with indicators (type_nums) to identify what kind of plot it is while
# plotting in subtabs.py: type_num = 1 : 1d data, type_num = 2 : 1d fit, type_num = 3 : 1d residuals
# type_num = 4 : 2d data, type_num = 5 : 2d fit, type_num = 6 : 2d residuals
# 2d plots cannot overlap each other as curves can do
# for every 2d data an additional plot is added and 1 plottable is inserted
if self.datacollector.get_data_by_fp(fitpage_index).is_2d():
plottable_data = PlottableItem(subplot_data, ["2d " + str(fitpage_id)], fitpage_id, 4)
else:
plottable_data = PlottableItem(subplot_data, [str(fitpage_id)], fitpage_id, 1)

#add fit and residuals in case it was generated
if self.datacollector.get_data_by_fp(fitpage_index).has_y_fit():
# on the fit tab: one central plot that shows the dataset and the according fit curve
# create tab for fit and residual plot
subtab_fit = SubTabItem(tab_item, ["Fit"], fitpage_index, 1)
subtab_residuals = SubTabItem(tab_item, ["Residuals"], fitpage_index, 2)
# if the data is 2d, then every plot contains only one plottable
if self.datacollector.get_data_by_fp(fitpage_index).is_2d():
subplot_data_subtab_fit = PlotItem(subtab_fit, ["Data"], fitpage_index, 1, 0, True)
plottable_subplot_data_subtab_fit = PlottableItem(subplot_data_subtab_fit, ["2d Plottable Fit Data"], fitpage_id, 4)

subplot_fit_subtab_fit = PlotItem(subtab_fit, ["Fit"], fitpage_index, 1, 1, True)
plottable_subplot_fit_subtab_fit = PlottableItem(subplot_fit_subtab_fit, ["2d Plottable Fit Fit"], fitpage_id, 5)


subplot_data_subtab_residuals = PlotItem(subtab_residuals, ["Data"], fitpage_index, 2, 0, True)
plottable_subplot_data_subtab_residuals = PlottableItem(subplot_data_subtab_residuals, ["2d Plottable Residuals Data"], fitpage_id, 4)

subplot_fit_subtab_residuals = PlotItem(subtab_residuals, ["Fit"], fitpage_index, 2, 1, True)
plottable_subplot_fit_subtab_residuals = PlottableItem(subplot_fit_subtab_residuals, ["2d Plottable Residuals Fit"], fitpage_id, 5)

subplot_residuals_subtab_residuals = PlotItem(subtab_residuals, ["Residuals"], fitpage_index, 2, 2, True)
plottable_subplot_residuals_subtab_residuals = PlottableItem(subplot_residuals_subtab_residuals, ["2d Plottable Residuals Residuals"], fitpage_id, 6)

else: # if the data is 1d, multiple plottables can be plotted in one plot
subplot_fit = PlotItem(subtab_fit, ["Fit Plot"], fitpage_index, 1, 0, False)
plottable_fit_data = PlottableItem(subplot_fit, ["Plottable Fit Data"], fitpage_id, 1)
plottable_fit_fit = PlottableItem(subplot_fit, ["Plottable Fit Fit"], fitpage_id, 2)

# on the residuals subtab: create 2 plots with 3 datasets: on the top plot is the data and the fit,
# on the bottom plot is the residuals displayed with the same x-axis for comparison
subplot_residuals_fit = PlotItem(subtab_residuals, ["Fit Plot"], fitpage_index, 2, 0, False)
plottable_res_data = PlottableItem(subplot_residuals_fit, ["Plottable Res Data"], fitpage_id, 1)
plottable_res_fit = PlottableItem(subplot_residuals_fit, ["Plottable Res Fit"], fitpage_id, 2)

subplot_res = PlotItem(subtab_residuals, ["Residuals Plot"], fitpage_index, 2, 1, False)
plottable_res = PlottableItem(subplot_res, ["Plottable Residuals"], fitpage_id, 3)

self.plotTreeWidget.expandAll()
self.redrawAll(fitpage_index, 0)

def redrawAll(self, redraw_fitpage_index, redraw_subtab_index):
"""
Redraws all tabs in the plotTreeWidget. parameters redraw_fitpage_index and redraw_subtab_index are used to show
the subtab for which the redrawAll was invoked, because a modifier was dragged onto a child plot or plottable
item in the plotTreeWidget.
If redrawing is invoked from the update_plot_tree method, only the fitpage_index will be used but 0 for
the subplot.
"""
if self.plotTreeWidget.topLevelItemCount() != 0:
for i in range(self.plotTreeWidget.topLevelItemCount()):
if isinstance(self.plotTreeWidget.topLevelItem(i).data(0, 1), TabItem):
self.plot_widget.redrawTab(self.plotTreeWidget.topLevelItem(i))

plotpage_index = self.datacollector.get_plotpage_index(redraw_fitpage_index)
self.plot_widget.setCurrentIndex(plotpage_index)
self.plot_widget.widget(plotpage_index).setCurrentIndex(redraw_subtab_index)

def onAddModifier(self):
"""
Add modifiers via button press to the plotTreeWidget. These can then be dragged around on PlotItems and
PlottableItems. Logic for dragging is in the PlotTreeWidget.py.
"""
currentmodifier = self.comboBoxModifier.currentText()
if 'color' in currentmodifier:
mod = ModifierLinecolor(self.plotTreeWidget, [currentmodifier])
if 'linestyle' in currentmodifier:
mod = ModifierLinestyle(self.plotTreeWidget, [currentmodifier])
if 'scheme' in currentmodifier:
mod = ModifierColormap(self.plotTreeWidget, [currentmodifier])
def setupMofifierCombobox(self):
"""
Gives all the different available modifiers to the combobox so that they can be created by user selection.
"""
self.comboBoxModifier.addItem("color=r")
self.comboBoxModifier.addItem("color=g")
self.comboBoxModifier.addItem("color=b")
self.comboBoxModifier.addItem("linestyle=solid")
self.comboBoxModifier.addItem("linestyle=dashed")
self.comboBoxModifier.addItem("linestyle=dotted")
self.comboBoxModifier.addItem("scheme=jet")
self.comboBoxModifier.addItem("scheme=spring")
self.comboBoxModifier.addItem("scheme=gray")

Loading
Loading