scitex 2.5.0__py3-none-any.whl → 2.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scitex/__init__.py +19 -8
- scitex/__main__.py +2 -1
- scitex/__version__.py +1 -1
- scitex/_optional_deps.py +13 -20
- scitex/ai/__init__.py +5 -0
- scitex/ai/_gen_ai/_Anthropic.py +3 -1
- scitex/ai/_gen_ai/_BaseGenAI.py +3 -2
- scitex/ai/_gen_ai/_DeepSeek.py +1 -1
- scitex/ai/_gen_ai/_Google.py +3 -2
- scitex/ai/_gen_ai/_Llama.py +4 -2
- scitex/ai/_gen_ai/_OpenAI.py +3 -1
- scitex/ai/_gen_ai/_PARAMS.py +1 -0
- scitex/ai/_gen_ai/_Perplexity.py +3 -1
- scitex/ai/_gen_ai/__init__.py +1 -0
- scitex/ai/_gen_ai/_format_output_func.py +3 -1
- scitex/ai/classification/CrossValidationExperiment.py +8 -14
- scitex/ai/classification/examples/timeseries_cv_demo.py +128 -112
- scitex/ai/classification/reporters/_BaseClassificationReporter.py +2 -0
- scitex/ai/classification/reporters/_ClassificationReporter.py +30 -45
- scitex/ai/classification/reporters/_MultiClassificationReporter.py +8 -11
- scitex/ai/classification/reporters/_SingleClassificationReporter.py +126 -182
- scitex/ai/classification/reporters/__init__.py +1 -1
- scitex/ai/classification/reporters/reporter_utils/_Plotter.py +213 -119
- scitex/ai/classification/reporters/reporter_utils/__init__.py +28 -36
- scitex/ai/classification/reporters/reporter_utils/aggregation.py +125 -143
- scitex/ai/classification/reporters/reporter_utils/data_models.py +128 -120
- scitex/ai/classification/reporters/reporter_utils/reporting.py +507 -340
- scitex/ai/classification/reporters/reporter_utils/storage.py +4 -1
- scitex/ai/classification/reporters/reporter_utils/validation.py +141 -154
- scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +204 -129
- scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +215 -171
- scitex/ai/classification/timeseries/_TimeSeriesMetadata.py +17 -17
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +67 -143
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +67 -143
- scitex/ai/classification/timeseries/_TimeSeriesStrategy.py +12 -13
- scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +231 -144
- scitex/ai/classification/timeseries/__init__.py +2 -4
- scitex/ai/classification/timeseries/_normalize_timestamp.py +3 -0
- scitex/ai/clustering/_pca.py +0 -1
- scitex/ai/clustering/_umap.py +1 -2
- scitex/ai/feature_extraction/__init__.py +10 -8
- scitex/ai/feature_extraction/vit.py +0 -1
- scitex/ai/feature_selection/feature_selection.py +3 -8
- scitex/ai/metrics/_calc_conf_mat.py +2 -0
- scitex/ai/metrics/_calc_feature_importance.py +3 -7
- scitex/ai/metrics/_calc_pre_rec_auc.py +5 -5
- scitex/ai/metrics/_calc_roc_auc.py +4 -2
- scitex/ai/metrics/_calc_seizure_prediction_metrics.py +35 -20
- scitex/ai/metrics/_calc_silhouette_score.py +1 -3
- scitex/ai/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger.py +0 -3
- scitex/ai/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger2020.py +0 -3
- scitex/ai/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger913A.py +0 -3
- scitex/ai/optim/_optimizers.py +1 -1
- scitex/ai/plt/__init__.py +6 -1
- scitex/ai/plt/_plot_feature_importance.py +1 -3
- scitex/ai/plt/_plot_learning_curve.py +9 -24
- scitex/ai/plt/_plot_optuna_study.py +4 -3
- scitex/ai/plt/_plot_pre_rec_curve.py +9 -15
- scitex/ai/plt/_plot_roc_curve.py +6 -8
- scitex/ai/plt/_stx_conf_mat.py +121 -122
- scitex/ai/sampling/undersample.py +3 -2
- scitex/ai/sklearn/__init__.py +2 -2
- scitex/ai/training/_LearningCurveLogger.py +23 -10
- scitex/ai/utils/_check_params.py +0 -1
- scitex/benchmark/__init__.py +15 -25
- scitex/benchmark/benchmark.py +124 -117
- scitex/benchmark/monitor.py +117 -107
- scitex/benchmark/profiler.py +61 -58
- scitex/bridge/__init__.py +110 -0
- scitex/bridge/_helpers.py +149 -0
- scitex/bridge/_plt_vis.py +529 -0
- scitex/bridge/_protocol.py +283 -0
- scitex/bridge/_stats_plt.py +261 -0
- scitex/bridge/_stats_vis.py +265 -0
- scitex/browser/__init__.py +0 -2
- scitex/browser/auth/__init__.py +0 -0
- scitex/browser/auth/google.py +16 -11
- scitex/browser/automation/CookieHandler.py +2 -3
- scitex/browser/collaboration/__init__.py +3 -0
- scitex/browser/collaboration/auth_helpers.py +3 -1
- scitex/browser/collaboration/collaborative_agent.py +2 -0
- scitex/browser/collaboration/interactive_panel.py +2 -2
- scitex/browser/collaboration/shared_session.py +20 -11
- scitex/browser/collaboration/standard_interactions.py +1 -0
- scitex/browser/core/BrowserMixin.py +12 -30
- scitex/browser/core/ChromeProfileManager.py +9 -24
- scitex/browser/debugging/_browser_logger.py +15 -25
- scitex/browser/debugging/_failure_capture.py +9 -2
- scitex/browser/debugging/_highlight_element.py +15 -6
- scitex/browser/debugging/_show_grid.py +5 -6
- scitex/browser/debugging/_sync_session.py +4 -3
- scitex/browser/debugging/_test_monitor.py +14 -5
- scitex/browser/debugging/_visual_cursor.py +46 -35
- scitex/browser/interaction/click_center.py +4 -3
- scitex/browser/interaction/click_with_fallbacks.py +7 -10
- scitex/browser/interaction/close_popups.py +79 -66
- scitex/browser/interaction/fill_with_fallbacks.py +8 -8
- scitex/browser/pdf/__init__.py +3 -1
- scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +11 -10
- scitex/browser/pdf/detect_chrome_pdf_viewer.py +3 -6
- scitex/browser/remote/CaptchaHandler.py +109 -96
- scitex/browser/remote/ZenRowsAPIClient.py +91 -97
- scitex/browser/remote/ZenRowsBrowserManager.py +138 -112
- scitex/browser/stealth/HumanBehavior.py +4 -9
- scitex/browser/stealth/StealthManager.py +11 -26
- scitex/capture/__init__.py +17 -17
- scitex/capture/__main__.py +2 -3
- scitex/capture/capture.py +23 -51
- scitex/capture/cli.py +14 -39
- scitex/capture/gif.py +5 -9
- scitex/capture/mcp_server.py +7 -20
- scitex/capture/session.py +4 -3
- scitex/capture/utils.py +18 -53
- scitex/cli/__init__.py +1 -1
- scitex/cli/cloud.py +158 -116
- scitex/cli/config.py +224 -0
- scitex/cli/main.py +41 -40
- scitex/cli/scholar.py +60 -27
- scitex/cli/security.py +14 -20
- scitex/cli/web.py +87 -90
- scitex/cli/writer.py +51 -45
- scitex/cloud/__init__.py +14 -11
- scitex/cloud/_matplotlib_hook.py +6 -6
- scitex/config/README.md +313 -0
- scitex/config/{PriorityConfig.py → _PriorityConfig.py} +114 -17
- scitex/config/_ScitexConfig.py +319 -0
- scitex/config/__init__.py +41 -9
- scitex/config/_paths.py +325 -0
- scitex/config/default.yaml +81 -0
- scitex/context/_suppress_output.py +2 -3
- scitex/db/_BaseMixins/_BaseBackupMixin.py +3 -1
- scitex/db/_BaseMixins/_BaseBatchMixin.py +3 -1
- scitex/db/_BaseMixins/_BaseBlobMixin.py +3 -1
- scitex/db/_BaseMixins/_BaseImportExportMixin.py +1 -3
- scitex/db/_BaseMixins/_BaseIndexMixin.py +3 -1
- scitex/db/_BaseMixins/_BaseMaintenanceMixin.py +1 -3
- scitex/db/_BaseMixins/_BaseQueryMixin.py +3 -1
- scitex/db/_BaseMixins/_BaseRowMixin.py +3 -1
- scitex/db/_BaseMixins/_BaseTableMixin.py +3 -1
- scitex/db/_BaseMixins/_BaseTransactionMixin.py +1 -3
- scitex/db/_BaseMixins/__init__.py +1 -1
- scitex/db/__init__.py +9 -1
- scitex/db/__main__.py +8 -21
- scitex/db/_check_health.py +15 -31
- scitex/db/_delete_duplicates.py +7 -4
- scitex/db/_inspect.py +22 -38
- scitex/db/_inspect_optimized.py +89 -85
- scitex/db/_postgresql/_PostgreSQL.py +0 -1
- scitex/db/_postgresql/_PostgreSQLMixins/_BlobMixin.py +3 -1
- scitex/db/_postgresql/_PostgreSQLMixins/_ConnectionMixin.py +1 -3
- scitex/db/_postgresql/_PostgreSQLMixins/_ImportExportMixin.py +1 -3
- scitex/db/_postgresql/_PostgreSQLMixins/_MaintenanceMixin.py +1 -4
- scitex/db/_postgresql/_PostgreSQLMixins/_QueryMixin.py +3 -3
- scitex/db/_postgresql/_PostgreSQLMixins/_RowMixin.py +3 -1
- scitex/db/_postgresql/_PostgreSQLMixins/_TransactionMixin.py +1 -3
- scitex/db/_postgresql/__init__.py +1 -1
- scitex/db/_sqlite3/_SQLite3.py +2 -4
- scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin.py +11 -12
- scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin_v01-need-_hash-col.py +19 -14
- scitex/db/_sqlite3/_SQLite3Mixins/_BatchMixin.py +3 -1
- scitex/db/_sqlite3/_SQLite3Mixins/_BlobMixin.py +7 -7
- scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin.py +118 -111
- scitex/db/_sqlite3/_SQLite3Mixins/_ConnectionMixin.py +8 -10
- scitex/db/_sqlite3/_SQLite3Mixins/_GitMixin.py +17 -45
- scitex/db/_sqlite3/_SQLite3Mixins/_ImportExportMixin.py +1 -3
- scitex/db/_sqlite3/_SQLite3Mixins/_IndexMixin.py +3 -1
- scitex/db/_sqlite3/_SQLite3Mixins/_QueryMixin.py +3 -4
- scitex/db/_sqlite3/_SQLite3Mixins/_RowMixin.py +9 -9
- scitex/db/_sqlite3/_SQLite3Mixins/_TableMixin.py +18 -11
- scitex/db/_sqlite3/_SQLite3Mixins/__init__.py +1 -0
- scitex/db/_sqlite3/__init__.py +1 -1
- scitex/db/_sqlite3/_delete_duplicates.py +13 -11
- scitex/decorators/__init__.py +29 -4
- scitex/decorators/_auto_order.py +43 -43
- scitex/decorators/_batch_fn.py +12 -6
- scitex/decorators/_cache_disk.py +8 -9
- scitex/decorators/_cache_disk_async.py +8 -7
- scitex/decorators/_combined.py +19 -13
- scitex/decorators/_converters.py +16 -3
- scitex/decorators/_deprecated.py +32 -22
- scitex/decorators/_numpy_fn.py +18 -4
- scitex/decorators/_pandas_fn.py +17 -5
- scitex/decorators/_signal_fn.py +17 -3
- scitex/decorators/_torch_fn.py +32 -15
- scitex/decorators/_xarray_fn.py +23 -9
- scitex/dev/_analyze_code_flow.py +0 -2
- scitex/dict/_DotDict.py +15 -19
- scitex/dict/_flatten.py +1 -0
- scitex/dict/_listed_dict.py +1 -0
- scitex/dict/_pop_keys.py +1 -0
- scitex/dict/_replace.py +1 -0
- scitex/dict/_safe_merge.py +1 -0
- scitex/dict/_to_str.py +2 -3
- scitex/dsp/__init__.py +13 -4
- scitex/dsp/_crop.py +3 -1
- scitex/dsp/_detect_ripples.py +3 -1
- scitex/dsp/_modulation_index.py +3 -1
- scitex/dsp/_time.py +3 -1
- scitex/dsp/_wavelet.py +0 -1
- scitex/dsp/example.py +0 -5
- scitex/dsp/filt.py +4 -0
- scitex/dsp/utils/__init__.py +4 -1
- scitex/dsp/utils/pac.py +3 -3
- scitex/dt/_normalize_timestamp.py +4 -1
- scitex/errors.py +3 -6
- scitex/etc/__init__.py +1 -1
- scitex/gen/_DimHandler.py +6 -6
- scitex/gen/__init__.py +5 -1
- scitex/gen/_deprecated_close.py +1 -0
- scitex/gen/_deprecated_start.py +5 -3
- scitex/gen/_detect_environment.py +44 -41
- scitex/gen/_detect_notebook_path.py +51 -47
- scitex/gen/_embed.py +1 -1
- scitex/gen/_get_notebook_path.py +81 -62
- scitex/gen/_inspect_module.py +0 -1
- scitex/gen/_norm.py +16 -7
- scitex/gen/_norm_cache.py +78 -65
- scitex/gen/_print_config.py +0 -3
- scitex/gen/_src.py +2 -3
- scitex/gen/_title_case.py +3 -2
- scitex/gen/_to_even.py +8 -8
- scitex/gen/_transpose.py +3 -3
- scitex/gen/misc.py +0 -3
- scitex/gists/_SigMacro_processFigure_S.py +2 -2
- scitex/gists/_SigMacro_toBlue.py +2 -2
- scitex/gists/__init__.py +4 -1
- scitex/git/_branch.py +19 -11
- scitex/git/_clone.py +23 -15
- scitex/git/_commit.py +10 -12
- scitex/git/_init.py +15 -38
- scitex/git/_remote.py +9 -3
- scitex/git/_result.py +3 -0
- scitex/git/_retry.py +2 -5
- scitex/git/_types.py +4 -0
- scitex/git/_validation.py +8 -8
- scitex/git/_workflow.py +4 -4
- scitex/io/__init__.py +2 -1
- scitex/io/_glob.py +2 -2
- scitex/io/_json2md.py +3 -3
- scitex/io/_load.py +6 -8
- scitex/io/_load_cache.py +71 -71
- scitex/io/_load_configs.py +2 -3
- scitex/io/_load_modules/_H5Explorer.py +6 -12
- scitex/io/_load_modules/_ZarrExplorer.py +3 -3
- scitex/io/_load_modules/_bibtex.py +62 -63
- scitex/io/_load_modules/_canvas.py +4 -9
- scitex/io/_load_modules/_catboost.py +7 -2
- scitex/io/_load_modules/_hdf5.py +2 -0
- scitex/io/_load_modules/_image.py +5 -1
- scitex/io/_load_modules/_matlab.py +3 -1
- scitex/io/_load_modules/_optuna.py +0 -1
- scitex/io/_load_modules/_pdf.py +38 -29
- scitex/io/_load_modules/_sqlite3.py +1 -0
- scitex/io/_load_modules/_txt.py +2 -0
- scitex/io/_load_modules/_xml.py +9 -9
- scitex/io/_load_modules/_zarr.py +12 -10
- scitex/io/_metadata.py +76 -37
- scitex/io/_qr_utils.py +18 -13
- scitex/io/_save.py +220 -63
- scitex/io/_save_modules/__init__.py +7 -2
- scitex/io/_save_modules/_bibtex.py +66 -61
- scitex/io/_save_modules/_canvas.py +5 -6
- scitex/io/_save_modules/_catboost.py +2 -2
- scitex/io/_save_modules/_csv.py +4 -4
- scitex/io/_save_modules/_excel.py +5 -9
- scitex/io/_save_modules/_hdf5.py +9 -21
- scitex/io/_save_modules/_html.py +5 -5
- scitex/io/_save_modules/_image.py +105 -8
- scitex/io/_save_modules/_joblib.py +2 -2
- scitex/io/_save_modules/_json.py +51 -6
- scitex/io/_save_modules/_listed_dfs_as_csv.py +2 -1
- scitex/io/_save_modules/_listed_scalars_as_csv.py +2 -1
- scitex/io/_save_modules/_matlab.py +2 -2
- scitex/io/_save_modules/_numpy.py +6 -8
- scitex/io/_save_modules/_pickle.py +4 -4
- scitex/io/_save_modules/_plotly.py +3 -3
- scitex/io/_save_modules/_tex.py +23 -25
- scitex/io/_save_modules/_text.py +2 -2
- scitex/io/_save_modules/_yaml.py +9 -9
- scitex/io/_save_modules/_zarr.py +15 -15
- scitex/io/utils/__init__.py +2 -1
- scitex/io/utils/h5_to_zarr.py +173 -155
- scitex/linalg/__init__.py +1 -1
- scitex/linalg/_geometric_median.py +4 -3
- scitex/logging/_Tee.py +5 -7
- scitex/logging/__init__.py +18 -19
- scitex/logging/_config.py +4 -1
- scitex/logging/_context.py +6 -5
- scitex/logging/_formatters.py +2 -3
- scitex/logging/_handlers.py +19 -20
- scitex/logging/_levels.py +9 -17
- scitex/logging/_logger.py +74 -15
- scitex/logging/_print_capture.py +17 -17
- scitex/nn/_BNet.py +1 -3
- scitex/nn/_Filters.py +6 -2
- scitex/nn/_ModulationIndex.py +3 -1
- scitex/nn/_PAC.py +3 -2
- scitex/nn/_PSD.py +0 -1
- scitex/nn/__init__.py +16 -3
- scitex/path/_clean.py +10 -8
- scitex/path/_find.py +1 -1
- scitex/path/_get_spath.py +1 -2
- scitex/path/_mk_spath.py +1 -1
- scitex/path/_symlink.py +5 -10
- scitex/pd/__init__.py +4 -1
- scitex/pd/_force_df.py +24 -24
- scitex/pd/_get_unique.py +1 -0
- scitex/pd/_merge_columns.py +1 -1
- scitex/pd/_round.py +11 -7
- scitex/pd/_to_xy.py +0 -1
- scitex/plt/REQUESTS.md +191 -0
- scitex/plt/__init__.py +185 -87
- scitex/plt/_subplots/_AxesWrapper.py +22 -6
- scitex/plt/_subplots/_AxisWrapper.py +100 -39
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +74 -52
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +183 -73
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +61 -45
- scitex/plt/_subplots/_AxisWrapperMixins/_TrackingMixin.py +26 -14
- scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +80 -73
- scitex/plt/_subplots/_FigWrapper.py +93 -60
- scitex/plt/_subplots/_SubplotsWrapper.py +135 -68
- scitex/plt/_subplots/__init__.py +10 -0
- scitex/plt/_subplots/_export_as_csv.py +89 -47
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +1 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +6 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_bar.py +88 -38
- scitex/plt/_subplots/_export_as_csv_formatters/_format_barh.py +25 -31
- scitex/plt/_subplots/_export_as_csv_formatters/_format_boxplot.py +53 -23
- scitex/plt/_subplots/_export_as_csv_formatters/_format_contour.py +38 -25
- scitex/plt/_subplots/_export_as_csv_formatters/_format_contourf.py +17 -9
- scitex/plt/_subplots/_export_as_csv_formatters/_format_errorbar.py +70 -124
- scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +12 -10
- scitex/plt/_subplots/_export_as_csv_formatters/_format_fill.py +31 -17
- scitex/plt/_subplots/_export_as_csv_formatters/_format_fill_between.py +33 -21
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hexbin.py +14 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hist.py +43 -29
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hist2d.py +14 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow.py +27 -11
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +7 -5
- scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +9 -7
- scitex/plt/_subplots/_export_as_csv_formatters/_format_pie.py +15 -6
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +85 -46
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_box.py +52 -27
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_imshow.py +1 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +16 -17
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +7 -5
- scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +10 -8
- scitex/plt/_subplots/_export_as_csv_formatters/_format_scatter.py +17 -6
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_barplot.py +43 -26
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_boxplot.py +68 -47
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_heatmap.py +52 -64
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_histplot.py +55 -50
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +9 -11
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_kdeplot.py +63 -29
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +4 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +6 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_scatterplot.py +44 -40
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_stripplot.py +46 -39
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_swarmplot.py +46 -39
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_violinplot.py +75 -94
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stem.py +12 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_step.py +12 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +10 -8
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_conf_mat.py +17 -15
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_ecdf.py +10 -9
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_fillv.py +35 -31
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_heatmap.py +18 -18
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_image.py +24 -18
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_joyplot.py +9 -7
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_line.py +34 -23
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_ci.py +15 -13
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_std.py +12 -10
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_median_iqr.py +15 -13
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_raster.py +11 -9
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_rectangle.py +84 -56
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter_hist.py +35 -32
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_shaded_line.py +46 -30
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_violin.py +51 -51
- scitex/plt/_subplots/_export_as_csv_formatters/_format_text.py +32 -31
- scitex/plt/_subplots/_export_as_csv_formatters/_format_violin.py +34 -31
- scitex/plt/_subplots/_export_as_csv_formatters/_format_violinplot.py +44 -37
- scitex/plt/_subplots/_export_as_csv_formatters/verify_formatters.py +91 -74
- scitex/plt/_tpl.py +6 -5
- scitex/plt/ax/_plot/__init__.py +24 -0
- scitex/plt/ax/_plot/_add_fitted_line.py +12 -11
- scitex/plt/ax/_plot/_plot_circular_hist.py +3 -1
- scitex/plt/ax/_plot/_plot_statistical_shaded_line.py +25 -19
- scitex/plt/ax/_plot/_stx_conf_mat.py +6 -3
- scitex/plt/ax/_plot/_stx_ecdf.py +5 -3
- scitex/plt/ax/_plot/_stx_fillv.py +4 -2
- scitex/plt/ax/_plot/_stx_heatmap.py +7 -4
- scitex/plt/ax/_plot/_stx_image.py +7 -5
- scitex/plt/ax/_plot/_stx_joyplot.py +32 -10
- scitex/plt/ax/_plot/_stx_raster.py +26 -11
- scitex/plt/ax/_plot/_stx_rectangle.py +2 -2
- scitex/plt/ax/_plot/_stx_shaded_line.py +15 -11
- scitex/plt/ax/_plot/_stx_violin.py +3 -1
- scitex/plt/ax/_style/_add_marginal_ax.py +6 -4
- scitex/plt/ax/_style/_auto_scale_axis.py +14 -10
- scitex/plt/ax/_style/_extend.py +3 -1
- scitex/plt/ax/_style/_force_aspect.py +5 -3
- scitex/plt/ax/_style/_format_units.py +2 -2
- scitex/plt/ax/_style/_hide_spines.py +5 -1
- scitex/plt/ax/_style/_map_ticks.py +5 -3
- scitex/plt/ax/_style/_rotate_labels.py +5 -4
- scitex/plt/ax/_style/_rotate_labels_v01.py +73 -63
- scitex/plt/ax/_style/_set_log_scale.py +120 -85
- scitex/plt/ax/_style/_set_meta.py +99 -76
- scitex/plt/ax/_style/_set_supxyt.py +33 -16
- scitex/plt/ax/_style/_set_xyt.py +27 -18
- scitex/plt/ax/_style/_share_axes.py +15 -5
- scitex/plt/ax/_style/_show_spines.py +58 -57
- scitex/plt/ax/_style/_style_barplot.py +1 -1
- scitex/plt/ax/_style/_style_boxplot.py +25 -14
- scitex/plt/ax/_style/_style_errorbar.py +0 -0
- scitex/plt/ax/_style/_style_scatter.py +1 -1
- scitex/plt/ax/_style/_style_suptitles.py +3 -3
- scitex/plt/ax/_style/_style_violinplot.py +8 -2
- scitex/plt/color/__init__.py +34 -2
- scitex/plt/color/_add_hue_col.py +1 -0
- scitex/plt/color/_colors.py +0 -1
- scitex/plt/color/_get_colors_from_conf_matap.py +3 -1
- scitex/plt/color/_vizualize_colors.py +0 -1
- scitex/plt/docs/FIGURE_ARCHITECTURE.md +155 -97
- scitex/plt/gallery/README.md +75 -0
- scitex/plt/gallery/__init__.py +29 -0
- scitex/plt/gallery/_generate.py +153 -0
- scitex/plt/gallery/_plots.py +594 -0
- scitex/plt/gallery/_registry.py +153 -0
- scitex/plt/styles/__init__.py +9 -9
- scitex/plt/styles/_plot_defaults.py +62 -61
- scitex/plt/styles/_plot_postprocess.py +126 -77
- scitex/plt/styles/_style_loader.py +0 -0
- scitex/plt/styles/presets.py +43 -18
- scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_between.json +110 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_betweenx.json +88 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fill_between.json +103 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fillv.json +106 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/bar.json +92 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/barh.json +92 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/boxplot.json +92 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_bar.json +84 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_barh.json +84 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_box.json +83 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_boxplot.json +93 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violin.json +91 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violinplot.json +91 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/violinplot.json +91 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/contour.json +97 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/contourf.json +98 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/stx_contour.json +84 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist.json +101 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist2d.json +96 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_ecdf.json +95 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_joyplot.json +95 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_kde.json +93 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/imshow.json +95 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/matshow.json +95 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_conf_mat.json +83 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_heatmap.json +92 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_image.json +121 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_imshow.json +84 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/line/plot.json +110 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/line/step.json +92 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_line.json +95 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_shaded_line.json +96 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/hexbin.json +95 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/scatter.json +95 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stem.json +92 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stx_scatter.json +84 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/special/pie.json +94 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_raster.json +109 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_rectangle.json +108 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/errorbar.json +93 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_errorbar.json +84 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_ci.json +96 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_std.json +96 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_median_iqr.json +96 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/vector/quiver.json +99 -0
- scitex/plt/templates/research-master/scitex/vis/gallery/vector/streamplot.json +100 -0
- scitex/plt/utils/__init__.py +29 -2
- scitex/plt/utils/_close.py +8 -3
- scitex/plt/utils/_collect_figure_metadata.py +3031 -265
- scitex/plt/utils/_colorbar.py +15 -17
- scitex/plt/utils/_configure_mpl.py +22 -14
- scitex/plt/utils/_crop.py +60 -27
- scitex/plt/utils/_csv_column_naming.py +123 -72
- scitex/plt/utils/_dimension_viewer.py +7 -19
- scitex/plt/utils/_figure_from_axes_mm.py +70 -16
- scitex/plt/utils/_figure_mm.py +3 -2
- scitex/plt/utils/_get_actual_font.py +5 -4
- scitex/plt/utils/_histogram_utils.py +52 -48
- scitex/plt/utils/_is_valid_axis.py +19 -13
- scitex/plt/utils/_mk_colorbar.py +3 -3
- scitex/plt/utils/_scientific_captions.py +202 -139
- scitex/plt/utils/_scitex_config.py +98 -98
- scitex/plt/utils/_units.py +0 -0
- scitex/plt/utils/metadata/__init__.py +36 -0
- scitex/plt/utils/metadata/_artist_extraction.py +119 -0
- scitex/plt/utils/metadata/_axes_metadata.py +93 -0
- scitex/plt/utils/metadata/_collection_artists.py +292 -0
- scitex/plt/utils/metadata/_core.py +208 -0
- scitex/plt/utils/metadata/_csv_column_extraction.py +186 -0
- scitex/plt/utils/metadata/_csv_hash.py +115 -0
- scitex/plt/utils/metadata/_csv_verification.py +95 -0
- scitex/plt/utils/metadata/_data_linkage.py +263 -0
- scitex/plt/utils/metadata/_dimensions.py +239 -0
- scitex/plt/utils/metadata/_figure_metadata.py +58 -0
- scitex/plt/utils/metadata/_image_text_artists.py +168 -0
- scitex/plt/utils/metadata/_label_parsing.py +82 -0
- scitex/plt/utils/metadata/_legend_extraction.py +120 -0
- scitex/plt/utils/metadata/_line_artists.py +367 -0
- scitex/plt/utils/metadata/_line_semantic_handling.py +173 -0
- scitex/plt/utils/metadata/_patch_artists.py +211 -0
- scitex/plt/utils/metadata/_plot_content.py +26 -0
- scitex/plt/utils/metadata/_plot_type_detection.py +184 -0
- scitex/plt/utils/metadata/_precision.py +134 -0
- scitex/plt/utils/metadata/_precision_config.py +68 -0
- scitex/plt/utils/metadata/_precision_sections.py +211 -0
- scitex/plt/utils/metadata/_recipe_extraction.py +267 -0
- scitex/plt/utils/metadata/_style_parsing.py +174 -0
- scitex/repro/_RandomStateManager.py +33 -38
- scitex/repro/__init__.py +16 -7
- scitex/repro/_gen_ID.py +7 -9
- scitex/repro/_gen_timestamp.py +7 -6
- scitex/repro/_hash_array.py +8 -12
- scitex/reproduce/__init__.py +1 -1
- scitex/resource/_get_processor_usages.py +3 -1
- scitex/resource/_log_processor_usages.py +3 -1
- scitex/rng/__init__.py +1 -1
- scitex/schema/README.md +178 -0
- scitex/schema/__init__.py +144 -0
- scitex/schema/_canvas.py +444 -0
- scitex/schema/_stats.py +762 -0
- scitex/schema/_validation.py +590 -0
- scitex/scholar/.legacy/Scholar.py +5 -12
- scitex/scholar/.legacy/_Scholar.py +66 -99
- scitex/scholar/.legacy/_ScholarAPI.py +75 -66
- scitex/scholar/.legacy/_tmp/search_engine/_BaseSearchEngine.py +3 -3
- scitex/scholar/.legacy/_tmp/search_engine/_UnifiedSearcher.py +4 -9
- scitex/scholar/.legacy/_tmp/search_engine/__init__.py +14 -21
- scitex/scholar/.legacy/_tmp/search_engine/local/_LocalSearchEngine.py +40 -37
- scitex/scholar/.legacy/_tmp/search_engine/local/_VectorSearchEngine.py +31 -28
- scitex/scholar/.legacy/_tmp/search_engine/web/_ArxivSearchEngine.py +74 -65
- scitex/scholar/.legacy/_tmp/search_engine/web/_CrossRefSearchEngine.py +122 -116
- scitex/scholar/.legacy/_tmp/search_engine/web/_GoogleScholarSearchEngine.py +65 -59
- scitex/scholar/.legacy/_tmp/search_engine/web/_PubMedSearchEngine.py +121 -107
- scitex/scholar/.legacy/_tmp/search_engine/web/_SemanticScholarSearchEngine.py +5 -12
- scitex/scholar/.legacy/database/_DatabaseEntry.py +49 -45
- scitex/scholar/.legacy/database/_DatabaseIndex.py +131 -94
- scitex/scholar/.legacy/database/_LibraryManager.py +65 -63
- scitex/scholar/.legacy/database/_PaperDatabase.py +138 -124
- scitex/scholar/.legacy/database/_ScholarDatabaseIntegration.py +14 -36
- scitex/scholar/.legacy/database/_StorageIntegratedDB.py +192 -156
- scitex/scholar/.legacy/database/_ZoteroCompatibleDB.py +300 -237
- scitex/scholar/.legacy/database/__init__.py +2 -1
- scitex/scholar/.legacy/database/manage.py +92 -84
- scitex/scholar/.legacy/lookup/_LookupIndex.py +157 -101
- scitex/scholar/.legacy/lookup/__init__.py +2 -1
- scitex/scholar/.legacy/metadata/doi/batch/_MetadataHandlerForBatchDOIResolution.py +4 -9
- scitex/scholar/.legacy/metadata/doi/batch/_ProgressManagerForBatchDOIResolution.py +10 -23
- scitex/scholar/.legacy/metadata/doi/batch/_SourceStatsManagerForBatchDOIResolution.py +4 -9
- scitex/scholar/.legacy/metadata/doi/batch/__init__.py +3 -1
- scitex/scholar/.legacy/metadata/doi/resolvers/_BatchDOIResolver.py +10 -25
- scitex/scholar/.legacy/metadata/doi/resolvers/_BibTeXDOIResolver.py +19 -49
- scitex/scholar/.legacy/metadata/doi/resolvers/_DOIResolver.py +1 -0
- scitex/scholar/.legacy/metadata/doi/resolvers/_SingleDOIResolver.py +8 -20
- scitex/scholar/.legacy/metadata/doi/sources/.combined-SemanticScholarSource/_SemanticScholarSource.py +37 -35
- scitex/scholar/.legacy/metadata/doi/sources/.combined-SemanticScholarSource/_SemanticScholarSourceEnhanced.py +49 -37
- scitex/scholar/.legacy/metadata/doi/sources/_ArXivSource.py +11 -30
- scitex/scholar/.legacy/metadata/doi/sources/_BaseDOISource.py +19 -47
- scitex/scholar/.legacy/metadata/doi/sources/_CrossRefLocalSource.py +1 -0
- scitex/scholar/.legacy/metadata/doi/sources/_CrossRefSource.py +12 -33
- scitex/scholar/.legacy/metadata/doi/sources/_OpenAlexSource.py +8 -20
- scitex/scholar/.legacy/metadata/doi/sources/_PubMedSource.py +10 -27
- scitex/scholar/.legacy/metadata/doi/sources/_SemanticScholarSource.py +11 -29
- scitex/scholar/.legacy/metadata/doi/sources/_SourceManager.py +8 -21
- scitex/scholar/.legacy/metadata/doi/sources/_SourceResolutionStrategy.py +24 -55
- scitex/scholar/.legacy/metadata/doi/sources/_SourceRotationManager.py +8 -21
- scitex/scholar/.legacy/metadata/doi/sources/_URLDOISource.py +9 -16
- scitex/scholar/.legacy/metadata/doi/sources/_UnifiedSource.py +8 -22
- scitex/scholar/.legacy/metadata/doi/sources/__init__.py +1 -0
- scitex/scholar/.legacy/metadata/doi/utils/_PubMedConverter.py +4 -8
- scitex/scholar/.legacy/metadata/doi/utils/_RateLimitHandler.py +17 -43
- scitex/scholar/.legacy/metadata/doi/utils/_TextNormalizer.py +8 -18
- scitex/scholar/.legacy/metadata/doi/utils/_URLDOIExtractor.py +4 -8
- scitex/scholar/.legacy/metadata/doi/utils/__init__.py +1 -0
- scitex/scholar/.legacy/metadata/doi/utils/_to_complete_metadata_structure.py +1 -0
- scitex/scholar/.legacy/metadata/enrichment/_LibraryEnricher.py +2 -3
- scitex/scholar/.legacy/metadata/enrichment/enrichers/_ImpactFactorEnricher.py +6 -12
- scitex/scholar/.legacy/metadata/enrichment/enrichers/_SmartEnricher.py +5 -10
- scitex/scholar/.legacy/metadata/enrichment/sources/_UnifiedMetadataSource.py +4 -5
- scitex/scholar/.legacy/metadata/query_to_full_meta_json.py +8 -12
- scitex/scholar/.legacy/metadata/urls/_URLMetadataHandler.py +3 -3
- scitex/scholar/.legacy/metadata/urls/_ZoteroTranslatorRunner.py +15 -21
- scitex/scholar/.legacy/metadata/urls/__init__.py +3 -3
- scitex/scholar/.legacy/metadata/urls/_finder.py +4 -6
- scitex/scholar/.legacy/metadata/urls/_handler.py +7 -15
- scitex/scholar/.legacy/metadata/urls/_resolver.py +6 -12
- scitex/scholar/.legacy/search/_Embedder.py +74 -69
- scitex/scholar/.legacy/search/_SemanticSearch.py +91 -90
- scitex/scholar/.legacy/search/_SemanticSearchEngine.py +104 -109
- scitex/scholar/.legacy/search/_UnifiedSearcher.py +530 -471
- scitex/scholar/.legacy/search/_VectorDatabase.py +111 -92
- scitex/scholar/.legacy/search/__init__.py +1 -0
- scitex/scholar/.legacy/storage/_EnhancedStorageManager.py +182 -154
- scitex/scholar/.legacy/storage/__init__.py +2 -1
- scitex/scholar/__init__.py +0 -2
- scitex/scholar/__main__.py +1 -3
- scitex/scholar/auth/ScholarAuthManager.py +13 -36
- scitex/scholar/auth/core/AuthenticationGateway.py +15 -29
- scitex/scholar/auth/core/BrowserAuthenticator.py +22 -57
- scitex/scholar/auth/core/StrategyResolver.py +10 -27
- scitex/scholar/auth/core/__init__.py +5 -1
- scitex/scholar/auth/gateway/_OpenURLLinkFinder.py +11 -21
- scitex/scholar/auth/gateway/_OpenURLResolver.py +10 -18
- scitex/scholar/auth/gateway/_resolve_functions.py +3 -3
- scitex/scholar/auth/providers/BaseAuthenticator.py +1 -0
- scitex/scholar/auth/providers/EZProxyAuthenticator.py +7 -14
- scitex/scholar/auth/providers/OpenAthensAuthenticator.py +29 -57
- scitex/scholar/auth/providers/ShibbolethAuthenticator.py +87 -73
- scitex/scholar/auth/session/AuthCacheManager.py +12 -22
- scitex/scholar/auth/session/SessionManager.py +4 -6
- scitex/scholar/auth/sso/BaseSSOAutomator.py +13 -19
- scitex/scholar/auth/sso/OpenAthensSSOAutomator.py +16 -45
- scitex/scholar/auth/sso/SSOAutomator.py +8 -15
- scitex/scholar/auth/sso/UniversityOfMelbourneSSOAutomator.py +13 -23
- scitex/scholar/browser/ScholarBrowserManager.py +31 -56
- scitex/scholar/browser/__init__.py +1 -0
- scitex/scholar/browser/utils/click_and_wait.py +3 -4
- scitex/scholar/browser/utils/close_unwanted_pages.py +4 -7
- scitex/scholar/browser/utils/wait_redirects.py +15 -40
- scitex/scholar/citation_graph/__init__.py +0 -0
- scitex/scholar/citation_graph/builder.py +3 -7
- scitex/scholar/citation_graph/database.py +4 -11
- scitex/scholar/citation_graph/example.py +5 -10
- scitex/scholar/citation_graph/models.py +0 -0
- scitex/scholar/cli/_url_utils.py +1 -1
- scitex/scholar/cli/chrome.py +5 -3
- scitex/scholar/cli/download_pdf.py +13 -14
- scitex/scholar/cli/handlers/bibtex_handler.py +4 -12
- scitex/scholar/cli/handlers/doi_handler.py +1 -3
- scitex/scholar/cli/handlers/project_handler.py +6 -20
- scitex/scholar/cli/open_browser.py +41 -39
- scitex/scholar/cli/open_browser_auto.py +31 -39
- scitex/scholar/cli/open_browser_monitored.py +27 -24
- scitex/scholar/config/ScholarConfig.py +5 -8
- scitex/scholar/config/__init__.py +1 -0
- scitex/scholar/config/core/_CascadeConfig.py +3 -3
- scitex/scholar/config/core/_PathManager.py +16 -28
- scitex/scholar/core/Paper.py +79 -78
- scitex/scholar/core/Papers.py +16 -27
- scitex/scholar/core/Scholar.py +98 -229
- scitex/scholar/core/journal_normalizer.py +52 -49
- scitex/scholar/core/oa_cache.py +27 -23
- scitex/scholar/core/open_access.py +17 -8
- scitex/scholar/docs/template.py +4 -3
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/clf_svm.py +0 -0
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/download.py +0 -0
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_conf_mat.py +0 -0
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_digits.py +0 -0
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_umap_space.py +0 -0
- scitex/scholar/examples/00_config.py +10 -9
- scitex/scholar/examples/01_auth.py +3 -0
- scitex/scholar/examples/02_browser.py +14 -10
- scitex/scholar/examples/03_01-engine.py +3 -0
- scitex/scholar/examples/03_02-engine-for-bibtex.py +4 -3
- scitex/scholar/examples/04_01-url.py +9 -9
- scitex/scholar/examples/04_02-url-for-bibtex.py +7 -3
- scitex/scholar/examples/04_02-url-for-dois.py +87 -97
- scitex/scholar/examples/05_download_pdf.py +10 -4
- scitex/scholar/examples/06_find_and_download.py +6 -6
- scitex/scholar/examples/06_parse_bibtex.py +17 -17
- scitex/scholar/examples/07_storage_integration.py +6 -9
- scitex/scholar/examples/99_fullpipeline-for-bibtex.py +14 -15
- scitex/scholar/examples/99_fullpipeline-for-one-entry.py +31 -23
- scitex/scholar/examples/99_maintenance.py +3 -0
- scitex/scholar/examples/dev.py +2 -3
- scitex/scholar/examples/zotero_integration.py +11 -18
- scitex/scholar/impact_factor/ImpactFactorEngine.py +7 -9
- scitex/scholar/impact_factor/estimation/__init__.py +4 -4
- scitex/scholar/impact_factor/estimation/core/__init__.py +3 -7
- scitex/scholar/impact_factor/estimation/core/cache_manager.py +223 -211
- scitex/scholar/impact_factor/estimation/core/calculator.py +165 -131
- scitex/scholar/impact_factor/estimation/core/journal_matcher.py +217 -172
- scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +6 -14
- scitex/scholar/impact_factor/jcr/build_database.py +4 -3
- scitex/scholar/integration/base.py +9 -17
- scitex/scholar/integration/mendeley/exporter.py +2 -4
- scitex/scholar/integration/mendeley/importer.py +3 -3
- scitex/scholar/integration/mendeley/linker.py +3 -3
- scitex/scholar/integration/mendeley/mapper.py +9 -6
- scitex/scholar/integration/zotero/__main__.py +26 -43
- scitex/scholar/integration/zotero/exporter.py +15 -11
- scitex/scholar/integration/zotero/importer.py +12 -10
- scitex/scholar/integration/zotero/linker.py +8 -12
- scitex/scholar/integration/zotero/mapper.py +17 -12
- scitex/scholar/metadata_engines/.combined-SemanticScholarSource/_SemanticScholarSource.py +37 -35
- scitex/scholar/metadata_engines/.combined-SemanticScholarSource/_SemanticScholarSourceEnhanced.py +47 -35
- scitex/scholar/metadata_engines/ScholarEngine.py +21 -43
- scitex/scholar/metadata_engines/__init__.py +1 -0
- scitex/scholar/metadata_engines/individual/ArXivEngine.py +15 -37
- scitex/scholar/metadata_engines/individual/CrossRefEngine.py +15 -42
- scitex/scholar/metadata_engines/individual/CrossRefLocalEngine.py +24 -45
- scitex/scholar/metadata_engines/individual/OpenAlexEngine.py +11 -21
- scitex/scholar/metadata_engines/individual/PubMedEngine.py +10 -27
- scitex/scholar/metadata_engines/individual/SemanticScholarEngine.py +28 -35
- scitex/scholar/metadata_engines/individual/URLDOIEngine.py +11 -22
- scitex/scholar/metadata_engines/individual/_BaseDOIEngine.py +20 -49
- scitex/scholar/metadata_engines/utils/_PubMedConverter.py +4 -8
- scitex/scholar/metadata_engines/utils/_URLDOIExtractor.py +5 -10
- scitex/scholar/metadata_engines/utils/__init__.py +2 -0
- scitex/scholar/metadata_engines/utils/_metadata2bibtex.py +3 -0
- scitex/scholar/metadata_engines/utils/_standardize_metadata.py +2 -3
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +25 -37
- scitex/scholar/pdf_download/strategies/chrome_pdf_viewer.py +11 -19
- scitex/scholar/pdf_download/strategies/direct_download.py +5 -9
- scitex/scholar/pdf_download/strategies/manual_download_fallback.py +3 -3
- scitex/scholar/pdf_download/strategies/manual_download_utils.py +6 -13
- scitex/scholar/pdf_download/strategies/open_access_download.py +49 -31
- scitex/scholar/pdf_download/strategies/response_body.py +8 -19
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +9 -18
- scitex/scholar/pipelines/ScholarPipelineMetadataParallel.py +25 -26
- scitex/scholar/pipelines/ScholarPipelineMetadataSingle.py +62 -23
- scitex/scholar/pipelines/ScholarPipelineParallel.py +13 -30
- scitex/scholar/pipelines/ScholarPipelineSearchParallel.py +299 -220
- scitex/scholar/pipelines/ScholarPipelineSearchSingle.py +202 -165
- scitex/scholar/pipelines/ScholarPipelineSingle.py +25 -51
- scitex/scholar/pipelines/SearchQueryParser.py +55 -55
- scitex/scholar/search_engines/ScholarSearchEngine.py +31 -27
- scitex/scholar/search_engines/_BaseSearchEngine.py +20 -23
- scitex/scholar/search_engines/individual/ArXivSearchEngine.py +53 -35
- scitex/scholar/search_engines/individual/CrossRefSearchEngine.py +47 -40
- scitex/scholar/search_engines/individual/OpenAlexSearchEngine.py +55 -50
- scitex/scholar/search_engines/individual/PubMedSearchEngine.py +8 -10
- scitex/scholar/search_engines/individual/SemanticScholarSearchEngine.py +55 -49
- scitex/scholar/storage/BibTeXHandler.py +150 -95
- scitex/scholar/storage/PaperIO.py +3 -6
- scitex/scholar/storage/ScholarLibrary.py +70 -49
- scitex/scholar/storage/_DeduplicationManager.py +52 -25
- scitex/scholar/storage/_LibraryCacheManager.py +19 -46
- scitex/scholar/storage/_LibraryManager.py +65 -175
- scitex/scholar/url_finder/ScholarURLFinder.py +9 -25
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_direct_links.py +1 -1
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_href.py +6 -10
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_navigation.py +4 -6
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_publisher_patterns.py +8 -15
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_zotero_translators.py +3 -3
- scitex/scholar/url_finder/strategies/find_supplementary_urls_by_href.py +3 -3
- scitex/scholar/url_finder/translators/core/patterns.py +6 -4
- scitex/scholar/url_finder/translators/core/registry.py +6 -9
- scitex/scholar/url_finder/translators/individual/BOFiP_Impots.py +60 -52
- scitex/scholar/url_finder/translators/individual/Baidu_Scholar.py +54 -62
- scitex/scholar/url_finder/translators/individual/Bangkok_Post.py +38 -44
- scitex/scholar/url_finder/translators/individual/Baruch_Foundation.py +43 -47
- scitex/scholar/url_finder/translators/individual/Beobachter.py +46 -50
- scitex/scholar/url_finder/translators/individual/Bezneng_Gajit.py +37 -41
- scitex/scholar/url_finder/translators/individual/BibLaTeX.py +59 -52
- scitex/scholar/url_finder/translators/individual/BibTeX.py +83 -79
- scitex/scholar/url_finder/translators/individual/Biblio_com.py +48 -51
- scitex/scholar/url_finder/translators/individual/Bibliontology_RDF.py +58 -56
- scitex/scholar/url_finder/translators/individual/Camara_Brasileira_do_Livro_ISBN.py +102 -99
- scitex/scholar/url_finder/translators/individual/CanLII.py +49 -43
- scitex/scholar/url_finder/translators/individual/Canada_com.py +36 -40
- scitex/scholar/url_finder/translators/individual/Canadian_Letters_and_Images.py +43 -43
- scitex/scholar/url_finder/translators/individual/Canadiana_ca.py +77 -66
- scitex/scholar/url_finder/translators/individual/Cascadilla_Proceedings_Project.py +68 -62
- scitex/scholar/url_finder/translators/individual/Central_and_Eastern_European_Online_Library_Journals.py +60 -60
- scitex/scholar/url_finder/translators/individual/Champlain_Society_Collection.py +63 -61
- scitex/scholar/url_finder/translators/individual/Chicago_Journal_of_Theoretical_Computer_Science.py +74 -58
- scitex/scholar/url_finder/translators/individual/Christian_Science_Monitor.py +32 -38
- scitex/scholar/url_finder/translators/individual/Columbia_University_Press.py +51 -47
- scitex/scholar/url_finder/translators/individual/Common_Place.py +66 -57
- scitex/scholar/url_finder/translators/individual/Cornell_LII.py +66 -62
- scitex/scholar/url_finder/translators/individual/Cornell_University_Press.py +38 -45
- scitex/scholar/url_finder/translators/individual/CourtListener.py +52 -56
- scitex/scholar/url_finder/translators/individual/DAI_Zenon.py +53 -54
- scitex/scholar/url_finder/translators/individual/access_medicine.py +27 -33
- scitex/scholar/url_finder/translators/individual/acm.py +1 -1
- scitex/scholar/url_finder/translators/individual/acm_digital_library.py +93 -63
- scitex/scholar/url_finder/translators/individual/airiti.py +3 -1
- scitex/scholar/url_finder/translators/individual/aosic.py +3 -1
- scitex/scholar/url_finder/translators/individual/archive_ouverte_aosic.py +3 -1
- scitex/scholar/url_finder/translators/individual/archive_ouverte_en_sciences_de_l_information_et_de_la_communication___aosic_.py +6 -2
- scitex/scholar/url_finder/translators/individual/artforum.py +35 -27
- scitex/scholar/url_finder/translators/individual/arxiv.py +1 -1
- scitex/scholar/url_finder/translators/individual/arxiv_org.py +8 -4
- scitex/scholar/url_finder/translators/individual/atlanta_journal_constitution.py +22 -18
- scitex/scholar/url_finder/translators/individual/atypon_journals.py +19 -11
- scitex/scholar/url_finder/translators/individual/austlii_and_nzlii.py +48 -44
- scitex/scholar/url_finder/translators/individual/australian_dictionary_of_biography.py +21 -17
- scitex/scholar/url_finder/translators/individual/bailii.py +22 -19
- scitex/scholar/url_finder/translators/individual/bbc.py +46 -42
- scitex/scholar/url_finder/translators/individual/bbc_genome.py +37 -25
- scitex/scholar/url_finder/translators/individual/biblioteca_nacional_de_maestros.py +24 -20
- scitex/scholar/url_finder/translators/individual/bibliotheque_archives_nationale_quebec_pistard.py +42 -43
- scitex/scholar/url_finder/translators/individual/bibliotheque_archives_nationales_quebec.py +87 -81
- scitex/scholar/url_finder/translators/individual/bibliotheque_nationale_france.py +39 -37
- scitex/scholar/url_finder/translators/individual/bibsys.py +32 -28
- scitex/scholar/url_finder/translators/individual/bioconductor.py +58 -52
- scitex/scholar/url_finder/translators/individual/biomed_central.py +23 -15
- scitex/scholar/url_finder/translators/individual/biorxiv.py +26 -13
- scitex/scholar/url_finder/translators/individual/blogger.py +39 -43
- scitex/scholar/url_finder/translators/individual/bloomberg.py +48 -52
- scitex/scholar/url_finder/translators/individual/bloomsbury_food_library.py +37 -37
- scitex/scholar/url_finder/translators/individual/bluesky.py +30 -28
- scitex/scholar/url_finder/translators/individual/bnf_isbn.py +1 -1
- scitex/scholar/url_finder/translators/individual/bocc.py +66 -60
- scitex/scholar/url_finder/translators/individual/boe.py +52 -52
- scitex/scholar/url_finder/translators/individual/brill.py +3 -1
- scitex/scholar/url_finder/translators/individual/business_standard.py +36 -38
- scitex/scholar/url_finder/translators/individual/cabi_cab_abstracts.py +39 -41
- scitex/scholar/url_finder/translators/individual/cambridge.py +3 -1
- scitex/scholar/url_finder/translators/individual/cambridge_core.py +30 -24
- scitex/scholar/url_finder/translators/individual/caod.py +50 -46
- scitex/scholar/url_finder/translators/individual/cbc.py +91 -67
- scitex/scholar/url_finder/translators/individual/ccfr_bnf.py +49 -53
- scitex/scholar/url_finder/translators/individual/cia_world_factbook.py +43 -33
- scitex/scholar/url_finder/translators/individual/crossref_rest.py +208 -174
- scitex/scholar/url_finder/translators/individual/current_affairs.py +29 -35
- scitex/scholar/url_finder/translators/individual/dabi.py +70 -66
- scitex/scholar/url_finder/translators/individual/dagens_nyheter.py +3 -1
- scitex/scholar/url_finder/translators/individual/dagstuhl.py +10 -15
- scitex/scholar/url_finder/translators/individual/dar_almandumah.py +13 -9
- scitex/scholar/url_finder/translators/individual/dart_europe.py +19 -22
- scitex/scholar/url_finder/translators/individual/data_gov.py +2 -2
- scitex/scholar/url_finder/translators/individual/databrary.py +27 -28
- scitex/scholar/url_finder/translators/individual/datacite_json.py +152 -137
- scitex/scholar/url_finder/translators/individual/dataverse.py +68 -64
- scitex/scholar/url_finder/translators/individual/daum_news.py +38 -38
- scitex/scholar/url_finder/translators/individual/dblp.py +4 -8
- scitex/scholar/url_finder/translators/individual/dblp_computer_science_bibliography.py +8 -3
- scitex/scholar/url_finder/translators/individual/dbpia.py +5 -3
- scitex/scholar/url_finder/translators/individual/defense_technical_information_center.py +30 -28
- scitex/scholar/url_finder/translators/individual/delpher.py +102 -79
- scitex/scholar/url_finder/translators/individual/demographic_research.py +35 -31
- scitex/scholar/url_finder/translators/individual/denik_cz.py +58 -54
- scitex/scholar/url_finder/translators/individual/depatisnet.py +7 -10
- scitex/scholar/url_finder/translators/individual/der_freitag.py +81 -66
- scitex/scholar/url_finder/translators/individual/der_spiegel.py +56 -54
- scitex/scholar/url_finder/translators/individual/digibib_net.py +3 -1
- scitex/scholar/url_finder/translators/individual/digizeitschriften.py +3 -1
- scitex/scholar/url_finder/translators/individual/dpla.py +13 -14
- scitex/scholar/url_finder/translators/individual/dspace.py +2 -2
- scitex/scholar/url_finder/translators/individual/ebrary.py +3 -1
- scitex/scholar/url_finder/translators/individual/ebscohost.py +3 -1
- scitex/scholar/url_finder/translators/individual/electronic_colloquium_on_computational_complexity.py +3 -1
- scitex/scholar/url_finder/translators/individual/elife.py +3 -1
- scitex/scholar/url_finder/translators/individual/elsevier_health_journals.py +3 -1
- scitex/scholar/url_finder/translators/individual/emerald.py +3 -1
- scitex/scholar/url_finder/translators/individual/emerald_insight.py +3 -1
- scitex/scholar/url_finder/translators/individual/epicurious.py +3 -1
- scitex/scholar/url_finder/translators/individual/eurogamerusgamer.py +3 -1
- scitex/scholar/url_finder/translators/individual/fachportal_padagogik.py +3 -1
- scitex/scholar/url_finder/translators/individual/frontiers.py +1 -1
- scitex/scholar/url_finder/translators/individual/gale_databases.py +3 -1
- scitex/scholar/url_finder/translators/individual/gms_german_medical_science.py +6 -2
- scitex/scholar/url_finder/translators/individual/ieee_computer_society.py +6 -2
- scitex/scholar/url_finder/translators/individual/ieee_xplore.py +41 -35
- scitex/scholar/url_finder/translators/individual/inter_research_science_center.py +6 -2
- scitex/scholar/url_finder/translators/individual/jisc_historical_texts.py +3 -1
- scitex/scholar/url_finder/translators/individual/jstor.py +14 -12
- scitex/scholar/url_finder/translators/individual/korean_national_library.py +3 -1
- scitex/scholar/url_finder/translators/individual/la_times.py +3 -1
- scitex/scholar/url_finder/translators/individual/landesbibliographie_baden_wurttemberg.py +3 -1
- scitex/scholar/url_finder/translators/individual/legislative_insight.py +3 -1
- scitex/scholar/url_finder/translators/individual/libraries_tasmania.py +3 -1
- scitex/scholar/url_finder/translators/individual/library_catalog__koha_.py +3 -1
- scitex/scholar/url_finder/translators/individual/lingbuzz.py +2 -2
- scitex/scholar/url_finder/translators/individual/max_planck_institute_for_the_history_of_science_virtual_laboratory_library.py +3 -1
- scitex/scholar/url_finder/translators/individual/mdpi.py +12 -6
- scitex/scholar/url_finder/translators/individual/microbiology_society_journals.py +3 -1
- scitex/scholar/url_finder/translators/individual/midas_journals.py +3 -1
- scitex/scholar/url_finder/translators/individual/nagoya_university_opac.py +3 -1
- scitex/scholar/url_finder/translators/individual/nature_publishing_group.py +32 -19
- scitex/scholar/url_finder/translators/individual/ntsb_accident_reports.py +3 -1
- scitex/scholar/url_finder/translators/individual/openedition_journals.py +8 -4
- scitex/scholar/url_finder/translators/individual/orcid.py +16 -15
- scitex/scholar/url_finder/translators/individual/oxford.py +25 -19
- scitex/scholar/url_finder/translators/individual/oxford_dictionaries_premium.py +3 -1
- scitex/scholar/url_finder/translators/individual/ozon_ru.py +3 -1
- scitex/scholar/url_finder/translators/individual/plos.py +9 -12
- scitex/scholar/url_finder/translators/individual/polygon.py +3 -1
- scitex/scholar/url_finder/translators/individual/primo.py +3 -1
- scitex/scholar/url_finder/translators/individual/project_muse.py +3 -1
- scitex/scholar/url_finder/translators/individual/pubfactory_journals.py +3 -1
- scitex/scholar/url_finder/translators/individual/pubmed.py +71 -65
- scitex/scholar/url_finder/translators/individual/pubmed_central.py +8 -6
- scitex/scholar/url_finder/translators/individual/rechtspraak_nl.py +3 -1
- scitex/scholar/url_finder/translators/individual/sage_journals.py +25 -17
- scitex/scholar/url_finder/translators/individual/sciencedirect.py +36 -17
- scitex/scholar/url_finder/translators/individual/semantics_visual_library.py +3 -1
- scitex/scholar/url_finder/translators/individual/silverchair.py +70 -52
- scitex/scholar/url_finder/translators/individual/sora.py +3 -1
- scitex/scholar/url_finder/translators/individual/springer.py +15 -11
- scitex/scholar/url_finder/translators/individual/ssrn.py +3 -3
- scitex/scholar/url_finder/translators/individual/stanford_encyclopedia_of_philosophy.py +3 -1
- scitex/scholar/url_finder/translators/individual/superlib.py +3 -1
- scitex/scholar/url_finder/translators/individual/treesearch.py +3 -1
- scitex/scholar/url_finder/translators/individual/university_of_chicago_press_books.py +3 -1
- scitex/scholar/url_finder/translators/individual/vlex.py +3 -1
- scitex/scholar/url_finder/translators/individual/web_of_science.py +3 -1
- scitex/scholar/url_finder/translators/individual/web_of_science_nextgen.py +3 -1
- scitex/scholar/url_finder/translators/individual/wiley.py +31 -25
- scitex/scholar/url_finder/translators/individual/wilson_center_digital_archive.py +3 -1
- scitex/scholar/utils/bibtex/_parse_bibtex.py +3 -3
- scitex/scholar/utils/cleanup/_cleanup_scholar_processes.py +5 -9
- scitex/scholar/utils/text/_TextNormalizer.py +249 -176
- scitex/scholar/utils/validation/DOIValidator.py +31 -28
- scitex/scholar/utils/validation/__init__.py +0 -0
- scitex/scholar/utils/validation/validate_library_dois.py +61 -57
- scitex/scholar/zotero/__init__.py +1 -1
- scitex/security/cli.py +7 -20
- scitex/security/github.py +45 -32
- scitex/session/__init__.py +8 -9
- scitex/session/_decorator.py +49 -42
- scitex/session/_lifecycle.py +39 -39
- scitex/session/_manager.py +24 -20
- scitex/sh/__init__.py +4 -3
- scitex/sh/_execute.py +10 -7
- scitex/sh/_security.py +3 -3
- scitex/sh/_types.py +2 -3
- scitex/stats/__init__.py +57 -6
- scitex/stats/_schema.py +42 -569
- scitex/stats/auto/__init__.py +188 -0
- scitex/stats/auto/_context.py +331 -0
- scitex/stats/auto/_formatting.py +679 -0
- scitex/stats/auto/_rules.py +901 -0
- scitex/stats/auto/_selector.py +554 -0
- scitex/stats/auto/_styles.py +721 -0
- scitex/stats/correct/__init__.py +4 -4
- scitex/stats/correct/_correct_bonferroni.py +43 -34
- scitex/stats/correct/_correct_fdr.py +14 -40
- scitex/stats/correct/_correct_fdr_.py +39 -46
- scitex/stats/correct/_correct_holm.py +14 -32
- scitex/stats/correct/_correct_sidak.py +36 -21
- scitex/stats/descriptive/_circular.py +20 -21
- scitex/stats/descriptive/_describe.py +19 -5
- scitex/stats/descriptive/_nan.py +5 -7
- scitex/stats/descriptive/_real.py +4 -3
- scitex/stats/effect_sizes/__init__.py +10 -11
- scitex/stats/effect_sizes/_cliffs_delta.py +35 -32
- scitex/stats/effect_sizes/_cohens_d.py +30 -31
- scitex/stats/effect_sizes/_epsilon_squared.py +19 -22
- scitex/stats/effect_sizes/_eta_squared.py +23 -27
- scitex/stats/effect_sizes/_prob_superiority.py +18 -21
- scitex/stats/posthoc/__init__.py +3 -3
- scitex/stats/posthoc/_dunnett.py +75 -55
- scitex/stats/posthoc/_games_howell.py +61 -43
- scitex/stats/posthoc/_tukey_hsd.py +42 -34
- scitex/stats/power/__init__.py +2 -2
- scitex/stats/power/_power.py +56 -56
- scitex/stats/tests/__init__.py +1 -1
- scitex/stats/tests/correlation/__init__.py +1 -1
- scitex/stats/tests/correlation/_test_pearson.py +28 -38
- scitex/stats/utils/__init__.py +14 -17
- scitex/stats/utils/_effect_size.py +85 -78
- scitex/stats/utils/_formatters.py +49 -43
- scitex/stats/utils/_normalizers.py +7 -14
- scitex/stats/utils/_power.py +56 -56
- scitex/str/__init__.py +1 -0
- scitex/str/_clean_path.py +3 -3
- scitex/str/_factor_out_digits.py +86 -58
- scitex/str/_format_plot_text.py +180 -111
- scitex/str/_latex.py +19 -19
- scitex/str/_latex_fallback.py +9 -10
- scitex/str/_parse.py +3 -6
- scitex/str/_print_debug.py +13 -13
- scitex/str/_printc.py +2 -0
- scitex/str/_search.py +3 -3
- scitex/template/.legacy/_clone_project.py +9 -13
- scitex/template/__init__.py +10 -2
- scitex/template/_clone_project.py +7 -2
- scitex/template/_copy.py +1 -0
- scitex/template/_customize.py +3 -6
- scitex/template/_git_strategy.py +2 -3
- scitex/template/_rename.py +1 -0
- scitex/template/clone_pip_project.py +6 -7
- scitex/template/clone_research.py +7 -10
- scitex/template/clone_singularity.py +6 -7
- scitex/template/clone_writer_directory.py +6 -7
- scitex/tex/_preview.py +26 -11
- scitex/tex/_to_vec.py +10 -7
- scitex/torch/__init__.py +11 -1
- scitex/types/_ArrayLike.py +2 -0
- scitex/types/_is_listed_X.py +3 -3
- scitex/units.py +110 -77
- scitex/utils/_compress_hdf5.py +3 -3
- scitex/utils/_email.py +8 -4
- scitex/utils/_notify.py +14 -8
- scitex/utils/_search.py +6 -6
- scitex/utils/_verify_scitex_format.py +17 -42
- scitex/utils/_verify_scitex_format_v01.py +12 -34
- scitex/utils/template.py +4 -3
- scitex/vis/__init__.py +0 -0
- scitex/vis/backend/__init__.py +3 -3
- scitex/vis/backend/{export.py → _export.py} +1 -1
- scitex/vis/backend/{parser.py → _parser.py} +1 -3
- scitex/vis/backend/{render.py → _render.py} +1 -1
- scitex/vis/canvas.py +15 -3
- scitex/vis/editor/__init__.py +0 -0
- scitex/vis/editor/_dearpygui_editor.py +450 -304
- scitex/vis/editor/_defaults.py +114 -123
- scitex/vis/editor/_edit.py +38 -26
- scitex/vis/editor/_flask_editor.py +8 -8
- scitex/vis/editor/_mpl_editor.py +63 -48
- scitex/vis/editor/_qt_editor.py +210 -159
- scitex/vis/editor/_tkinter_editor.py +146 -89
- scitex/vis/editor/flask_editor/__init__.py +10 -10
- scitex/vis/editor/flask_editor/_bbox.py +529 -0
- scitex/vis/editor/flask_editor/{core.py → _core.py} +45 -29
- scitex/vis/editor/flask_editor/_plotter.py +567 -0
- scitex/vis/editor/flask_editor/_renderer.py +393 -0
- scitex/vis/editor/flask_editor/{utils.py → _utils.py} +13 -14
- scitex/vis/editor/flask_editor/templates/__init__.py +5 -5
- scitex/vis/editor/flask_editor/templates/{html.py → _html.py} +234 -16
- scitex/vis/editor/flask_editor/templates/_scripts.py +1261 -0
- scitex/vis/editor/flask_editor/templates/{styles.py → _styles.py} +192 -2
- scitex/vis/io/__init__.py +5 -5
- scitex/vis/io/{canvas.py → _canvas.py} +8 -4
- scitex/vis/io/{data.py → _data.py} +13 -9
- scitex/vis/io/{directory.py → _directory.py} +7 -4
- scitex/vis/io/{export.py → _export.py} +15 -12
- scitex/vis/io/{load.py → _load.py} +1 -1
- scitex/vis/io/{panel.py → _panel.py} +21 -13
- scitex/vis/io/{save.py → _save.py} +0 -0
- scitex/vis/model/__init__.py +7 -7
- scitex/vis/model/{annotations.py → _annotations.py} +2 -4
- scitex/vis/model/{axes.py → _axes.py} +1 -1
- scitex/vis/model/{figure.py → _figure.py} +0 -0
- scitex/vis/model/{guides.py → _guides.py} +1 -1
- scitex/vis/model/{plot.py → _plot.py} +2 -4
- scitex/vis/model/{plot_types.py → _plot_types.py} +0 -0
- scitex/vis/model/{styles.py → _styles.py} +0 -0
- scitex/vis/utils/__init__.py +2 -2
- scitex/vis/utils/{defaults.py → _defaults.py} +1 -2
- scitex/vis/utils/{validate.py → _validate.py} +3 -9
- scitex/web/__init__.py +7 -1
- scitex/web/_scraping.py +54 -38
- scitex/web/_search_pubmed.py +30 -14
- scitex/writer/.legacy/Writer_v01-refactored.py +4 -4
- scitex/writer/.legacy/_compile.py +18 -28
- scitex/writer/Writer.py +8 -21
- scitex/writer/__init__.py +11 -11
- scitex/writer/_clone_writer_project.py +2 -6
- scitex/writer/_compile/__init__.py +1 -0
- scitex/writer/_compile/_parser.py +1 -0
- scitex/writer/_compile/_runner.py +35 -38
- scitex/writer/_compile/_validator.py +1 -0
- scitex/writer/_compile/manuscript.py +1 -0
- scitex/writer/_compile/revision.py +1 -0
- scitex/writer/_compile/supplementary.py +1 -0
- scitex/writer/_compile_async.py +5 -12
- scitex/writer/_project/__init__.py +1 -0
- scitex/writer/_project/_create.py +10 -25
- scitex/writer/_project/_trees.py +4 -9
- scitex/writer/_project/_validate.py +2 -3
- scitex/writer/_validate_tree_structures.py +7 -18
- scitex/writer/dataclasses/__init__.py +8 -10
- scitex/writer/dataclasses/config/_CONSTANTS.py +2 -3
- scitex/writer/dataclasses/config/_WriterConfig.py +4 -9
- scitex/writer/dataclasses/contents/_ManuscriptContents.py +14 -25
- scitex/writer/dataclasses/contents/_RevisionContents.py +21 -16
- scitex/writer/dataclasses/contents/_SupplementaryContents.py +21 -24
- scitex/writer/dataclasses/core/_Document.py +2 -3
- scitex/writer/dataclasses/core/_DocumentSection.py +8 -23
- scitex/writer/dataclasses/results/_CompilationResult.py +2 -3
- scitex/writer/dataclasses/results/_LaTeXIssue.py +3 -6
- scitex/writer/dataclasses/results/_SaveSectionsResponse.py +20 -9
- scitex/writer/dataclasses/results/_SectionReadResponse.py +24 -10
- scitex/writer/dataclasses/tree/_ConfigTree.py +7 -4
- scitex/writer/dataclasses/tree/_ManuscriptTree.py +10 -13
- scitex/writer/dataclasses/tree/_RevisionTree.py +16 -17
- scitex/writer/dataclasses/tree/_ScriptsTree.py +10 -5
- scitex/writer/dataclasses/tree/_SharedTree.py +10 -13
- scitex/writer/dataclasses/tree/_SupplementaryTree.py +15 -14
- scitex/writer/utils/.legacy_git_retry.py +3 -8
- scitex/writer/utils/_parse_latex_logs.py +2 -3
- scitex/writer/utils/_parse_script_args.py +20 -23
- scitex/writer/utils/_watch.py +5 -5
- {scitex-2.5.0.dist-info → scitex-2.7.0.dist-info}/METADATA +4 -10
- {scitex-2.5.0.dist-info → scitex-2.7.0.dist-info}/RECORD +1071 -975
- scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin_v01-indentation-issues.py +0 -583
- scitex/plt/_subplots/_export_as_csv_formatters.py +0 -112
- scitex/vis/editor/flask_editor/bbox.py +0 -216
- scitex/vis/editor/flask_editor/plotter.py +0 -130
- scitex/vis/editor/flask_editor/renderer.py +0 -184
- scitex/vis/editor/flask_editor/templates/scripts.py +0 -614
- {scitex-2.5.0.dist-info → scitex-2.7.0.dist-info}/WHEEL +0 -0
- {scitex-2.5.0.dist-info → scitex-2.7.0.dist-info}/entry_points.txt +0 -0
- {scitex-2.5.0.dist-info → scitex-2.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -48,7 +48,7 @@ def _create_checkerboard(width: int, height: int, square_size: int = 10) -> "Ima
|
|
|
48
48
|
else:
|
|
49
49
|
img_array[y, x] = dark_gray
|
|
50
50
|
|
|
51
|
-
return Image.fromarray(img_array,
|
|
51
|
+
return Image.fromarray(img_array, "RGBA")
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
class DearPyGuiEditor:
|
|
@@ -81,6 +81,7 @@ class DearPyGuiEditor:
|
|
|
81
81
|
|
|
82
82
|
# Get SciTeX defaults and merge with metadata
|
|
83
83
|
from ._defaults import get_scitex_defaults, extract_defaults_from_metadata
|
|
84
|
+
|
|
84
85
|
self.scitex_defaults = get_scitex_defaults()
|
|
85
86
|
self.metadata_defaults = extract_defaults_from_metadata(metadata)
|
|
86
87
|
|
|
@@ -97,7 +98,9 @@ class DearPyGuiEditor:
|
|
|
97
98
|
# Click-to-select state
|
|
98
99
|
self._selected_element = None # {'type': 'trace'|'title'|'xlabel'|'ylabel'|'legend'|'xaxis'|'yaxis', 'index': int|None}
|
|
99
100
|
self._selected_trace_index = None # Legacy compat
|
|
100
|
-
self._preview_bounds =
|
|
101
|
+
self._preview_bounds = (
|
|
102
|
+
None # (x_offset, y_offset, width, height) of figure in preview
|
|
103
|
+
)
|
|
101
104
|
self._axes_transform = None # Transform info for data coordinates
|
|
102
105
|
self._element_bboxes = {} # Store bboxes for all selectable elements
|
|
103
106
|
|
|
@@ -139,7 +142,7 @@ class DearPyGuiEditor:
|
|
|
139
142
|
width=width,
|
|
140
143
|
height=height,
|
|
141
144
|
default_value=texture_data,
|
|
142
|
-
tag="preview_texture"
|
|
145
|
+
tag="preview_texture",
|
|
143
146
|
)
|
|
144
147
|
|
|
145
148
|
# Create main window
|
|
@@ -166,7 +169,10 @@ class DearPyGuiEditor:
|
|
|
166
169
|
def _create_preview_panel(self, dpg):
|
|
167
170
|
"""Create the preview panel with figure image, click handler, and hover detection."""
|
|
168
171
|
with dpg.child_window(width=900, height=-1, tag="preview_panel"):
|
|
169
|
-
dpg.add_text(
|
|
172
|
+
dpg.add_text(
|
|
173
|
+
"Figure Preview (click to select, hover to highlight)",
|
|
174
|
+
color=(100, 200, 100),
|
|
175
|
+
)
|
|
170
176
|
dpg.add_separator()
|
|
171
177
|
|
|
172
178
|
# Image display with click and move handlers
|
|
@@ -191,7 +197,7 @@ class DearPyGuiEditor:
|
|
|
191
197
|
with dpg.collapsing_header(label="Labels", default_open=True):
|
|
192
198
|
dpg.add_input_text(
|
|
193
199
|
label="Title",
|
|
194
|
-
default_value=self.current_overrides.get(
|
|
200
|
+
default_value=self.current_overrides.get("title", ""),
|
|
195
201
|
tag="title_input",
|
|
196
202
|
callback=self._on_value_change,
|
|
197
203
|
on_enter=True,
|
|
@@ -199,7 +205,7 @@ class DearPyGuiEditor:
|
|
|
199
205
|
)
|
|
200
206
|
dpg.add_input_text(
|
|
201
207
|
label="X Label",
|
|
202
|
-
default_value=self.current_overrides.get(
|
|
208
|
+
default_value=self.current_overrides.get("xlabel", ""),
|
|
203
209
|
tag="xlabel_input",
|
|
204
210
|
callback=self._on_value_change,
|
|
205
211
|
on_enter=True,
|
|
@@ -207,7 +213,7 @@ class DearPyGuiEditor:
|
|
|
207
213
|
)
|
|
208
214
|
dpg.add_input_text(
|
|
209
215
|
label="Y Label",
|
|
210
|
-
default_value=self.current_overrides.get(
|
|
216
|
+
default_value=self.current_overrides.get("ylabel", ""),
|
|
211
217
|
tag="ylabel_input",
|
|
212
218
|
callback=self._on_value_change,
|
|
213
219
|
on_enter=True,
|
|
@@ -217,7 +223,7 @@ class DearPyGuiEditor:
|
|
|
217
223
|
# Axis Limits Section
|
|
218
224
|
with dpg.collapsing_header(label="Axis Limits", default_open=False):
|
|
219
225
|
with dpg.group(horizontal=True):
|
|
220
|
-
xlim = self.current_overrides.get(
|
|
226
|
+
xlim = self.current_overrides.get("xlim", [0, 1])
|
|
221
227
|
dpg.add_input_float(
|
|
222
228
|
label="X Min",
|
|
223
229
|
default_value=xlim[0] if xlim else 0,
|
|
@@ -231,7 +237,7 @@ class DearPyGuiEditor:
|
|
|
231
237
|
width=100,
|
|
232
238
|
)
|
|
233
239
|
with dpg.group(horizontal=True):
|
|
234
|
-
ylim = self.current_overrides.get(
|
|
240
|
+
ylim = self.current_overrides.get("ylim", [0, 1])
|
|
235
241
|
dpg.add_input_float(
|
|
236
242
|
label="Y Min",
|
|
237
243
|
default_value=ylim[0] if ylim else 0,
|
|
@@ -254,7 +260,7 @@ class DearPyGuiEditor:
|
|
|
254
260
|
with dpg.collapsing_header(label="Line Style", default_open=True):
|
|
255
261
|
dpg.add_slider_float(
|
|
256
262
|
label="Line Width (pt)",
|
|
257
|
-
default_value=self.current_overrides.get(
|
|
263
|
+
default_value=self.current_overrides.get("linewidth", 1.0),
|
|
258
264
|
min_value=0.1,
|
|
259
265
|
max_value=5.0,
|
|
260
266
|
tag="linewidth_slider",
|
|
@@ -266,7 +272,7 @@ class DearPyGuiEditor:
|
|
|
266
272
|
with dpg.collapsing_header(label="Font Settings", default_open=False):
|
|
267
273
|
dpg.add_slider_int(
|
|
268
274
|
label="Title Font Size",
|
|
269
|
-
default_value=self.current_overrides.get(
|
|
275
|
+
default_value=self.current_overrides.get("title_fontsize", 8),
|
|
270
276
|
min_value=6,
|
|
271
277
|
max_value=20,
|
|
272
278
|
tag="title_fontsize_slider",
|
|
@@ -275,7 +281,7 @@ class DearPyGuiEditor:
|
|
|
275
281
|
)
|
|
276
282
|
dpg.add_slider_int(
|
|
277
283
|
label="Axis Font Size",
|
|
278
|
-
default_value=self.current_overrides.get(
|
|
284
|
+
default_value=self.current_overrides.get("axis_fontsize", 7),
|
|
279
285
|
min_value=6,
|
|
280
286
|
max_value=16,
|
|
281
287
|
tag="axis_fontsize_slider",
|
|
@@ -284,7 +290,7 @@ class DearPyGuiEditor:
|
|
|
284
290
|
)
|
|
285
291
|
dpg.add_slider_int(
|
|
286
292
|
label="Tick Font Size",
|
|
287
|
-
default_value=self.current_overrides.get(
|
|
293
|
+
default_value=self.current_overrides.get("tick_fontsize", 7),
|
|
288
294
|
min_value=6,
|
|
289
295
|
max_value=16,
|
|
290
296
|
tag="tick_fontsize_slider",
|
|
@@ -293,7 +299,7 @@ class DearPyGuiEditor:
|
|
|
293
299
|
)
|
|
294
300
|
dpg.add_slider_int(
|
|
295
301
|
label="Legend Font Size",
|
|
296
|
-
default_value=self.current_overrides.get(
|
|
302
|
+
default_value=self.current_overrides.get("legend_fontsize", 6),
|
|
297
303
|
min_value=4,
|
|
298
304
|
max_value=14,
|
|
299
305
|
tag="legend_fontsize_slider",
|
|
@@ -305,7 +311,7 @@ class DearPyGuiEditor:
|
|
|
305
311
|
with dpg.collapsing_header(label="Tick Settings", default_open=False):
|
|
306
312
|
dpg.add_slider_int(
|
|
307
313
|
label="N Ticks",
|
|
308
|
-
default_value=self.current_overrides.get(
|
|
314
|
+
default_value=self.current_overrides.get("n_ticks", 4),
|
|
309
315
|
min_value=2,
|
|
310
316
|
max_value=10,
|
|
311
317
|
tag="n_ticks_slider",
|
|
@@ -314,7 +320,7 @@ class DearPyGuiEditor:
|
|
|
314
320
|
)
|
|
315
321
|
dpg.add_slider_float(
|
|
316
322
|
label="Tick Length (mm)",
|
|
317
|
-
default_value=self.current_overrides.get(
|
|
323
|
+
default_value=self.current_overrides.get("tick_length", 0.8),
|
|
318
324
|
min_value=0.2,
|
|
319
325
|
max_value=3.0,
|
|
320
326
|
tag="tick_length_slider",
|
|
@@ -323,7 +329,7 @@ class DearPyGuiEditor:
|
|
|
323
329
|
)
|
|
324
330
|
dpg.add_slider_float(
|
|
325
331
|
label="Tick Width (mm)",
|
|
326
|
-
default_value=self.current_overrides.get(
|
|
332
|
+
default_value=self.current_overrides.get("tick_width", 0.2),
|
|
327
333
|
min_value=0.05,
|
|
328
334
|
max_value=1.0,
|
|
329
335
|
tag="tick_width_slider",
|
|
@@ -333,7 +339,7 @@ class DearPyGuiEditor:
|
|
|
333
339
|
dpg.add_combo(
|
|
334
340
|
label="Tick Direction",
|
|
335
341
|
items=["out", "in", "inout"],
|
|
336
|
-
default_value=self.current_overrides.get(
|
|
342
|
+
default_value=self.current_overrides.get("tick_direction", "out"),
|
|
337
343
|
tag="tick_direction_combo",
|
|
338
344
|
callback=self._on_value_change,
|
|
339
345
|
width=150,
|
|
@@ -343,31 +349,31 @@ class DearPyGuiEditor:
|
|
|
343
349
|
with dpg.collapsing_header(label="Style", default_open=True):
|
|
344
350
|
dpg.add_checkbox(
|
|
345
351
|
label="Show Grid",
|
|
346
|
-
default_value=self.current_overrides.get(
|
|
352
|
+
default_value=self.current_overrides.get("grid", False),
|
|
347
353
|
tag="grid_checkbox",
|
|
348
354
|
callback=self._on_value_change,
|
|
349
355
|
)
|
|
350
356
|
dpg.add_checkbox(
|
|
351
357
|
label="Hide Top Spine",
|
|
352
|
-
default_value=self.current_overrides.get(
|
|
358
|
+
default_value=self.current_overrides.get("hide_top_spine", True),
|
|
353
359
|
tag="hide_top_spine_checkbox",
|
|
354
360
|
callback=self._on_value_change,
|
|
355
361
|
)
|
|
356
362
|
dpg.add_checkbox(
|
|
357
363
|
label="Hide Right Spine",
|
|
358
|
-
default_value=self.current_overrides.get(
|
|
364
|
+
default_value=self.current_overrides.get("hide_right_spine", True),
|
|
359
365
|
tag="hide_right_spine_checkbox",
|
|
360
366
|
callback=self._on_value_change,
|
|
361
367
|
)
|
|
362
368
|
dpg.add_checkbox(
|
|
363
369
|
label="Transparent Background",
|
|
364
|
-
default_value=self.current_overrides.get(
|
|
370
|
+
default_value=self.current_overrides.get("transparent", True),
|
|
365
371
|
tag="transparent_checkbox",
|
|
366
372
|
callback=self._on_value_change,
|
|
367
373
|
)
|
|
368
374
|
dpg.add_slider_float(
|
|
369
375
|
label="Axis Width (mm)",
|
|
370
|
-
default_value=self.current_overrides.get(
|
|
376
|
+
default_value=self.current_overrides.get("axis_width", 0.2),
|
|
371
377
|
min_value=0.05,
|
|
372
378
|
max_value=1.0,
|
|
373
379
|
tag="axis_width_slider",
|
|
@@ -379,30 +385,47 @@ class DearPyGuiEditor:
|
|
|
379
385
|
with dpg.collapsing_header(label="Legend", default_open=False):
|
|
380
386
|
dpg.add_checkbox(
|
|
381
387
|
label="Show Legend",
|
|
382
|
-
default_value=self.current_overrides.get(
|
|
388
|
+
default_value=self.current_overrides.get("legend_visible", True),
|
|
383
389
|
tag="legend_visible_checkbox",
|
|
384
390
|
callback=self._on_value_change,
|
|
385
391
|
)
|
|
386
392
|
dpg.add_checkbox(
|
|
387
393
|
label="Show Frame",
|
|
388
|
-
default_value=self.current_overrides.get(
|
|
394
|
+
default_value=self.current_overrides.get("legend_frameon", False),
|
|
389
395
|
tag="legend_frameon_checkbox",
|
|
390
396
|
callback=self._on_value_change,
|
|
391
397
|
)
|
|
392
398
|
dpg.add_combo(
|
|
393
399
|
label="Position",
|
|
394
|
-
items=[
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
400
|
+
items=[
|
|
401
|
+
"best",
|
|
402
|
+
"upper right",
|
|
403
|
+
"upper left",
|
|
404
|
+
"lower right",
|
|
405
|
+
"lower left",
|
|
406
|
+
"center right",
|
|
407
|
+
"center left",
|
|
408
|
+
"upper center",
|
|
409
|
+
"lower center",
|
|
410
|
+
"center",
|
|
411
|
+
],
|
|
412
|
+
default_value=self.current_overrides.get("legend_loc", "best"),
|
|
398
413
|
tag="legend_loc_combo",
|
|
399
414
|
callback=self._on_value_change,
|
|
400
415
|
width=150,
|
|
401
416
|
)
|
|
402
417
|
|
|
403
418
|
# Selected Element Section (click on preview to select)
|
|
404
|
-
with dpg.collapsing_header(
|
|
405
|
-
|
|
419
|
+
with dpg.collapsing_header(
|
|
420
|
+
label="Selected Element",
|
|
421
|
+
default_open=True,
|
|
422
|
+
tag="selected_element_header",
|
|
423
|
+
):
|
|
424
|
+
dpg.add_text(
|
|
425
|
+
"Click on preview to select elements",
|
|
426
|
+
tag="element_hint_text",
|
|
427
|
+
color=(150, 150, 150),
|
|
428
|
+
)
|
|
406
429
|
dpg.add_combo(
|
|
407
430
|
label="Element",
|
|
408
431
|
items=self._get_all_element_labels(),
|
|
@@ -542,9 +565,18 @@ class DearPyGuiEditor:
|
|
|
542
565
|
)
|
|
543
566
|
dpg.add_combo(
|
|
544
567
|
label="Position",
|
|
545
|
-
items=[
|
|
546
|
-
|
|
547
|
-
|
|
568
|
+
items=[
|
|
569
|
+
"best",
|
|
570
|
+
"upper right",
|
|
571
|
+
"upper left",
|
|
572
|
+
"lower right",
|
|
573
|
+
"lower left",
|
|
574
|
+
"center right",
|
|
575
|
+
"center left",
|
|
576
|
+
"upper center",
|
|
577
|
+
"lower center",
|
|
578
|
+
"center",
|
|
579
|
+
],
|
|
548
580
|
default_value="best",
|
|
549
581
|
tag="legend_loc_edit",
|
|
550
582
|
callback=self._on_legend_element_change,
|
|
@@ -568,7 +600,7 @@ class DearPyGuiEditor:
|
|
|
568
600
|
|
|
569
601
|
# Dimensions Section
|
|
570
602
|
with dpg.collapsing_header(label="Dimensions", default_open=False):
|
|
571
|
-
fig_size = self.current_overrides.get(
|
|
603
|
+
fig_size = self.current_overrides.get("fig_size", [3.15, 2.68])
|
|
572
604
|
with dpg.group(horizontal=True):
|
|
573
605
|
dpg.add_input_float(
|
|
574
606
|
label="Width (in)",
|
|
@@ -584,7 +616,7 @@ class DearPyGuiEditor:
|
|
|
584
616
|
)
|
|
585
617
|
dpg.add_slider_int(
|
|
586
618
|
label="DPI",
|
|
587
|
-
default_value=self.current_overrides.get(
|
|
619
|
+
default_value=self.current_overrides.get("dpi", 300),
|
|
588
620
|
min_value=72,
|
|
589
621
|
max_value=600,
|
|
590
622
|
tag="dpi_slider",
|
|
@@ -657,6 +689,7 @@ class DearPyGuiEditor:
|
|
|
657
689
|
def _on_value_change(self, sender, app_data, user_data=None):
|
|
658
690
|
"""Handle value changes from widgets."""
|
|
659
691
|
import dearpygui.dearpygui as dpg
|
|
692
|
+
|
|
660
693
|
self._user_modified = True
|
|
661
694
|
self._collect_overrides(dpg)
|
|
662
695
|
self._update_preview(dpg)
|
|
@@ -664,43 +697,55 @@ class DearPyGuiEditor:
|
|
|
664
697
|
def _collect_overrides(self, dpg):
|
|
665
698
|
"""Collect current values from all widgets."""
|
|
666
699
|
# Labels
|
|
667
|
-
self.current_overrides[
|
|
668
|
-
self.current_overrides[
|
|
669
|
-
self.current_overrides[
|
|
700
|
+
self.current_overrides["title"] = dpg.get_value("title_input")
|
|
701
|
+
self.current_overrides["xlabel"] = dpg.get_value("xlabel_input")
|
|
702
|
+
self.current_overrides["ylabel"] = dpg.get_value("ylabel_input")
|
|
670
703
|
|
|
671
704
|
# Line style
|
|
672
|
-
self.current_overrides[
|
|
705
|
+
self.current_overrides["linewidth"] = dpg.get_value("linewidth_slider")
|
|
673
706
|
|
|
674
707
|
# Font settings
|
|
675
|
-
self.current_overrides[
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
self.current_overrides[
|
|
708
|
+
self.current_overrides["title_fontsize"] = dpg.get_value(
|
|
709
|
+
"title_fontsize_slider"
|
|
710
|
+
)
|
|
711
|
+
self.current_overrides["axis_fontsize"] = dpg.get_value("axis_fontsize_slider")
|
|
712
|
+
self.current_overrides["tick_fontsize"] = dpg.get_value("tick_fontsize_slider")
|
|
713
|
+
self.current_overrides["legend_fontsize"] = dpg.get_value(
|
|
714
|
+
"legend_fontsize_slider"
|
|
715
|
+
)
|
|
679
716
|
|
|
680
717
|
# Tick settings
|
|
681
|
-
self.current_overrides[
|
|
682
|
-
self.current_overrides[
|
|
683
|
-
self.current_overrides[
|
|
684
|
-
self.current_overrides[
|
|
718
|
+
self.current_overrides["n_ticks"] = dpg.get_value("n_ticks_slider")
|
|
719
|
+
self.current_overrides["tick_length"] = dpg.get_value("tick_length_slider")
|
|
720
|
+
self.current_overrides["tick_width"] = dpg.get_value("tick_width_slider")
|
|
721
|
+
self.current_overrides["tick_direction"] = dpg.get_value("tick_direction_combo")
|
|
685
722
|
|
|
686
723
|
# Style
|
|
687
|
-
self.current_overrides[
|
|
688
|
-
self.current_overrides[
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
self.current_overrides[
|
|
724
|
+
self.current_overrides["grid"] = dpg.get_value("grid_checkbox")
|
|
725
|
+
self.current_overrides["hide_top_spine"] = dpg.get_value(
|
|
726
|
+
"hide_top_spine_checkbox"
|
|
727
|
+
)
|
|
728
|
+
self.current_overrides["hide_right_spine"] = dpg.get_value(
|
|
729
|
+
"hide_right_spine_checkbox"
|
|
730
|
+
)
|
|
731
|
+
self.current_overrides["transparent"] = dpg.get_value("transparent_checkbox")
|
|
732
|
+
self.current_overrides["axis_width"] = dpg.get_value("axis_width_slider")
|
|
692
733
|
|
|
693
734
|
# Legend
|
|
694
|
-
self.current_overrides[
|
|
695
|
-
|
|
696
|
-
|
|
735
|
+
self.current_overrides["legend_visible"] = dpg.get_value(
|
|
736
|
+
"legend_visible_checkbox"
|
|
737
|
+
)
|
|
738
|
+
self.current_overrides["legend_frameon"] = dpg.get_value(
|
|
739
|
+
"legend_frameon_checkbox"
|
|
740
|
+
)
|
|
741
|
+
self.current_overrides["legend_loc"] = dpg.get_value("legend_loc_combo")
|
|
697
742
|
|
|
698
743
|
# Dimensions
|
|
699
|
-
self.current_overrides[
|
|
744
|
+
self.current_overrides["fig_size"] = [
|
|
700
745
|
dpg.get_value("fig_width_input"),
|
|
701
746
|
dpg.get_value("fig_height_input"),
|
|
702
747
|
]
|
|
703
|
-
self.current_overrides[
|
|
748
|
+
self.current_overrides["dpi"] = dpg.get_value("dpi_slider")
|
|
704
749
|
|
|
705
750
|
def _apply_limits(self, sender=None, app_data=None, user_data=None):
|
|
706
751
|
"""Apply axis limits."""
|
|
@@ -712,9 +757,9 @@ class DearPyGuiEditor:
|
|
|
712
757
|
ymax = dpg.get_value("ymax_input")
|
|
713
758
|
|
|
714
759
|
if xmin < xmax:
|
|
715
|
-
self.current_overrides[
|
|
760
|
+
self.current_overrides["xlim"] = [xmin, xmax]
|
|
716
761
|
if ymin < ymax:
|
|
717
|
-
self.current_overrides[
|
|
762
|
+
self.current_overrides["ylim"] = [ymin, ymax]
|
|
718
763
|
|
|
719
764
|
self._user_modified = True
|
|
720
765
|
self._update_preview(dpg)
|
|
@@ -730,16 +775,18 @@ class DearPyGuiEditor:
|
|
|
730
775
|
x = dpg.get_value("annot_x_input")
|
|
731
776
|
y = dpg.get_value("annot_y_input")
|
|
732
777
|
|
|
733
|
-
if
|
|
734
|
-
self.current_overrides[
|
|
735
|
-
|
|
736
|
-
self.current_overrides[
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
778
|
+
if "annotations" not in self.current_overrides:
|
|
779
|
+
self.current_overrides["annotations"] = []
|
|
780
|
+
|
|
781
|
+
self.current_overrides["annotations"].append(
|
|
782
|
+
{
|
|
783
|
+
"type": "text",
|
|
784
|
+
"text": text,
|
|
785
|
+
"x": x,
|
|
786
|
+
"y": y,
|
|
787
|
+
"fontsize": self.current_overrides.get("axis_fontsize", 7),
|
|
788
|
+
}
|
|
789
|
+
)
|
|
743
790
|
|
|
744
791
|
dpg.set_value("annot_text_input", "")
|
|
745
792
|
self._update_annotations_list(dpg)
|
|
@@ -751,7 +798,7 @@ class DearPyGuiEditor:
|
|
|
751
798
|
import dearpygui.dearpygui as dpg
|
|
752
799
|
|
|
753
800
|
selected = dpg.get_value("annotations_listbox")
|
|
754
|
-
annotations = self.current_overrides.get(
|
|
801
|
+
annotations = self.current_overrides.get("annotations", [])
|
|
755
802
|
|
|
756
803
|
if selected and annotations:
|
|
757
804
|
# Find index by text
|
|
@@ -767,10 +814,10 @@ class DearPyGuiEditor:
|
|
|
767
814
|
|
|
768
815
|
def _update_annotations_list(self, dpg):
|
|
769
816
|
"""Update the annotations listbox."""
|
|
770
|
-
annotations = self.current_overrides.get(
|
|
817
|
+
annotations = self.current_overrides.get("annotations", [])
|
|
771
818
|
items = []
|
|
772
819
|
for ann in annotations:
|
|
773
|
-
if ann.get(
|
|
820
|
+
if ann.get("type") == "text":
|
|
774
821
|
label = f"{ann.get('text', '')[:20]} ({ann.get('x', 0):.2f}, {ann.get('y', 0):.2f})"
|
|
775
822
|
items.append(label)
|
|
776
823
|
|
|
@@ -805,27 +852,45 @@ class DearPyGuiEditor:
|
|
|
805
852
|
try:
|
|
806
853
|
# Start with a copy of cached base
|
|
807
854
|
img = self._cached_base_image.copy()
|
|
808
|
-
draw = ImageDraw.Draw(img,
|
|
855
|
+
draw = ImageDraw.Draw(img, "RGBA")
|
|
809
856
|
|
|
810
857
|
# Get hover element type
|
|
811
|
-
hovered_type =
|
|
812
|
-
|
|
858
|
+
hovered_type = (
|
|
859
|
+
self._hovered_element.get("type") if self._hovered_element else None
|
|
860
|
+
)
|
|
861
|
+
selected_type = (
|
|
862
|
+
self._selected_element.get("type") if self._selected_element else None
|
|
863
|
+
)
|
|
813
864
|
|
|
814
865
|
# Draw hover highlight (outline only, no fill) for non-trace elements
|
|
815
|
-
if
|
|
866
|
+
if (
|
|
867
|
+
hovered_type
|
|
868
|
+
and hovered_type != "trace"
|
|
869
|
+
and hovered_type != selected_type
|
|
870
|
+
):
|
|
816
871
|
bbox = self._element_bboxes.get(hovered_type)
|
|
817
872
|
if bbox:
|
|
818
873
|
x0, y0, x1, y1 = bbox
|
|
819
874
|
# Transparent outline only - no fill to avoid covering content
|
|
820
|
-
draw.rectangle(
|
|
875
|
+
draw.rectangle(
|
|
876
|
+
[x0 - 2, y0 - 2, x1 + 2, y1 + 2],
|
|
877
|
+
fill=None,
|
|
878
|
+
outline=(100, 180, 255, 100),
|
|
879
|
+
width=1,
|
|
880
|
+
)
|
|
821
881
|
|
|
822
882
|
# Draw selection highlight (outline only, no fill) for non-trace elements
|
|
823
|
-
if selected_type and selected_type !=
|
|
883
|
+
if selected_type and selected_type != "trace":
|
|
824
884
|
bbox = self._element_bboxes.get(selected_type)
|
|
825
885
|
if bbox:
|
|
826
886
|
x0, y0, x1, y1 = bbox
|
|
827
887
|
# Transparent outline only - no fill to avoid covering content
|
|
828
|
-
draw.rectangle(
|
|
888
|
+
draw.rectangle(
|
|
889
|
+
[x0 - 2, y0 - 2, x1 + 2, y1 + 2],
|
|
890
|
+
fill=None,
|
|
891
|
+
outline=(255, 200, 80, 150),
|
|
892
|
+
width=2,
|
|
893
|
+
)
|
|
829
894
|
|
|
830
895
|
# Convert to DearPyGui texture format
|
|
831
896
|
img_array = np.array(img).astype(np.float32) / 255.0
|
|
@@ -841,7 +906,8 @@ class DearPyGuiEditor:
|
|
|
841
906
|
def _render_figure(self):
|
|
842
907
|
"""Render figure and return as RGBA data for texture."""
|
|
843
908
|
import matplotlib
|
|
844
|
-
|
|
909
|
+
|
|
910
|
+
matplotlib.use("Agg")
|
|
845
911
|
import matplotlib.pyplot as plt
|
|
846
912
|
from matplotlib.ticker import MaxNLocator
|
|
847
913
|
import numpy as np
|
|
@@ -855,72 +921,78 @@ class DearPyGuiEditor:
|
|
|
855
921
|
|
|
856
922
|
# Dimensions - use fixed size for preview
|
|
857
923
|
preview_dpi = 100
|
|
858
|
-
fig_size = o.get(
|
|
924
|
+
fig_size = o.get("fig_size", [3.15, 2.68])
|
|
859
925
|
|
|
860
926
|
# Create figure with white background for preview
|
|
861
927
|
fig, ax = plt.subplots(figsize=fig_size, dpi=preview_dpi)
|
|
862
928
|
|
|
863
929
|
# For preview, use white background (transparent doesn't show well in GUI)
|
|
864
|
-
fig.patch.set_facecolor(
|
|
865
|
-
ax.patch.set_facecolor(
|
|
930
|
+
fig.patch.set_facecolor("white")
|
|
931
|
+
ax.patch.set_facecolor("white")
|
|
866
932
|
|
|
867
933
|
# Plot from CSV data (only pass selection, hover is via PIL overlay for speed)
|
|
868
934
|
if self.csv_data is not None:
|
|
869
935
|
self._plot_from_csv(ax, o, highlight_trace=self._selected_trace_index)
|
|
870
936
|
else:
|
|
871
|
-
ax.text(
|
|
872
|
-
|
|
873
|
-
|
|
937
|
+
ax.text(
|
|
938
|
+
0.5,
|
|
939
|
+
0.5,
|
|
940
|
+
"No plot data available\n(CSV not found)",
|
|
941
|
+
ha="center",
|
|
942
|
+
va="center",
|
|
943
|
+
transform=ax.transAxes,
|
|
944
|
+
fontsize=o.get("axis_fontsize", 7),
|
|
945
|
+
)
|
|
874
946
|
|
|
875
947
|
# Apply labels
|
|
876
|
-
if o.get(
|
|
877
|
-
ax.set_title(o[
|
|
878
|
-
if o.get(
|
|
879
|
-
ax.set_xlabel(o[
|
|
880
|
-
if o.get(
|
|
881
|
-
ax.set_ylabel(o[
|
|
948
|
+
if o.get("title"):
|
|
949
|
+
ax.set_title(o["title"], fontsize=o.get("title_fontsize", 8))
|
|
950
|
+
if o.get("xlabel"):
|
|
951
|
+
ax.set_xlabel(o["xlabel"], fontsize=o.get("axis_fontsize", 7))
|
|
952
|
+
if o.get("ylabel"):
|
|
953
|
+
ax.set_ylabel(o["ylabel"], fontsize=o.get("axis_fontsize", 7))
|
|
882
954
|
|
|
883
955
|
# Tick styling
|
|
884
956
|
ax.tick_params(
|
|
885
|
-
axis=
|
|
886
|
-
labelsize=o.get(
|
|
887
|
-
length=o.get(
|
|
888
|
-
width=o.get(
|
|
889
|
-
direction=o.get(
|
|
957
|
+
axis="both",
|
|
958
|
+
labelsize=o.get("tick_fontsize", 7),
|
|
959
|
+
length=o.get("tick_length", 0.8) * mm_to_pt,
|
|
960
|
+
width=o.get("tick_width", 0.2) * mm_to_pt,
|
|
961
|
+
direction=o.get("tick_direction", "out"),
|
|
890
962
|
)
|
|
891
963
|
|
|
892
964
|
# Number of ticks
|
|
893
|
-
ax.xaxis.set_major_locator(MaxNLocator(nbins=o.get(
|
|
894
|
-
ax.yaxis.set_major_locator(MaxNLocator(nbins=o.get(
|
|
965
|
+
ax.xaxis.set_major_locator(MaxNLocator(nbins=o.get("n_ticks", 4)))
|
|
966
|
+
ax.yaxis.set_major_locator(MaxNLocator(nbins=o.get("n_ticks", 4)))
|
|
895
967
|
|
|
896
968
|
# Grid
|
|
897
|
-
if o.get(
|
|
898
|
-
ax.grid(True, linewidth=o.get(
|
|
969
|
+
if o.get("grid"):
|
|
970
|
+
ax.grid(True, linewidth=o.get("axis_width", 0.2) * mm_to_pt, alpha=0.3)
|
|
899
971
|
|
|
900
972
|
# Axis limits
|
|
901
|
-
if o.get(
|
|
902
|
-
ax.set_xlim(o[
|
|
903
|
-
if o.get(
|
|
904
|
-
ax.set_ylim(o[
|
|
973
|
+
if o.get("xlim"):
|
|
974
|
+
ax.set_xlim(o["xlim"])
|
|
975
|
+
if o.get("ylim"):
|
|
976
|
+
ax.set_ylim(o["ylim"])
|
|
905
977
|
|
|
906
978
|
# Spines
|
|
907
|
-
if o.get(
|
|
908
|
-
ax.spines[
|
|
909
|
-
if o.get(
|
|
910
|
-
ax.spines[
|
|
979
|
+
if o.get("hide_top_spine", True):
|
|
980
|
+
ax.spines["top"].set_visible(False)
|
|
981
|
+
if o.get("hide_right_spine", True):
|
|
982
|
+
ax.spines["right"].set_visible(False)
|
|
911
983
|
|
|
912
984
|
for spine in ax.spines.values():
|
|
913
|
-
spine.set_linewidth(o.get(
|
|
985
|
+
spine.set_linewidth(o.get("axis_width", 0.2) * mm_to_pt)
|
|
914
986
|
|
|
915
987
|
# Annotations
|
|
916
|
-
for annot in o.get(
|
|
917
|
-
if annot.get(
|
|
988
|
+
for annot in o.get("annotations", []):
|
|
989
|
+
if annot.get("type") == "text":
|
|
918
990
|
ax.text(
|
|
919
|
-
annot.get(
|
|
920
|
-
annot.get(
|
|
921
|
-
annot.get(
|
|
991
|
+
annot.get("x", 0.5),
|
|
992
|
+
annot.get("y", 0.5),
|
|
993
|
+
annot.get("text", ""),
|
|
922
994
|
transform=ax.transAxes,
|
|
923
|
-
fontsize=annot.get(
|
|
995
|
+
fontsize=annot.get("fontsize", o.get("axis_fontsize", 7)),
|
|
924
996
|
)
|
|
925
997
|
|
|
926
998
|
fig.tight_layout()
|
|
@@ -945,8 +1017,11 @@ class DearPyGuiEditor:
|
|
|
945
1017
|
if ax.title.get_text():
|
|
946
1018
|
try:
|
|
947
1019
|
title_bbox = ax.title.get_window_extent(fig.canvas.get_renderer())
|
|
948
|
-
self._element_bboxes_raw[
|
|
949
|
-
title_bbox.x0,
|
|
1020
|
+
self._element_bboxes_raw["title"] = (
|
|
1021
|
+
title_bbox.x0,
|
|
1022
|
+
title_bbox.y0,
|
|
1023
|
+
title_bbox.x1,
|
|
1024
|
+
title_bbox.y1,
|
|
950
1025
|
)
|
|
951
1026
|
except Exception:
|
|
952
1027
|
pass
|
|
@@ -954,9 +1029,14 @@ class DearPyGuiEditor:
|
|
|
954
1029
|
# X label bbox
|
|
955
1030
|
if ax.xaxis.label.get_text():
|
|
956
1031
|
try:
|
|
957
|
-
xlabel_bbox = ax.xaxis.label.get_window_extent(
|
|
958
|
-
|
|
959
|
-
|
|
1032
|
+
xlabel_bbox = ax.xaxis.label.get_window_extent(
|
|
1033
|
+
fig.canvas.get_renderer()
|
|
1034
|
+
)
|
|
1035
|
+
self._element_bboxes_raw["xlabel"] = (
|
|
1036
|
+
xlabel_bbox.x0,
|
|
1037
|
+
xlabel_bbox.y0,
|
|
1038
|
+
xlabel_bbox.x1,
|
|
1039
|
+
xlabel_bbox.y1,
|
|
960
1040
|
)
|
|
961
1041
|
except Exception:
|
|
962
1042
|
pass
|
|
@@ -964,9 +1044,14 @@ class DearPyGuiEditor:
|
|
|
964
1044
|
# Y label bbox
|
|
965
1045
|
if ax.yaxis.label.get_text():
|
|
966
1046
|
try:
|
|
967
|
-
ylabel_bbox = ax.yaxis.label.get_window_extent(
|
|
968
|
-
|
|
969
|
-
|
|
1047
|
+
ylabel_bbox = ax.yaxis.label.get_window_extent(
|
|
1048
|
+
fig.canvas.get_renderer()
|
|
1049
|
+
)
|
|
1050
|
+
self._element_bboxes_raw["ylabel"] = (
|
|
1051
|
+
ylabel_bbox.x0,
|
|
1052
|
+
ylabel_bbox.y0,
|
|
1053
|
+
ylabel_bbox.x1,
|
|
1054
|
+
ylabel_bbox.y1,
|
|
970
1055
|
)
|
|
971
1056
|
except Exception:
|
|
972
1057
|
pass
|
|
@@ -976,40 +1061,57 @@ class DearPyGuiEditor:
|
|
|
976
1061
|
if legend:
|
|
977
1062
|
try:
|
|
978
1063
|
legend_bbox = legend.get_window_extent(fig.canvas.get_renderer())
|
|
979
|
-
self._element_bboxes_raw[
|
|
980
|
-
legend_bbox.x0,
|
|
1064
|
+
self._element_bboxes_raw["legend"] = (
|
|
1065
|
+
legend_bbox.x0,
|
|
1066
|
+
legend_bbox.y0,
|
|
1067
|
+
legend_bbox.x1,
|
|
1068
|
+
legend_bbox.y1,
|
|
981
1069
|
)
|
|
982
1070
|
except Exception:
|
|
983
1071
|
pass
|
|
984
1072
|
|
|
985
1073
|
# X axis (bottom spine area)
|
|
986
1074
|
try:
|
|
987
|
-
xaxis_bbox = ax.spines[
|
|
1075
|
+
xaxis_bbox = ax.spines["bottom"].get_window_extent(
|
|
1076
|
+
fig.canvas.get_renderer()
|
|
1077
|
+
)
|
|
988
1078
|
# Expand bbox slightly for easier clicking
|
|
989
|
-
self._element_bboxes_raw[
|
|
990
|
-
xaxis_bbox.x0,
|
|
1079
|
+
self._element_bboxes_raw["xaxis"] = (
|
|
1080
|
+
xaxis_bbox.x0,
|
|
1081
|
+
xaxis_bbox.y0 - 20,
|
|
1082
|
+
xaxis_bbox.x1,
|
|
1083
|
+
xaxis_bbox.y1 + 10,
|
|
991
1084
|
)
|
|
992
1085
|
except Exception:
|
|
993
1086
|
pass
|
|
994
1087
|
|
|
995
1088
|
# Y axis (left spine area)
|
|
996
1089
|
try:
|
|
997
|
-
yaxis_bbox = ax.spines[
|
|
1090
|
+
yaxis_bbox = ax.spines["left"].get_window_extent(fig.canvas.get_renderer())
|
|
998
1091
|
# Expand bbox slightly for easier clicking
|
|
999
|
-
self._element_bboxes_raw[
|
|
1000
|
-
yaxis_bbox.x0 - 20,
|
|
1092
|
+
self._element_bboxes_raw["yaxis"] = (
|
|
1093
|
+
yaxis_bbox.x0 - 20,
|
|
1094
|
+
yaxis_bbox.y0,
|
|
1095
|
+
yaxis_bbox.x1 + 10,
|
|
1096
|
+
yaxis_bbox.y1,
|
|
1001
1097
|
)
|
|
1002
1098
|
except Exception:
|
|
1003
1099
|
pass
|
|
1004
1100
|
|
|
1005
1101
|
# Convert to RGBA data for DearPyGui texture
|
|
1006
1102
|
buf = io.BytesIO()
|
|
1007
|
-
fig.savefig(
|
|
1008
|
-
|
|
1103
|
+
fig.savefig(
|
|
1104
|
+
buf,
|
|
1105
|
+
format="png",
|
|
1106
|
+
dpi=preview_dpi,
|
|
1107
|
+
bbox_inches="tight",
|
|
1108
|
+
facecolor="white",
|
|
1109
|
+
edgecolor="none",
|
|
1110
|
+
)
|
|
1009
1111
|
buf.seek(0)
|
|
1010
1112
|
|
|
1011
1113
|
# Load with PIL and convert to normalized RGBA
|
|
1012
|
-
img = Image.open(buf).convert(
|
|
1114
|
+
img = Image.open(buf).convert("RGBA")
|
|
1013
1115
|
width, height = img.size
|
|
1014
1116
|
|
|
1015
1117
|
# Resize to fit within max preview size while preserving aspect ratio
|
|
@@ -1027,7 +1129,7 @@ class DearPyGuiEditor:
|
|
|
1027
1129
|
# Scale element bboxes to preview coordinates
|
|
1028
1130
|
# Note: matplotlib uses bottom-left origin, we need top-left for preview
|
|
1029
1131
|
self._element_bboxes = {}
|
|
1030
|
-
for elem_type, raw_bbox in getattr(self,
|
|
1132
|
+
for elem_type, raw_bbox in getattr(self, "_element_bboxes_raw", {}).items():
|
|
1031
1133
|
if raw_bbox is None:
|
|
1032
1134
|
continue
|
|
1033
1135
|
rx0, ry0, rx1, ry1 = raw_bbox
|
|
@@ -1050,12 +1152,12 @@ class DearPyGuiEditor:
|
|
|
1050
1152
|
self._axes_transform = (ax_x0, ax_y0, ax_width, ax_height, xlim, ylim)
|
|
1051
1153
|
|
|
1052
1154
|
# Create background - checkerboard for transparent, white otherwise
|
|
1053
|
-
transparent = o.get(
|
|
1155
|
+
transparent = o.get("transparent", True)
|
|
1054
1156
|
if transparent:
|
|
1055
1157
|
# Create checkerboard pattern for transparency preview
|
|
1056
1158
|
padded = _create_checkerboard(max_width, max_height, square_size=10)
|
|
1057
1159
|
else:
|
|
1058
|
-
padded = Image.new(
|
|
1160
|
+
padded = Image.new("RGBA", (max_width, max_height), (255, 255, 255, 255))
|
|
1059
1161
|
|
|
1060
1162
|
# Paste figure centered on background
|
|
1061
1163
|
padded.paste(img, (x_offset, y_offset), img) # Use img as mask for alpha
|
|
@@ -1085,10 +1187,12 @@ class DearPyGuiEditor:
|
|
|
1085
1187
|
renderer = fig.canvas.get_renderer()
|
|
1086
1188
|
|
|
1087
1189
|
# Only draw selection highlights here (hover is done via fast PIL overlay)
|
|
1088
|
-
selected_type =
|
|
1190
|
+
selected_type = (
|
|
1191
|
+
self._selected_element.get("type") if self._selected_element else None
|
|
1192
|
+
)
|
|
1089
1193
|
|
|
1090
1194
|
# Skip if selecting traces (handled separately in _plot_from_csv)
|
|
1091
|
-
if selected_type ==
|
|
1195
|
+
if selected_type == "trace":
|
|
1092
1196
|
selected_type = None
|
|
1093
1197
|
|
|
1094
1198
|
def add_highlight_box(text_obj, color, alpha, linewidth=2):
|
|
@@ -1104,7 +1208,7 @@ class DearPyGuiEditor:
|
|
|
1104
1208
|
fig_bbox.width + 2 * padding,
|
|
1105
1209
|
fig_bbox.height + 2 * padding,
|
|
1106
1210
|
boxstyle="round,pad=0.02,rounding_size=0.01",
|
|
1107
|
-
facecolor=
|
|
1211
|
+
facecolor="none",
|
|
1108
1212
|
edgecolor=color,
|
|
1109
1213
|
alpha=0.7,
|
|
1110
1214
|
linewidth=linewidth,
|
|
@@ -1126,7 +1230,7 @@ class DearPyGuiEditor:
|
|
|
1126
1230
|
fig_bbox.width + 2 * padding,
|
|
1127
1231
|
fig_bbox.height + 2 * padding,
|
|
1128
1232
|
boxstyle="round,pad=0.01",
|
|
1129
|
-
facecolor=
|
|
1233
|
+
facecolor="none",
|
|
1130
1234
|
edgecolor=color,
|
|
1131
1235
|
alpha=0.7,
|
|
1132
1236
|
linewidth=linewidth,
|
|
@@ -1139,20 +1243,22 @@ class DearPyGuiEditor:
|
|
|
1139
1243
|
|
|
1140
1244
|
# Map element types to matplotlib objects
|
|
1141
1245
|
element_map = {
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1246
|
+
"title": ax.title,
|
|
1247
|
+
"xlabel": ax.xaxis.label,
|
|
1248
|
+
"ylabel": ax.yaxis.label,
|
|
1145
1249
|
}
|
|
1146
1250
|
|
|
1147
1251
|
# Draw selection highlight (outline only, no fill)
|
|
1148
|
-
select_color =
|
|
1252
|
+
select_color = "#FFC850" # Soft warm yellow for outline
|
|
1149
1253
|
if selected_type in element_map:
|
|
1150
|
-
add_highlight_box(
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
elif selected_type ==
|
|
1154
|
-
add_spine_highlight(ax.spines[
|
|
1155
|
-
elif selected_type ==
|
|
1254
|
+
add_highlight_box(
|
|
1255
|
+
element_map[selected_type], select_color, 0.0, linewidth=2
|
|
1256
|
+
)
|
|
1257
|
+
elif selected_type == "xaxis":
|
|
1258
|
+
add_spine_highlight(ax.spines["bottom"], select_color, 0.0, linewidth=2)
|
|
1259
|
+
elif selected_type == "yaxis":
|
|
1260
|
+
add_spine_highlight(ax.spines["left"], select_color, 0.0, linewidth=2)
|
|
1261
|
+
elif selected_type == "legend":
|
|
1156
1262
|
legend = ax.get_legend()
|
|
1157
1263
|
if legend:
|
|
1158
1264
|
try:
|
|
@@ -1164,7 +1270,7 @@ class DearPyGuiEditor:
|
|
|
1164
1270
|
fig_bbox.width + 2 * padding,
|
|
1165
1271
|
fig_bbox.height + 2 * padding,
|
|
1166
1272
|
boxstyle="round,pad=0.02",
|
|
1167
|
-
facecolor=
|
|
1273
|
+
facecolor="none",
|
|
1168
1274
|
edgecolor=select_color,
|
|
1169
1275
|
alpha=0.7,
|
|
1170
1276
|
linewidth=2,
|
|
@@ -1198,31 +1304,33 @@ class DearPyGuiEditor:
|
|
|
1198
1304
|
return
|
|
1199
1305
|
|
|
1200
1306
|
df = self.csv_data
|
|
1201
|
-
linewidth = o.get(
|
|
1202
|
-
legend_visible = o.get(
|
|
1203
|
-
legend_fontsize = o.get(
|
|
1204
|
-
legend_frameon = o.get(
|
|
1205
|
-
legend_loc = _normalize_legend_loc(o.get(
|
|
1307
|
+
linewidth = o.get("linewidth", 1.0)
|
|
1308
|
+
legend_visible = o.get("legend_visible", True)
|
|
1309
|
+
legend_fontsize = o.get("legend_fontsize", 6)
|
|
1310
|
+
legend_frameon = o.get("legend_frameon", False)
|
|
1311
|
+
legend_loc = _normalize_legend_loc(o.get("legend_loc", "best"))
|
|
1206
1312
|
|
|
1207
|
-
traces = o.get(
|
|
1313
|
+
traces = o.get("traces", [])
|
|
1208
1314
|
|
|
1209
1315
|
if traces:
|
|
1210
1316
|
for i, trace in enumerate(traces):
|
|
1211
|
-
csv_cols = trace.get(
|
|
1212
|
-
x_col = csv_cols.get(
|
|
1213
|
-
y_col = csv_cols.get(
|
|
1317
|
+
csv_cols = trace.get("csv_columns", {})
|
|
1318
|
+
x_col = csv_cols.get("x")
|
|
1319
|
+
y_col = csv_cols.get("y")
|
|
1214
1320
|
|
|
1215
1321
|
if x_col in df.columns and y_col in df.columns:
|
|
1216
|
-
trace_linewidth = trace.get(
|
|
1217
|
-
is_selected =
|
|
1218
|
-
is_hovered = (
|
|
1322
|
+
trace_linewidth = trace.get("linewidth", linewidth)
|
|
1323
|
+
is_selected = highlight_trace is not None and i == highlight_trace
|
|
1324
|
+
is_hovered = (
|
|
1325
|
+
hover_trace is not None and i == hover_trace and not is_selected
|
|
1326
|
+
)
|
|
1219
1327
|
|
|
1220
1328
|
# Draw selection glow (yellow, stronger)
|
|
1221
1329
|
if is_selected:
|
|
1222
1330
|
ax.plot(
|
|
1223
1331
|
df[x_col],
|
|
1224
1332
|
df[y_col],
|
|
1225
|
-
color=
|
|
1333
|
+
color="yellow",
|
|
1226
1334
|
linewidth=trace_linewidth * 4,
|
|
1227
1335
|
alpha=0.5,
|
|
1228
1336
|
zorder=0,
|
|
@@ -1232,7 +1340,7 @@ class DearPyGuiEditor:
|
|
|
1232
1340
|
ax.plot(
|
|
1233
1341
|
df[x_col],
|
|
1234
1342
|
df[y_col],
|
|
1235
|
-
color=
|
|
1343
|
+
color="cyan",
|
|
1236
1344
|
linewidth=trace_linewidth * 3,
|
|
1237
1345
|
alpha=0.3,
|
|
1238
1346
|
zorder=0,
|
|
@@ -1241,61 +1349,70 @@ class DearPyGuiEditor:
|
|
|
1241
1349
|
ax.plot(
|
|
1242
1350
|
df[x_col],
|
|
1243
1351
|
df[y_col],
|
|
1244
|
-
label=trace.get(
|
|
1245
|
-
color=trace.get(
|
|
1246
|
-
linestyle=trace.get(
|
|
1247
|
-
linewidth=trace_linewidth
|
|
1248
|
-
|
|
1249
|
-
|
|
1352
|
+
label=trace.get("label", trace.get("id", "")),
|
|
1353
|
+
color=trace.get("color"),
|
|
1354
|
+
linestyle=trace.get("linestyle", "-"),
|
|
1355
|
+
linewidth=trace_linewidth
|
|
1356
|
+
* (1.5 if is_selected else (1.2 if is_hovered else 1.0)),
|
|
1357
|
+
marker=trace.get("marker", None),
|
|
1358
|
+
markersize=trace.get("markersize", 6),
|
|
1250
1359
|
zorder=10 if is_selected else (5 if is_hovered else 1),
|
|
1251
1360
|
)
|
|
1252
1361
|
|
|
1253
|
-
if legend_visible and any(t.get(
|
|
1254
|
-
ax.legend(
|
|
1362
|
+
if legend_visible and any(t.get("label") for t in traces):
|
|
1363
|
+
ax.legend(
|
|
1364
|
+
fontsize=legend_fontsize, frameon=legend_frameon, loc=legend_loc
|
|
1365
|
+
)
|
|
1255
1366
|
else:
|
|
1256
1367
|
# Fallback: parse column names
|
|
1257
1368
|
cols = df.columns.tolist()
|
|
1258
1369
|
trace_groups = {}
|
|
1259
1370
|
|
|
1260
1371
|
for col in cols:
|
|
1261
|
-
if col.endswith(
|
|
1372
|
+
if col.endswith("_x"):
|
|
1262
1373
|
trace_id = col[:-2]
|
|
1263
|
-
y_col = trace_id +
|
|
1374
|
+
y_col = trace_id + "_y"
|
|
1264
1375
|
if y_col in cols:
|
|
1265
|
-
parts = trace_id.split(
|
|
1376
|
+
parts = trace_id.split("_")
|
|
1266
1377
|
label = parts[2] if len(parts) > 2 else trace_id
|
|
1267
1378
|
trace_groups[trace_id] = {
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1379
|
+
"x_col": col,
|
|
1380
|
+
"y_col": y_col,
|
|
1381
|
+
"label": label,
|
|
1271
1382
|
}
|
|
1272
1383
|
|
|
1273
1384
|
if trace_groups:
|
|
1274
1385
|
for trace_id, info in trace_groups.items():
|
|
1275
1386
|
ax.plot(
|
|
1276
|
-
df[info[
|
|
1277
|
-
df[info[
|
|
1278
|
-
label=info[
|
|
1387
|
+
df[info["x_col"]],
|
|
1388
|
+
df[info["y_col"]],
|
|
1389
|
+
label=info["label"],
|
|
1279
1390
|
linewidth=linewidth,
|
|
1280
1391
|
)
|
|
1281
1392
|
if legend_visible:
|
|
1282
|
-
ax.legend(
|
|
1393
|
+
ax.legend(
|
|
1394
|
+
fontsize=legend_fontsize, frameon=legend_frameon, loc=legend_loc
|
|
1395
|
+
)
|
|
1283
1396
|
elif len(cols) >= 2:
|
|
1284
1397
|
x_col = cols[0]
|
|
1285
1398
|
for y_col in cols[1:]:
|
|
1286
1399
|
try:
|
|
1287
|
-
ax.plot(
|
|
1400
|
+
ax.plot(
|
|
1401
|
+
df[x_col], df[y_col], label=str(y_col), linewidth=linewidth
|
|
1402
|
+
)
|
|
1288
1403
|
except Exception:
|
|
1289
1404
|
pass
|
|
1290
1405
|
if len(cols) > 2 and legend_visible:
|
|
1291
|
-
ax.legend(
|
|
1406
|
+
ax.legend(
|
|
1407
|
+
fontsize=legend_fontsize, frameon=legend_frameon, loc=legend_loc
|
|
1408
|
+
)
|
|
1292
1409
|
|
|
1293
1410
|
def _get_trace_labels(self):
|
|
1294
1411
|
"""Get list of trace labels for selection combo."""
|
|
1295
|
-
traces = self.current_overrides.get(
|
|
1412
|
+
traces = self.current_overrides.get("traces", [])
|
|
1296
1413
|
if not traces:
|
|
1297
1414
|
return ["(no traces)"]
|
|
1298
|
-
return [t.get(
|
|
1415
|
+
return [t.get("label", t.get("id", f"Trace {i}")) for i, t in enumerate(traces)]
|
|
1299
1416
|
|
|
1300
1417
|
def _get_all_element_labels(self):
|
|
1301
1418
|
"""Get list of all selectable element labels."""
|
|
@@ -1310,9 +1427,9 @@ class DearPyGuiEditor:
|
|
|
1310
1427
|
labels.append("Legend")
|
|
1311
1428
|
|
|
1312
1429
|
# Traces
|
|
1313
|
-
traces = self.current_overrides.get(
|
|
1430
|
+
traces = self.current_overrides.get("traces", [])
|
|
1314
1431
|
for i, t in enumerate(traces):
|
|
1315
|
-
label = t.get(
|
|
1432
|
+
label = t.get("label", t.get("id", f"Trace {i}"))
|
|
1316
1433
|
labels.append(f"Trace: {label}")
|
|
1317
1434
|
|
|
1318
1435
|
return labels
|
|
@@ -1352,9 +1469,11 @@ class DearPyGuiEditor:
|
|
|
1352
1469
|
self._select_element(element, dpg)
|
|
1353
1470
|
else:
|
|
1354
1471
|
# Fall back to trace selection
|
|
1355
|
-
trace_idx = self._find_nearest_trace(
|
|
1472
|
+
trace_idx = self._find_nearest_trace(
|
|
1473
|
+
click_x, click_y, max_width, max_height
|
|
1474
|
+
)
|
|
1356
1475
|
if trace_idx is not None:
|
|
1357
|
-
self._select_element({
|
|
1476
|
+
self._select_element({"type": "trace", "index": trace_idx}, dpg)
|
|
1358
1477
|
|
|
1359
1478
|
def _on_preview_hover(self, sender, app_data):
|
|
1360
1479
|
"""Handle mouse move for hover effects on preview (optimized with caching)."""
|
|
@@ -1396,24 +1515,26 @@ class DearPyGuiEditor:
|
|
|
1396
1515
|
|
|
1397
1516
|
if element is None:
|
|
1398
1517
|
# Check for trace hover
|
|
1399
|
-
trace_idx = self._find_nearest_trace(
|
|
1518
|
+
trace_idx = self._find_nearest_trace(
|
|
1519
|
+
hover_x, hover_y, max_width, max_height
|
|
1520
|
+
)
|
|
1400
1521
|
if trace_idx is not None:
|
|
1401
|
-
element = {
|
|
1522
|
+
element = {"type": "trace", "index": trace_idx}
|
|
1402
1523
|
|
|
1403
1524
|
# Check if hover changed
|
|
1404
1525
|
old_hover = self._hovered_element
|
|
1405
1526
|
if element != old_hover:
|
|
1406
1527
|
self._hovered_element = element
|
|
1407
1528
|
if element:
|
|
1408
|
-
elem_type = element.get(
|
|
1409
|
-
elem_idx = element.get(
|
|
1410
|
-
if elem_type ==
|
|
1411
|
-
traces = self.current_overrides.get(
|
|
1529
|
+
elem_type = element.get("type", "")
|
|
1530
|
+
elem_idx = element.get("index")
|
|
1531
|
+
if elem_type == "trace" and elem_idx is not None:
|
|
1532
|
+
traces = self.current_overrides.get("traces", [])
|
|
1412
1533
|
if elem_idx < len(traces):
|
|
1413
|
-
label = traces[elem_idx].get(
|
|
1534
|
+
label = traces[elem_idx].get("label", f"Trace {elem_idx}")
|
|
1414
1535
|
dpg.set_value("hover_text", f"Hover: {label} (click to select)")
|
|
1415
1536
|
else:
|
|
1416
|
-
label = elem_type.replace(
|
|
1537
|
+
label = elem_type.replace("x", "X ").replace("y", "Y ").title()
|
|
1417
1538
|
dpg.set_value("hover_text", f"Hover: {label} (click to select)")
|
|
1418
1539
|
else:
|
|
1419
1540
|
dpg.set_value("hover_text", "")
|
|
@@ -1432,15 +1553,15 @@ class DearPyGuiEditor:
|
|
|
1432
1553
|
continue
|
|
1433
1554
|
x0, y0, x1, y1 = bbox
|
|
1434
1555
|
if x0 <= click_x <= x1 and y0 <= click_y <= y1:
|
|
1435
|
-
return {
|
|
1556
|
+
return {"type": element_type, "index": None}
|
|
1436
1557
|
|
|
1437
1558
|
return None
|
|
1438
1559
|
|
|
1439
1560
|
def _select_element(self, element, dpg):
|
|
1440
1561
|
"""Select an element and show appropriate controls."""
|
|
1441
1562
|
self._selected_element = element
|
|
1442
|
-
elem_type = element.get(
|
|
1443
|
-
elem_idx = element.get(
|
|
1563
|
+
elem_type = element.get("type")
|
|
1564
|
+
elem_idx = element.get("index")
|
|
1444
1565
|
|
|
1445
1566
|
# Hide all control groups first
|
|
1446
1567
|
dpg.configure_item("trace_controls_group", show=False)
|
|
@@ -1449,19 +1570,21 @@ class DearPyGuiEditor:
|
|
|
1449
1570
|
dpg.configure_item("legend_controls_group", show=False)
|
|
1450
1571
|
|
|
1451
1572
|
# Update combo selection
|
|
1452
|
-
if elem_type ==
|
|
1453
|
-
traces = self.current_overrides.get(
|
|
1573
|
+
if elem_type == "trace":
|
|
1574
|
+
traces = self.current_overrides.get("traces", [])
|
|
1454
1575
|
if elem_idx is not None and elem_idx < len(traces):
|
|
1455
1576
|
trace = traces[elem_idx]
|
|
1456
|
-
label =
|
|
1577
|
+
label = (
|
|
1578
|
+
f"Trace: {trace.get('label', trace.get('id', f'Trace {elem_idx}'))}"
|
|
1579
|
+
)
|
|
1457
1580
|
dpg.set_value("element_selector_combo", label)
|
|
1458
1581
|
|
|
1459
1582
|
# Show trace controls and populate
|
|
1460
1583
|
dpg.configure_item("trace_controls_group", show=True)
|
|
1461
1584
|
self._selected_trace_index = elem_idx
|
|
1462
|
-
dpg.set_value("trace_label_input", trace.get(
|
|
1585
|
+
dpg.set_value("trace_label_input", trace.get("label", ""))
|
|
1463
1586
|
|
|
1464
|
-
color_hex = trace.get(
|
|
1587
|
+
color_hex = trace.get("color", "#0080bf")
|
|
1465
1588
|
try:
|
|
1466
1589
|
r = int(color_hex[1:3], 16)
|
|
1467
1590
|
g = int(color_hex[3:5], 16)
|
|
@@ -1470,56 +1593,66 @@ class DearPyGuiEditor:
|
|
|
1470
1593
|
except (ValueError, IndexError):
|
|
1471
1594
|
dpg.set_value("trace_color_picker", [128, 128, 191])
|
|
1472
1595
|
|
|
1473
|
-
dpg.set_value("trace_linewidth_slider", trace.get(
|
|
1474
|
-
dpg.set_value("trace_linestyle_combo", trace.get(
|
|
1475
|
-
dpg.set_value("trace_marker_combo", trace.get(
|
|
1476
|
-
dpg.set_value("trace_markersize_slider", trace.get(
|
|
1596
|
+
dpg.set_value("trace_linewidth_slider", trace.get("linewidth", 1.0))
|
|
1597
|
+
dpg.set_value("trace_linestyle_combo", trace.get("linestyle", "-"))
|
|
1598
|
+
dpg.set_value("trace_marker_combo", trace.get("marker", "") or "")
|
|
1599
|
+
dpg.set_value("trace_markersize_slider", trace.get("markersize", 6.0))
|
|
1477
1600
|
|
|
1478
|
-
dpg.set_value(
|
|
1601
|
+
dpg.set_value(
|
|
1602
|
+
"selection_text",
|
|
1603
|
+
f"Selected: {trace.get('label', f'Trace {elem_idx}')}",
|
|
1604
|
+
)
|
|
1479
1605
|
|
|
1480
|
-
elif elem_type in (
|
|
1481
|
-
dpg.set_value(
|
|
1606
|
+
elif elem_type in ("title", "xlabel", "ylabel"):
|
|
1607
|
+
dpg.set_value(
|
|
1608
|
+
"element_selector_combo",
|
|
1609
|
+
elem_type.replace("x", "X ").replace("y", "Y ").title(),
|
|
1610
|
+
)
|
|
1482
1611
|
dpg.configure_item("text_controls_group", show=True)
|
|
1483
1612
|
|
|
1484
1613
|
o = self.current_overrides
|
|
1485
|
-
if elem_type ==
|
|
1486
|
-
dpg.set_value("element_text_input", o.get(
|
|
1487
|
-
dpg.set_value("element_fontsize_slider", o.get(
|
|
1488
|
-
elif elem_type ==
|
|
1489
|
-
dpg.set_value("element_text_input", o.get(
|
|
1490
|
-
dpg.set_value("element_fontsize_slider", o.get(
|
|
1491
|
-
elif elem_type ==
|
|
1492
|
-
dpg.set_value("element_text_input", o.get(
|
|
1493
|
-
dpg.set_value("element_fontsize_slider", o.get(
|
|
1614
|
+
if elem_type == "title":
|
|
1615
|
+
dpg.set_value("element_text_input", o.get("title", ""))
|
|
1616
|
+
dpg.set_value("element_fontsize_slider", o.get("title_fontsize", 8))
|
|
1617
|
+
elif elem_type == "xlabel":
|
|
1618
|
+
dpg.set_value("element_text_input", o.get("xlabel", ""))
|
|
1619
|
+
dpg.set_value("element_fontsize_slider", o.get("axis_fontsize", 7))
|
|
1620
|
+
elif elem_type == "ylabel":
|
|
1621
|
+
dpg.set_value("element_text_input", o.get("ylabel", ""))
|
|
1622
|
+
dpg.set_value("element_fontsize_slider", o.get("axis_fontsize", 7))
|
|
1494
1623
|
|
|
1495
1624
|
dpg.set_value("selection_text", f"Selected: {elem_type.title()}")
|
|
1496
1625
|
|
|
1497
|
-
elif elem_type in (
|
|
1498
|
-
label = "X Axis" if elem_type ==
|
|
1626
|
+
elif elem_type in ("xaxis", "yaxis"):
|
|
1627
|
+
label = "X Axis" if elem_type == "xaxis" else "Y Axis"
|
|
1499
1628
|
dpg.set_value("element_selector_combo", label)
|
|
1500
1629
|
dpg.configure_item("axis_controls_group", show=True)
|
|
1501
1630
|
|
|
1502
1631
|
o = self.current_overrides
|
|
1503
|
-
dpg.set_value("axis_linewidth_slider", o.get(
|
|
1504
|
-
dpg.set_value("axis_tick_length_slider", o.get(
|
|
1505
|
-
dpg.set_value("axis_tick_fontsize_slider", o.get(
|
|
1632
|
+
dpg.set_value("axis_linewidth_slider", o.get("axis_width", 0.2))
|
|
1633
|
+
dpg.set_value("axis_tick_length_slider", o.get("tick_length", 0.8))
|
|
1634
|
+
dpg.set_value("axis_tick_fontsize_slider", o.get("tick_fontsize", 7))
|
|
1506
1635
|
|
|
1507
|
-
if elem_type ==
|
|
1508
|
-
dpg.set_value(
|
|
1636
|
+
if elem_type == "xaxis":
|
|
1637
|
+
dpg.set_value(
|
|
1638
|
+
"axis_show_spine_checkbox", not o.get("hide_bottom_spine", False)
|
|
1639
|
+
)
|
|
1509
1640
|
else:
|
|
1510
|
-
dpg.set_value(
|
|
1641
|
+
dpg.set_value(
|
|
1642
|
+
"axis_show_spine_checkbox", not o.get("hide_left_spine", False)
|
|
1643
|
+
)
|
|
1511
1644
|
|
|
1512
1645
|
dpg.set_value("selection_text", f"Selected: {label}")
|
|
1513
1646
|
|
|
1514
|
-
elif elem_type ==
|
|
1647
|
+
elif elem_type == "legend":
|
|
1515
1648
|
dpg.set_value("element_selector_combo", "Legend")
|
|
1516
1649
|
dpg.configure_item("legend_controls_group", show=True)
|
|
1517
1650
|
|
|
1518
1651
|
o = self.current_overrides
|
|
1519
|
-
dpg.set_value("legend_visible_edit", o.get(
|
|
1520
|
-
dpg.set_value("legend_frameon_edit", o.get(
|
|
1521
|
-
dpg.set_value("legend_loc_edit", o.get(
|
|
1522
|
-
dpg.set_value("legend_fontsize_edit", o.get(
|
|
1652
|
+
dpg.set_value("legend_visible_edit", o.get("legend_visible", True))
|
|
1653
|
+
dpg.set_value("legend_frameon_edit", o.get("legend_frameon", False))
|
|
1654
|
+
dpg.set_value("legend_loc_edit", o.get("legend_loc", "best"))
|
|
1655
|
+
dpg.set_value("legend_fontsize_edit", o.get("legend_fontsize", 6))
|
|
1523
1656
|
|
|
1524
1657
|
dpg.set_value("selection_text", "Selected: Legend")
|
|
1525
1658
|
|
|
@@ -1531,24 +1664,24 @@ class DearPyGuiEditor:
|
|
|
1531
1664
|
import dearpygui.dearpygui as dpg
|
|
1532
1665
|
|
|
1533
1666
|
if app_data == "Title":
|
|
1534
|
-
self._select_element({
|
|
1667
|
+
self._select_element({"type": "title", "index": None}, dpg)
|
|
1535
1668
|
elif app_data == "X Label":
|
|
1536
|
-
self._select_element({
|
|
1669
|
+
self._select_element({"type": "xlabel", "index": None}, dpg)
|
|
1537
1670
|
elif app_data == "Y Label":
|
|
1538
|
-
self._select_element({
|
|
1671
|
+
self._select_element({"type": "ylabel", "index": None}, dpg)
|
|
1539
1672
|
elif app_data == "X Axis":
|
|
1540
|
-
self._select_element({
|
|
1673
|
+
self._select_element({"type": "xaxis", "index": None}, dpg)
|
|
1541
1674
|
elif app_data == "Y Axis":
|
|
1542
|
-
self._select_element({
|
|
1675
|
+
self._select_element({"type": "yaxis", "index": None}, dpg)
|
|
1543
1676
|
elif app_data == "Legend":
|
|
1544
|
-
self._select_element({
|
|
1677
|
+
self._select_element({"type": "legend", "index": None}, dpg)
|
|
1545
1678
|
elif app_data.startswith("Trace: "):
|
|
1546
1679
|
# Find trace index
|
|
1547
1680
|
trace_label = app_data[7:] # Remove "Trace: " prefix
|
|
1548
|
-
traces = self.current_overrides.get(
|
|
1681
|
+
traces = self.current_overrides.get("traces", [])
|
|
1549
1682
|
for i, t in enumerate(traces):
|
|
1550
|
-
if t.get(
|
|
1551
|
-
self._select_element({
|
|
1683
|
+
if t.get("label", t.get("id", f"Trace {i}")) == trace_label:
|
|
1684
|
+
self._select_element({"type": "trace", "index": i}, dpg)
|
|
1552
1685
|
break
|
|
1553
1686
|
|
|
1554
1687
|
def _on_text_element_change(self, sender, app_data, user_data=None):
|
|
@@ -1558,22 +1691,22 @@ class DearPyGuiEditor:
|
|
|
1558
1691
|
if self._selected_element is None:
|
|
1559
1692
|
return
|
|
1560
1693
|
|
|
1561
|
-
elem_type = self._selected_element.get(
|
|
1562
|
-
if elem_type not in (
|
|
1694
|
+
elem_type = self._selected_element.get("type")
|
|
1695
|
+
if elem_type not in ("title", "xlabel", "ylabel"):
|
|
1563
1696
|
return
|
|
1564
1697
|
|
|
1565
1698
|
text = dpg.get_value("element_text_input")
|
|
1566
1699
|
fontsize = dpg.get_value("element_fontsize_slider")
|
|
1567
1700
|
|
|
1568
|
-
if elem_type ==
|
|
1569
|
-
self.current_overrides[
|
|
1570
|
-
self.current_overrides[
|
|
1571
|
-
elif elem_type ==
|
|
1572
|
-
self.current_overrides[
|
|
1573
|
-
self.current_overrides[
|
|
1574
|
-
elif elem_type ==
|
|
1575
|
-
self.current_overrides[
|
|
1576
|
-
self.current_overrides[
|
|
1701
|
+
if elem_type == "title":
|
|
1702
|
+
self.current_overrides["title"] = text
|
|
1703
|
+
self.current_overrides["title_fontsize"] = fontsize
|
|
1704
|
+
elif elem_type == "xlabel":
|
|
1705
|
+
self.current_overrides["xlabel"] = text
|
|
1706
|
+
self.current_overrides["axis_fontsize"] = fontsize
|
|
1707
|
+
elif elem_type == "ylabel":
|
|
1708
|
+
self.current_overrides["ylabel"] = text
|
|
1709
|
+
self.current_overrides["axis_fontsize"] = fontsize
|
|
1577
1710
|
|
|
1578
1711
|
self._user_modified = True
|
|
1579
1712
|
self._update_preview(dpg)
|
|
@@ -1585,19 +1718,21 @@ class DearPyGuiEditor:
|
|
|
1585
1718
|
if self._selected_element is None:
|
|
1586
1719
|
return
|
|
1587
1720
|
|
|
1588
|
-
elem_type = self._selected_element.get(
|
|
1589
|
-
if elem_type not in (
|
|
1721
|
+
elem_type = self._selected_element.get("type")
|
|
1722
|
+
if elem_type not in ("xaxis", "yaxis"):
|
|
1590
1723
|
return
|
|
1591
1724
|
|
|
1592
|
-
self.current_overrides[
|
|
1593
|
-
self.current_overrides[
|
|
1594
|
-
self.current_overrides[
|
|
1725
|
+
self.current_overrides["axis_width"] = dpg.get_value("axis_linewidth_slider")
|
|
1726
|
+
self.current_overrides["tick_length"] = dpg.get_value("axis_tick_length_slider")
|
|
1727
|
+
self.current_overrides["tick_fontsize"] = dpg.get_value(
|
|
1728
|
+
"axis_tick_fontsize_slider"
|
|
1729
|
+
)
|
|
1595
1730
|
|
|
1596
1731
|
show_spine = dpg.get_value("axis_show_spine_checkbox")
|
|
1597
|
-
if elem_type ==
|
|
1598
|
-
self.current_overrides[
|
|
1732
|
+
if elem_type == "xaxis":
|
|
1733
|
+
self.current_overrides["hide_bottom_spine"] = not show_spine
|
|
1599
1734
|
else:
|
|
1600
|
-
self.current_overrides[
|
|
1735
|
+
self.current_overrides["hide_left_spine"] = not show_spine
|
|
1601
1736
|
|
|
1602
1737
|
self._user_modified = True
|
|
1603
1738
|
self._update_preview(dpg)
|
|
@@ -1609,14 +1744,16 @@ class DearPyGuiEditor:
|
|
|
1609
1744
|
if self._selected_element is None:
|
|
1610
1745
|
return
|
|
1611
1746
|
|
|
1612
|
-
elem_type = self._selected_element.get(
|
|
1613
|
-
if elem_type !=
|
|
1747
|
+
elem_type = self._selected_element.get("type")
|
|
1748
|
+
if elem_type != "legend":
|
|
1614
1749
|
return
|
|
1615
1750
|
|
|
1616
|
-
self.current_overrides[
|
|
1617
|
-
self.current_overrides[
|
|
1618
|
-
self.current_overrides[
|
|
1619
|
-
self.current_overrides[
|
|
1751
|
+
self.current_overrides["legend_visible"] = dpg.get_value("legend_visible_edit")
|
|
1752
|
+
self.current_overrides["legend_frameon"] = dpg.get_value("legend_frameon_edit")
|
|
1753
|
+
self.current_overrides["legend_loc"] = dpg.get_value("legend_loc_edit")
|
|
1754
|
+
self.current_overrides["legend_fontsize"] = dpg.get_value(
|
|
1755
|
+
"legend_fontsize_edit"
|
|
1756
|
+
)
|
|
1620
1757
|
|
|
1621
1758
|
self._user_modified = True
|
|
1622
1759
|
self._update_preview(dpg)
|
|
@@ -1646,7 +1783,7 @@ class DearPyGuiEditor:
|
|
|
1646
1783
|
if self.csv_data is None or not isinstance(self.csv_data, pd.DataFrame):
|
|
1647
1784
|
return None
|
|
1648
1785
|
|
|
1649
|
-
traces = self.current_overrides.get(
|
|
1786
|
+
traces = self.current_overrides.get("traces", [])
|
|
1650
1787
|
if not traces:
|
|
1651
1788
|
return None
|
|
1652
1789
|
|
|
@@ -1685,13 +1822,13 @@ class DearPyGuiEditor:
|
|
|
1685
1822
|
|
|
1686
1823
|
# Find nearest trace
|
|
1687
1824
|
df = self.csv_data
|
|
1688
|
-
min_dist = float(
|
|
1825
|
+
min_dist = float("inf")
|
|
1689
1826
|
nearest_idx = None
|
|
1690
1827
|
|
|
1691
1828
|
for i, trace in enumerate(traces):
|
|
1692
|
-
csv_cols = trace.get(
|
|
1693
|
-
x_col = csv_cols.get(
|
|
1694
|
-
y_col = csv_cols.get(
|
|
1829
|
+
csv_cols = trace.get("csv_columns", {})
|
|
1830
|
+
x_col = csv_cols.get("x")
|
|
1831
|
+
y_col = csv_cols.get("y")
|
|
1695
1832
|
|
|
1696
1833
|
if x_col not in df.columns or y_col not in df.columns:
|
|
1697
1834
|
continue
|
|
@@ -1713,7 +1850,9 @@ class DearPyGuiEditor:
|
|
|
1713
1850
|
norm_trace_y = (trace_y - ylim[0]) / y_range if y_range > 0 else trace_y
|
|
1714
1851
|
|
|
1715
1852
|
# Calculate distances to all points
|
|
1716
|
-
distances = np.sqrt(
|
|
1853
|
+
distances = np.sqrt(
|
|
1854
|
+
(norm_trace_x - norm_click_x) ** 2 + (norm_trace_y - norm_click_y) ** 2
|
|
1855
|
+
)
|
|
1717
1856
|
min_trace_dist = np.min(distances)
|
|
1718
1857
|
|
|
1719
1858
|
if min_trace_dist < min_dist:
|
|
@@ -1733,28 +1872,28 @@ class DearPyGuiEditor:
|
|
|
1733
1872
|
if self._selected_trace_index is None:
|
|
1734
1873
|
return
|
|
1735
1874
|
|
|
1736
|
-
traces = self.current_overrides.get(
|
|
1875
|
+
traces = self.current_overrides.get("traces", [])
|
|
1737
1876
|
if self._selected_trace_index >= len(traces):
|
|
1738
1877
|
return
|
|
1739
1878
|
|
|
1740
1879
|
trace = traces[self._selected_trace_index]
|
|
1741
1880
|
|
|
1742
1881
|
# Update trace properties from widgets
|
|
1743
|
-
trace[
|
|
1882
|
+
trace["label"] = dpg.get_value("trace_label_input")
|
|
1744
1883
|
|
|
1745
1884
|
# Convert RGB to hex
|
|
1746
1885
|
color_rgb = dpg.get_value("trace_color_picker")
|
|
1747
1886
|
if color_rgb and len(color_rgb) >= 3:
|
|
1748
1887
|
r, g, b = int(color_rgb[0]), int(color_rgb[1]), int(color_rgb[2])
|
|
1749
|
-
trace[
|
|
1888
|
+
trace["color"] = f"#{r:02x}{g:02x}{b:02x}"
|
|
1750
1889
|
|
|
1751
|
-
trace[
|
|
1752
|
-
trace[
|
|
1890
|
+
trace["linewidth"] = dpg.get_value("trace_linewidth_slider")
|
|
1891
|
+
trace["linestyle"] = dpg.get_value("trace_linestyle_combo")
|
|
1753
1892
|
|
|
1754
1893
|
marker = dpg.get_value("trace_marker_combo")
|
|
1755
|
-
trace[
|
|
1894
|
+
trace["marker"] = marker if marker else None
|
|
1756
1895
|
|
|
1757
|
-
trace[
|
|
1896
|
+
trace["markersize"] = dpg.get_value("trace_markersize_slider")
|
|
1758
1897
|
|
|
1759
1898
|
self._user_modified = True
|
|
1760
1899
|
self._update_preview(dpg)
|
|
@@ -1779,12 +1918,14 @@ class DearPyGuiEditor:
|
|
|
1779
1918
|
self._user_modified = False
|
|
1780
1919
|
|
|
1781
1920
|
# Update all widgets
|
|
1782
|
-
dpg.set_value("title_input", self.current_overrides.get(
|
|
1783
|
-
dpg.set_value("xlabel_input", self.current_overrides.get(
|
|
1784
|
-
dpg.set_value("ylabel_input", self.current_overrides.get(
|
|
1785
|
-
dpg.set_value("linewidth_slider", self.current_overrides.get(
|
|
1786
|
-
dpg.set_value("grid_checkbox", self.current_overrides.get(
|
|
1787
|
-
dpg.set_value(
|
|
1921
|
+
dpg.set_value("title_input", self.current_overrides.get("title", ""))
|
|
1922
|
+
dpg.set_value("xlabel_input", self.current_overrides.get("xlabel", ""))
|
|
1923
|
+
dpg.set_value("ylabel_input", self.current_overrides.get("ylabel", ""))
|
|
1924
|
+
dpg.set_value("linewidth_slider", self.current_overrides.get("linewidth", 1.0))
|
|
1925
|
+
dpg.set_value("grid_checkbox", self.current_overrides.get("grid", False))
|
|
1926
|
+
dpg.set_value(
|
|
1927
|
+
"transparent_checkbox", self.current_overrides.get("transparent", True)
|
|
1928
|
+
)
|
|
1788
1929
|
|
|
1789
1930
|
self._update_preview(dpg)
|
|
1790
1931
|
dpg.set_value("status_text", "Reset to original")
|
|
@@ -1793,33 +1934,38 @@ class DearPyGuiEditor:
|
|
|
1793
1934
|
"""Export current view to PNG."""
|
|
1794
1935
|
import dearpygui.dearpygui as dpg
|
|
1795
1936
|
import matplotlib
|
|
1796
|
-
|
|
1937
|
+
|
|
1938
|
+
matplotlib.use("Agg")
|
|
1797
1939
|
import matplotlib.pyplot as plt
|
|
1798
1940
|
|
|
1799
1941
|
try:
|
|
1800
1942
|
self._collect_overrides(dpg)
|
|
1801
|
-
output_path = self.json_path.with_suffix(
|
|
1943
|
+
output_path = self.json_path.with_suffix(".edited.png")
|
|
1802
1944
|
|
|
1803
1945
|
# Full resolution render
|
|
1804
1946
|
o = self.current_overrides
|
|
1805
|
-
fig_size = o.get(
|
|
1806
|
-
dpi = o.get(
|
|
1947
|
+
fig_size = o.get("fig_size", [3.15, 2.68])
|
|
1948
|
+
dpi = o.get("dpi", 300)
|
|
1807
1949
|
|
|
1808
1950
|
fig, ax = plt.subplots(figsize=fig_size, dpi=dpi)
|
|
1809
1951
|
|
|
1810
1952
|
if self.csv_data is not None:
|
|
1811
1953
|
self._plot_from_csv(ax, o)
|
|
1812
1954
|
|
|
1813
|
-
if o.get(
|
|
1814
|
-
ax.set_title(o[
|
|
1815
|
-
if o.get(
|
|
1816
|
-
ax.set_xlabel(o[
|
|
1817
|
-
if o.get(
|
|
1818
|
-
ax.set_ylabel(o[
|
|
1955
|
+
if o.get("title"):
|
|
1956
|
+
ax.set_title(o["title"], fontsize=o.get("title_fontsize", 8))
|
|
1957
|
+
if o.get("xlabel"):
|
|
1958
|
+
ax.set_xlabel(o["xlabel"], fontsize=o.get("axis_fontsize", 7))
|
|
1959
|
+
if o.get("ylabel"):
|
|
1960
|
+
ax.set_ylabel(o["ylabel"], fontsize=o.get("axis_fontsize", 7))
|
|
1819
1961
|
|
|
1820
1962
|
fig.tight_layout()
|
|
1821
|
-
fig.savefig(
|
|
1822
|
-
|
|
1963
|
+
fig.savefig(
|
|
1964
|
+
output_path,
|
|
1965
|
+
dpi=dpi,
|
|
1966
|
+
bbox_inches="tight",
|
|
1967
|
+
transparent=o.get("transparent", True),
|
|
1968
|
+
)
|
|
1823
1969
|
plt.close(fig)
|
|
1824
1970
|
|
|
1825
1971
|
dpg.set_value("status_text", f"Exported: {output_path.name}")
|