From 20454e64f4d58b784b8486409713317a0cda6618 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 23 Jun 2026 15:32:36 +0200 Subject: [PATCH] feat: allow the user to include the model and params in the tsv file name --- CHANGELOG | 1 + pyjibe/fd/main.py | 24 +++++++++++++++++++++++- pyjibe/fd/main.ui | 10 ++++++++++ tests/test_fd_fit.py | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index fda13cc..57d6aaa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ 0.16.4 + - feat: option to include model and params in autosave tsv filename (#49) - setup: support latest python versions (#32, #46) - setup: support latest matplotlib versions (#32, #46) - fix: remember user's choice upon curve open (#44, #45) diff --git a/pyjibe/fd/main.py b/pyjibe/fd/main.py index 35c27b9..8808cf7 100644 --- a/pyjibe/fd/main.py +++ b/pyjibe/fd/main.py @@ -31,6 +31,22 @@ DlgAutosave = uic.loadUiType(dlg_autosave_path)[0] +def _make_params_suffix(fit_props): + """Build a filename-safe suffix from model key and fixed initial params. + + Sections are separated by hyphens; underscores within model key or + parameter names are preserved. Example: + ``hertz_cone-E4.5e+03-alpha30-nu0.5-contact_point0`` + """ + parts = [fit_props["model_key"]] + fp = fit_props.get("params_initial", {}) + for key in sorted(fp): + p = fp[key] + if not p.vary and not p.expr and not key.startswith("_"): + parts.append(f"{key}{p.value:.3g}") + return "-".join(parts) + + class UiForceDistance(QtWidgets.QWidget): _instance_counter = 0 # remember the user's autosave overwrite choice for the current gui @@ -266,7 +282,13 @@ def autosave(self, fdist): ): exp_curv.append(ar) # The file to export - fname = os.path.join(adir, "pyjibe_fit_results_leaf.tsv") + if (self.cb_autosave_name_params.checkState() + == QtCore.Qt.CheckState.Checked): + suffix = _make_params_suffix(fdist.fit_properties) + basename = f"pyjibe_fit_results_leaf-{suffix}.tsv" + else: + basename = "pyjibe_fit_results_leaf.tsv" + fname = os.path.join(adir, basename) # Only export if we have curves to export if exp_curv: diff --git a/pyjibe/fd/main.ui b/pyjibe/fd/main.ui index 0bddabc..bfd4caf 100644 --- a/pyjibe/fd/main.ui +++ b/pyjibe/fd/main.ui @@ -501,6 +501,16 @@ + + + + Include model and params in filename + + + false + + + diff --git a/tests/test_fd_fit.py b/tests/test_fd_fit.py index 5f37733..2ef68d7 100644 --- a/tests/test_fd_fit.py +++ b/tests/test_fd_fit.py @@ -262,3 +262,36 @@ def test_set_indentation_depth_manually_infdoublespinbox(qtbot): qtbot.keyClicks(war.tab_fit.sp_range_1, text_entered) assert war.tab_fit.sp_range_1.value() == resulting_value main_window.close() + + +def test_autosave_name_params(qtbot, tmp_path): + """cb_autosave_name_params embeds model+params in the TSV filename.""" + import shutil + src = data_path / "spot3-0192.jpk-force" + dest = tmp_path / "spot3-0192.jpk-force" + shutil.copy2(src, dest) + + main_window = pyjibe.head.PyJibe() + qtbot.addWidget(main_window) + main_window.load_data(files=[dest]) + war = main_window.subwindows[0].widget() + war.tab_preprocess.set_preprocessing(["compute_tip_position"]) + war.tab_fit.cb_weight_cp.setCheckState(QtCore.Qt.CheckState.Unchecked) + + # Default (checkbox off): standard filename + war.cb_autosave.setChecked(True) + war.cb_autosave_name_params.setChecked(False) + war.on_tab_changed() + default_files = list(tmp_path.glob("pyjibe_fit_results_leaf.tsv")) + assert len(default_files) == 1 + + # Remove it and re-run with checkbox on + default_files[0].unlink() + war._autosave_original_files.clear() + war.cb_autosave_name_params.setChecked(True) + war.on_tab_changed() + param_files = [f for f in tmp_path.glob("pyjibe_fit_results_leaf-*.tsv")] + assert len(param_files) == 1 + assert "hertz" in param_files[0].name + + main_window.close()