visualdynamics 0.1.0a42__tar.gz → 0.1.0a44__tar.gz
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.
- {visualdynamics-0.1.0a42/src/visualdynamics.egg-info → visualdynamics-0.1.0a44}/PKG-INFO +1 -1
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/__init__.py +1 -1
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/data.py +3 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/shapes.py +6 -2
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/main_window.py +135 -76
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/movie.py +45 -38
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/object_tables.py +5 -5
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/__init__.py +22 -37
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/project.py +23 -8
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/report/__init__.py +2 -2
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/rotate.py +15 -2
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/theme.py +6 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/animate.py +164 -247
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/marks.py +54 -40
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/paired.py +2 -11
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/pick.py +26 -14
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/waterfall.py +1 -3
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44/src/visualdynamics.egg-info}/PKG-INFO +1 -1
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/LICENSE +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/README.md +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/pyproject.toml +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/setup.cfg +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/__main__.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/compatibility.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/__init__.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/author.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/averaging.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/channel_table.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/compliance.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/correlate.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/detect.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/entities.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/fem.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/filters.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/geometry.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/kurtosis.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/matches.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/merge.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/mesh.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/modal_fit.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/octave.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/photos.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/progress.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/replication.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/report.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/rigid.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/shocks.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/sine.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/sine_tracking.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/snr.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/srs.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/tables.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/transform.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/truncate.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/unit_choices.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/validate.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/core/wavelet.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/decimate.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/deform.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/demo/__init__.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/demo/barc.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/demo/drone.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/demo/frame.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/demo/plate.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/__init__.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/app_icon.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/ask.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/author_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/averaging_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/console.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/disclaimer.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/drawer_tab.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/editors.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/filter_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/glyphs.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/icons/drawer-tab-shape.svg +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/icons/drawer-tab.svg +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/icons.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/mesh_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/octave_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/panes.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/preferences.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/project_tree.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/record_grid.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/report_editor.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/rigid_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/run_reports.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/settings_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/shock_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/sine_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/stage_drag.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/stream_window.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/tables.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/toolbars.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/truncate_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/updater.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/wavelet_panel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/gui/windows.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/__init__.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/adf.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_objects.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/LICENSE +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/activity_result.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/channel_table.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/data.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/data_physics_random_control_parameters.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/data_physics_shock_response_synthesis_control_parameters.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/data_physics_sine_control_parameters.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/geometry.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/global_analysis_attributes.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/global_test_attributes.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/matrix.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/mechanical_control_parameters.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/modal_test_parameters.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/mode.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/parameter_set.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/point_cloud.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/rattlesnake_random_control_parameters.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/rattlesnake_sysid_parameters.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/rattlesnake_transient_control_parameters.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/response_spectrum.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/scalar.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/unknown.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/vector.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/escdf_specifications/vibration_channel_table.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/excel.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/exodus.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/exporters.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/femap.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/matlab.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/nastran.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/native.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/notes.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/photo_files.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/punch.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/rattlesnake.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/rattlesnake_sine.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/rattlesnake_specification.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/report_template.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/sdynpy_data.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/sdynpy_npz.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/sdynpy_shapes.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/sep005.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/sniffing.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/step.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/stl.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/threemf.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/io/unv.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/names.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/averaging.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/bands.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/bars.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/filtering.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/scalogram.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/shocks.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/sine_tracking.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/tracking_filter.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/plot/truncation.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/py.typed +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/report/markdown.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/report/page.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/units.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/update.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/__init__.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/_quiet.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/banded.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/geometry.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/mac_bars.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/rigid.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/scalogram.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics/viz/sinespec.py +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics.egg-info/SOURCES.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics.egg-info/dependency_links.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics.egg-info/entry_points.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics.egg-info/requires.txt +0 -0
- {visualdynamics-0.1.0a42 → visualdynamics-0.1.0a44}/src/visualdynamics.egg-info/top_level.txt +0 -0
|
@@ -90,7 +90,7 @@ from .units import (
|
|
|
90
90
|
#: alpha, said in the version itself so the dialog, the About text, the
|
|
91
91
|
#: installers and latest.json all say the same thing, and the first
|
|
92
92
|
#: non-alpha release is offered as an upgrade (Brandon, 2026-09-11)
|
|
93
|
-
__version__ = '0.1.
|
|
93
|
+
__version__ = '0.1.0a44'
|
|
94
94
|
|
|
95
95
|
|
|
96
96
|
def launch_gui(*paths: str, in_process: bool | None = None) -> Any:
|
|
@@ -3032,6 +3032,9 @@ class Psd(_Bands, DataArray):
|
|
|
3032
3032
|
"""
|
|
3033
3033
|
spec = _recast(self, Specification)
|
|
3034
3034
|
spec.limits = {}
|
|
3035
|
+
# a requirement is not scaled to be compared: the test level
|
|
3036
|
+
# belongs to the measurement
|
|
3037
|
+
spec.__dict__.pop('scale_db', None)
|
|
3035
3038
|
spec.interpolation = ('bin' if self.bandwidth is not None
|
|
3036
3039
|
else Specification.reading_of(self.abscissa))
|
|
3037
3040
|
return spec
|
|
@@ -893,6 +893,7 @@ class ShapeSet:
|
|
|
893
893
|
other: ShapeSet, other_mode: int,
|
|
894
894
|
other_geometry: Geometry | None = None, *,
|
|
895
895
|
on_basis: bool = False,
|
|
896
|
+
projected: ShapeSet | None = None,
|
|
896
897
|
names: tuple[str, str] = ('first', 'second'),
|
|
897
898
|
**kwargs: Any) -> Any:
|
|
898
899
|
"""This mode and another set's overlaid, swinging together, as
|
|
@@ -920,6 +921,10 @@ class ShapeSet:
|
|
|
920
921
|
The other set's geometry; this one's when omitted.
|
|
921
922
|
on_basis : bool, default False
|
|
922
923
|
Draw the other set's projection on this geometry instead.
|
|
924
|
+
projected : ShapeSet, optional
|
|
925
|
+
The other set already carried onto this one's DOFs
|
|
926
|
+
(`correlate.project_shapes`), for a script animating many
|
|
927
|
+
pairs of the same two sets: made here when omitted.
|
|
923
928
|
names : tuple of str
|
|
924
929
|
What the caption calls the two sets.
|
|
925
930
|
**kwargs
|
|
@@ -934,8 +939,7 @@ class ShapeSet:
|
|
|
934
939
|
from ..viz.animate import animate_pair, pair_deflections
|
|
935
940
|
|
|
936
941
|
other_geometry = other_geometry or geometry
|
|
937
|
-
projected
|
|
938
|
-
if other_geometry is not geometry:
|
|
942
|
+
if other_geometry is not geometry and projected is None:
|
|
939
943
|
from .correlate import project_shapes
|
|
940
944
|
projected, _report = project_shapes(other, other_geometry,
|
|
941
945
|
self, geometry)
|
|
@@ -151,9 +151,14 @@ from ..rotate import (
|
|
|
151
151
|
snapped,
|
|
152
152
|
wrapped,
|
|
153
153
|
)
|
|
154
|
-
from ..theme import
|
|
154
|
+
from ..theme import PAIR_COLORS
|
|
155
155
|
from ..theme import theme as resolve_theme
|
|
156
156
|
from ..units import DEFAULT_SYSTEM, SYSTEMS, UnitSystem
|
|
157
|
+
|
|
158
|
+
# the playback clock is the viz layer's, so a saved movie and a script's
|
|
159
|
+
# `movie=` play at the window's own rate by construction
|
|
160
|
+
from ..viz.animate import MOVIE_FPS as FRAMES_PER_SECOND
|
|
161
|
+
from ..viz.animate import SECONDS_PER_CYCLE, SECONDS_PER_RECORD
|
|
157
162
|
from ..viz.geometry import (
|
|
158
163
|
AXIS_COLORS,
|
|
159
164
|
ENTITY_LABEL_LIMIT,
|
|
@@ -222,10 +227,7 @@ COMBO_CELL_PADDING = 44
|
|
|
222
227
|
#: a dragged turn snaps to whole degrees of this; a typed angle does not
|
|
223
228
|
ANGLE_STEP = 1.0
|
|
224
229
|
|
|
225
|
-
FRAMES_PER_SECOND = 30
|
|
226
230
|
PHASE_STEPS = 120 # frames in one mode-shape cycle
|
|
227
|
-
SECONDS_PER_CYCLE = 2.0 # every mode animates at this rate, whatever its Hz
|
|
228
|
-
SECONDS_PER_RECORD = 10.0 # a time record plays in about this long
|
|
229
231
|
|
|
230
232
|
# What Faster and Slower step through. Doublings, because that is how a
|
|
231
233
|
# speed reads — half as fast, twice as fast — and a ladder rather than a
|
|
@@ -771,6 +773,7 @@ class MainWindow(QMainWindow):
|
|
|
771
773
|
self._gizmo_reading = None # the drag's number, while it lasts
|
|
772
774
|
self._sliding = None # the arrow gesture in progress (2026-10-02)
|
|
773
775
|
self._rotate_observers = []
|
|
776
|
+
self._gizmo_hovered = None # ('ring' or 'arrow', axis) under the cursor
|
|
774
777
|
self._last_axis = 2 # the ring a typed angle turns about
|
|
775
778
|
self._pick_observers = []
|
|
776
779
|
self._cursor = None
|
|
@@ -1138,7 +1141,6 @@ class MainWindow(QMainWindow):
|
|
|
1138
1141
|
self._fit_parabola = None
|
|
1139
1142
|
self._fit_damping_label = None
|
|
1140
1143
|
self._fit_coherence_name = None
|
|
1141
|
-
self._fit_records = None
|
|
1142
1144
|
#: what the plot's top and bottom edges mean as damping, kept
|
|
1143
1145
|
#: across fits — an article's plausible range rarely changes
|
|
1144
1146
|
#: between two of its own FRF sets
|
|
@@ -3182,8 +3184,12 @@ class MainWindow(QMainWindow):
|
|
|
3182
3184
|
rewrites per line is in every frame; then playback is put back
|
|
3183
3185
|
where it was. `path` skips the dialog (scripts, tests).
|
|
3184
3186
|
"""
|
|
3185
|
-
from ..viz.animate import
|
|
3186
|
-
|
|
3187
|
+
from ..viz.animate import (
|
|
3188
|
+
cycle_parameters,
|
|
3189
|
+
movie_frames,
|
|
3190
|
+
sweep_parameters,
|
|
3191
|
+
)
|
|
3192
|
+
from .movie import write_movie
|
|
3187
3193
|
|
|
3188
3194
|
if self.animator is None or self.scene.plotter is None:
|
|
3189
3195
|
return None
|
|
@@ -3201,28 +3207,24 @@ class MainWindow(QMainWindow):
|
|
|
3201
3207
|
phase = self.phase_slider.value()
|
|
3202
3208
|
held = self._cursor.value() if self._cursor is not None else None
|
|
3203
3209
|
if self._shape_mode:
|
|
3204
|
-
parameters = cycle_parameters(SECONDS_PER_CYCLE / self.speed
|
|
3205
|
-
|
|
3210
|
+
parameters = cycle_parameters(SECONDS_PER_CYCLE / self.speed)
|
|
3211
|
+
step = self.animator.set_parameter
|
|
3206
3212
|
else:
|
|
3207
3213
|
parameters = sweep_parameters(len(self._cursor_abscissa),
|
|
3208
|
-
SECONDS_PER_RECORD / self.speed
|
|
3209
|
-
MOVIE_FPS)
|
|
3214
|
+
SECONDS_PER_RECORD / self.speed)
|
|
3210
3215
|
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
else:
|
|
3216
|
-
self._cursor.setValue(
|
|
3217
|
-
float(self._cursor_abscissa[parameter]))
|
|
3218
|
-
yield self.scene.plotter.screenshot(return_img=True)
|
|
3216
|
+
def step(index):
|
|
3217
|
+
# the cursor, not the animator: it is where an envelope
|
|
3218
|
+
# rewrites its caption, so every frame carries its line
|
|
3219
|
+
self._cursor.setValue(float(self._cursor_abscissa[index]))
|
|
3219
3220
|
|
|
3220
3221
|
# seconds on a large model or a Retina screen, with input held
|
|
3221
3222
|
# off: say so, rather than look hung
|
|
3222
3223
|
self._show_status(f'Saving {os.path.basename(path)}…')
|
|
3223
3224
|
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
|
3224
3225
|
try:
|
|
3225
|
-
count = write_movie(path,
|
|
3226
|
+
count = write_movie(path, movie_frames(self.scene.plotter, step,
|
|
3227
|
+
parameters))
|
|
3226
3228
|
except RuntimeError as error: # MovieUnavailable among them
|
|
3227
3229
|
self._show_status(str(error))
|
|
3228
3230
|
return None
|
|
@@ -3234,7 +3236,7 @@ class MainWindow(QMainWindow):
|
|
|
3234
3236
|
self._draw_frame(phase / PHASE_STEPS * 2 * np.pi)
|
|
3235
3237
|
self.set_playing(playing)
|
|
3236
3238
|
self._show_status(
|
|
3237
|
-
f'Saved {os.path.basename(path)} — {count /
|
|
3239
|
+
f'Saved {os.path.basename(path)} — {count / FRAMES_PER_SECOND:.3g} s, '
|
|
3238
3240
|
f'{os.path.getsize(path) / 1e6:.2g} MB')
|
|
3239
3241
|
return path
|
|
3240
3242
|
|
|
@@ -3774,7 +3776,7 @@ class MainWindow(QMainWindow):
|
|
|
3774
3776
|
|
|
3775
3777
|
# the Basis keeps the comparison overlay's baseline blue; other
|
|
3776
3778
|
# groups cycle the curve palette
|
|
3777
|
-
LINK_ROLE_COLORS: ClassVar[dict] = {'Basis':
|
|
3779
|
+
LINK_ROLE_COLORS: ClassVar[dict] = {'Basis': PAIR_COLORS[0]}
|
|
3778
3780
|
|
|
3779
3781
|
def _role_holder(self, role):
|
|
3780
3782
|
"""The real object group holding the type's `role`.
|
|
@@ -5121,6 +5123,7 @@ class MainWindow(QMainWindow):
|
|
|
5121
5123
|
self._rotate_observers = []
|
|
5122
5124
|
self._rotating = None
|
|
5123
5125
|
self._sliding = None
|
|
5126
|
+
self._gizmo_hovered = None
|
|
5124
5127
|
if self.scene.plotter is not None:
|
|
5125
5128
|
for axis in range(3):
|
|
5126
5129
|
for kind in ('ring', 'arrow', 'head'):
|
|
@@ -5137,7 +5140,7 @@ class MainWindow(QMainWindow):
|
|
|
5137
5140
|
span = np.ptp(_points, axis=0).max() if len(_points) > 1 else 1.0
|
|
5138
5141
|
return 0.12 * (span or 1.0) * 1.15
|
|
5139
5142
|
|
|
5140
|
-
def _draw_rings(self):
|
|
5143
|
+
def _draw_rings(self, render=True):
|
|
5141
5144
|
"""Three rings, one about each of the frame's own axes."""
|
|
5142
5145
|
import pyvista as pv
|
|
5143
5146
|
|
|
@@ -5152,18 +5155,22 @@ class MainWindow(QMainWindow):
|
|
|
5152
5155
|
self.scene.plotter.add_mesh(
|
|
5153
5156
|
pv.lines_from_points(loop).tube(radius=radius * 0.03,
|
|
5154
5157
|
n_sides=12),
|
|
5155
|
-
color=
|
|
5158
|
+
color=self._gizmo_color('ring', axis),
|
|
5159
|
+
name=f'rotate-ring-{axis}')
|
|
5156
5160
|
# and an arrow along each axis, for sliding (2026-10-02)
|
|
5157
5161
|
shaft = arrow_points(matrix, axis, self._arrow_length(), steps=2)
|
|
5158
5162
|
self.scene.plotter.add_mesh(
|
|
5159
5163
|
pv.lines_from_points(shaft).tube(radius=radius * 0.03,
|
|
5160
5164
|
n_sides=12),
|
|
5161
|
-
color=
|
|
5165
|
+
color=self._gizmo_color('arrow', axis),
|
|
5166
|
+
name=f'rotate-arrow-{axis}')
|
|
5162
5167
|
self.scene.plotter.add_mesh(
|
|
5163
5168
|
pv.Cone(center=shaft[-1], direction=matrix[axis],
|
|
5164
5169
|
height=radius * 0.3, radius=radius * 0.1),
|
|
5165
|
-
color=
|
|
5166
|
-
|
|
5170
|
+
color=self._gizmo_color('arrow', axis),
|
|
5171
|
+
name=f'rotate-head-{axis}')
|
|
5172
|
+
if render:
|
|
5173
|
+
self.scene.plotter.render()
|
|
5167
5174
|
|
|
5168
5175
|
def _arrow_length(self):
|
|
5169
5176
|
"""An arrow reaches past the rings, so its head is clear of
|
|
@@ -5207,11 +5214,64 @@ class MainWindow(QMainWindow):
|
|
|
5207
5214
|
radius = self._ring_radius()
|
|
5208
5215
|
rings = []
|
|
5209
5216
|
for axis in range(3):
|
|
5217
|
+
points = ring_points(matrix, axis, radius)
|
|
5218
|
+
# closed, as drawn, so the last stretch of ring is a line too
|
|
5210
5219
|
projector = ScreenProjector(self.scene.plotter.renderer,
|
|
5211
|
-
|
|
5220
|
+
np.vstack([points, points[:1]]))
|
|
5212
5221
|
rings.append((axis, projector.screen()[0]))
|
|
5213
5222
|
return rings
|
|
5214
5223
|
|
|
5224
|
+
def _gizmo_under_cursor(self, position):
|
|
5225
|
+
"""('arrow' or 'ring', axis) — what a press at `position` takes,
|
|
5226
|
+
or None. One answer for the press and the hover, so what lights
|
|
5227
|
+
up is what a press would grab. An arrow first: the arrows cross
|
|
5228
|
+
the rings, and a press there is a slide, the gesture that needs
|
|
5229
|
+
the origin."""
|
|
5230
|
+
reach = self._gizmo_reach()
|
|
5231
|
+
axis = ring_under_cursor(self._arrow_screen_points(), position, reach)
|
|
5232
|
+
if axis is not None:
|
|
5233
|
+
return 'arrow', axis
|
|
5234
|
+
axis = ring_under_cursor(self._ring_screen_points(), position, reach)
|
|
5235
|
+
return None if axis is None else ('ring', axis)
|
|
5236
|
+
|
|
5237
|
+
def _gizmo_color(self, kind, axis):
|
|
5238
|
+
"""An axis's own color, or the scene's highlight — the color a
|
|
5239
|
+
hovered node takes — while that ring or arrow is under the
|
|
5240
|
+
cursor (2026-10-10)."""
|
|
5241
|
+
if self._gizmo_hovered == (kind, axis):
|
|
5242
|
+
return resolve_theme(self.theme_name)['scene_highlight']
|
|
5243
|
+
return AXIS_COLORS[axis]
|
|
5244
|
+
|
|
5245
|
+
def _hover_gizmo(self):
|
|
5246
|
+
"""Light the ring or arrow under the cursor, so a press lands
|
|
5247
|
+
knowing what it will take. Not while a button is down: an orbit
|
|
5248
|
+
sweeps the rings past the cursor, and nothing there is on
|
|
5249
|
+
offer."""
|
|
5250
|
+
position = self._cursor_position()
|
|
5251
|
+
if position is None or self.scene.plotter is None:
|
|
5252
|
+
return
|
|
5253
|
+
part = None
|
|
5254
|
+
if QApplication.mouseButtons() == Qt.MouseButton.NoButton:
|
|
5255
|
+
part = self._gizmo_under_cursor(position)
|
|
5256
|
+
if part == self._gizmo_hovered:
|
|
5257
|
+
return # nothing changed, so nothing to redraw
|
|
5258
|
+
self._gizmo_hovered = part
|
|
5259
|
+
actors = self.scene.plotter.renderer.actors
|
|
5260
|
+
for axis in range(3):
|
|
5261
|
+
for kind, name in (('ring', 'ring'), ('arrow', 'arrow'),
|
|
5262
|
+
('arrow', 'head')):
|
|
5263
|
+
actor = actors.get(f'rotate-{name}-{axis}')
|
|
5264
|
+
if actor is not None:
|
|
5265
|
+
actor.prop.color = self._gizmo_color(kind, axis)
|
|
5266
|
+
self.scene.plotter.render()
|
|
5267
|
+
|
|
5268
|
+
def _gizmo_reach(self):
|
|
5269
|
+
"""How near a ring or an arrow a press must land: 14 points,
|
|
5270
|
+
counted in the device pixels VTK reports the cursor and projects
|
|
5271
|
+
the rings in. Counted in pixels until 2026-10-10, which on a
|
|
5272
|
+
Retina screen — two pixels to the point — was a 7-point target."""
|
|
5273
|
+
return 14.0 * self.devicePixelRatioF()
|
|
5274
|
+
|
|
5215
5275
|
def _abort(self, caller, observer):
|
|
5216
5276
|
"""Stop VTK passing this event on to the camera."""
|
|
5217
5277
|
with contextlib.suppress(Exception):
|
|
@@ -5221,10 +5281,11 @@ class MainWindow(QMainWindow):
|
|
|
5221
5281
|
position = self._cursor_position()
|
|
5222
5282
|
if position is None:
|
|
5223
5283
|
return
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5284
|
+
part = self._gizmo_under_cursor(position)
|
|
5285
|
+
if part is None:
|
|
5286
|
+
return # not on the gizmo: let the camera have it
|
|
5287
|
+
kind, axis = part
|
|
5288
|
+
if kind == 'arrow':
|
|
5228
5289
|
row, matrix = self._rotating_frame()
|
|
5229
5290
|
world = self._cursor_on_axis(matrix, axis, position)
|
|
5230
5291
|
if world is None:
|
|
@@ -5235,9 +5296,6 @@ class MainWindow(QMainWindow):
|
|
|
5235
5296
|
'from': distance_along(self._display_frame(matrix), axis, world)}
|
|
5236
5297
|
self._abort(caller, self._rotate_observers[0])
|
|
5237
5298
|
return
|
|
5238
|
-
axis = ring_under_cursor(self._ring_screen_points(), position)
|
|
5239
|
-
if axis is None:
|
|
5240
|
-
return # not on a ring: let the camera have it
|
|
5241
5299
|
row, matrix = self._rotating_frame()
|
|
5242
5300
|
world = self._cursor_on_ring(matrix, axis, position)
|
|
5243
5301
|
if world is None:
|
|
@@ -5265,6 +5323,7 @@ class MainWindow(QMainWindow):
|
|
|
5265
5323
|
self._abort(caller, self._rotate_observers[1])
|
|
5266
5324
|
return
|
|
5267
5325
|
if self._rotating is None:
|
|
5326
|
+
self._hover_gizmo()
|
|
5268
5327
|
return
|
|
5269
5328
|
position = self._cursor_position()
|
|
5270
5329
|
if position is None:
|
|
@@ -5375,14 +5434,8 @@ class MainWindow(QMainWindow):
|
|
|
5375
5434
|
said['origin'] = tuple(float(v) for v in matrix[3])
|
|
5376
5435
|
cs_id = int(geometry.cs_id[row])
|
|
5377
5436
|
geometry.place_coordinate_system(cs_id, **said)
|
|
5378
|
-
journal = self.project.journal
|
|
5379
|
-
before = len(journal)
|
|
5380
5437
|
self.project.record_call(geometry, 'place_coordinate_system', cs_id,
|
|
5381
|
-
**said)
|
|
5382
|
-
if len(journal) > before > 0:
|
|
5383
|
-
stem = journal[-1].split('=', 1)[0]
|
|
5384
|
-
if journal[-2].split('=', 1)[0] == stem:
|
|
5385
|
-
journal[-2:] = journal[-1:]
|
|
5438
|
+
settle=True, **said)
|
|
5386
5439
|
|
|
5387
5440
|
def _cursor_on_ring(self, matrix, axis, position):
|
|
5388
5441
|
"""Where the cursor's ray meets the plane the ring lies in."""
|
|
@@ -5799,7 +5852,7 @@ class MainWindow(QMainWindow):
|
|
|
5799
5852
|
|
|
5800
5853
|
def hover_at(self, x: float, y: float) -> int | None:
|
|
5801
5854
|
"""Light up whatever is under this pixel; returns the entity."""
|
|
5802
|
-
entity = self._picker.pick(x, y)
|
|
5855
|
+
entity = self._picker.pick(x, y, pixel_ratio=self.devicePixelRatioF())
|
|
5803
5856
|
if entity == self._hovered:
|
|
5804
5857
|
return entity # nothing changed, so nothing to redraw
|
|
5805
5858
|
self._hovered = entity
|
|
@@ -6007,6 +6060,12 @@ class MainWindow(QMainWindow):
|
|
|
6007
6060
|
# scene, and a rebuilt scene would otherwise re-frame itself
|
|
6008
6061
|
self.scene.set_home_view(geometry.opening_view, geometry)
|
|
6009
6062
|
self.scene.plotter.camera_position = camera
|
|
6063
|
+
if self._rotate_observers:
|
|
6064
|
+
# the clear above took the rings with it, and every committed
|
|
6065
|
+
# drag comes through here (its row refresh is an edit): until
|
|
6066
|
+
# 2026-10-10 they vanished after the first turn while still
|
|
6067
|
+
# answering clicks where they had been
|
|
6068
|
+
self._draw_rings(render=False)
|
|
6010
6069
|
self.scene.plotter.render()
|
|
6011
6070
|
|
|
6012
6071
|
def _add_hover_mesh(self, geometry, colors):
|
|
@@ -8336,7 +8395,7 @@ class MainWindow(QMainWindow):
|
|
|
8336
8395
|
color_a = self._link_color(a_name)
|
|
8337
8396
|
color_b = self._link_color(b_name)
|
|
8338
8397
|
if color_b is None or color_b == color_a:
|
|
8339
|
-
color_b = next(c for c in (
|
|
8398
|
+
color_b = next(c for c in (PAIR_COLORS[1], '#3fb950')
|
|
8340
8399
|
if c != color_a)
|
|
8341
8400
|
self._compare['colors'] = (color_a, color_b)
|
|
8342
8401
|
alphas = overlay_alphas(self.link_role(a_name),
|
|
@@ -8358,9 +8417,7 @@ class MainWindow(QMainWindow):
|
|
|
8358
8417
|
return None
|
|
8359
8418
|
|
|
8360
8419
|
def _build_comparison_animator(self, first_pair, second_pair,
|
|
8361
|
-
caption, showing,
|
|
8362
|
-
colors=(None, '#ff8c2b'),
|
|
8363
|
-
alphas=(1.0, OVERLAY_ALPHA)):
|
|
8420
|
+
caption, showing, colors, alphas):
|
|
8364
8421
|
"""Like _build_animator, twice: two moving copies in one
|
|
8365
8422
|
scene (`viz.animate.build_pair`), each (geometry, deflection)
|
|
8366
8423
|
pair on its own mesh, in its own color and at its own opacity."""
|
|
@@ -8495,7 +8552,9 @@ class MainWindow(QMainWindow):
|
|
|
8495
8552
|
if start is None:
|
|
8496
8553
|
return
|
|
8497
8554
|
end = iren.interactor.GetEventPosition()
|
|
8498
|
-
|
|
8555
|
+
# 3 points of slop, in the device pixels VTK reports
|
|
8556
|
+
slop = 3 * self.devicePixelRatioF()
|
|
8557
|
+
if abs(end[0] - start[0]) <= slop and abs(end[1] - start[1]) <= slop:
|
|
8499
8558
|
self._mac_bars_clicked(end)
|
|
8500
8559
|
|
|
8501
8560
|
iren.add_observer('LeftButtonPressEvent', pressed)
|
|
@@ -9809,20 +9868,21 @@ class MainWindow(QMainWindow):
|
|
|
9809
9868
|
plot another (Brandon, 2026-08-30).
|
|
9810
9869
|
"""
|
|
9811
9870
|
from ..plot import octave_preview
|
|
9871
|
+
from ..viz.marks import octave_steps
|
|
9812
9872
|
|
|
9813
9873
|
self._clear_octave()
|
|
9814
9874
|
panel = self.data_pane.octave_panel
|
|
9815
9875
|
try:
|
|
9816
|
-
|
|
9817
|
-
self.data_pane.graphics.ci.items, psd, panel.per_octave(),
|
|
9818
|
-
self.unit_system, resolve_theme(self.theme_name), records)
|
|
9819
|
-
banded = psd.to_octave(panel.per_octave())
|
|
9876
|
+
steps = octave_steps(psd, panel.per_octave(), self.unit_system)
|
|
9820
9877
|
except ValueError as refusal:
|
|
9821
9878
|
panel.show_bands(None)
|
|
9822
9879
|
panel.show()
|
|
9823
9880
|
self._show_status(f'No octave preview: {refusal}')
|
|
9824
9881
|
return
|
|
9825
|
-
|
|
9882
|
+
self.octave_previews = octave_preview(
|
|
9883
|
+
self.data_pane.graphics.ci.items, steps,
|
|
9884
|
+
resolve_theme(self.theme_name), records)
|
|
9885
|
+
panel.show_bands(len(steps[0].abscissa))
|
|
9826
9886
|
panel.show()
|
|
9827
9887
|
self._journal_octave_view(psd, panel.per_octave())
|
|
9828
9888
|
|
|
@@ -10320,7 +10380,7 @@ class MainWindow(QMainWindow):
|
|
|
10320
10380
|
return self._render_banded(
|
|
10321
10381
|
spec_name, spec, spec_records, m_data, m_name,
|
|
10322
10382
|
m_records,
|
|
10323
|
-
scale_db=self.
|
|
10383
|
+
scale_db=self.project.comparison_scale(spec, m_name))
|
|
10324
10384
|
# a specification bounds autospectra; drawn beside a full CPSD its 30
|
|
10325
10385
|
# cross terms have no limit near them and bury the six that do —
|
|
10326
10386
|
# and the window resolves each measured entry's comparison scale
|
|
@@ -11813,7 +11873,8 @@ class MainWindow(QMainWindow):
|
|
|
11813
11873
|
def read_as_specification_act(self) -> None:
|
|
11814
11874
|
"""The bar's Read as Specification: the selected PSD becomes the
|
|
11815
11875
|
requirement it is, in place (`Project.read_as_specification`)."""
|
|
11816
|
-
self._read_as(
|
|
11876
|
+
self._read_as('read_as_specification',
|
|
11877
|
+
'Select a PSD to read as a specification',
|
|
11817
11878
|
self.project.read_as_specification,
|
|
11818
11879
|
'read as a specification — compare a measurement '
|
|
11819
11880
|
'against it by selecting both')
|
|
@@ -11821,23 +11882,26 @@ class MainWindow(QMainWindow):
|
|
|
11821
11882
|
def read_as_psd_act(self) -> None:
|
|
11822
11883
|
"""The bar's Read as PSD: the selected specification is plain
|
|
11823
11884
|
data again, in place (`Project.read_as_psd`)."""
|
|
11824
|
-
self._read_as(
|
|
11885
|
+
self._read_as('read_as_psd',
|
|
11886
|
+
'Select a specification without limits to read as a PSD',
|
|
11825
11887
|
self.project.read_as_psd, 'read as a PSD')
|
|
11826
11888
|
|
|
11827
|
-
def _read_as(self,
|
|
11889
|
+
def _read_as(self, verb_name, refusal, verb, said) -> None:
|
|
11828
11890
|
"""Swap the selected object for its other reading, under the
|
|
11829
11891
|
same name: the tree row, its grid and the view follow, the way a
|
|
11830
|
-
recompute's in-place swap does.
|
|
11831
|
-
|
|
11892
|
+
recompute's in-place swap does. Whether it applies is the
|
|
11893
|
+
project's own answer (`Project.verbs`), the one the bar asked."""
|
|
11894
|
+
def applies(obj):
|
|
11895
|
+
return obj is not None and verb_name in dict(
|
|
11896
|
+
self.project.verbs(self.project.name_of(obj)))
|
|
11897
|
+
|
|
11898
|
+
acted = self._act_on(applies, refusal, verb)
|
|
11832
11899
|
if acted is None:
|
|
11833
11900
|
return
|
|
11834
11901
|
name = acted[0]
|
|
11835
|
-
obj = self.objects[name]
|
|
11836
11902
|
item = self._item_for_object(name)
|
|
11837
11903
|
if item is not None:
|
|
11838
|
-
self._refresh_item(item,
|
|
11839
|
-
item.setToolTip(0, self._object_tooltip(name, obj))
|
|
11840
|
-
self._build_children(item, obj, name)
|
|
11904
|
+
self._refresh_item(item, self.objects[name])
|
|
11841
11905
|
self._report_content_changed()
|
|
11842
11906
|
self.render_current()
|
|
11843
11907
|
self._show_status(f'{name} {said}')
|
|
@@ -12330,8 +12394,6 @@ class MainWindow(QMainWindow):
|
|
|
12330
12394
|
# every mode's residues. Chosen by the project's rule, and
|
|
12331
12395
|
# journaled with the records, so the fit_modes line replays
|
|
12332
12396
|
# this fit and not another (it did not, until 2026-10-09)
|
|
12333
|
-
self._fit_records = None if records is None else [
|
|
12334
|
-
int(i) for i in records]
|
|
12335
12397
|
coherence = self.project.fit_coherence(name, records)
|
|
12336
12398
|
self.fit = ModalFitSession(
|
|
12337
12399
|
obj, records,
|
|
@@ -13253,8 +13315,10 @@ class MainWindow(QMainWindow):
|
|
|
13253
13315
|
f'at={picks!r}'
|
|
13254
13316
|
+ (f', refine={self.fit.refined}' if self.fit.refined
|
|
13255
13317
|
else '')
|
|
13256
|
-
|
|
13257
|
-
|
|
13318
|
+
# the session's own rows: every record is the default
|
|
13319
|
+
+ (f', records={self.fit.rows!r}'
|
|
13320
|
+
if self.fit.rows != list(range(self.fit.frf.num_records))
|
|
13321
|
+
else '')
|
|
13258
13322
|
+ (f', coherence={self._fit_coherence_name!r}'
|
|
13259
13323
|
if self._fit_coherence_name else '')
|
|
13260
13324
|
+ f', name={self.fit_object_name!r})')
|
|
@@ -13291,17 +13355,12 @@ class MainWindow(QMainWindow):
|
|
|
13291
13355
|
if isinstance(data, Specification)]
|
|
13292
13356
|
if len(specs) != 1:
|
|
13293
13357
|
return None
|
|
13294
|
-
return {name: self.
|
|
13358
|
+
return {name: self.project.comparison_scale(specs[0], name)
|
|
13295
13359
|
for name, data, _r in series
|
|
13296
13360
|
if isinstance(data, Psd)
|
|
13297
13361
|
and not isinstance(data, Specification)
|
|
13298
13362
|
and name in self.objects}
|
|
13299
13363
|
|
|
13300
|
-
def _family_scale_db(self, spec, name):
|
|
13301
|
-
"""The comparison scale for `name`, by the project's rule
|
|
13302
|
-
(`Project.comparison_scale`), which the report reads too."""
|
|
13303
|
-
return self.project.comparison_scale(spec, name)
|
|
13304
|
-
|
|
13305
13364
|
def _show_comparison_scaling(self, series):
|
|
13306
13365
|
"""Put the comparison's scaling on the bar, or take it away.
|
|
13307
13366
|
|
|
@@ -13325,7 +13384,7 @@ class MainWindow(QMainWindow):
|
|
|
13325
13384
|
self.data_pane.show_scaling(None)
|
|
13326
13385
|
return
|
|
13327
13386
|
self._scaling_pair = (specs[0][0], measured[0][0])
|
|
13328
|
-
db = self.
|
|
13387
|
+
db = self.project.comparison_scale(specs[0][1], measured[0][0])
|
|
13329
13388
|
self.data_pane.show_scaling(f'{db:+d} dB' if db else '0 dB')
|
|
13330
13389
|
|
|
13331
13390
|
def _comparison_scale_edited(self, text):
|
|
@@ -13370,7 +13429,7 @@ class MainWindow(QMainWindow):
|
|
|
13370
13429
|
else f'{measured_name} and {len(family) - 1} linked '
|
|
13371
13430
|
f'PSD{"s" * (len(family) > 2)}')
|
|
13372
13431
|
if value is None:
|
|
13373
|
-
detected = self.
|
|
13432
|
+
detected = self.project.comparison_scale(spec, measured_name)
|
|
13374
13433
|
self._show_status('Scaling returned to automatic — detected '
|
|
13375
13434
|
f'{detected:+d} dB from the data')
|
|
13376
13435
|
else:
|
|
@@ -13399,7 +13458,7 @@ class MainWindow(QMainWindow):
|
|
|
13399
13458
|
return None
|
|
13400
13459
|
name, data, records = measured[0]
|
|
13401
13460
|
rows = compare_all(specs[0][0], data, specs[0][1], records,
|
|
13402
|
-
scale_db=self.
|
|
13461
|
+
scale_db=self.project.comparison_scale(specs[0][0], name))
|
|
13403
13462
|
if not rows:
|
|
13404
13463
|
return None
|
|
13405
13464
|
# a pair that is not compared says why, on the status line the
|