Class Reference
PhysPlot is both a table-first GUI application and an importable backend package. The classes below describe the current runtime components most useful to users and contributors.
Core classes
physplot.PhysPlotPublic backend facade for loading data, assigning roles, transforming columns, plotting with modules, exporting outputs, and running workflows.
physplot_gui.app.main_window.MainWindowModern PyQt6 main window. Orchestrates the central table, Simple/Advanced panels, protocol menus, Help/About links, and backend API calls.
physplot_gui.widgets.central_table.CentralTableSpreadsheet widget with column-role dropdowns, cell editing, copy/paste, rename, row deletion, and column deletion behavior.
physplot.steps.WorkflowStepBase class for replayable workflow steps such as loading data, setting roles, transforming columns, calculating formulas, deleting rows/columns, renaming columns, editing cells, and generating plot modules.
physplot.plotting_modules.PlotterRegistryRegistry for built-in plotter modules and their available plot types.
Autodoc view
PhysPlot package.
- class PhysPlot[source]
Bases:
objectPackage-first backend facade for loading, transforming, fitting, and exporting data.
- calculate(formula: str, output: str, record=True)[source]
- delete_columns(column_references)[source]
- delete_rows(row_indices)[source]
- describe_columns()[source]
- export(output)[source]
- export_workflow(path)[source]
Write an importable and headless-runnable Python sequence file.
- fit(kind='linear')[source]
- get_active_dataset()[source]
- get_column_metadata(column_reference)[source]
- insert_step(index, step)[source]
Insert
stepintoself.workflowbefore positionindex.indexmay equallen(self.workflow)to append. Negative indices are rejected so positions stay unambiguous for the GUI.
- load(path, loader='auto', dataset_name=None)[source]
- load_workflow(path)[source]
- move_step(old_index, new_index)[source]
Move the step at
old_indexso it ends up atnew_index.
- plot(mode='single', output=None)[source]
- plot_with_module(plotter_id, plot_type=None, record=True, **config)[source]
Render a plot through the modular plotter registry.
- rename_column(old_reference, new_name: str)[source]
- rerun_from(index, steps=None, *, allow_column_number_fallback=False, raise_on_error=False) list[StepResult][source]
Restore the saved state before step
indexand run from there.stepsdefaults toself.workflow. Steps beforeindexmust be unchanged since the run that saved the state; editingindexor a later step is fine. If the exact resume point was evicted, the latest valid earlier one is used. RaisesRuntimeErrorwhen no valid saved state exists, in which case run the whole sequence first.
- run_bulk(workflow, input_folder, output_folder, **kwargs)[source]
- run_workflow(steps, allow_column_number_fallback=False)[source]
Run steps in order and raise the first failure.
Per-step outcomes are still recorded on
last_results. Userun_workflow_detailedto get results without raising and to keep resume points forrerun_from.
- run_workflow_detailed(steps, *, start_index=0, allow_column_number_fallback=False, raise_on_error=False, keep_snapshots=True) list[StepResult][source]
Run steps and return one
StepResultper step.Execution stops at the first failing step; that step is
failedand every later step isskipped. Withraise_on_errorthe failure is re-raised afterlast_resultsis set. Withkeep_snapshotsthe state before each executed step is saved sorerun_fromcan resume without replaying earlier steps.
- save_workflow(path)[source]
- set_cell_value(row_index: int, column_reference, value)[source]
- set_roles(record=True, **roles)[source]
Assign column roles; recorded as a
SetRoleStepso replays keep them.
- start_recording()[source]
- stop_recording()[source]
- transform(input_column, function_name, output=None, record=True, **params)[source]
- workflow_script() str[source]
Return the same runnable Python source used by
export_workflow.
Build and run the PhysPlot main window: table, mode panels, menus and status bar.
This module defines MainWindow, the main window of the PyQt6 desktop GUI, the helper
figureforge_plugin_dirs() and a few module constants. The function run_app in
physplot_gui.app.runner (used by python -m physplot_gui and by the
physplot-gui / python-physplot-gui entry points) creates the QApplication, builds
one MainWindow and shows it.
The window is an orchestration layer only. It owns the widgets, reacts to what the user does and
forwards every scientific operation to the backend physplot.PhysPlot object kept in
self.state.pp. Loading, transforming, plotting, exporting and sequence replay all happen in
the physplot package; this module calls the backend, redraws the table from the backend
dataset and records the user’s actions as rows of the protocol, most of them linked to
replayable backend steps.
The user documentation pages “GUI Walkthrough” and “UI Reference” in the project wiki
(wiki/), and the Read the Docs walkthrough (docs/getting_started.rst), describe the same
window from the user’s point of view.
Window layout
MainWindow._build_ui() stacks the parts of the window from top to bottom:
+--------------------------------------------------------------------------------------+
| File Protocol View Plot Help (native menu bar) |
+--------------------------------------------------------------------------------------+
| [LSF] [PhysLab] [ PhysPlot wide logo ] Mode: [Simple] [Advanced] |
+--------------------------------------------------------------------------------------+
| | Column 1 | 2: Time | 3: Volts | ... <- headers: number and name |
| | [Ignore v] | [X v] | [Y v] | ... <- role dropdown row |
| 1 | | 0.0 | 1.2 | |
| 2 | | 0.5 | 1.9 | central spreadsheet table |
| .. | | | | (CentralTable, spare height) |
+--------------------------------------------------------------------------------------+
| Lower mode panel (QStackedWidget owned by ModeManager) |
| Simple: [1. Data Importer] [2. Mathematical Transformation] [3. Plotter Module] |
| Advanced: tabs [Build Protocol] [Run Sequence] |
+--------------------------------------------------------------------------------------+
| (o) Status: <last message> Rows: N Columns: N File: <name> Workflow Mode |
+--------------------------------------------------------------------------------------+
Menu bar. Created with
QMainWindow.menuBar(); on macOS Qt shows it in the system menu bar at the top of the screen instead of inside the window.Header (
MainWindow._header()). The LSF and PhysLab logos sit on the far left, the wide PhysPlot logo is centred and the Simple/Advanced switcher (ModeSwitcher) is on the right. When the wide logo file is missing, a text title “PhysPlot” with the subtitle “Advanced Plotting Made Simple” is shown instead. A missing LSF or PhysLab image is simply left out.Central table (
CentralTable). Row 0 holds one role dropdown per column (Ignore, X, Y, X Error, Y Error, Group, Label, Batch Key, Fit Weight). Data rows are numbered from 1 in the row header. Column headers readColumn Nfor default names andN: nameotherwise. Double-click a header to rename the column; right-click a header, a row number or a cell for rename, copy, paste, clear and delete. The table always shows at least 100 data rows and 26 columns and grows when it is scrolled or typed into, so it usually shows more (empty) columns than the dataset has.Lower mode panel (
ModeManager). Simple Mode showsSimpleModePanel(three panels, sized to exactly their height). Advanced Mode showsAdvancedModePanelwith the tabs Build Protocol and Run Sequence (300 to 430 px tall). Simple Mode is shown at start-up.Status bar (
PhysPlotStatusBar). ShowsStatus: <message>(long messages are cut with an ellipsis; hover for the full text), the row and column counts of the backend dataset and the loaded file name (File: -when none). In Advanced Mode it also shows a green dot,Workflow: <sequence file name>(Untitleduntil a sequence is saved or imported) andMode: Advanced.
Native menu bar
MainWindow._build_menu_bar() creates five menus. Shortcuts are Qt key sequences, so
Ctrl appears as the Command key on macOS.
File
Import Data… (
Ctrl+O):MainWindow.import_data()with the Auto Loader. Pick a file; it replaces the table and is recorded as a File Loader protocol row.Import Folder…:
MainWindow.import_folder(). Pick a folder; the status bar reportsFolder selected: <name>. No data is loaded (folders are processed from Advanced Mode > Run Sequence).Export Data… (
Ctrl+E):MainWindow.export_data(). Pick a folder; the backend writesdata.csv,columns.csvandworkflow.pythere, plusfit.jsonandplot.pngwhen a fit result or a figure exists.Open Config Folder: opens the per-user
Documents/PhysPlot/configfolder (or theconfigfolder underPHYSPLOT_USER_DIRwhen that variable is set) in the system file manager, creating the folder tree first when it is missing.Reload Config Modules (
Ctrl+Shift+R): re-scans theconfig/folders without a restart. It rebuilds the Insert Protocol Module submenu, asks every panel that has arefresh_pluginsmethod (Simple Mode) to rebuild its loader, function, plotter, template and fit-style lists, refreshes the window and reportsReloaded config modules from <folder>.
Protocol
Import Sequence.py…:
MainWindow.open_workflow(). Replaces the protocol with the steps of a sequence file. The steps are not run.Export Sequence.py… (
Ctrl+S):MainWindow.save_workflow(). Writes the protocol as a runnable Python file.Apply This Sequence (
Ctrl+R):MainWindow.apply_current_sequence(). Replays the whole protocol on the table and fills the Status column.Copy Sequence Code: copies the generated Python of the protocol (the text
physplot.PhysPlot.workflow_script()returns) to the clipboard and reportsSequence script copied.Clear Sequence: empties the protocol rows and the backend step list without asking. The table data is left as it is.
Insert Protocol Module (submenu): one item per
.pyfile found inconfig/protocol_modules(label from the file’sDISPLAY_NAMEor its file name, tooltip and status tip fromDESCRIPTION). A disabled item “No protocol modules in config/protocol_modules” is shown when there are none. Choosing a module appends its steps to the end of the protocol without running them and reportsInserted protocol module <name>; a module that cannot be loaded is reported as “Insert protocol module failed”.
View
Simple Mode (
Ctrl+1) and Advanced Mode (Ctrl+2): switch the lower panel throughphysplot_gui.app.mode_manager.ModeManager.set_mode(), exactly like the header switcher.
Plot
Generate Plot (
Ctrl+G):MainWindow.generate_plot(). A Basic Plotter scatter plot of the X and Y role columns, styled with the Template selected in Simple Mode and opened in the Figure Editor.Update Integrated Preview:
MainWindow.generate_integrated_plot(). Refreshes the panels’ plotter lists and adds a display-only protocol row.
Help
Documentation: opens https://physplot.readthedocs.io/en/latest/ in the default browser.
GitHub Repository: opens https://github.com/MShirazAhmad/PhysPlot.
Report Issues or Bugs: opens https://github.com/MShirazAhmad/PhysPlot/issues.
About PhysPlot:
MainWindow.show_about_dialog(). The item carries Qt’sAboutRole, so on macOS Qt moves it into the application menu.
What the panel controls call
ModeManager(self) hands this window to every panel as its actions object. The panels call
its public methods directly and read shared data through actions.state:
Simple Mode, 1. Data Importer: the Data Loader list comes from
MainWindow.backend_loader_entries(); Import Data callsMainWindow.import_data()with the selected entry; Import Folder callsMainWindow.import_folder(); Export Data callsMainWindow.export_data().Simple Mode, 2. Mathematical Transformation: the Function list comes from
MainWindow.simple_function_entries(); Apply callsMainWindow.apply_backend_transform()with the input column, the function entry, a multiplier of1.0, the+offset and the output column.Simple Mode, 3. Plotter Module: the Plotter Module, Plot Type, Template and Fit Style lists come from
MainWindow.plotter_entries(),MainWindow.plot_type_entries(),MainWindow.style_module_entries()andMainWindow.fit_style_entries(); Generate Plot callsMainWindow.generate_module_plot(); Export Plot callsMainWindow.export_module_plot().Advanced Mode, Build Protocol: Import Sequence.py, Export Sequence.py, Apply This Sequence, Copy as Script and Clear Sequence call the same methods as the Protocol menu. Apply Code to Table calls
apply_sequence_code(it replaces the protocol with the steps defined by the edited code, without running them). Each row’s Delete button callsdelete_timeline_step(removes the row’s steps, then replays what is left). The row context menu item Rerun from this step callsMainWindow.rerun_from_timeline_step(). The Status column askstimeline_row_statusfor OK / Failed / Skipped and a tooltip, and the Code view showssequence_code_text.Advanced Mode, Run Sequence: the Browse buttons call
MainWindow.browse_input_folder(),MainWindow.browse_workflow_file()andMainWindow.browse_output_folder(); Run Bulk Workflow callsMainWindow.run_bulk_workflow().
Edits in the central table arrive as signals connected in MainWindow._build_ui():
role_changed to MainWindow.set_column_role(), column_renamed to
MainWindow.rename_column(), cell_value_changed to MainWindow.record_cell_edit(),
rows_deleted to MainWindow.record_row_delete(), columns_deleted to
MainWindow.record_column_delete() and table_edited to
MainWindow.sync_table_to_backend().
How actions reach the backend and the protocol
All shared state lives in self.state (GuiState) and
survives mode switches: pp (the backend), timeline (protocol rows), transformations
(a display list of applied transformations), mode, current_file and workflow_file.
Two lists describe the protocol:
self.state.pp.workflowThe ordered backend step objects (
LoadDataStep,SetRoleStep,TransformColumnStep,PlotModuleStep,RenameColumnStep,SetCellValueStep,DeleteRowsStep,DeleteColumnsStep, …). This list is the replayable source of truth: Apply This Sequence, Export Sequence.py, Copy Sequence Code, the Build Protocol Code view and bulk runs all read it.self.state.timelineOne dict per row of the Build Protocol and Run Sequence tables, with the keys
action,details,target,workflow_index,workflow_indicesandcode.workflow_indiceslinks the row to one or more positions inpp.workflow(a File Loader row covers theLoadDataStepand theSetRoleStepthat follows it). A row without indices is display-only and is never replayed.
Every recording goes through MainWindow._append_sequence(), in one of three ways:
The GUI builds the step object and passes it in;
_append_sequenceappends it topp.workflow. Used for imports, role changes, column renames, cell edits and row and column deletions.The backend records the step itself (
physplot.PhysPlot.transform()andphysplot.PhysPlot.plot_with_module()append topp.workflow); the GUI passes the new step’s index so the row links to it. Used for transformations and plots.Nothing replayable is recorded:
MainWindow._record()adds a display-only row (used by Update Integrated Preview), and plots from loader-declared callable plotters add a row without a step.
A typical action, Apply in Simple Mode, runs:
apply_backend_transform() -> apply_simple_transform() ->
_apply_transform() -> sync_table_to_backend() (table
contents copied into the backend dataset) -> physplot.PhysPlot.transform() (adds the
column and records a TransformColumnStep) -> table redrawn from the backend dataframe ->
_append_sequence() -> status Transformation applied ->
_refresh_all().
MainWindow._refresh_all() redraws the role dropdowns, the panels’ column lists, both
protocol tables (including the Status column), the plotter lists and the status bar counts.
Role changes, cell edits and row or column deletions record their rows without calling it, so
those rows appear in Build Protocol at the next full refresh.
Apply This Sequence replays pp.workflow from its first step through
physplot.PhysPlot.run_workflow_detailed() (a LoadDataStep reads its file from disk
again), redraws the table from the backend dataset and fills the Status column from
pp.last_results. The run stops at the first failing step; later steps are marked Skipped
and the table keeps the state reached before the failure. Rerun from this step resumes from
a state snapshot saved by an earlier run. Import Sequence.py, Apply Code to Table and
Insert Protocol Module replace or extend the protocol but do not run it.
Dialogs and status messages
File dialogs: Import Data (the built-in types, loader-plugin types or any file), Import Folder, Export Data, Export Plot (PNG, PDF or SVG), Save Sequence.py and Load Sequence.py (starting in the writable
config/sequencesfolder), Import Pipeline and Export Pipeline (config/pipelines) and the Run Sequence folder and file pickers. Cancelling a dialog leaves the data and the protocol unchanged.Message boxes: About PhysPlot, Fit Results, Sequence Manager and the error warnings described below.
Plot windows: every plot opens in a non-modal PhysPlot dialog titled
PhysPlot - <plotter>: <plot type>with the Matplotlib navigation toolbar and an Advanced Styling… button that opens the figure in the Figure Editor (same process).Status messages set by this module include
Ready,Transformation applied,Enter or import data before applying a transformation,Plot generated,Plot preview updated,Plot exported,Exported,Fit complete,Pipeline exported,Sequence saved,Sequence loaded,Sequence complete,Sequence updated,Sequence cleared,Sequence code applied,Sequence script copied,Reran from row N,Row N has no replayable step,Row N failed (<StepName>): <error>,Bulk complete: N outputs,Folder selected: <name>,Inserted protocol module <name>andReloaded config modules from <folder>. After an error the status bar shows the error title (for exampleImport failed).
Figure Editor (FigureForge)
A plot window’s Advanced Styling… button opens its figure in FigureForge, which the UI
calls the “Figure Editor”. PhysPlot ships its own editable copy in
physplot_gui/figure_editor (FigureForge 0.3.3, MIT License); the PyPI package is not used.
MainWindow._open_figure_editor():
The editor uses the same PyQt6 and Matplotlib as the rest of PhysPlot and runs in the same process, on the same figure object:
Points FigureForge’s
preferences.jsonat the copy’s built-inpluginsfolder. PhysPlot’s own plugins (the bundledconfig/figureforge_pluginsfolder, then the per-user copy, whose files win) are loaded in place from the folders inPHYSPLOT_FIGURE_EDITOR_PLUGIN_DIRS; nothing is copied.Adds hidden placeholder artists (line, scatter, legend, annotation) to every axes.
Opens the editor window on the figure (one editor per figure; a second click raises it). Each redraw in the editor also redraws the plot window, so edits show there live.
When the editor closes, the plot window takes the figure back with the edits. Nothing is saved to a file and there is no save prompt.
Edits made in the Figure Editor change the figure only; they are not recorded in the protocol.
Bulk runs
Run Bulk Workflow on the Run Sequence tab calls MainWindow.run_bulk_workflow(), which
passes the chosen sequence file, or a copy of the current protocol when no file is given, to
physplot.PhysPlot.run_bulk() (physplot.bulk.run_folder()). Each matching file of the
input folder is processed in name order with a fresh backend and exported to
<output folder>/<file stem>/. The run happens in the GUI thread, so the window does not
respond until it finishes. The first failing file stops the run; the error names it, and
files before it have already been exported.
Error reporting
Nearly every action method catches exceptions and passes them to MainWindow._error(),
which puts the error title in the status bar, stores (title, exception) in
MainWindow.last_error and then either prints <title>: <message> to stderr (when the
Qt platform is offscreen, as in headless tests and CI, where no one can dismiss a dialog)
or shows a modal warning box with the title and the exception text. The window stays usable
after an error.
Module constants
LOGO_WIDE,LOGO_ICON,LSF_LOGO,PHYSLAB_LOGOImage files in
physplot/inc: the centred header logo (PhysPlotWide1.png), the window icon that is also shown in the About dialog and passed to the Figure Editor (PhysPlot.png), and the two left header logos (lsf.jpegandphyslab.png).FIGUREFORGE_PLUGIN_DIRThe bundled
config/figureforge_pluginsfolder, named in the error raised when no Figure Editor plugin folder exists.BUILTIN_FUNCTIONSMenu label and tooltip of each built-in transformation in the Simple Mode Function list, keyed by the backend function name that sequences record.
Related modules
physplot_gui.app.gui_state:GuiState, the shared state holder.physplot_gui.app.mode_manager: the lower panel stack and Simple/Advanced switching.physplot_gui.panels: the Simple Mode panels, Build Protocol (SequenceTablePanel), Run Sequence (RecorderModePanel) andBulkPanel.physplot_gui.widgets:CentralTable,ModeSwitcherandPhysPlotStatusBar.physplot_gui.plot_styles: figure templates inconfig/templates.physplot_gui.fit_styles: LSQ fit-style presets inconfig/figureforge_fit_styles.physplot_gui.app.plugin_discovery: loader plugins, transformation plugins and loader-declared plotters.physplot_gui.style.theme:APP_STYLESHEET, the window style sheet.Backend:
physplot(PhysPlot),physplot.steps,physplot.workflow,physplot.execution,physplot.bulkandphysplot.user_paths.
- BUILT_IN_DATA_EXTENSIONS = ['.csv', '.txt', '.dat', '.tsv', '.msa', '.xls', '.xlsx', '.xrdml']
File types the built-in loaders read, listed first in the Import Data dialog.
- DATA_ROLES = {'U', 'V', 'W', 'X', 'X Error', 'Y', 'Y Error', 'Y2', 'Z'}
Roles that feed a plot’s axes or error bars; a plot type that does not read one clears it.
- FIGURE_EDITOR_PACKAGE_DIR = PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/physplot/checkouts/latest/physplot_gui/figure_editor')
PhysPlot’s own copy of FigureForge (the Figure Editor), on the same PyQt6 as the rest of the GUI.
- class MainWindow(*args: Any, **kwargs: Any)[source]
Bases:
QMainWindowShow the PhysPlot window and route every user action to the backend.
MainWindowis the main window of the GUI. See the module documentation above for the layout sketch, the complete menu bar and the flow from a click to a recorded protocol step.Responsibilities
Build the window: native menu bar, branded header with the mode switcher, the central spreadsheet, the lower Simple/Advanced panel stack and the status bar.
Act as the
actionsobject of the panels.ModeManager(self)passes this window toSimpleModePanelandAdvancedModePanel(and from there to the Build Protocol, Run Sequence and Bulk Run widgets). Those panels call its public methods directly, for exampleimport_data(),apply_backend_transform(),generate_module_plot(),apply_current_sequence()andrun_bulk_workflow(), and fill their dropdowns from the*_entriesmethods.Turn each action into calls on the backend
physplot.PhysPlot(state.pp) and record it as a protocol step with_append_sequence().Keep every widget in step with the backend after each action (
_refresh_all()).Open plot windows (an in-app Matplotlib dialog and, from it, the Figure Editor) and report errors (
_error()).
Attributes
stateThe
GuiState: the backendpp, the protocol rowstimeline, the display listtransformations, the currentmode, the loaded data filecurrent_fileand the saved or imported sequence fileworkflow_file.central_tableThe
CentralTablespreadsheet with the role dropdown row.mode_managerThe
ModeManager.mode_manager.stackis the lowerQStackedWidgetandmode_manager.panelsmaps"Simple"and"Advanced"to the panel widgets.mode_switcherThe
ModeSwitcheron the right of the header (created by_header()).statusThe
PhysPlotStatusBarat the bottom.file_menu,protocol_menu,view_menu,plot_menu,help_menuThe
QMenuobjects of the native menu bar.protocol_modules_menuis the Protocol > Insert Protocol Module submenu.last_error(title, exception)of the most recent error passed to_error(), orNone. Tests read it because no dialog is shown on theoffscreenplatform._active_loader_entryThe loader-plugin entry used for the last import, or
Noneafter a built-in loader ornew_table(). Plotters declared by that plugin are added to the Plotter Module list byplotter_entries()._custom_plottersLoader-declared callable plotters by their
"loader:<id>"identifier, rebuilt byplotter_entries().
Attributes created on first use:
_figure_editors(open Figure Editor windows by figure),_module_plot_dialogs(open plot dialogs) and, for the legacy plot windows,plot_config_window,plot_config_ui,plot_windowand_main_window.Signals connected
mode_switcher.mode_changedtomode_manager.set_mode(header buttons).mode_manager.mode_changedto_mode_changed().central_table.role_changedtoset_column_role().central_table.column_renamedtorename_column().central_table.cell_value_changedtorecord_cell_edit().central_table.rows_deletedtorecord_row_delete().central_table.columns_deletedtorecord_column_delete().central_table.table_editedtosync_table_to_backend().Each menu action’s
triggeredsignal to its handler (see_build_menu_bar()).
- add_pipeline_step(payload: dict) None[source]
Apply a pipeline-style transformation; same as
apply_pipeline_step().- Parameters:
payload – See
apply_pipeline_step().
- apply_backend_transform(input_column: str, function_entry: str | dict, multiplier: float, offset: float, output: str) None[source]
Run the transformation configured in Simple Mode’s Mathematical Transformation.
Called by the panel’s Apply button with the Input column, the selected Function entry, a multiplier of
1.0, the+offset and the Output text. Does nothing when no input column is selected. The function name is read from the entry’sfunction_name(built-in functions) ordisplay_name(plugins); plugin entries are passed on whole so the plugin module can be used. An empty output defaults to<input>_<function name>. The work is done byapply_simple_transform().- Parameters:
input_column – Name of the source column.
function_entry – An entry from
simple_function_entries(), or a function name.multiplier – Factor passed on to
apply_simple_transform().offset – Offset passed on to
apply_simple_transform().output – Name of the output column, or an empty string for the default name.
- apply_current_sequence() None[source]
Replay the whole protocol on the table and show each row’s status.
Triggered by Protocol > Apply This Sequence (
Ctrl+R) and the Apply This Sequence button of Build Protocol. With an empty protocol, “Apply sequence failed” is reported with “Build or import a protocol sequence first.”. Otherwise_run_current_sequence()replays every step from the first one, redraws the table and fills the Status column (OK, Failed or Skipped), and the status readsSequence complete.When a step fails, the replay stops there, later steps are Skipped and the table keeps the state reached before the failure. The failure is reported as “Apply sequence failed” with the text
Row N failed (<StepName>): <error>(a dialog, or stderr on the offscreen platform), and the status bar keeps that text. An exception raised by the run itself (outside the per-step results) is also reported as “Apply sequence failed”.
- apply_pipeline_step(payload: dict) None[source]
Apply a transformation described by a pipeline-style payload.
The payload’s
paramstext, such as"factor=2, value=0.5", is parsed by_parse_params()(numbers become floats). The function defaults tomultiplyand the output to<input>_<function>. The transformation then runs through_apply_transform(), which records it. No control in the bundled panels calls this method.- Parameters:
payload – A dict with the keys
input,function,params(text) andoutput(optional).
- apply_sequence_code(source: str) None[source]
- apply_simple_transform(input_column: str, output: str, function_name: str | dict, multiplier: float, offset: float)[source]
Apply a built-in or plugin transformation to a column, as Simple Mode’s Apply does.
Does nothing when
input_columnis empty. When the input column has no non-blank cell in the table, the status readsEnter or import data before applying a transformationand nothing else happens. An emptyoutputmeans “overwrite the input column”.A plugin entry (a dict with a
module) is handed to_apply_function_plugin(), which passesmultiplierandoffsetto the plugin. Built-in functions are mapped to backend parameters:identityruns the backendmultiplywithfactor=multiplier(so the protocol showsmultiply);multiplyusesfactor=multiplier;addandsubtractusevalue=offset;divideusesdivisor=multiplier(1when the multiplier is 0);every other function runs without parameters.
Each call goes through
_apply_transform(). For any built-in function other thanaddandsubtract, a non-zerooffsetis then applied by a secondaddtransformation on the output column, which is recorded as a separate protocol row.- Parameters:
input_column – Name of the source column.
output – Name of the output column; a new name adds a column and an existing name overwrites that column.
function_name – A backend function name, or a plugin entry from
simple_function_entries().multiplier – Factor for
identity,multiplyanddivide; passed to plugins.offset – Value added to the result; used directly by
addandsubtract.
- apply_step_edits(row_index: int, values: list[dict])[source]
Update a row’s steps with edited field values and replay from it.
valuesholds one field mapping per step in the row, as returned byStepEditorDialog.validated_values(). All steps are validated before any is changed.
- assign_roles_for_plot_type(plotter_id: str, plot_type: str) list[tuple[str, str]][source]
Give free columns the roles a plot type still needs, in table order.
Called when the user picks a plotter, category or plot type. Data roles the plot type does not read (X, Y, Y2, Z, U, V, W, X Error, Y Error) are first set back to
Ignore; Group, Label, Batch Key and Fit Weight are kept. Each required role no column has yet goes to the next column whose role isIgnore: a numeric column for X, Y, Z and the other axis roles, a text column (or any free column) for Label and Group. Each assignment goes throughset_column_role(), so it is recorded in the protocol like a role picked by hand. Nothing happens for plotters that read columns by name.- Returns:
The
(column, role)pairs assigned.
- backend_loader_entries() list[dict][source]
Return the entries of the Simple Mode Data Loader dropdown.
The list starts with the built-in backend loaders in the order
physplot.loaders.list_loaders()gives them (currently Auto Loader, CSV, TXT, Excel, Nanoindentation, XRDML and DataFrame loaders), each as{"display_name", "loader_id", "enabled"}.enabledisFalseonly for the internaldataframeloader, which the panel shows greyed out andimport_data()refuses. Loader plugins fromconfig/data_importersfollow, as returned byphysplot_gui.app.plugin_discovery.discover_fileloaders()({"display_name", "path", "module"}); the plugin files are imported again on every call.The panel stores each entry as item data and passes the selected one back to
import_data(). The list is also rebuilt after File > Reload Config Modules.- Returns:
The loader entries, built-in loaders first.
- backend_transform_entries() list[str][source]
Return the names of the built-in backend transformations.
A thin wrapper around
physplot.core.transformations.list_transforms(). No control in the bundled panels calls it; seesimple_function_entries()for the list the user sees.- Returns:
Backend function names such as
"normalize_max"or"log10".
- browse_input_folder(field: PyQt6.QtWidgets.QLineEdit) None[source]
Pick the bulk-run input folder (Run Sequence, Input Folder > Browse).
Opens an Input Folder directory dialog in the current working directory and writes the chosen path into
field. Cancelling leaves the field unchanged.- Parameters:
field – The Input Folder line edit of the Bulk Run panel.
- browse_output_folder(field: PyQt6.QtWidgets.QLineEdit) None[source]
Pick the bulk-run output folder (Run Sequence, Output Folder > Browse).
Opens an Output Folder directory dialog in the current working directory and writes the chosen path into
field. Cancelling leaves the field unchanged.- Parameters:
field – The Output Folder line edit of the Bulk Run panel.
- browse_workflow_file(field: PyQt6.QtWidgets.QLineEdit) None[source]
Pick a sequence file for a bulk run (Run Sequence, Sequence File > Browse).
Opens a Sequence File dialog in the writable
config/sequencesfolder, filtered to Python files, and writes the chosen path intofield. Cancelling leaves the field unchanged. When the field stays empty, the bulk run uses the current protocol.- Parameters:
field – The Sequence File line edit of the Bulk Run panel.
- can_move_timeline_row(row_index: int, delta: int) bool[source]
Rows that load data stay first; nothing moves above them.
- check_for_updates(manual: bool = True) None[source]
Ask GitHub for the newest commit on the update channel, without blocking the UI.
Help > Check for Updates… (
manual) always reports the result; the automatic check only speaks up when an update is available that was not skipped.
- clear_pipeline() None[source]
Empty the display list of applied transformations.
Only
state.transformationsis cleared; table data, the backend sequence and the protocol rows are unchanged. No control in the bundled panels calls this method.
- clear_recording() None[source]
- copy_workflow_script() None[source]
- delete_pipeline_step(index: int) None[source]
Remove one entry from the display list of applied transformations.
Only
state.transformationschanges: the column the transformation created, the backend sequence and the protocol rows stay as they are. Out-of-range indices are ignored. No control in the bundled panels calls this method.- Parameters:
index – Position of the entry in
state.transformations.
- delete_timeline_step(index: int) None[source]
- discover_function_entries() list[dict][source]
Return the transformation plugins in
config/transformations, or a placeholder.No control in the bundled panels calls this method; the Simple Mode Function list comes from
simple_function_entries().- Returns:
The entries from
physplot_gui.app.plugin_discovery.discover_functions()(keysname,display_name,pathandmodule). When no plugin is found, a single placeholder{"display_name": "x", "path": None, "module": None}.
- discover_loader_entries() list[dict][source]
Return the loader plugins in
config/data_importers, or an Auto Loader placeholder.No control in the bundled panels calls this method; the Simple Mode Data Loader list comes from
backend_loader_entries().- Returns:
The entries from
physplot_gui.app.plugin_discovery.discover_fileloaders()(keysdisplay_name,pathandmodule). When no plugin is found, a single entry{"display_name": "Auto Loader", "path": None, "module": None, "loader_id": "auto"}.
- edit_timeline_step(row_index: int) None[source]
Open the step editor for a row and apply the result.
- export_data() None[source]
Export the current dataset, sequence, fit and plot to a folder.
Triggered by File > Export Data… (
Ctrl+E) and Simple Mode’s Export Data button. The table is first synced to the backend (sync_table_to_backend()), then an Export Data directory dialog opens in the current working directory. For the chosen folderphysplot.PhysPlot.export()writesdata.csv(the table),columns.csv(column metadata) andworkflow.py(the protocol as a runnable sequence file), plusfit.jsonwhen a fit result exists andplot.pngwhen a figure has been generated. The status then readsExported; errors are reported as “Export failed”. The export is not recorded in the protocol.
- export_module_plot() None[source]
Save the most recently generated plot to an image file.
Triggered by Simple Mode’s Export Plot button. Uses
state.pp.last_figure; when no plot has been generated yet, “Export plot failed” is reported with “Generate a plot before exporting.”. Otherwise an Export Plot save dialog opens with the suggested filephysplot_plot.pngin the current working directory and the filters PNG, PDF, SVG and All Files, and the figure is saved at 300 dpi. The status then readsPlot exported; errors are reported as “Export plot failed”. Changes made in the Figure Editor are not included, because they live in the editor’s own process. Nothing is recorded in the protocol.
- export_pipeline() None[source]
Save the display list of applied transformations as a pipeline JSON file.
An Export Pipeline save dialog suggests
pipeline.jsonin the writableconfig/pipelinesfolder.state.transformations(one{"input", "function", "params", "output"}entry per applied transformation, withparamsas display text) is written as indented JSON and the status readsPipeline exported. Write errors are not caught here. No control in the bundled panels calls this method.
- fit_model() None[source]
Fit a straight line to the X and Y role columns in the backend.
Syncs the table, then calls
physplot.PhysPlot.fit()with"linear", which stores the slope and intercept instate.pp.fit_result(seeshow_fit_results()). The status readsFit completeand the window is refreshed. The fit is not recorded in the protocol. Errors, such as a missing X or Y role, are reported as “Fit failed”. No control in the bundled panels calls this method; Simple Mode fits through the LSQ fit option ofgenerate_module_plot().
- fit_style_entries() list[dict][source]
Return the entries of the Simple Mode Fit Style dropdown.
The first entry,
{"name": "Default", "path": None, "style": None}, keeps the Fit Line fields as they are. It is followed by the LSQ fit-style presets fromphysplot_gui.fit_styles.list_fit_style_presets()(config/figureforge_fit_styles, or the folder inPHYSPLOT_FIT_STYLE_DIR), sorted by name. Choosing a preset fills the fit label, line style, line width and legend fields from itsstylepayload.- Returns:
Entries of the form
{"name", "path", "style"}, wherestyleis the preset’s JSON content.
- generate_integrated_plot() None[source]
Refresh the panels’ plot controls and log a display-only protocol row.
Triggered by Plot > Update Integrated Preview. The table is synced to the backend and
ModeManager.refresh_plotsruns (Simple Mode rebuilds its plotter, plot type and template lists; the Advanced panel’srefresh_plotdoes nothing). A Generate Plot row with the detailsCreate <mode> integrated plotand the targetPlot Previewis added through_record(); it has no backend step, so it is not replayed. The status readsPlot preview updated. No figure is drawn, and because_refresh_all()is not called the new row shows in Build Protocol at the next full refresh. Errors are reported as “Plot failed”.
- generate_module_plot(plotter_id: str, plot_type: str, style_module=None, fit_config=None) None[source]
Draw a plot with the selected plotter module, as Simple Mode’s Generate Plot does.
Does nothing when no plotter is selected. The table is synced to the backend first. A
fit_configis passed to the backend aslsq_fit=fit_configso a least-squares fit is overlaid. Then, by plotter:"basic"(Basic Plotter):physplot.PhysPlot.plot_with_module()draws the figure and records aPlotModuleStep(including the fit settings); the Template is applied and the figure is shown in a PhysPlot plot dialog (_show_module_figure()).A loader-declared callable plotter (id
"loader:<name>"): run by_run_custom_plotter(); no backend step is recorded, so the protocol row is display-only. Asking for an LSQ fit raises “LSQ fit from Simple Mode is available for backend plotter modules.”. The Template is applied and the figure is shown in a PhysPlot plot dialog (_show_module_figure()).Any other backend plotter: drawn, recorded and shown like the Basic Plotter.
Every dialog is titled
PhysPlot - <plotter>: <plot type>and its Advanced Styling… button opens the figure in the Figure Editor.The Template is applied to the figure after the backend call and is not part of the recorded step. A Generate Plot row with the details
Create <plotter> <plot type>and the targetPlotter Moduleis added, the status readsPlot generatedand the window is refreshed. Errors are reported as “Plot failed”; if the error happens after the backend call, thePlotModuleStepis already recorded inpp.workflowbut has no protocol row.- Parameters:
plotter_id – Id from
plotter_entries(), for example"basic".plot_type – Plot type from
plot_type_entries(), for example"scatter".style_module – Path of the template JSON file, or
Nonefor no template.fit_config – The panel’s LSQ fit settings (
enabled,expression,parameters,initial,label,line_style,line_width,show_legend), orNonewhen LSQ fit is not ticked.
- generate_plot() None[source]
Plot the X and Y columns as a Basic Plotter scatter plot in a PhysPlot plot window.
Triggered by Plot > Generate Plot (
Ctrl+G). The table is synced to the backend, thenphysplot.PhysPlot.plot_with_module()draws("basic", "scatter")from the X and Y role columns and records aPlotModuleStep. The Template selected in Simple Mode (_selected_style_module()) is applied to the figure, which then opens in a PhysPlot plot window (_show_module_figure()); its Advanced Styling… button opens the figure in the Figure Editor. A Generate Plot row with the detailsCreate <mode> plot(Singlein Simple Mode,Sequencein Advanced Mode; see_current_plot_mode()) and the targetX vs Yis linked to the recorded step, the status readsPlot generatedand the window is refreshed.Errors, such as missing X/Y roles or a Figure Editor that is not installed, are reported as “Plot failed”. If the error happens after the backend call, the
PlotModuleStepis already inpp.workflowbut no protocol row is added for it.
- import_data(loader: str | dict = 'auto') None[source]
Ask for a data file, load it into the table and record a File Loader row.
Triggered by File > Import Data… (
Ctrl+O, always the Auto Loader) and by the Import Data button of Simple Mode’s 1. Data Importer (the loader selected in Data Loader). An Import Data file dialog opens in the current working directory with two filters: “Data Files” fromdata_file_filter()(the built-in types plus every loader plugin’sFILE_EXTENSIONS) and “All Files”. Cancelling does nothing.Loader plugin (an entry with a
module, fromconfig/data_importers): the plugin’sload_data(path)is called. A returned DataFrame keeps its column names unless the plugin definesCOLUMN_NAMES(orcolumn_names); any other result is turned into an array and named from those names orColumn N(see_plugin_column_names()). A 1-D result becomes one column; anything that is not 2-D raises “Loader must return a 2D table-like array.”. The table is loaded into the backend through thedataframeloader under the file’s stem, the plugin path and name are stored in the dataset metadata (loader_plugin,loader_name), the plugin’sDEFAULT_COLUMN_ROLESare applied (_apply_loader_roles()) and the entry is remembered as the active loader, so its declared plotters appear in the Plotter Module list. The recorded step isLoadDataStep(path, loader="dataframe", dataset_name=<stem>, loader_plugin=<plugin path>).Built-in loader (a loader id string or an entry with a
loader_id):physplot.PhysPlot.load()reads the file ("auto"picks the loader from the file extension), the loader’s suggested roles are applied and the active loader plugin is cleared. The recorded step isLoadDataStep(path, loader=<id>, dataset_name=<stem>).In both cases the file becomes
state.current_file(shown asFile:in the status bar) and the table is redrawn from the backend dataset. The load step and, when any column has a role other than Ignore, aSetRoleStepwith those roles are appended to the protocol as one File Loader row whose details read"<loader> (column names and role setup)"(or"(column names)"without roles) and whose target is the file name. The status is set toReadyand the window refreshed.Errors, including choosing a disabled entry such as the DataFrame loader (”… is not available yet.”), are reported as “Import failed” through
_error().- Parameters:
loader – A backend loader id such as
"auto"or"csv", or an entry frombackend_loader_entries().
- import_folder() None[source]
Ask for a folder and report the choice in the status bar.
Triggered by File > Import Folder… and Simple Mode’s Import Folder button. An Import Folder directory dialog opens in the current working directory; after a choice the status reads
Folder selected: <folder name>. No files are loaded and nothing is recorded. To process every file of a folder, use Advanced Mode > Run Sequence (run_bulk_workflow()).
- import_pipeline() None[source]
Load the display list of transformations from a pipeline JSON file.
An Import Pipeline dialog opens in the writable
config/pipelinesfolder. The chosen file’s JSON content replacesstate.transformations; the transformations are not applied to the data and nothing is recorded in the protocol. Errors are reported as “Import pipeline failed”. No control in the bundled panels calls this method.
- insert_protocol_module(path, after_row: int | None = None) None[source]
Insert a reusable protocol module after
after_row(default: append).
- insert_step_dialog(after_row: int | None = None) None[source]
Ask for a step type, edit its fields, and insert it after
after_row.
- insert_steps(steps: list, after_row: int | None = None, message: str = 'Steps inserted')[source]
Insert steps as new rows after
after_row(Noneappends).New rows never go above the leading rows that load data.
- install_update(channel: str) None[source]
Start the installer for
channelin its own window, then quit PhysPlot.
- last_error: tuple[str, Exception] | None
- load_file(path, loader: str | dict = 'auto') bool[source]
Load
pathinto the table and record a File Loader row, without a dialog.This is
import_data()after the file has been chosen; see there for what each kind of loader does. Errors are reported as “Import failed”.- Parameters:
path – The data file.
loader – A backend loader id or an entry from
backend_loader_entries().
- Returns:
Truewhen the file was loaded.
- move_timeline_row(row_index: int, delta: int)[source]
Swap a row with its neighbour and replay from the earlier one.
- new_table(rows: int, columns: int, delete_old: bool) None[source]
Replace the data with a blank or resized table named “Untitled”.
CentralTable.resize_tableeither builds a blank table (delete_oldtrue) or keeps the current values, padding or cutting them to the new size; in both cases the roles are cleared. The result is loaded into the backend asUntitled, the active loader plugin and the current file are forgotten, the status is set toReadyand the window is refreshed. Nothing is recorded in the protocol. No control in the bundled panels or menus calls this method.- Parameters:
rows – Number of data rows.
columns – Number of columns.
delete_old –
Trueto discard the current values.
- open_and_plot(path) None[source]
Load a file with the Auto Loader and plot it, for Open with PhysPlot.
Used for files named on the command line (
physplot-gui data.csv) and files the operating system asks PhysPlot to open (right-click > Open With > PhysPlot, or a double-click when PhysPlot is the default app). The Auto Loader picks the loader from the file extension, including loader plugins’FILE_EXTENSIONS. When the loaded columns have both an X and a Y role,generate_plot()draws them; otherwise the table is left for the user to assign roles.- Parameters:
path – The data file.
- open_in_figure_editor
When true, plots open straight in the Figure Editor instead of a plot window (Simple Mode’s Advanced Figure Editor tick box; remembered by
run_app).
- open_user_config_folder() None[source]
- open_workflow() None[source]
Replace the protocol with the steps of a
Sequence.pyfile.Triggered by Protocol > Import Sequence.py… and the Import Sequence.py button of Build Protocol. A Load Sequence.py dialog opens in the writable
config/sequencesfolder. The chosen file is executed as Python byphysplot.PhysPlot.load_workflow()and must defineWORKFLOW_STEPSorbuild_workflow(). Its steps replacepp.workflow, the protocol rows are rebuilt from them (_sequence_rows_from_steps()), the file becomesstate.workflow_fileand the status readsSequence loaded. The steps are not run and the table is not changed; use Apply This Sequence to replay them. Errors are reported as “Load sequence failed” and leave the protocol as it was. The window is refreshed whenever a file was chosen.
- plot_type_categories(plotter_id: str) list[dict] | None[source]
Return the plotter’s plot types grouped into categories, or
None.The Basic Plotter groups its types like the Matplotlib gallery (
physplot.plotting_modules.gallery.PLOT_CATEGORIES). Only the types the plotter offers are kept (a subclass such as the Line Plotter offers fewer), and plot-type presets fromconfig/plot_typesgo in a last Presets category. Plotters without categories returnNoneand keep the flat Plot Type menu.- Parameters:
plotter_id – Id of the selected plotter.
- Returns:
[{"name": str, "types": [{"id", "label", "description"}, ...]}, ...].
- plot_type_entries(plotter_id: str) list[str][source]
Return the Plot Type choices for the selected plotter module.
Called by Simple Mode whenever the Plotter Module selection changes.
- Parameters:
plotter_id – Id of the selected plotter, as returned by
plotter_entries().- Returns:
For a loader-declared callable plotter, its declared
plot_types(or["publication_ready"]when it declares none). For a backend plotter, the typesphysplot.plotting_modules.PlotterRegistry.list_plot_types()offers for the current dataset (for the Basic Plotter, for examplescatter,lineandscatter_line). An empty list whenplotter_idis empty.
- plot_type_selected(plotter_id: str, plot_type: str) dict[source]
Limit the table’s role menus to the roles a plot type uses; return its hint.
Called by Simple Mode whenever Plot Type changes (also during refreshes); it never changes a role. For a catalogued plot type the role menus offer
Ignore, the roles it uses, andGroup,LabelandBatch Key; a column keeps a role the plot type does not use (shown greyed as “not used by this plot type”). Other plotters offer every role.- Returns:
{"hint": "Uses: X, Y, Z", "description": ...}(empty for other plotters).
- plotter_entries() list[dict][source]
Return the entries of the Simple Mode Plotter Module dropdown.
The list starts with the backend plotter modules that
physplot.plotting_modules.PlotterRegistry.list_plotters()offers for the current dataset, each as{"plotter_id", "name", "category"}.When the last import used a loader plugin (
self._active_loader_entry), the plotters that plugin declares (seephysplot_gui.app.plugin_discovery.discover_loader_plotters()) are appended with the category"Loader":An entry backed by a Python callable gets the id
"loader:<plotter_id>"and is stored inself._custom_plotterssogenerate_module_plot()can run it.Any other entry uses its
backend_plotter_idand is plotted by the backend.An id already in the list is skipped.
self._custom_plottersis reset on every call. The Simple Mode panel calls this whenever the window refreshes (throughModeManager.refresh_plots).- Returns:
The plotter entries in display order.
- record_cell_edit(row_index: int, column: str, value: str, column_number: int) None[source]
Record one edited cell as a
SetCellValueStep.Connected to
CentralTable.cell_value_changed, which fires for each cell the user types into and for each cell filled by a paste. Adds an Edit Cell row with the detailsRow <row>, <column>and the new value as target, linked toSetCellValueStep(row_index, column, value, column_number=column_number). The new value itself reaches the backend throughsync_table_to_backend(), which runs on thetable_editedsignal. The window is not refreshed here.- Parameters:
row_index – 1-based data row number, as shown in the row header.
column – Name of the edited column.
value – The cell’s new text.
column_number – 1-based column position, used on replay when the name is not found.
- record_column_delete(columns: list[str], column_numbers: list[int]) None[source]
Record deleted table columns as a
DeleteColumnsStep.Connected to
CentralTable.columns_deleted(Delete Column in the header context menu). Adds a Delete Columns row with the column names as details and the targetTable, linked toDeleteColumnsStep(columns, column_numbers=column_numbers). The columns have already been removed from the table; the backend dataset follows throughsync_table_to_backend(). The window is not refreshed here.- Parameters:
columns – Names of the deleted columns.
column_numbers – Their 1-based positions before the deletion.
- record_row_delete(row_indices: list[int]) None[source]
Record deleted table rows as a
DeleteRowsStep.Connected to
CentralTable.rows_deleted(Delete Row in the row-number context menu). Adds a Delete Rows row with the detailsRows 3, 4and the targetTable, linked toDeleteRowsStep(row_indices). The rows have already been removed from the table; the backend dataset follows throughsync_table_to_backend(). The window is not refreshed here.- Parameters:
row_indices – 1-based data row numbers that were deleted, in ascending order.
- refresh_style_modules() None[source]
Refresh the plotter-related dropdowns of the panels.
Calls
ModeManager.refresh_plots: Simple Mode rebuilds its Plotter Module, Plot Type and Template lists, and Advanced Mode’srefresh_plotdoes nothing. No control in the bundled panels calls this method; the Reload button next to Template calls the panel’s ownrefresh_styles.
- reload_config_modules() None[source]
Re-scan every
config/folder without restarting the application.
- rename_column(old_name: str, new_name: str) None[source]
Rename a column in the backend and record a
RenameColumnStep.Connected to
CentralTable.column_renamed, emitted after the user renames a column (double-click on the header, or Rename Column in the header’s context menu) and the table has already changed its header. When the backend dataset has a column calledold_name, its 1-based column number is looked up and the column is renamed there withphysplot.PhysPlot.rename_column(); otherwise the number is taken from a default name such asColumn 4(or left asNone) and the backend is not changed. In both cases a Rename Column row (old -> new, target the new name) is recorded withRenameColumnStep(old_name, new_name, old_column_number=<number>), so a replay can fall back to the column number when no column has the old name. The window is refreshed. Errors are reported as “Column rename failed”.- Parameters:
old_name – The column’s previous name.
new_name – The column’s new name.
- rerun_from_timeline_step(row_index: int) None[source]
Resume the sequence at a table row without replaying earlier rows.
Triggered by Rerun from this step in the context menu of a Build Protocol row. The backend restores the state it saved before the row’s first step during an earlier run (
physplot.PhysPlot.rerun_from(); when that snapshot is no longer kept, the latest valid earlier one is used) and runs from there to the end, so edits to that step or later ones take effect. Steps before the resume point are reported as OK. The results are shown like a full run (_show_sequence_results()) with the statusReran from row N, or the failure text when a step fails.Out-of-range rows are ignored. A row without backend steps (a display-only row) only sets the status to
Row N has no replayable step. When no saved state is usable (for example no full run yet, or earlier steps changed since that run), the backend’s error is reported as “Rerun failed”.- Parameters:
row_index – 0-based row index in the protocol table.
- run_bulk_workflow(payload: dict) None[source]
Run a sequence over every matching file of a folder and export each result.
Triggered by Run Bulk Workflow on the Advanced Mode Run Sequence tab. The sequence is the Sequence File when one is given (the backend loads it), otherwise a copy of the current protocol, including its load step, whose loader plugin is reused for every file; an empty protocol raises “Build or import a protocol sequence before running bulk automation.”.
physplot.PhysPlot.run_bulk()(physplot.bulk.run_folder()) then processes each matching file of the input folder in name order with a fresh backend, replays the sequence withallow_column_number_fallback=Trueand exports the result to<output folder>/<file stem>/(data.csv,columns.csv,workflow.pyand, when present,fit.jsonandplot.png). Which files match depends on the sequence’s load step: a plugin format limits the run to that file extension, otherwise the built-in table formats are used.On success the status reads
Bulk complete: N outputs. The run happens in the GUI thread, so the window does not respond until it ends. The first failing file stops the run; the error is reported as “Bulk run failed” with the messageBulk run stopped at <file name>: <error>and a note that files before it were exported and later files were not run. Other errors are reported as “Bulk run failed” as they are. The folder texts are passed to the backend without checks here. The table and the protocol are not changed.- Parameters:
payload – The Bulk Run panel’s fields:
input_folder,workflow_file(may be empty) andoutput_folder.
- run_workflow() None[source]
Replay the current protocol; same as
apply_current_sequence().
- save_workflow() None[source]
Save the protocol as a runnable
Sequence.pyfile.Triggered by Protocol > Export Sequence.py… (
Ctrl+S) and the Export Sequence.py button of Build Protocol. A Save Sequence.py dialog suggestssequence.pyin the writableconfig/sequencesfolder. The backend writes the same Python source that Copy Sequence Code produces (physplot.PhysPlot.save_workflow()): aWORKFLOW_STEPSlist plusbuild_workflow()andrun()helpers, usable from notebooks, scripts orphysplot run-workflow. The file becomesstate.workflow_file(shown asWorkflow:in the Advanced Mode status bar), the status readsSequence savedand the window is refreshed. Errors are reported as “Save workflow failed”.
- schedule_update_check(delay_ms: int = 5000) None[source]
Check for updates in the background after start-up (at most once a day).
Called by
run_app. Skipped when Check for Updates Automatically is off, when the last check was less than a day ago, and for off-screen runs (tests).
- sequence_code_text() str[source]
- set_column_role(column: str, role: str) None[source]
Apply a role picked in a column’s dropdown and record it.
Connected to
CentralTable.role_changed. The role is set on the backend dataset (the backend moves a single-use role such as X or Y away from the column that had it, which then becomes Ignore). For every role exceptIgnorea row is recorded with the actionSet <role>, the detailsSet column as <role>, the column as target and aSetRoleStepsuch asSetRoleStep({"x": "Time"})(role names are converted by_role_key()). ChoosingIgnorefor a column that had a role records a Clear Role row withSetRoleStep({"ignore": column})so a replay ends with the same roles; for a column that was already Ignore nothing is recorded. The role dropdowns are then redrawn from the backend roles and the status bar counts updated;_refresh_all()is not called, so the new row shows in Build Protocol at the next full refresh.Errors, for example a column that the backend dataset does not contain, are reported as “Role update failed”.
- Parameters:
column – Name of the column whose dropdown changed.
role – The chosen role label, for example
"X"or"Y Error".
- set_open_in_figure_editor(enabled: bool) None[source]
Open new plots in the Figure Editor (
True) or a plot window (False).Set by Simple Mode’s Advanced Figure Editor tick box and saved in the PhysPlot settings, so the choice is kept between sessions.
- set_timeline_row_enabled(row_index: int, enabled: bool)[source]
Enable or disable every step in a row and replay from it.
- set_update_channel(channel: str) None[source]
Follow
channel(main, indevelopment or bleedingedge) and check it now.
- show_about_dialog() None[source]
Show the modal About PhysPlot dialog (Help > About PhysPlot).
The dialog shows, top to bottom: the PhysPlot icon (64 px, when the image exists), the title “PhysPlot”, the summary “Table-first scientific plotting and replayable workflow builder.”, three links (Documentation on Read the Docs, GitHub Repository and Report issues or bugs) that open in the default browser, and a Close button. The call blocks until the dialog is closed. Nothing is recorded and the status bar is not changed.
- show_fit_results() None[source]
Show the backend’s last fit result in a Fit Results message box.
Each entry of
state.pp.fit_resultis shown on its ownkey: valueline (for a linear fit: kind, x, y, slope and intercept; for an LSQ fit from a plot: method, expression and parameters). Without a result the box reads “No fit result yet.”. No control in the bundled panels calls this method.
- simple_function_entries() list[dict][source]
Return the entries of the Simple Mode Function dropdown.
The order is:
identityfollowed by every built-in backend transformation fromphysplot.core.transformations.list_transforms(). Each becomes{"display_name", "function_name", "tooltip"}, with the label and tooltip taken fromBUILTIN_FUNCTIONS(for examplebaseline_subtractis shown as “subtract first value”); a name missing from that table is shown as is, without a tooltip.Every transformation plugin from
config/transformations(physplot_gui.app.plugin_discovery.discover_functions()), keeping itsname,display_name,pathandmodulekeys. Its tooltip is the first line of the plugin module’s docstring followed by the file name in brackets, or just the file name when the module has no docstring.
Labels are made unique: a plugin whose label is already taken is relabelled
"<label> (<name>)"so it stays reachable, and any other repeated label is dropped (the first entry wins). The selected entry is passed back toapply_backend_transform()when the user clicks Apply.- Returns:
The function entries in display order.
- start_recording() None[source]
Set the backend’s recording flag and log a display-only Start Tracking row.
Calls
physplot.PhysPlot.start_recording()and adds a row reading “Sequence tracking is always on” with the targetAdvanced; it has no backend step. The GUI records every action regardless of this flag. No control in the bundled panels calls this method.
- stop_recording() None[source]
Log a display-only Tracking row and clear the backend’s recording flag.
Adds a row reading “Sequence tracking stays on” with the target
Advanced(no backend step), then callsphysplot.PhysPlot.stop_recording(). The GUI keeps recording every action regardless of this flag. No control in the bundled panels calls this method.
- style_module_entries() list[dict][source]
Return the entries of the Simple Mode Template dropdown.
The first entry,
{"name": "None", "path": None}, means “no template”. It is followed by every figure template JSON file fromphysplot_gui.plot_styles.list_style_modules()(the per-userconfig/templatesfolder first, then the bundled one, or only the folder inPHYSPLOT_STYLE_DIRwhen that variable is set), sorted by name. Templates are saved from the Figure Editor with PhysPlot > Save as Template.- Returns:
Entries of the form
{"name", "path"}.
- sync_table_to_backend() None[source]
Copy the visible table contents into the backend dataset.
Connected to
CentralTable.table_edited(emitted after typing, pasting, clearing, renaming and deleting rows or columns) and called before every action that reads the data: export, plotting, transformations, fitting and sequence replay.CentralTable.to_dataframetrims the table to its used extent (keeping columns that have a role) and converts columns whose non-empty cells are all numbers to numeric.refresh_dataset_values()then reloads that frame intostate.ppwhile keeping the dataset name, roles, metadata, source path and loader information. The status bar counts are updated.Nothing is recorded here; the individual edits are recorded by
record_cell_edit(),record_row_delete(),record_column_delete()andrename_column().
- timeline_row_enabled(row: dict) bool | None[source]
Return whether a row’s steps run, or
Noneif it has no steps.
- timeline_row_status(row: dict) tuple[str | None, str | None][source]
Return
(status, tooltip)for a Build Protocol row.
- update_channel() str[source]
The branch PhysPlot updates from: the saved choice, else the installed branch.
- workflow_manager() None[source]
- ROLE_LABELS = {'batch_key': 'Batch Key', 'fit_weight': 'Fit Weight', 'group': 'Group', 'ignore': 'Ignore', 'label': 'Label', 'u': 'U', 'v': 'V', 'w': 'W', 'x': 'X', 'xerr': 'X Error', 'y': 'Y', 'y2': 'Y2', 'yerr': 'Y Error', 'z': 'Z'}
Role labels by the keys
SetRoleStepstores (the inverse ofMainWindow._role_key).
- data_file_extensions() list[str][source]
Return every extension PhysPlot can open: built-in types, then loader-plugin types.
The installers register these with the operating system so Open With > PhysPlot appears when a data file is right-clicked.
- data_file_filter() str[source]
Return the Import Data dialog filter: built-in types plus loader-plugin types.
Every extension a loader plugin declares in
FILE_EXTENSIONS(for example.rasor.jdx) is added, so a file a plugin can read is listed without switching the dialog to All Files.- Returns:
A Qt name filter such as
"Data Files (*.csv ... *.ras);;All Files (*)".
- figure_editor_version() str[source]
Return
__version__of PhysPlot’s FigureForge copy without importing it.
- figureforge_plugin_dirs() list[Path][source]
Return the Figure Editor plugin folders in copy order: bundled first, then per-user.
physplot.user_paths.plugin_search_dirs()lists the per-userDocuments/PhysPlot/config/figureforge_pluginsfolder (or the one underPHYSPLOT_USER_DIR) before the bundledconfig/figureforge_pluginsfolder. This function reverses that order because the Figure Editor loads the folders one after another: a per-user plugin file with the same name as a bundled one is loaded last and so replaces it. Folders are returned whether or not they exist; the caller skips missing ones.- Returns:
The plugin folders, bundled folder first.
- loader_label(step) str[source]
Return the Data Loader menu label for a recorded
LoadDataStep.A loader plugin is named by its
DISPLAY_NAME(matched on the plugin file name, or the file name itself when the plugin is missing); a built-in loader by its menu name, for example"auto"becomes “Auto Loader”. This is the text a live import records, so rows rebuilt from a saved sequence read the same as the rows recorded while working.- Parameters:
step – The
LoadDataStep.- Returns:
The loader label.
- plot_details(plotter_id: str, plot_type: str | None, fit_config=None) str[source]
Return the Details text of a Generate Plot row, for example “Create line line”.
- Parameters:
plotter_id – The plotter module id.
plot_type – The plot type, or
Nonefor the plotter’s default.fit_config – The step’s
lsq_fitsettings; an enabled fit adds “ with LSQ fit”.
- Returns:
The row text.
- transform_label(function_name: str) str[source]
Return the protocol-row text for a transformation, as a live Apply records it.
Built-in transformations keep their backend name (
normalize_max); a plugin fromconfig/transformationsis shown by itsDISPLAY_NAME(14_xrd_baseline_removebecomes “XRD: Baseline Remove”). An unknown name is returned unchanged.- Parameters:
function_name – The recorded
function_name.- Returns:
The row text.