Skip to content

Commit 737cde8

Browse files
juliuskarliczekbackmari
authored andcommitted
Multiple plots can be plotted in one window on the first try. Therefore i introduced some way to reorganize the already existing axes in a subtab window.
1 parent 68e8693 commit 737cde8

4 files changed

Lines changed: 61 additions & 50 deletions

File tree

src/sas/qtgui/MainWindow/DataExplorer.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,20 +1099,19 @@ def displayDataByName(self, name=None, is_data=True, id=None):
10991099
# Residuals get their own plot
11001100
if plot.plot_role in [DataRole.ROLE_RESIDUAL, DataRole.ROLE_STAND_ALONE]:
11011101
plot.yscale = 'linear'
1102-
self.plotData([(item, plot)])
1102+
self.plotData([(item, plot)], id)
11031103
else:
11041104
new_plots.append((item, plot))
11051105

11061106
if new_plots:
1107-
self.plotData(new_plots)
1107+
self.plotData(new_plots, id)
11081108

1109-
def displayData(self, data_list, id=None):
1109+
def displayData(self, data_list, id):
11101110
"""
11111111
Forces display of charts for the given data set
11121112
"""
1113-
# data_list = [QStandardItem, [Axes] Data1D/Data2D]
1114-
plots_to_show = data_list[2:]
1115-
tpw_ax = data_list[1]
1113+
# data_list = [QStandardItem, Data1D/Data2D]
1114+
plots_to_show = data_list[1:]
11161115
plot_item = data_list[0]
11171116

11181117
# plots to show
@@ -1133,7 +1132,7 @@ def displayData(self, data_list, id=None):
11331132
if self.isPlotShown(main_data):
11341133
self.active_plots[main_data.name].showNormal()
11351134
else:
1136-
self.plotData([(plot_item, tpw_ax, main_data)])
1135+
self.plotData([(plot_item, main_data)], id)
11371136

11381137
append = False
11391138
plot_to_append_to = None
@@ -1159,7 +1158,7 @@ def displayData(self, data_list, id=None):
11591158
continue
11601159
elif role in stand_alone_types:
11611160
# Stand-alone plots should always be separate
1162-
self.plotData([(plot_item, tpw_ax, plot_to_show)])
1161+
self.plotData([(plot_item, plot_to_show)], id)
11631162
elif append:
11641163
# Assume all other plots sent together should be on the same chart if a previous plot exists
11651164
if not plot_to_append_to:
@@ -1177,8 +1176,8 @@ def displayData(self, data_list, id=None):
11771176
and not isinstance(main_data, Data2D)
11781177
and role != DataRole.ROLE_SIZE_DISTRIBUTION
11791178
):
1180-
new_plots.append((plot_item, tpw_ax, main_data))
1181-
new_plots.append((plot_item, tpw_ax, plot_to_show))
1179+
new_plots.append((plot_item, main_data))
1180+
new_plots.append((plot_item, plot_to_show))
11821181

11831182
if append:
11841183
# Append any plots handled in loop before an existing plot was found
@@ -1188,7 +1187,7 @@ def displayData(self, data_list, id=None):
11881187
new_plots = []
11891188

11901189
if new_plots:
1191-
self.plotData(new_plots)
1190+
self.plotData(new_plots, id)
11921191

11931192
self.parent.tabbedPlotWidget.show_or_activate()
11941193

@@ -1226,18 +1225,22 @@ def addDataPlot2D(self, plot_set, item):
12261225
# sv.show()
12271226
# ============================================
12281227

1229-
def plotData(self, plots, transform=True):
1228+
def plotData(self, plots, tab_id, transform=True):
12301229
"""
12311230
Takes 1D/2D data and generates a single plot (1D) or multiple plots (2D)
12321231
"""
1232+
tab_index = self.parent.tabbedPlotWidget.tab_fitpage_dict[tab_id]
1233+
print("plotData")
12331234
# Call show on requested plots
12341235
# All same-type charts in one plot
1235-
for item, tpw_ax, plot_set in plots:
1236+
for item, plot_set in plots:
12361237
if isinstance(plot_set, Data1D):
12371238
if 'new_plot' not in locals():
12381239
# Create only one PlotterWidget(QWidget) for a number of datasets that are supposed to be shown in
12391240
# the same Widget
1240-
print("created PlotterWidget for:", item)
1241+
self.parent.tabbedPlotWidget.widget(tab_index).add_more_axes()
1242+
tpw_ax = self.parent.tabbedPlotWidget.widget(tab_index).last_axes()
1243+
12411244
new_plot = PlotterWidget(manager=self, parent=self, tpw_ax=tpw_ax)
12421245
new_plot.item = item
12431246
# Ensure new plots use the default transform, not the transform of any previous plots the data were in
@@ -1264,7 +1267,6 @@ def plotData(self, plots, transform=True):
12641267
msg = "Incorrect data type passed to Plotting"
12651268
raise AttributeError(msg)
12661269

1267-
print("from DataExplorer.plotData: self.active_plots", self.active_plots)
12681270

12691271
if 'new_plot' in locals() and \
12701272
hasattr(new_plot, 'data') and \
@@ -1340,6 +1342,7 @@ def appendPlot(self):
13401342
@staticmethod
13411343
def appendOrUpdatePlot(self, data, plot):
13421344
name = data.name
1345+
print("append or update plot")
13431346
if isinstance(plot, Plotter2DWidget) or name in plot.plot_dict.keys():
13441347
plot.replacePlot(name, data)
13451348
else:

src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,10 +2125,8 @@ def onPlot(self) -> None:
21252125
self.cmdPlot.setText("Compute/Plot")
21262126
# Force data recalculation so existing charts are updated
21272127
if not self.data_is_loaded:
2128-
print("showTheoryPlot from FittingWidget")
21292128
self.showTheoryPlot()
21302129
else:
2131-
print("showPlot from FittingWidget")
21322130
self.showPlot()
21332131
# This is an important processEvent.
21342132
# This allows charts to be properly updated in order
@@ -2189,10 +2187,6 @@ def _requestPlots(self, item_name: str, item_model: Any) -> Any | None:
21892187

21902188
# send this information to the TabbedPlotWidget so that it can unpack and show the plots as well
21912189
self.parent.tabbedPlotWidget.add_tab(item_name, item_model, self.tab_id)
2192-
tab_index = self.parent.tabbedPlotWidget.tab_fitpage_dict[self.tab_id]
2193-
tpw_axes = self.parent.tabbedPlotWidget.widget(tab_index).ax
2194-
2195-
print("axes received in FittingWidget:", tpw_axes)
21962190
plots = GuiUtils.plotsFromDisplayName(item_name, item_model)
21972191
# Has the fitted data been shown?
21982192
data_shown = False
@@ -2201,8 +2195,10 @@ def _requestPlots(self, item_name: str, item_model: Any) -> Any | None:
22012195
item, plot = item_plot
22022196
if plot.plot_role != DataRole.ROLE_DATA and fitpage_name in plot.name:
22032197
data_shown = True
2204-
self.communicate.plotRequestedSignal.emit([item, tpw_axes[i], plot], self.tab_id)
2198+
self.communicate.plotRequestedSignal.emit([item, plot], self.tab_id)
22052199
# return the last data item seen, if nothing was plotted; supposed to be just data)
2200+
tab_index = self.parent.tabbedPlotWidget.tab_fitpage_dict[self.tab_id]
2201+
self.parent.tabbedPlotWidget.widget(tab_index).rearrange_plots()
22062202
return None if data_shown else item
22072203

22082204
def onOptionsUpdate(self) -> None:

src/sas/qtgui/Plotting/PlotterBase.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def __init__(self, parent=None, manager=None, quickplot=False, tpw_ax=None):
2828
self.quickplot = quickplot
2929

3030
# Set auto layout so x/y axis captions don't get cut off
31-
rcParams.update({'figure.autolayout': True})
31+
# rcParams.update({'figure.autolayout': True})
3232

3333
#plt.style.use('ggplot')
3434
#plt.style.use('seaborn-darkgrid')

src/sas/qtgui/Plotting/SubTabs.py

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from PySide6 import QtCore
33

44
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
5-
from matplotlib.figure import Figure
5+
import matplotlib.pyplot as plt
66

77
from sas.qtgui.Utilities import GuiUtils
88

@@ -36,8 +36,6 @@ def __init__(self, parent: TabbedPlotWidget, plots: list):
3636
def set_parent_tab_index(self):
3737
self.parent_tab_index = self.parent.indexOf(self)
3838
self.tab_id = self.parent.inv_tab_fitpage_dict[self.parent_tab_index]
39-
print(self.parent_tab_index)
40-
print(self.tab_id)
4139

4240
def add_subtab(self, plots):
4341
"""
@@ -62,34 +60,48 @@ def add_subtab(self, plots):
6260
# The idea behind creating the figure here already is to feed it to the creation of the canvas right away,
6361
# because otherwise it can be quite tricky to navigate through all the layers in between to add the figure
6462
# or manipulate all the axes for example
65-
self.figure = Figure(figsize=(5, 5))
66-
67-
# filling the slots for the plots temporary to try out the functionalities of the dock container and the
68-
# clickable canvas
69-
print("subplot_count len(plots)", len(plots))
70-
subplot_count = len(plots)
71-
if subplot_count <= 1:
72-
self.ax = self.figure.subplots(subplot_count)
73-
# putting the axes object in a list so that the access can be generic for both cases with multiple
74-
# subplots and without
75-
self.ax = [self.ax]
76-
else:
77-
# for multiple subplots: decide on the ratios for the bigger, central plot and the smaller, side plots
78-
# region for the big central plot in gridspec
79-
gridspec = self.figure.add_gridspec(ncols=2, width_ratios=[3, 1])
80-
# region for the small side plots in sub_gridspec
81-
sub_gridspec = gridspec[1].subgridspec(ncols=1, nrows=subplot_count-1)
82-
83-
self.ax = [self.figure.add_subplot(gridspec[0])]
84-
# add small plots to axes list, so it can be accessed that way
85-
for idx in range(subplot_count - 1):
86-
self.ax.append(self.figure.add_subplot(sub_gridspec[idx]))
87-
88-
print("axes created in SubTabs:", self.ax[0])
63+
self.figure = plt.figure()
8964

9065
self.addTab(DockContainer(self.figure), str(self.counter))
9166
self.counter += 1
9267

68+
def add_more_axes(self):
69+
"""
70+
Simply adds a new subplot to the figure.
71+
"""
72+
self.figure.add_subplot()
73+
74+
def last_axes(self):
75+
"""
76+
Get the last axes that was created by add_more_axes
77+
"""
78+
return self.figure.get_axes()[-1]
79+
80+
def rearrange_plots(self):
81+
"""
82+
This method is called after plotting the results for this tab. It arranges the plots in two columns with the
83+
big plot on the left side and all the other plots on the right side.
84+
"""
85+
print("rearrange_plots")
86+
axes = self.figure.get_axes()
87+
if len(axes) > 2:
88+
pass # nothing to do, just one plot needs to be shown in the middle
89+
elif len(axes) == 2:
90+
# two column gridspec needs to be applied
91+
self.gs = self.figure.add_gridspec(nrows=1, ncols=2)
92+
93+
# this for loop cannot be replaced by for ax in axes, because the ax is modified in the list :)
94+
for i in range(len(axes)):
95+
axes[i].set_position(self.gs[i].get_position(self.figure))
96+
else:
97+
# subgridspec needs to be applied
98+
self.gs = self.figure.add_gridspec(nrows=1, ncols=2)
99+
self.sub_gs = self.gs[1].subgridspec(ncols=1, nrows=len(axes)-1)
100+
101+
axes[0].set_position(self.gs[0].get_position(self.figure))
102+
for i in range(len(axes)-1):
103+
axes[i+1].set_position(self.gs[i].get_position(self.figure))
104+
93105

94106
class DockContainer(QtWidgets.QMainWindow):
95107
"""

0 commit comments

Comments
 (0)