@@ -889,57 +889,33 @@ def add_plot(
889889 self .manager .add_plot (plot , plot_id )
890890
891891
892- class SyncPlotWindow (QW .QMainWindow ):
893- """Window for showing plots, optionally synchronized
894-
895- Args:
896- parent: parent widget
897- toolbar: show/hide toolbar
898- options: plot options
899- panels: additionnal panels
900- auto_tools: If True, the plot tools are automatically registered.
901- If False, the user must register the tools manually.
902- title: The window title
903- icon: The window icon
904- size: The window size (width, height). Defaults to None (no resize)
905-
906- Usage: first, create a window, then add plots to it, then call the
907- :py:meth:`.SyncPlotWindow.finalize_configuration` method to add panels and
908- eventually register tools.
909-
910- Example::
911-
912- from plotpy.plot import BasePlot, SyncPlotWindow
913- win = SyncPlotWindow(title="My window")
914- plot = BasePlot()
915- win.add_plot(plot)
916- win.finalize_configuration()
917- win.show()
918- """
892+ class BaseSyncPlot :
893+ """Base class for synchronized plot windows and dialogs"""
919894
920895 def __init__ (
921896 self ,
922- parent : QWidget | None = None ,
923897 toolbar : bool = True ,
924898 options : PlotOptions | dict [str , Any ] | None = None ,
925899 auto_tools : bool = True ,
926900 title : str = "PlotPy" ,
927901 icon : str = "plotpy.svg" ,
928902 size : tuple [int , int ] | None = None ,
929903 ) -> None :
930- super ().__init__ (parent )
931- set_widget_title_icon (self , title , icon , size )
932904 self .manager = PlotManager (None )
933905 self .manager .set_main (self )
934906 self .subplotwidget = SubplotWidget (self .manager , parent = self , options = options )
935- self .setCentralWidget (self .subplotwidget )
936907 self .toolbar = QW .QToolBar (_ ("Tools" ), self )
937908 self .toolbar .setVisible (toolbar )
938909 self .manager .add_toolbar (self .toolbar , "default" )
939910 self .toolbar .setMovable (True )
940911 self .toolbar .setFloatable (True )
941- self .addToolBar (self .toolbar )
942912 self .auto_tools = auto_tools
913+ set_widget_title_icon (self , title , icon , size )
914+ # Note: setup_layout() is called by subclasses after Qt widget initialization
915+
916+ def setup_layout (self ) -> None :
917+ """Setup the layout - to be implemented by subclasses"""
918+ raise NotImplementedError ("Subclasses must implement `setup_layout` method" )
943919
944920 def get_toolbar (self ) -> QW .QToolBar :
945921 """Return main toolbar
@@ -969,11 +945,6 @@ def rescale_plots(self) -> None:
969945 for plot in self .subplotwidget .plots :
970946 plot .do_autoscale ()
971947
972- def showEvent (self , event ): # pylint: disable=C0103
973- """Reimplement Qt method"""
974- super ().showEvent (event )
975- QC .QTimer .singleShot (0 , self .rescale_plots )
976-
977948 def add_plot (
978949 self ,
979950 row : int ,
@@ -995,10 +966,15 @@ def add_plot(
995966 plot_id = str (len (self .subplotwidget .plots ) + 1 )
996967 self .subplotwidget .add_plot (plot , row , col , plot_id )
997968 if sync and len (self .subplotwidget .plots ) > 1 :
998- syncaxis = self .manager .synchronize_axis
999- for i_plot in range (len (self .subplotwidget .plots ) - 1 ):
1000- syncaxis (X_BOTTOM , [plot_id , f"{ i_plot + 1 } " ])
1001- syncaxis (Y_LEFT , [plot_id , f"{ i_plot + 1 } " ])
969+ self ._synchronize_with_existing_plots (plot_id )
970+
971+ def _synchronize_with_existing_plots (self , plot_id : str ) -> None :
972+ """Synchronize the new plot with existing plots"""
973+ syncaxis = self .manager .synchronize_axis
974+ for i_plot in range (len (self .subplotwidget .plots ) - 1 ):
975+ existing_plot_id = f"{ i_plot + 1 } "
976+ syncaxis (X_BOTTOM , [plot_id , existing_plot_id ])
977+ syncaxis (Y_LEFT , [plot_id , existing_plot_id ])
1002978
1003979 def get_plots (self ) -> list [BasePlot ]:
1004980 """Return the plots
@@ -1007,3 +983,117 @@ def get_plots(self) -> list[BasePlot]:
1007983 list[BasePlot]: The plots
1008984 """
1009985 return self .subplotwidget .get_plots ()
986+
987+
988+ class SyncPlotWindow (QW .QMainWindow , BaseSyncPlot ):
989+ """Window for showing plots, optionally synchronized
990+
991+ Args:
992+ parent: parent widget
993+ toolbar: show/hide toolbar
994+ options: plot options
995+ panels: additionnal panels
996+ auto_tools: If True, the plot tools are automatically registered.
997+ If False, the user must register the tools manually.
998+ title: The window title
999+ icon: The window icon
1000+ size: The window size (width, height). Defaults to None (no resize)
1001+
1002+ Usage: first, create a window, then add plots to it, then call the
1003+ :py:meth:`.SyncPlotWindow.finalize_configuration` method to add panels and
1004+ eventually register tools.
1005+
1006+ Example::
1007+
1008+ from plotpy.plot import BasePlot, SyncPlotWindow
1009+ win = SyncPlotWindow(title="My window")
1010+ plot = BasePlot()
1011+ win.add_plot(plot)
1012+ win.finalize_configuration()
1013+ win.show()
1014+ """
1015+
1016+ def __init__ (
1017+ self ,
1018+ parent : QWidget | None = None ,
1019+ toolbar : bool = True ,
1020+ options : PlotOptions | dict [str , Any ] | None = None ,
1021+ auto_tools : bool = True ,
1022+ title : str = "PlotPy" ,
1023+ icon : str = "plotpy.svg" ,
1024+ size : tuple [int , int ] | None = None ,
1025+ ) -> None :
1026+ self .subplotwidget : SubplotWidget
1027+ self .toolbar : QW .QToolBar
1028+ QW .QMainWindow .__init__ (self , parent )
1029+ BaseSyncPlot .__init__ (self , toolbar , options , auto_tools , title , icon , size )
1030+ self .setup_layout ()
1031+
1032+ def showEvent (self , event ): # pylint: disable=C0103
1033+ """Reimplement Qt method"""
1034+ super ().showEvent (event )
1035+ QC .QTimer .singleShot (0 , self .rescale_plots )
1036+
1037+ def setup_layout (self ) -> None :
1038+ """Setup the main window layout"""
1039+ self .setCentralWidget (self .subplotwidget )
1040+ self .addToolBar (self .toolbar )
1041+
1042+
1043+ class SyncPlotDialog (QW .QDialog , BaseSyncPlot ):
1044+ """Dialog for showing plots, optionally synchronized
1045+
1046+ Args:
1047+ parent: parent widget
1048+ toolbar: show/hide toolbar
1049+ options: plot options
1050+ auto_tools: If True, the plot tools are automatically registered.
1051+ If False, the user must register the tools manually.
1052+ title: The window title
1053+ icon: The window icon
1054+ size: The window size (width, height). Defaults to None (no resize)
1055+
1056+ Usage: first, create a dialog, then add plots to it, then call the
1057+ :py:meth:`.SyncPlotDialog.finalize_configuration` method to add panels and
1058+ eventually register tools.
1059+
1060+ Example::
1061+
1062+ from plotpy.plot import BasePlot, SyncPlotDialog
1063+ dlg = SyncPlotDialog(title="My dialog")
1064+ plot = BasePlot()
1065+ dlg.add_plot(plot)
1066+ dlg.finalize_configuration()
1067+ dlg.exec()
1068+ """
1069+
1070+ def __init__ (
1071+ self ,
1072+ parent : QWidget | None = None ,
1073+ toolbar : bool = True ,
1074+ options : PlotOptions | dict [str , Any ] | None = None ,
1075+ auto_tools : bool = True ,
1076+ title : str = "PlotPy" ,
1077+ icon : str = "plotpy.svg" ,
1078+ size : tuple [int , int ] | None = None ,
1079+ ) -> None :
1080+ self .subplotwidget : SubplotWidget
1081+ self .toolbar : QW .QToolBar
1082+ QW .QDialog .__init__ (self , parent )
1083+ BaseSyncPlot .__init__ (self , toolbar , options , auto_tools , title , icon , size )
1084+ self .setup_layout ()
1085+ self .setWindowFlags (QC .Qt .Window )
1086+
1087+ def showEvent (self , event ): # pylint: disable=C0103
1088+ """Reimplement Qt method"""
1089+ super ().showEvent (event )
1090+ QC .QTimer .singleShot (0 , self .rescale_plots )
1091+
1092+ def setup_layout (self ) -> None :
1093+ """Setup the dialog layout"""
1094+ self .plot_layout = QW .QGridLayout ()
1095+ self .plot_layout .addWidget (self .subplotwidget )
1096+ layout = QW .QVBoxLayout ()
1097+ layout .addWidget (self .toolbar )
1098+ layout .addLayout (self .plot_layout )
1099+ self .setLayout (layout )
0 commit comments