├── .coveragerc ├── .env.template ├── .github └── workflows │ ├── build.yml │ ├── build_deploy.yml │ └── test_pyqt5.yml ├── .gitignore ├── .pylintrc ├── .readthedocs.yaml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── colormaps ├── README.md ├── _cm.py ├── colormap.py └── matplotlib_cmaps.py ├── doc ├── _static │ └── favicon.ico ├── changelog.rst ├── conf.py ├── dev │ ├── build.rst │ ├── contribute.rst │ ├── guiqwt_to_plotpy.csv │ ├── guiqwt_to_plotpy.rst │ ├── index.rst │ ├── platforms.rst │ ├── v1_to_guidata_v3.csv │ ├── v1_to_v2.csv │ └── v1_to_v2.rst ├── features │ ├── colormapmanager.rst │ ├── events.rst │ ├── fit.rst │ ├── fliprotate.rst │ ├── imagefile.rst │ ├── index.rst │ ├── io.rst │ ├── items │ │ ├── builder.rst │ │ ├── examples.rst │ │ ├── index.rst │ │ ├── overview.rst │ │ └── reference.rst │ ├── mathutils │ │ ├── colormaps.rst │ │ ├── geometry.rst │ │ ├── index.rst │ │ └── scaler.rst │ ├── panels │ │ ├── index.rst │ │ ├── overview.rst │ │ └── reference.rst │ ├── plot │ │ ├── examples.rst │ │ ├── index.rst │ │ ├── overview.rst │ │ └── reference.rst │ ├── pyplot.rst │ ├── resizedialog.rst │ ├── rotatecrop.rst │ ├── selectdialog.rst │ ├── signals.rst │ ├── styles │ │ ├── index.rst │ │ ├── overview.rst │ │ └── reference.rst │ └── tools │ │ ├── examples.rst │ │ ├── index.rst │ │ ├── overview.rst │ │ └── reference.rst ├── images │ ├── my_plot_manager.png │ ├── my_plot_manager.svg │ ├── panorama-vertical.png │ ├── panorama-vertical.svg │ ├── panorama.png │ ├── panorama.svg │ ├── plot_widgets.png │ ├── plot_widgets.svg │ ├── plotpy-banner.png │ ├── plotpy-vertical.png │ └── screenshots │ │ ├── __init__.png │ │ ├── computations.png │ │ ├── contrast.png │ │ ├── cross_section.png │ │ ├── cross_section2.png │ │ ├── dotarraydemo.png │ │ ├── filtertest1.png │ │ ├── filtertest2.png │ │ ├── fit.png │ │ ├── get_point.png │ │ ├── hist2d.png │ │ ├── image_plot_tools.png │ │ ├── imagefilter.png │ │ ├── imagesuperp.png │ │ ├── imagexy.png │ │ ├── manager.png │ │ ├── mandelbrot.png │ │ ├── pcolor.png │ │ ├── plot.png │ │ ├── simple_dialog.png │ │ ├── simple_window.png │ │ └── transform.png ├── index.rst ├── intro │ ├── examples.rst │ ├── index.rst │ ├── installation.rst │ ├── licenses.rst │ ├── motivation.rst │ └── overview.rst ├── requirements.rst └── update_requirements.py ├── media ├── LinkedIn │ └── 2023_10_31-V2.md └── X │ └── 2023_10_31-V2.txt ├── plotpy-tests.desktop ├── plotpy ├── __init__.py ├── builder │ ├── __init__.py │ ├── annotation.py │ ├── curvemarker.py │ ├── image.py │ ├── label.py │ ├── plot.py │ └── shape.py ├── config.py ├── constants.py ├── coords.py ├── data │ ├── colormaps_default.json │ └── icons │ │ ├── apply.png │ │ ├── arredit.png │ │ ├── arrow_down.png │ │ ├── arrow_up.png │ │ ├── autorefresh.png │ │ ├── autoscale.png │ │ ├── axes.png │ │ ├── busy.png │ │ ├── cell_edit.png │ │ ├── center.png │ │ ├── cmap_edit.png │ │ ├── contrast.png │ │ ├── copy.png │ │ ├── copytoclipboard.png │ │ ├── csapplylut.png │ │ ├── csautoscale.png │ │ ├── csection.png │ │ ├── csection_a.png │ │ ├── csection_line.png │ │ ├── csection_oblique.png │ │ ├── csperimage.png │ │ ├── curve_downsample.png │ │ ├── curvestyles │ │ ├── dots.png │ │ ├── lines.png │ │ ├── steps.png │ │ └── sticks.png │ │ ├── curvetypes │ │ ├── xfy.png │ │ └── yfx.png │ │ ├── delete.png │ │ ├── edit.png │ │ ├── edit_point_selection.png │ │ ├── editors │ │ ├── edit.png │ │ ├── edit_add.png │ │ ├── editcopy.png │ │ ├── editdelete.png │ │ ├── editpaste.png │ │ ├── fileimport.png │ │ ├── filesave.png │ │ ├── imshow.png │ │ ├── insert.png │ │ ├── plot.png │ │ └── rename.png │ │ ├── eliminate_outliers.png │ │ ├── eraser.png │ │ ├── exit.png │ │ ├── expander_down.png │ │ ├── expander_right.png │ │ ├── export.png │ │ ├── file.png │ │ ├── fileclose.png │ │ ├── fileimport.png │ │ ├── filenew.png │ │ ├── fileopen.png │ │ ├── filesave.png │ │ ├── filesaveas.png │ │ ├── filetypes │ │ ├── doc.png │ │ ├── gif.png │ │ ├── html.png │ │ ├── jpg.png │ │ ├── pdf.png │ │ ├── png.png │ │ ├── pps.png │ │ ├── ps.png │ │ ├── tar.png │ │ ├── tgz.png │ │ ├── tif.png │ │ ├── txt.png │ │ ├── xls.png │ │ └── zip.png │ │ ├── font.png │ │ ├── full_range.png │ │ ├── funct.png │ │ ├── hcursor.png │ │ ├── hflip.png │ │ ├── imagestats.png │ │ ├── item_list.png │ │ ├── items │ │ ├── annotation.png │ │ ├── curve.png │ │ ├── errorbar.png │ │ ├── grid.png │ │ ├── histogram.png │ │ ├── histogram2d.png │ │ ├── image.png │ │ ├── label.png │ │ ├── legend.png │ │ └── polygonmap.png │ │ ├── magnifier.png │ │ ├── markers │ │ ├── cross.png │ │ ├── diamond.png │ │ ├── ellipse.png │ │ ├── hexagon.png │ │ ├── point.png │ │ ├── square.png │ │ ├── star.png │ │ ├── triangle_d.png │ │ ├── triangle_l.png │ │ ├── triangle_r.png │ │ ├── triangle_u.png │ │ └── xcross.png │ │ ├── markerstyles │ │ ├── cross_marker.png │ │ ├── horiz_marker.png │ │ └── vert_marker.png │ │ ├── mask │ │ ├── mask_circle.png │ │ ├── mask_circle_outside.png │ │ ├── mask_rectangle.png │ │ ├── mask_rectangle_outside.png │ │ └── mask_tool.png │ │ ├── max.png │ │ ├── min.png │ │ ├── move.png │ │ ├── multipoint_selection.png │ │ ├── none.png │ │ ├── not_found.png │ │ ├── on_curve.png │ │ ├── patterns │ │ ├── bdiagpattern.png │ │ ├── crosspattern.png │ │ ├── dense1pattern.png │ │ ├── dense2pattern.png │ │ ├── dense3pattern.png │ │ ├── dense4pattern.png │ │ ├── dense5pattern.png │ │ ├── dense6pattern.png │ │ ├── dense7pattern.png │ │ ├── diagcrosspattern.png │ │ ├── fdiagpattern.png │ │ ├── horpattern.png │ │ ├── nobrush.png │ │ ├── solidpattern.png │ │ └── verpattern.png │ │ ├── plotpy-banner.svg │ │ ├── plotpy-vertical.svg │ │ ├── plotpy.svg │ │ ├── point_selection.png │ │ ├── print.png │ │ ├── python.png │ │ ├── quickview.png │ │ ├── refresh.png │ │ ├── rotationcenter.jpg │ │ ├── save_all.png │ │ ├── scales │ │ ├── lin_lin.png │ │ ├── lin_log.png │ │ ├── log_lin.png │ │ ├── log_log.png │ │ └── source.pdn │ │ ├── select.svg │ │ ├── select_area.svg │ │ ├── settings.png │ │ ├── shape.png │ │ ├── shapes │ │ ├── circle.png │ │ ├── contour.png │ │ ├── ellipse_shape.png │ │ ├── gtaxes.png │ │ ├── marker.png │ │ ├── oblique_rectangle.png │ │ ├── point_shape.png │ │ ├── polygon.png │ │ ├── polyline.png │ │ ├── rectangle.png │ │ └── segment.png │ │ ├── snapshot.png │ │ ├── styles │ │ ├── dash.png │ │ ├── dashdot.png │ │ ├── dashdotdot.png │ │ ├── dot.png │ │ └── solid.png │ │ ├── trash.png │ │ ├── trimage_lock.png │ │ ├── trimage_unlock.png │ │ ├── vcursor.png │ │ ├── vflip.png │ │ ├── xcursor.png │ │ ├── xmax.png │ │ ├── xmin.png │ │ ├── xrange.png │ │ └── zlog.svg ├── events.py ├── external │ ├── __init__.py │ └── sliders │ │ ├── __init__.py │ │ ├── _generic_range_slider.py │ │ ├── _generic_slider.py │ │ ├── _labeled.py │ │ ├── _misc.py │ │ ├── _range_style.py │ │ └── _sliders.py ├── interfaces │ ├── __init__.py │ ├── items.py │ ├── panel.py │ └── plotmanager.py ├── io.py ├── items │ ├── __init__.py │ ├── annotation.py │ ├── contour.py │ ├── curve │ │ ├── __init__.py │ │ ├── base.py │ │ └── errorbar.py │ ├── grid.py │ ├── histogram.py │ ├── image │ │ ├── __init__.py │ │ ├── base.py │ │ ├── filter.py │ │ ├── image_items.py │ │ ├── masked.py │ │ ├── misc.py │ │ └── transform.py │ ├── label.py │ ├── polygonmap.py │ └── shape │ │ ├── __init__.py │ │ ├── axis.py │ │ ├── base.py │ │ ├── ellipse.py │ │ ├── marker.py │ │ ├── point.py │ │ ├── polygon.py │ │ ├── range.py │ │ ├── rectangle.py │ │ ├── segment.py │ │ └── svg.py ├── locale │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── plotpy.mo │ │ │ └── plotpy.po │ └── plotpy.pot ├── lutrange.py ├── mathutils │ ├── __init__.py │ ├── arrayfuncs.py │ ├── colormap.py │ ├── geometry.py │ └── scaler.py ├── panels │ ├── __init__.py │ ├── base.py │ ├── contrastadjustment.py │ ├── csection │ │ ├── __init__.py │ │ ├── csitem.py │ │ ├── csplot.py │ │ └── cswidget.py │ └── itemlist.py ├── plot │ ├── __init__.py │ ├── base.py │ ├── interactive.py │ ├── manager.py │ └── plotwidget.py ├── pyplot.py ├── styles │ ├── __init__.py │ ├── axes.py │ ├── base.py │ ├── curve.py │ ├── errorbar.py │ ├── histogram.py │ ├── image.py │ ├── label.py │ ├── polygonmap.py │ └── shape.py ├── tests │ ├── __init__.py │ ├── benchmarks │ │ ├── __init__.py │ │ ├── test_benchmarks.py │ │ ├── test_bigimages.py │ │ └── test_loadtest.py │ ├── conftest.py │ ├── data.py │ ├── data │ │ ├── brain.png │ │ ├── brain_cylinder.png │ │ ├── mr-brain.dcm │ │ ├── svg_target.svg │ │ └── svg_tool.svg │ ├── features │ │ ├── __init__.py │ │ ├── test_auto_curve_image.py │ │ ├── test_autoscale_shapes.py │ │ ├── test_builder.py │ │ ├── test_colormap_editor.py │ │ ├── test_colormap_manager.py │ │ ├── test_computations.py │ │ ├── test_contrast.py │ │ ├── test_cursors.py │ │ ├── test_data_update_curve.py │ │ ├── test_data_update_image.py │ │ ├── test_dicom_image.py │ │ ├── test_fit.py │ │ ├── test_image_coords.py │ │ ├── test_image_filter.py │ │ ├── test_image_superp.py │ │ ├── test_loadsaveitems_hdf5.py │ │ ├── test_loadsaveitems_json.py │ │ ├── test_loadsaveitems_pickle.py │ │ ├── test_manager.py │ │ ├── test_no_auto_tools.py │ │ ├── test_plot_log.py │ │ ├── test_plot_types.py │ │ ├── test_plot_yreverse.py │ │ ├── test_pyplot.py │ │ └── test_resize.py │ ├── items │ │ ├── __init__.py │ │ ├── test_annotations.py │ │ ├── test_curves.py │ │ ├── test_curves_highdpi.py │ │ ├── test_hist2d.py │ │ ├── test_histogram.py │ │ ├── test_image.py │ │ ├── test_image_contour.py │ │ ├── test_image_masked.py │ │ ├── test_image_masked_xy.py │ │ ├── test_image_rgb.py │ │ ├── test_image_xy.py │ │ ├── test_mandelbrot.py │ │ ├── test_pcolor.py │ │ ├── test_polygons.py │ │ ├── test_svgshapes.py │ │ └── test_transform.py │ ├── tools │ │ ├── __init__.py │ │ ├── test_actiontool.py │ │ ├── test_cross_section.py │ │ ├── test_cross_section_line.py │ │ ├── test_cross_section_oblique.py │ │ ├── test_customize_shape_tool.py │ │ ├── test_cyclic_import.py │ │ ├── test_downsample_curve.py │ │ ├── test_edit_point.py │ │ ├── test_get_point.py │ │ ├── test_get_points.py │ │ ├── test_get_rectangle.py │ │ ├── test_get_rectangle_with_svg.py │ │ ├── test_get_segment.py │ │ ├── test_image_plot_tools.py │ │ ├── test_stats_tools.py │ │ └── test_zaxislog.py │ ├── unit │ │ ├── __init__.py │ │ ├── test_annotation_tools.py │ │ ├── test_aspect_ratio_tool.py │ │ ├── test_baseplot.py │ │ ├── test_builder_annotation.py │ │ ├── test_builder_curve.py │ │ ├── test_builder_image.py │ │ ├── test_builder_shape.py │ │ ├── test_contour.py │ │ ├── test_cursor_tools.py │ │ ├── test_curve_tools.py │ │ ├── test_display_coords_tool.py │ │ ├── test_events.py │ │ ├── test_fontparam.py │ │ ├── test_geometry.py │ │ ├── test_io.py │ │ ├── test_line.py │ │ ├── test_line_cross_section_tool.py │ │ ├── test_manipulate_selection.py │ │ ├── test_mask_tool.py │ │ ├── test_multiline_tools.py │ │ ├── test_oblique_cross_section_tool.py │ │ ├── test_plot_curve.py │ │ ├── test_plot_image.py │ │ ├── test_rect_zoom.py │ │ ├── test_seg_dist.py │ │ ├── test_styles.py │ │ ├── test_tools_export.py │ │ └── utils.py │ ├── vistools.py │ └── widgets │ │ ├── __init__.py │ │ ├── test_dotarraydemo.py │ │ ├── test_filtertest1.py │ │ ├── test_filtertest2.py │ │ ├── test_fliprotate.py │ │ ├── test_plot_timecurve.py │ │ ├── test_qtdesigner.py │ │ ├── test_qtdesigner.ui │ │ ├── test_resize_dialog.py │ │ ├── test_rotatecrop.py │ │ ├── test_simple_dialog.py │ │ ├── test_simple_window.py │ │ ├── test_syncplot.py │ │ └── test_theme.py ├── tools │ ├── __init__.py │ ├── annotation.py │ ├── axes.py │ ├── base.py │ ├── cross_section.py │ ├── cursor.py │ ├── curve.py │ ├── image.py │ ├── item.py │ ├── label.py │ ├── misc.py │ ├── plot.py │ ├── selection.py │ └── shape.py └── widgets │ ├── __init__.py │ ├── about.py │ ├── basetransform.py │ ├── colormap │ ├── __init__.py │ ├── _slider.py │ ├── editor.py │ ├── manager.py │ └── widget.py │ ├── fit.py │ ├── fliprotate.py │ ├── imagefile.py │ ├── qtdesigner.py │ ├── resizedialog.py │ ├── rotatecrop.py │ └── selectdialog.py ├── pyproject.toml ├── qtdesigner └── plotplugin.py ├── requirements.txt ├── scripts ├── build-wheels.sh ├── build_dist.bat ├── build_doc.bat ├── build_inplace.bat ├── build_wheels.bat ├── clean_up.bat ├── display_cov.bat ├── gettext.bat ├── run_coverage.bat ├── run_pylint.bat ├── run_pytest.bat ├── run_ruff.bat ├── upgrade_env.bat ├── upgrade_stack.bat └── utils.bat ├── setup.py └── src ├── arrays.hpp ├── debug.hpp ├── histogram2d.pyx ├── mandelbrot.pyx ├── pcolor.cpp ├── points.hpp ├── scaler.cpp ├── scaler.hpp └── traits.hpp /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | parallel = True 3 | concurrency = multiprocessing,thread 4 | omit = 5 | */plotpy/tests/* 6 | */plotpy/external/* 7 | */plotpy/plot/interactive.py 8 | *.vscode/extensions* 9 | */qwt/* 10 | */guidata/* 11 | 12 | [report] 13 | exclude_also = 14 | def __repr__ 15 | raise AssertionError 16 | raise NotImplementedError 17 | if __name__ == .__main__.: 18 | if TYPE_CHECKING: 19 | -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | PYTHONPATH=. -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build_wheels: 8 | name: Build wheels on ${{ matrix.os }} 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | matrix: 12 | # macos-13 is an intel runner, macos-14 is apple silicon 13 | os: [ubuntu-latest, windows-latest, macos-13, macos-14] 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Build wheels 19 | run: pipx run cibuildwheel==2.21.2 20 | 21 | - uses: actions/upload-artifact@v4 22 | with: 23 | name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} 24 | path: ./wheelhouse/*.whl 25 | -------------------------------------------------------------------------------- /.github/workflows/build_deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build and upload to PyPI 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: 7 | - published 8 | 9 | jobs: 10 | build_wheels: 11 | name: Build wheels on ${{ matrix.os }} 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | # macos-13 is an intel runner, macos-14 is apple silicon 16 | os: [ubuntu-latest, windows-latest, macos-13, macos-14] 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Build wheels 22 | uses: pypa/cibuildwheel@v2.21.2 23 | 24 | - uses: actions/upload-artifact@v4 25 | with: 26 | name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} 27 | path: ./wheelhouse/*.whl 28 | 29 | build_sdist: 30 | name: Build source distribution 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v4 34 | 35 | - name: Build sdist 36 | run: pipx run build --sdist 37 | 38 | - uses: actions/upload-artifact@v4 39 | with: 40 | name: cibw-sdist 41 | path: dist/*.tar.gz 42 | 43 | upload_pypi: 44 | needs: [build_wheels, build_sdist] 45 | runs-on: ubuntu-latest 46 | environment: pypi 47 | permissions: 48 | id-token: write 49 | if: github.event_name == 'release' && github.event.action == 'published' 50 | steps: 51 | - uses: actions/download-artifact@v4 52 | with: 53 | # unpacks all CIBW artifacts into dist/ 54 | pattern: cibw-* 55 | path: dist 56 | merge-multiple: true 57 | 58 | - uses: pypa/gh-action-pypi-publish@release/v1 59 | with: 60 | password: ${{ secrets.PYPI_API_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/test_pyqt5.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | # Inspired from https://pytest-qt.readthedocs.io/en/latest/troubleshooting.html#github-actions 5 | 6 | name: Build, install and test with PyQt5 7 | 8 | on: 9 | push: 10 | branches: [ "master", "develop" ] 11 | pull_request: 12 | branches: [ "master", "develop" ] 13 | 14 | jobs: 15 | build: 16 | 17 | env: 18 | DISPLAY: ':99.0' 19 | 20 | runs-on: ubuntu-latest 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | python-version: ["3.9", "3.13"] 25 | 26 | steps: 27 | - uses: actions/checkout@v4 28 | - name: Set up Python ${{ matrix.python-version }} 29 | uses: actions/setup-python@v5 30 | with: 31 | python-version: ${{ matrix.python-version }} 32 | - name: Install dependencies 33 | run: | 34 | sudo apt install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils 35 | /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1200x24 -ac +extension GLX 36 | python -m pip install --upgrade pip 37 | python -m pip install ruff pytest 38 | pip install PyQt5 setuptools numpy Cython 39 | python setup.py build_ext --inplace 40 | pip install .[test] 41 | - name: Lint with Ruff 42 | run: ruff check --output-format=github plotpy 43 | - name: Test with pytest 44 | run: | 45 | pytest 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Visual Studio Code 7 | .env 8 | .venv 9 | 10 | # C extensions 11 | *.so 12 | *.pyd 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | eggs/ 20 | .eggs/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | MANIFEST 25 | 26 | # Tests 27 | .tox/ 28 | .hypothesis/ 29 | .coverage 30 | .coverage.* 31 | .cache 32 | unittests.xml 33 | coverage.xml 34 | coverage/ 35 | .pytest_cache/ 36 | pylint_report.txt 37 | /*.h5 38 | /*.png 39 | /*.tif 40 | /*.pickle 41 | 42 | # Sphinx documentation 43 | docs/build/ 44 | 45 | # Generated cython c file 46 | src/histogram2d.c 47 | src/mandelbrot.c 48 | 49 | # qt.conf files 50 | doc/source/deployment_example/qt.conf 51 | 52 | # Coverage 53 | htmlcov 54 | 55 | # Other 56 | *.bak 57 | *_ui.py 58 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [FORMAT] 2 | # Essential to be able to compare code side-by-side (`black` default setting) 3 | # and best compromise to minimize file size 4 | max-line-length=88 5 | 6 | [TYPECHECK] 7 | ignored-modules=qtpy.QtWidgets,qtpy.QtCore,qtpy.QtGui,qtpy.QtSvg,qtpy.QtPrintSupport,qtpy.QtDesigner,plotpy._scaler,plotpy.mandelbrot,plotpy.histogram2d,PyQt5.QtWidgets 8 | 9 | [MESSAGES CONTROL] 10 | disable=wrong-import-order 11 | 12 | [DESIGN] 13 | max-args=8 # default: 5 14 | max-attributes=12 # default: 7 15 | max-branches=17 # default: 12 16 | max-locals=20 # default: 15 17 | min-public-methods=0 # default: 2 18 | max-public-methods=25 # default: 20 -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | version: 2 5 | build: 6 | os: ubuntu-22.04 7 | tools: 8 | python: "3.11" 9 | jobs: 10 | post_create_environment: 11 | - pip install PyQt5 setuptools numpy Cython 12 | - python setup.py build_ext --inplace 13 | sphinx: 14 | configuration: doc/conf.py 15 | formats: 16 | - pdf 17 | python: 18 | install: 19 | - method: pip 20 | path: . 21 | extra_requirements: 22 | - doc 23 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Run Test Launcher", 9 | "type": "debugpy", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/plotpy/tests/__init__.py", 12 | "console": "integratedTerminal", 13 | "envFile": "${workspaceFolder}/.env", 14 | "python": "${config:python.defaultInterpreterPath}", 15 | "justMyCode": true, 16 | "env": { 17 | "QT_COLOR_MODE": "light", 18 | } 19 | }, 20 | { 21 | "name": "Run current file", 22 | "type": "debugpy", 23 | "request": "launch", 24 | "program": "${file}", 25 | "console": "integratedTerminal", 26 | "envFile": "${workspaceFolder}/.env", 27 | "python": "${config:python.defaultInterpreterPath}", 28 | "justMyCode": false, 29 | "pythonArgs": [ 30 | "-W error::DeprecationWarning", 31 | "-W error::RuntimeWarning", 32 | ], 33 | "env": {} 34 | }, 35 | { 36 | "name": "Run current file (unattended)", 37 | "type": "debugpy", 38 | "request": "launch", 39 | "program": "${file}", 40 | "console": "integratedTerminal", 41 | "envFile": "${workspaceFolder}/.env", 42 | "python": "${config:python.defaultInterpreterPath}", 43 | "pythonArgs": [ 44 | "-W error::DeprecationWarning", 45 | ], 46 | "justMyCode": false, 47 | "args": [ 48 | "--unattended" 49 | ], 50 | "env": { 51 | "GUIDATA_PARSE_ARGS": "1", 52 | } 53 | } 54 | ] 55 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[bat]": { 3 | "files.encoding": "cp850", 4 | }, 5 | "editor.rulers": [ 6 | 88 7 | ], 8 | "files.exclude": { 9 | "**/__pycache__": true, 10 | "**/.pytest_cache": true, 11 | "**/.hypothesis": true, 12 | "**/*.pyc": true, 13 | "**/*.pyo": true, 14 | "**/*.pyd": true, 15 | ".venv": true 16 | }, 17 | "files.trimFinalNewlines": true, 18 | "files.trimTrailingWhitespace": true, 19 | "python.defaultInterpreterPath": "${env:PPSTACK_PYTHONEXE}", 20 | "editor.formatOnSave": true, 21 | "python.analysis.autoFormatStrings": true, 22 | "python.testing.unittestEnabled": false, 23 | "python.testing.pytestEnabled": true, 24 | "python.testing.pytestPath": "pytest", 25 | "python.testing.pytestArgs": [ 26 | "plotpy" 27 | ], 28 | "[python]": { 29 | "editor.defaultFormatter": "charliermarsh.ruff" 30 | }, 31 | "editor.codeActionsOnSave": { 32 | "source.organizeImports": "explicit", 33 | }, 34 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, CEA-Codra, Pierre Raybaut. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft doc 2 | graft qtdesigner 3 | graft src 4 | graft colormaps 5 | include *.desktop 6 | include CHANGELOG.md 7 | include requirements.txt -------------------------------------------------------------------------------- /colormaps/README.md: -------------------------------------------------------------------------------- 1 | This directory contains functions and data useful to generate default colormaps used 2 | in Plotpy. Launch `colormap.py` to create/overwrite the colormaps_default.json file. -------------------------------------------------------------------------------- /doc/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/_static/favicon.ico -------------------------------------------------------------------------------- /doc/changelog.rst: -------------------------------------------------------------------------------- 1 | :tocdepth: 1 2 | 3 | .. include:: ../CHANGELOG.md 4 | :parser: myst_parser.sphinx_ 5 | -------------------------------------------------------------------------------- /doc/dev/build.rst: -------------------------------------------------------------------------------- 1 | How to build, test and deploy 2 | ----------------------------- 3 | 4 | Build instructions 5 | ^^^^^^^^^^^^^^^^^^ 6 | 7 | To build the wheel, you need: 8 | 9 | * Python 10 | * numpy 11 | * Cython 12 | * A C++ compiler like gcc or `Build Tools for Visual Studio 2017 `_ 13 | 14 | Then run the following command:: 15 | 16 | python setup.py bdist_wheel 17 | 18 | It should generate a ``.whl`` file in the `dist` directory. 19 | 20 | 21 | Running unittests 22 | ^^^^^^^^^^^^^^^^^ 23 | 24 | To run the unittests, you need: 25 | 26 | * Python 27 | * pytest 28 | * coverage (optional) 29 | 30 | Then run the following command:: 31 | 32 | pytest plotpy 33 | 34 | To run test with coverage support, use the following command:: 35 | 36 | pytest -v --cov --cov-report=html plotpy 37 | 38 | 39 | Code formatting 40 | ^^^^^^^^^^^^^^^ 41 | 42 | The code is formatted with `ruff `_. 43 | 44 | If you are using `Visual Studio Code `_, 45 | the formatting is done automatically when you save a file, thanks to the 46 | project settings in the `.vscode` directory. 47 | -------------------------------------------------------------------------------- /doc/dev/index.rst: -------------------------------------------------------------------------------- 1 | Development 2 | =========== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | contribute 9 | build 10 | guiqwt_to_plotpy 11 | v1_to_v2 12 | platforms 13 | -------------------------------------------------------------------------------- /doc/dev/v1_to_guidata_v3.csv: -------------------------------------------------------------------------------- 1 | plotpy v1,guidata v3 2 | 3 | ``.gui.dataitems.*``,``.dataset.*`` 4 | ``.gui.datatypes.*``,``.dataset.*`` 5 | ``.gui.dataset.qtitemwidgets``,``.dataset.qtitemwidgets`` 6 | ``.gui.dataset.qtwidgets``,``.dataset.qtwidgets`` 7 | ``.core.io.hdf5io``,``.dataset.io.h5fmt`` 8 | ``.core.config.userconfigio``,``.dataset.io.inifmt`` 9 | ``.core.config.userconfig``,``.userconfig`` 10 | ``.core.utils.disthelpers``,*removed* 11 | -------------------------------------------------------------------------------- /doc/features/colormapmanager.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.widgets.colormap 2 | -------------------------------------------------------------------------------- /doc/features/events.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.events 2 | -------------------------------------------------------------------------------- /doc/features/fit.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.widgets.fit 2 | -------------------------------------------------------------------------------- /doc/features/fliprotate.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.widgets.fliprotate 2 | -------------------------------------------------------------------------------- /doc/features/imagefile.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.widgets.imagefile 2 | -------------------------------------------------------------------------------- /doc/features/index.rst: -------------------------------------------------------------------------------- 1 | Features 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | plot/index 9 | items/index 10 | tools/index 11 | styles/index 12 | panels/index 13 | colormapmanager 14 | fit 15 | pyplot 16 | resizedialog 17 | rotatecrop 18 | fliprotate 19 | selectdialog 20 | imagefile 21 | io 22 | signals 23 | mathutils/index 24 | events 25 | -------------------------------------------------------------------------------- /doc/features/io.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.io -------------------------------------------------------------------------------- /doc/features/items/builder.rst: -------------------------------------------------------------------------------- 1 | .. _builder: 2 | 3 | Item builder 4 | ------------ 5 | 6 | The `builder` module provides a builder singleton class that can be 7 | used to simplify the creation of plot items. 8 | 9 | .. autodata:: plotpy.builder.make 10 | 11 | .. autoclass:: plotpy.constants.LUTAlpha 12 | :members: 13 | 14 | .. autoclass:: plotpy.builder.PlotBuilder 15 | :members: widget,dialog,window,gridparam,grid,mcurve,pcurve,curve,merror,perror,error,histogram,phistogram,range,vcursor,hcursor,xcursor,marker,image,maskedimage,maskedxyimage,rgbimage,quadgrid,pcolor,trimage,xyimage,imagefilter,contours,histogram2D,rectangle,ellipse,polygon,circle,segment,svg,annotated_point,annotated_rectangle,annotated_ellipse,annotated_circle,annotated_segment,annotated_polygon,label,legend,info_label,range_info_label,computation,computations,computation2d,computations2d 16 | -------------------------------------------------------------------------------- /doc/features/items/index.rst: -------------------------------------------------------------------------------- 1 | .. _items: 2 | 3 | Plot items 4 | ========== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: Contents: 9 | 10 | overview 11 | examples 12 | builder 13 | reference 14 | -------------------------------------------------------------------------------- /doc/features/mathutils/colormaps.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.mathutils.colormap -------------------------------------------------------------------------------- /doc/features/mathutils/geometry.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.mathutils.geometry -------------------------------------------------------------------------------- /doc/features/mathutils/index.rst: -------------------------------------------------------------------------------- 1 | Utilities 2 | ========= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | geometry 9 | scaler 10 | colormaps 11 | -------------------------------------------------------------------------------- /doc/features/mathutils/scaler.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.mathutils.scaler -------------------------------------------------------------------------------- /doc/features/panels/index.rst: -------------------------------------------------------------------------------- 1 | .. _panels: 2 | 3 | Plot panels 4 | =========== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: Contents: 9 | 10 | overview 11 | reference 12 | -------------------------------------------------------------------------------- /doc/features/panels/overview.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | -------- 3 | 4 | A `plot panel` is a graphical user interface element that interacts with a 5 | `plot` object, `plot items` and `plot tools`. 6 | 7 | Panels are objects inheriting from the :py:class:`.PanelWidget` class. 8 | 9 | .. seealso:: 10 | 11 | :ref:`plot` 12 | Ready-to-use curve and image plotting widgets and dialog boxes 13 | 14 | :ref:`items` 15 | Plot items: curves, images, markers, etc. 16 | 17 | :ref:`tools` 18 | Plot tools: zoom, pan, etc. 19 | 20 | 21 | The built-in panels are: 22 | 23 | * :py:data:`plotpy.constants.ID_ITEMLIST`: `item list` panel 24 | * :py:data:`plotpy.constants.ID_CONTRAST`: `contrast adjustment` panel 25 | * :py:data:`plotpy.constants.ID_XCS`: `X-axis cross section` panel 26 | * :py:data:`plotpy.constants.ID_YCS`: `Y-axis cross section` panel 27 | * :py:data:`plotpy.constants.ID_OCS`: `oblique cross section` panel 28 | * :py:data:`plotpy.constants.ID_LCS`: `line cross section` panel 29 | -------------------------------------------------------------------------------- /doc/features/panels/reference.rst: -------------------------------------------------------------------------------- 1 | :tocdepth: 3 2 | 3 | Reference 4 | --------- 5 | 6 | .. automodule:: plotpy.panels.base 7 | 8 | .. automodule:: plotpy.panels.itemlist 9 | 10 | .. automodule:: plotpy.panels.contrastadjustment 11 | 12 | .. automodule:: plotpy.panels.csection 13 | -------------------------------------------------------------------------------- /doc/features/plot/examples.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | -------- 3 | 4 | Using :class:`.PlotWidget` 5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | 7 | The following example shows how to use the :class:`.PlotWidget` class to create 8 | a simple plot with a curve and a filtering tool. In this example, the plot 9 | manager (see :class:`.PlotManager`) is not used, at least not directly: 10 | the plot manager is integrated in the :class:`.PlotWidget` class. 11 | 12 | .. literalinclude:: ../../../plotpy/tests/widgets/test_filtertest1.py 13 | :start-after: guitest: 14 | 15 | .. image:: ../../images/screenshots/filtertest1.png 16 | 17 | Using a plot manager 18 | ^^^^^^^^^^^^^^^^^^^^ 19 | 20 | Even if this simple example does not justify the use of the :class:`.PlotManager` 21 | (this is an unnecessary complication here), it shows how to use it. In more complex 22 | applications, using the :class:`.PlotManager` allows to design highly versatile 23 | graphical user interfaces. 24 | 25 | .. literalinclude:: ../../../plotpy/tests/widgets/test_filtertest2.py 26 | :start-after: guitest: 27 | 28 | .. image:: ../../images/screenshots/filtertest2.png 29 | -------------------------------------------------------------------------------- /doc/features/plot/index.rst: -------------------------------------------------------------------------------- 1 | .. _plot: 2 | 3 | Plot widgets 4 | ============ 5 | 6 | A :mod:`plotpy`-based plotting widget may be constructed using one of the following 7 | methods: 8 | 9 | * *Interactive mode*: when manipulating and visualizing data in an interactive 10 | Python or IPython interpreter, the :py:mod`.pyplot` module provide 11 | the easiest way to plot curves, show images and more. Syntax is similar 12 | to MATLAB's, thus very easy to learn and to use interactively. 13 | 14 | * *Script mode*: when manipulating and visualizing data using a script, the 15 | :py:mod`.pyplot` module is still a good choice as long as you don't 16 | need to customize the figure graphical user interface (GUI) layout. 17 | However, if you want to add other widgets to the GUI, like menus, buttons 18 | and so on, you should rather use plotting widget classes instead of 19 | the `pyplot` helper functions. 20 | 21 | There are two kinds of plotting widgets defined in :mod:`plotpy`: 22 | 23 | * low-level plotting widget: :py:class:`.plot.base.BasePlot` 24 | 25 | * high-level plotting widgets (ready-to-use widgets with integrated tools 26 | and panels): :py:class:`.plot.PlotWidget` and corresponding dialog box 27 | :py:class:`.plot.PlotDialog` and window 28 | :py:class:`.plot.PlotWindow` 29 | 30 | Plot widgets with integrated plot manager: 31 | 32 | .. image:: ../../images/plot_widgets.png 33 | 34 | .. seealso:: 35 | 36 | :ref:`items` 37 | Plot items: curves, images, markers, etc. 38 | 39 | :ref:`plot` 40 | Ready-to-use curve and image plotting widgets and dialog boxes 41 | 42 | .. toctree:: 43 | :maxdepth: 2 44 | :caption: Contents: 45 | 46 | overview 47 | examples 48 | reference 49 | -------------------------------------------------------------------------------- /doc/features/plot/overview.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | -------- 3 | 4 | Features 5 | ^^^^^^^^ 6 | 7 | The `plot` module provides the following features: 8 | 9 | * :py:class:`.PlotManager`: the `plot manager` is an object to 10 | link `plots`, `panels` and `tools` together for designing highly 11 | versatile graphical user interfaces 12 | 13 | * :py:class:`.PlotWidget`: a ready-to-use widget for curve/image 14 | displaying with an integrated and preconfigured `plot manager` providing 15 | the `item list panel` and curve/image-related `tools` 16 | 17 | * :py:class:`.PlotDialog`: a ready-to-use dialog box for 18 | curve/image displaying with an integrated and preconfigured `plot manager` 19 | providing the `item list panel` and curve/image-related `tools` 20 | 21 | * :py:class:`.SyncPlotWindow`: a ready-to-use window for curve/image 22 | displaying with plot axes synchronization 23 | 24 | .. seealso:: 25 | 26 | :ref:`items` 27 | Plot items: curves, images, markers, text, etc. 28 | 29 | :ref:`tools` 30 | Plot tools: zoom, pan, etc. 31 | 32 | 33 | Class diagrams 34 | ^^^^^^^^^^^^^^ 35 | 36 | Plot widgets with integrated plot manager: 37 | 38 | .. image:: ../../images/plot_widgets.png 39 | 40 | Building your own plot manager: 41 | 42 | .. image:: ../../images/my_plot_manager.png 43 | -------------------------------------------------------------------------------- /doc/features/plot/reference.rst: -------------------------------------------------------------------------------- 1 | :tocdepth: 3 2 | 3 | Reference 4 | --------- 5 | 6 | High-level features 7 | ^^^^^^^^^^^^^^^^^^^ 8 | 9 | .. autoclass:: plotpy.plot.manager.PlotManager 10 | :members: 11 | .. autoclass:: plotpy.plot.PlotOptions 12 | :members: 13 | .. autoclass:: plotpy.plot.PlotWidget 14 | :members: 15 | .. autoclass:: plotpy.plot.PlotDialog 16 | :members: 17 | .. autoclass:: plotpy.plot.PlotWindow 18 | :members: 19 | .. autoclass:: plotpy.plot.SyncPlotWindow 20 | :members: 21 | 22 | Low-level features 23 | ^^^^^^^^^^^^^^^^^^ 24 | 25 | .. autoclass:: plotpy.constants.PlotType 26 | :members: 27 | .. autoclass:: plotpy.plot.BasePlot 28 | :members: 29 | .. autoclass:: plotpy.plot.BasePlotOptions 30 | :members: 31 | -------------------------------------------------------------------------------- /doc/features/pyplot.rst: -------------------------------------------------------------------------------- 1 | .. module:: pyplot 2 | .. automodule:: plotpy.pyplot 3 | -------------------------------------------------------------------------------- /doc/features/resizedialog.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.widgets.resizedialog 2 | -------------------------------------------------------------------------------- /doc/features/rotatecrop.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.widgets.rotatecrop 2 | -------------------------------------------------------------------------------- /doc/features/selectdialog.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: plotpy.widgets.selectdialog 2 | -------------------------------------------------------------------------------- /doc/features/signals.rst: -------------------------------------------------------------------------------- 1 | Qt signals 2 | ---------- 3 | 4 | In `guiqwt` version 2, the `signals` module used to contain constants defining 5 | the custom Qt ``SIGNAL`` objects used by `guiqwt`: the signals definition were 6 | gathered there to avoid misspelling signals at connect and emit sites (with 7 | old-style signals, any misspelled signal string would have lead to a silent 8 | failure of signal emission or connection). 9 | 10 | Since version 3, to ensure PyQt5 compatibility, `guiqwt` and thus plotpy are using 11 | only new-style signals and slots. 12 | 13 | All signals are summarized below, in order to facilitate migration 14 | from `guiqwt` v2 to v3, then to plotpy. 15 | 16 | Signals emitted by :py:class:`.BasePlot` objects: 17 | 18 | - :py:attr:`.BasePlot.SIG_ITEM_MOVED` 19 | - :py:attr:`.BasePlot.SIG_ITEM_HANDLE_MOVED` 20 | - :py:attr:`.BasePlot.SIG_ITEM_RESIZED` 21 | - :py:attr:`.BasePlot.SIG_ITEM_ROTATED` 22 | - :py:attr:`.BasePlot.SIG_MARKER_CHANGED` 23 | - :py:attr:`.BasePlot.SIG_AXES_CHANGED` 24 | - :py:attr:`.BasePlot.SIG_ANNOTATION_CHANGED` 25 | - :py:attr:`.BasePlot.SIG_RANGE_CHANGED` 26 | - :py:attr:`.BasePlot.SIG_ITEMS_CHANGED` 27 | - :py:attr:`.BasePlot.SIG_ITEM_PARAMETERS_CHANGED` 28 | - :py:attr:`.BasePlot.SIG_ACTIVE_ITEM_CHANGED` 29 | - :py:attr:`.BasePlot.SIG_ITEM_REMOVED` 30 | - :py:attr:`.BasePlot.SIG_ITEM_SELECTION_CHANGED` 31 | - :py:attr:`.BasePlot.SIG_PLOT_LABELS_CHANGED` 32 | - :py:attr:`.BasePlot.SIG_AXIS_DIRECTION_CHANGED` 33 | - :py:attr:`.BasePlot.SIG_LUT_CHANGED` 34 | - :py:attr:`.BasePlot.SIG_MASK_CHANGED` 35 | - :py:attr:`.BasePlot.SIG_CS_CURVE_CHANGED` 36 | 37 | Signals emitted by other objects: 38 | 39 | - :py:attr:`.PanelWidget.SIG_VISIBILITY_CHANGED` 40 | - :py:attr:`.InteractiveTool.SIG_VALIDATE_TOOL` 41 | - :py:attr:`.InteractiveTool.SIG_TOOL_JOB_FINISHED` 42 | - :py:attr:`.OpenFileTool.SIG_OPEN_FILE` 43 | - :py:attr:`.ImageMaskTool.SIG_APPLIED_MASK_TOOL` 44 | -------------------------------------------------------------------------------- /doc/features/styles/index.rst: -------------------------------------------------------------------------------- 1 | .. _styles: 2 | 3 | Styles for items and tools 4 | ========================== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: Contents: 9 | 10 | overview 11 | reference 12 | -------------------------------------------------------------------------------- /doc/features/styles/overview.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | -------- 3 | 4 | The `styles` module (see :ref:`styles`) provides the classes for configuring 5 | the plot items and the plot tools. Those classes are data sets 6 | (:py:class:`guidata.dataset.DataSet`) 7 | containing parameters that affect the visual appearance of the plot items and 8 | the plot tools behavior. 9 | 10 | .. seealso:: 11 | 12 | :ref:`plot` 13 | Ready-to-use curve and image plotting widgets and dialog boxes 14 | 15 | :ref:`items` 16 | Plot items: curve, image, shapes, etc. 17 | 18 | :ref:`tools` 19 | Plot tools: zoom, pan, etc. 20 | -------------------------------------------------------------------------------- /doc/features/tools/examples.rst: -------------------------------------------------------------------------------- 1 | Example 2 | ------- 3 | 4 | The following example add all the existing image tools to a :class:`.PlotWidget` 5 | object for testing purpose: 6 | 7 | .. literalinclude:: ../../../plotpy/tests/tools/test_image_plot_tools.py 8 | :start-after: guitest: 9 | 10 | .. image:: /images/screenshots/image_plot_tools.png 11 | -------------------------------------------------------------------------------- /doc/features/tools/index.rst: -------------------------------------------------------------------------------- 1 | .. _tools: 2 | 3 | Plot tools 4 | ========== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: Contents: 9 | 10 | overview 11 | examples 12 | reference 13 | -------------------------------------------------------------------------------- /doc/features/tools/overview.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | -------- 3 | 4 | A `plot tool` is an object providing various features to a plotting widget 5 | (:py:class:`.BasePlot`): 6 | 7 | * Buttons, 8 | * Menus, 9 | * Selection tools, 10 | * Image I/O tools, 11 | * Etc. 12 | 13 | Before being used, a tool has to be registered to a plotting widget's manager, 14 | i.e. an instance of the :py:class:`.PlotManager` class (see :ref:`plot` 15 | for more details). 16 | 17 | The :py:class:`.BasePlot` widget do not provide any :py:class:`.PlotManager`: 18 | the manager has to be created separately. On the contrary, the ready-to-use widget 19 | :py:class:`.PlotWidget` are higher-level plotting widgets with 20 | integrated manager, tools and panels. 21 | 22 | .. seealso:: 23 | 24 | :ref:`plot` 25 | Ready-to-use curve and image plotting widgets and dialog boxes 26 | 27 | :ref:`items` 28 | Plot items: curves, images, markers, etc. 29 | -------------------------------------------------------------------------------- /doc/images/my_plot_manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/my_plot_manager.png -------------------------------------------------------------------------------- /doc/images/panorama-vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/panorama-vertical.png -------------------------------------------------------------------------------- /doc/images/panorama.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/panorama.png -------------------------------------------------------------------------------- /doc/images/plot_widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/plot_widgets.png -------------------------------------------------------------------------------- /doc/images/plotpy-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/plotpy-banner.png -------------------------------------------------------------------------------- /doc/images/plotpy-vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/plotpy-vertical.png -------------------------------------------------------------------------------- /doc/images/screenshots/__init__.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/__init__.png -------------------------------------------------------------------------------- /doc/images/screenshots/computations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/computations.png -------------------------------------------------------------------------------- /doc/images/screenshots/contrast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/contrast.png -------------------------------------------------------------------------------- /doc/images/screenshots/cross_section.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/cross_section.png -------------------------------------------------------------------------------- /doc/images/screenshots/cross_section2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/cross_section2.png -------------------------------------------------------------------------------- /doc/images/screenshots/dotarraydemo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/dotarraydemo.png -------------------------------------------------------------------------------- /doc/images/screenshots/filtertest1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/filtertest1.png -------------------------------------------------------------------------------- /doc/images/screenshots/filtertest2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/filtertest2.png -------------------------------------------------------------------------------- /doc/images/screenshots/fit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/fit.png -------------------------------------------------------------------------------- /doc/images/screenshots/get_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/get_point.png -------------------------------------------------------------------------------- /doc/images/screenshots/hist2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/hist2d.png -------------------------------------------------------------------------------- /doc/images/screenshots/image_plot_tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/image_plot_tools.png -------------------------------------------------------------------------------- /doc/images/screenshots/imagefilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/imagefilter.png -------------------------------------------------------------------------------- /doc/images/screenshots/imagesuperp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/imagesuperp.png -------------------------------------------------------------------------------- /doc/images/screenshots/imagexy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/imagexy.png -------------------------------------------------------------------------------- /doc/images/screenshots/manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/manager.png -------------------------------------------------------------------------------- /doc/images/screenshots/mandelbrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/mandelbrot.png -------------------------------------------------------------------------------- /doc/images/screenshots/pcolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/pcolor.png -------------------------------------------------------------------------------- /doc/images/screenshots/plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/plot.png -------------------------------------------------------------------------------- /doc/images/screenshots/simple_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/simple_dialog.png -------------------------------------------------------------------------------- /doc/images/screenshots/simple_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/simple_window.png -------------------------------------------------------------------------------- /doc/images/screenshots/transform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/doc/images/screenshots/transform.png -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to :mod:`plotpy`'s documentation! 2 | ========================================= 3 | 4 | .. image:: images/plotpy-banner.png 5 | :align: center 6 | 7 | :mod:`plotpy` is is a Python library providing efficient 2D data-plotting 8 | features for interactive computing and signal/image processing application 9 | development. 10 | 11 | :mod:`plotpy` is part of the `PlotPyStack`_ project, which aims at providing 12 | a full set of Python libraries for data plotting and data analysis. 13 | 14 | :mod:`plotpy` is based on: 15 | 16 | * `Python`_ language and `Qt`_ GUI toolkit (via `PySide`_ or `PyQt`_) 17 | * `guidata`_ automatic GUI generation library (`PlotPyStack`_ project) 18 | * `PythonQwt`_ plotting widgets library (`PlotPyStack`_ project) 19 | * `NumPy`_ and `SciPy`_ scientific computing libraries 20 | 21 | .. figure:: images/panorama.png 22 | 23 | A panorama of :mod:`plotpy`'s features. 24 | 25 | External resources: 26 | 27 | * Python Package Index: `PyPI`_ 28 | * Bug reports and feature requests: `GitHub`_ 29 | 30 | .. _Python: http://www.python.org 31 | .. _Qt: https://doc.qt.io/ 32 | .. _PySide: https://doc.qt.io/qtforpython-6/ 33 | .. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/intro 34 | .. _PyPI: https://pypi.python.org/pypi/plotpy 35 | .. _GitHub: https://github.com/PlotPyStack/plotpy 36 | .. _guidata: https://pypi.python.org/pypi/guidata 37 | .. _PythonQwt: https://pypi.python.org/pypi/PythonQwt 38 | .. _NumPy: https://pypi.python.org/pypi/NumPy 39 | .. _SciPy: https://pypi.python.org/pypi/SciPy 40 | .. _PlotPyStack: https://github.com/PlotPyStack 41 | 42 | .. module:: plotpy 43 | 44 | Table of contents 45 | ----------------- 46 | 47 | .. toctree:: 48 | :maxdepth: 2 49 | 50 | intro/index 51 | features/index 52 | dev/index 53 | changelog 54 | 55 | * :ref:`genindex` 56 | -------------------------------------------------------------------------------- /doc/intro/index.rst: -------------------------------------------------------------------------------- 1 | Getting started 2 | =============== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | overview 9 | motivation 10 | installation 11 | examples 12 | licenses 13 | -------------------------------------------------------------------------------- /doc/intro/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | Dependencies 5 | ------------ 6 | 7 | .. note:: 8 | 9 | See :ref:`platforms` section for more information about supported platforms, 10 | Python versions and Qt bindings. 11 | 12 | .. include:: ../requirements.rst 13 | 14 | Installation using pip 15 | ---------------------- 16 | 17 | The easiest way to install plotpy is using `pip `_:: 18 | 19 | pip install plotpy 20 | 21 | Installation from source 22 | ------------------------ 23 | 24 | To install from source, clone the repository or download the source package 25 | from `PyPI `_. 26 | 27 | Then run the following command (using `build `_):: 28 | 29 | python -m build 30 | -------------------------------------------------------------------------------- /doc/update_requirements.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Update requirements.rst file from pyproject.toml or setup.cfg file 4 | 5 | Warning: this has to be done manually at release time. 6 | It is not done automatically by the sphinx 'conf.py' file because it 7 | requires an internet connection to fetch the dependencies metadata - this 8 | is not always possible (e.g., when building the documentation on a machine 9 | without internet connection like the Debian package management infrastructure). 10 | """ 11 | 12 | from guidata.utils.genreqs import gen_module_req_rst # noqa: E402 13 | 14 | import plotpy 15 | 16 | if __name__ == "__main__": 17 | print("Updating requirements.rst file...", end=" ") 18 | gen_module_req_rst(plotpy, ["Python>=3.9", "PyQt5>=5.11"]) 19 | print("done.") 20 | -------------------------------------------------------------------------------- /media/LinkedIn/2023_10_31-V2.md: -------------------------------------------------------------------------------- 1 | # Announcement: Release of PlotPy V2 📊 2 | 3 | PlotPy V2 distinguishes itself in the realm of plotting libraries. Designed for Python/Qt applications, this library offers a blend of superior performance and enhanced interactive features. Its image display features, driven by a C++ transform engine, include real-time high-quality interpolation, LUT, and geometric transformations, elevating data interaction. 4 | 5 | PlotPy is part of the PlotPyStack project (), dedicated to delivering a comprehensive toolkit for crafting scientific and technical data visualization applications. 6 | 7 | The development efforts for PlotPy V2 were financed by the CEA (). 8 | 9 | What's New in PlotPy V2 🌟: 10 | 11 | 🔍 Major Updates: 12 | 13 | Refined and unified API for curve and image plotting features (widget, dialog, window). Introduction of a new window for synchronized multi-plot displays 🔄. 14 | 15 | 🎨 Enhancements: 16 | 17 | Expanded Image Lookup Table functionalities. 18 | Integration of SVG-based shapes. 19 | 20 | 📖 Documentation: 21 | Comprehensive Sphinx-based documentation enriched with API links, examples, and tutorials. 22 | 23 | ⚙️ Development Features: 24 | Black code formatting, robust `pytest`-based automated test suite, and a 70% test coverage milestone ✅. 25 | 26 | We invite the community to explore PlotPy V2's capabilities. 27 | 28 | Explore PlotPy V2 on PyPI: . 29 | View the project on GitHub: . 30 | Review the documentation: . 31 | -------------------------------------------------------------------------------- /media/X/2023_10_31-V2.txt: -------------------------------------------------------------------------------- 1 | PlotPy V2 is now live! 🎉Introducing an optimized 2D curve/image plotting library📊. 2 | It's the successor to guiqwt. 3 | PlotPy is part of PlotPyStack, representing 15 years of expertise 4 | in Python-Qt scientific software development. 5 | #Python #Plotting 6 | -------------------------------------------------------------------------------- /plotpy-tests.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Name=PlotPy 5 | GenericName=PlotPy Test launcher 6 | Comment=The PlotPy Python library provides powerful curve and image plotting tools 7 | TryExec=plotpy-tests 8 | Exec=plotpy-tests 9 | Icon=plotpy.svg 10 | Categories=Education;Science;Physics; 11 | -------------------------------------------------------------------------------- /plotpy/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | plotpy 4 | ====== 5 | 6 | Based on `PythonQwt` (plotting widgets for Qt graphical user interfaces) and 7 | on the scientific modules NumPy and SciPy, :mod:`plotpy` is a Python library 8 | providing efficient 2D data-plotting features (curve/image visualization 9 | and related tools) for interactive computing and signal/image processing 10 | application development. 11 | 12 | .. image:: images/panorama.png 13 | 14 | 15 | External resources: 16 | * Python Package Index: `PyPI`_ 17 | * Bug reports and feature requests: `GitHub`_ 18 | 19 | .. _PyPI: https://pypi.python.org/pypi/plotpy 20 | .. _GitHub: https://github.com/PierreRaybaut/plotpy 21 | """ 22 | 23 | __version__ = "2.7.4" 24 | __VERSION__ = tuple([int(number) for number in __version__.split(".")]) 25 | 26 | # --- Important note: DATAPATH and LOCALEPATH are used by guidata.configtools 27 | # --- to retrieve data and translation files paths 28 | # 29 | # Dear (Debian, RPM, ...) package makers, please feel free to customize the 30 | # following path to module's data (e.g. icons) and translations: 31 | DATAPATH = LOCALEPATH = "" 32 | -------------------------------------------------------------------------------- /plotpy/builder/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | # pylint: disable=C0103 7 | 8 | """ 9 | Item builder 10 | ------------ 11 | 12 | The `builder` module provides a builder singleton class that can be 13 | used to simplify the creation of plot items. 14 | """ 15 | 16 | from __future__ import annotations 17 | 18 | from .annotation import AnnotationBuilder 19 | from .curvemarker import CurveMarkerCursorBuilder 20 | from .image import ImageBuilder 21 | from .label import LabelBuilder 22 | from .plot import WidgetBuilder 23 | from .shape import ShapeBuilder 24 | 25 | 26 | class PlotBuilder( 27 | WidgetBuilder, 28 | CurveMarkerCursorBuilder, 29 | ImageBuilder, 30 | LabelBuilder, 31 | ShapeBuilder, 32 | AnnotationBuilder, 33 | ): 34 | """Class regrouping a set of factory functions to simplify the creation 35 | of plot widgets and plot items. 36 | 37 | It is a singleton class, so you should not create instances of this class 38 | but use the :py:data:`plotpy.builder.make` instance instead. 39 | """ 40 | 41 | def __init__(self): 42 | super().__init__() 43 | 44 | 45 | #: Instance of :py:class:`.PlotBuilder` 46 | make = PlotBuilder() 47 | -------------------------------------------------------------------------------- /plotpy/data/icons/apply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/apply.png -------------------------------------------------------------------------------- /plotpy/data/icons/arredit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/arredit.png -------------------------------------------------------------------------------- /plotpy/data/icons/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/arrow_down.png -------------------------------------------------------------------------------- /plotpy/data/icons/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/arrow_up.png -------------------------------------------------------------------------------- /plotpy/data/icons/autorefresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/autorefresh.png -------------------------------------------------------------------------------- /plotpy/data/icons/autoscale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/autoscale.png -------------------------------------------------------------------------------- /plotpy/data/icons/axes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/axes.png -------------------------------------------------------------------------------- /plotpy/data/icons/busy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/busy.png -------------------------------------------------------------------------------- /plotpy/data/icons/cell_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/cell_edit.png -------------------------------------------------------------------------------- /plotpy/data/icons/center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/center.png -------------------------------------------------------------------------------- /plotpy/data/icons/cmap_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/cmap_edit.png -------------------------------------------------------------------------------- /plotpy/data/icons/contrast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/contrast.png -------------------------------------------------------------------------------- /plotpy/data/icons/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/copy.png -------------------------------------------------------------------------------- /plotpy/data/icons/copytoclipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/copytoclipboard.png -------------------------------------------------------------------------------- /plotpy/data/icons/csapplylut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/csapplylut.png -------------------------------------------------------------------------------- /plotpy/data/icons/csautoscale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/csautoscale.png -------------------------------------------------------------------------------- /plotpy/data/icons/csection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/csection.png -------------------------------------------------------------------------------- /plotpy/data/icons/csection_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/csection_a.png -------------------------------------------------------------------------------- /plotpy/data/icons/csection_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/csection_line.png -------------------------------------------------------------------------------- /plotpy/data/icons/csection_oblique.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/csection_oblique.png -------------------------------------------------------------------------------- /plotpy/data/icons/csperimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/csperimage.png -------------------------------------------------------------------------------- /plotpy/data/icons/curve_downsample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/curve_downsample.png -------------------------------------------------------------------------------- /plotpy/data/icons/curvestyles/dots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/curvestyles/dots.png -------------------------------------------------------------------------------- /plotpy/data/icons/curvestyles/lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/curvestyles/lines.png -------------------------------------------------------------------------------- /plotpy/data/icons/curvestyles/steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/curvestyles/steps.png -------------------------------------------------------------------------------- /plotpy/data/icons/curvestyles/sticks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/curvestyles/sticks.png -------------------------------------------------------------------------------- /plotpy/data/icons/curvetypes/xfy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/curvetypes/xfy.png -------------------------------------------------------------------------------- /plotpy/data/icons/curvetypes/yfx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/curvetypes/yfx.png -------------------------------------------------------------------------------- /plotpy/data/icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/delete.png -------------------------------------------------------------------------------- /plotpy/data/icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/edit.png -------------------------------------------------------------------------------- /plotpy/data/icons/edit_point_selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/edit_point_selection.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/edit.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/edit_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/edit_add.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/editcopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/editcopy.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/editdelete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/editdelete.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/editpaste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/editpaste.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/fileimport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/fileimport.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/filesave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/filesave.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/imshow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/imshow.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/insert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/insert.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/plot.png -------------------------------------------------------------------------------- /plotpy/data/icons/editors/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/editors/rename.png -------------------------------------------------------------------------------- /plotpy/data/icons/eliminate_outliers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/eliminate_outliers.png -------------------------------------------------------------------------------- /plotpy/data/icons/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/eraser.png -------------------------------------------------------------------------------- /plotpy/data/icons/exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/exit.png -------------------------------------------------------------------------------- /plotpy/data/icons/expander_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/expander_down.png -------------------------------------------------------------------------------- /plotpy/data/icons/expander_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/expander_right.png -------------------------------------------------------------------------------- /plotpy/data/icons/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/export.png -------------------------------------------------------------------------------- /plotpy/data/icons/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/file.png -------------------------------------------------------------------------------- /plotpy/data/icons/fileclose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/fileclose.png -------------------------------------------------------------------------------- /plotpy/data/icons/fileimport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/fileimport.png -------------------------------------------------------------------------------- /plotpy/data/icons/filenew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filenew.png -------------------------------------------------------------------------------- /plotpy/data/icons/fileopen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/fileopen.png -------------------------------------------------------------------------------- /plotpy/data/icons/filesave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filesave.png -------------------------------------------------------------------------------- /plotpy/data/icons/filesaveas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filesaveas.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/doc.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/gif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/gif.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/html.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/jpg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/jpg.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/pdf.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/png.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/pps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/pps.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/ps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/ps.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/tar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/tar.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/tgz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/tgz.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/tif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/tif.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/txt.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/xls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/xls.png -------------------------------------------------------------------------------- /plotpy/data/icons/filetypes/zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/filetypes/zip.png -------------------------------------------------------------------------------- /plotpy/data/icons/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/font.png -------------------------------------------------------------------------------- /plotpy/data/icons/full_range.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/full_range.png -------------------------------------------------------------------------------- /plotpy/data/icons/funct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/funct.png -------------------------------------------------------------------------------- /plotpy/data/icons/hcursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/hcursor.png -------------------------------------------------------------------------------- /plotpy/data/icons/hflip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/hflip.png -------------------------------------------------------------------------------- /plotpy/data/icons/imagestats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/imagestats.png -------------------------------------------------------------------------------- /plotpy/data/icons/item_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/item_list.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/annotation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/annotation.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/curve.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/errorbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/errorbar.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/grid.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/histogram.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/histogram2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/histogram2d.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/image.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/label.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/legend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/legend.png -------------------------------------------------------------------------------- /plotpy/data/icons/items/polygonmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/items/polygonmap.png -------------------------------------------------------------------------------- /plotpy/data/icons/magnifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/magnifier.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/cross.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/diamond.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/ellipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/ellipse.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/hexagon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/hexagon.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/point.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/square.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/star.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/triangle_d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/triangle_d.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/triangle_l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/triangle_l.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/triangle_r.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/triangle_r.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/triangle_u.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/triangle_u.png -------------------------------------------------------------------------------- /plotpy/data/icons/markers/xcross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markers/xcross.png -------------------------------------------------------------------------------- /plotpy/data/icons/markerstyles/cross_marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markerstyles/cross_marker.png -------------------------------------------------------------------------------- /plotpy/data/icons/markerstyles/horiz_marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markerstyles/horiz_marker.png -------------------------------------------------------------------------------- /plotpy/data/icons/markerstyles/vert_marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/markerstyles/vert_marker.png -------------------------------------------------------------------------------- /plotpy/data/icons/mask/mask_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/mask/mask_circle.png -------------------------------------------------------------------------------- /plotpy/data/icons/mask/mask_circle_outside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/mask/mask_circle_outside.png -------------------------------------------------------------------------------- /plotpy/data/icons/mask/mask_rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/mask/mask_rectangle.png -------------------------------------------------------------------------------- /plotpy/data/icons/mask/mask_rectangle_outside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/mask/mask_rectangle_outside.png -------------------------------------------------------------------------------- /plotpy/data/icons/mask/mask_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/mask/mask_tool.png -------------------------------------------------------------------------------- /plotpy/data/icons/max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/max.png -------------------------------------------------------------------------------- /plotpy/data/icons/min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/min.png -------------------------------------------------------------------------------- /plotpy/data/icons/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/move.png -------------------------------------------------------------------------------- /plotpy/data/icons/multipoint_selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/multipoint_selection.png -------------------------------------------------------------------------------- /plotpy/data/icons/none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/none.png -------------------------------------------------------------------------------- /plotpy/data/icons/not_found.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/not_found.png -------------------------------------------------------------------------------- /plotpy/data/icons/on_curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/on_curve.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/bdiagpattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/bdiagpattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/crosspattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/crosspattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/dense1pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/dense1pattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/dense2pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/dense2pattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/dense3pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/dense3pattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/dense4pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/dense4pattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/dense5pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/dense5pattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/dense6pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/dense6pattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/dense7pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/dense7pattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/diagcrosspattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/diagcrosspattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/fdiagpattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/fdiagpattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/horpattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/horpattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/nobrush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/nobrush.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/solidpattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/solidpattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/patterns/verpattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/patterns/verpattern.png -------------------------------------------------------------------------------- /plotpy/data/icons/point_selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/point_selection.png -------------------------------------------------------------------------------- /plotpy/data/icons/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/print.png -------------------------------------------------------------------------------- /plotpy/data/icons/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/python.png -------------------------------------------------------------------------------- /plotpy/data/icons/quickview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/quickview.png -------------------------------------------------------------------------------- /plotpy/data/icons/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/refresh.png -------------------------------------------------------------------------------- /plotpy/data/icons/rotationcenter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/rotationcenter.jpg -------------------------------------------------------------------------------- /plotpy/data/icons/save_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/save_all.png -------------------------------------------------------------------------------- /plotpy/data/icons/scales/lin_lin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/scales/lin_lin.png -------------------------------------------------------------------------------- /plotpy/data/icons/scales/lin_log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/scales/lin_log.png -------------------------------------------------------------------------------- /plotpy/data/icons/scales/log_lin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/scales/log_lin.png -------------------------------------------------------------------------------- /plotpy/data/icons/scales/log_log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/scales/log_log.png -------------------------------------------------------------------------------- /plotpy/data/icons/scales/source.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/scales/source.pdn -------------------------------------------------------------------------------- /plotpy/data/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/settings.png -------------------------------------------------------------------------------- /plotpy/data/icons/shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shape.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/circle.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/contour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/contour.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/ellipse_shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/ellipse_shape.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/gtaxes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/gtaxes.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/marker.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/oblique_rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/oblique_rectangle.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/point_shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/point_shape.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/polygon.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/polyline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/polyline.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/rectangle.png -------------------------------------------------------------------------------- /plotpy/data/icons/shapes/segment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/shapes/segment.png -------------------------------------------------------------------------------- /plotpy/data/icons/snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/snapshot.png -------------------------------------------------------------------------------- /plotpy/data/icons/styles/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/styles/dash.png -------------------------------------------------------------------------------- /plotpy/data/icons/styles/dashdot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/styles/dashdot.png -------------------------------------------------------------------------------- /plotpy/data/icons/styles/dashdotdot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/styles/dashdotdot.png -------------------------------------------------------------------------------- /plotpy/data/icons/styles/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/styles/dot.png -------------------------------------------------------------------------------- /plotpy/data/icons/styles/solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/styles/solid.png -------------------------------------------------------------------------------- /plotpy/data/icons/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/trash.png -------------------------------------------------------------------------------- /plotpy/data/icons/trimage_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/trimage_lock.png -------------------------------------------------------------------------------- /plotpy/data/icons/trimage_unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/trimage_unlock.png -------------------------------------------------------------------------------- /plotpy/data/icons/vcursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/vcursor.png -------------------------------------------------------------------------------- /plotpy/data/icons/vflip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/vflip.png -------------------------------------------------------------------------------- /plotpy/data/icons/xcursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/xcursor.png -------------------------------------------------------------------------------- /plotpy/data/icons/xmax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/xmax.png -------------------------------------------------------------------------------- /plotpy/data/icons/xmin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/xmin.png -------------------------------------------------------------------------------- /plotpy/data/icons/xrange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/data/icons/xrange.png -------------------------------------------------------------------------------- /plotpy/external/__init__.py: -------------------------------------------------------------------------------- 1 | from .sliders import ( 2 | QDoubleRangeSlider, 3 | QDoubleSlider, 4 | QLabeledDoubleRangeSlider, 5 | QLabeledDoubleSlider, 6 | QLabeledRangeSlider, 7 | QLabeledSlider, 8 | QRangeSlider, 9 | ) 10 | 11 | __all__ = [ 12 | "QDoubleRangeSlider", 13 | "QDoubleSlider", 14 | "QLabeledDoubleRangeSlider", 15 | "QLabeledDoubleSlider", 16 | "QLabeledRangeSlider", 17 | "QLabeledSlider", 18 | "QRangeSlider", 19 | ] 20 | -------------------------------------------------------------------------------- /plotpy/external/sliders/_misc.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | from typing import TYPE_CHECKING, Iterator 3 | 4 | if TYPE_CHECKING: 5 | from qtpy.QtCore import QObject 6 | 7 | 8 | @contextmanager 9 | def signals_blocked(obj: "QObject") -> Iterator[None]: 10 | """Context manager to temporarily block signals emitted by QObject: `obj`. 11 | 12 | Parameters 13 | ---------- 14 | obj : QObject 15 | The QObject whose signals should be blocked. 16 | 17 | Examples 18 | -------- 19 | ```python 20 | from qtpy.QtWidgets import QSpinBox 21 | from superqt import signals_blocked 22 | 23 | spinbox = QSpinBox() 24 | with signals_blocked(spinbox): 25 | spinbox.setValue(10) 26 | ``` 27 | """ 28 | previous = obj.blockSignals(True) 29 | try: 30 | yield 31 | finally: 32 | obj.blockSignals(previous) 33 | -------------------------------------------------------------------------------- /plotpy/external/sliders/_sliders.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtCore import Signal 2 | 3 | from ._generic_range_slider import _GenericRangeSlider 4 | from ._generic_slider import _GenericSlider 5 | 6 | 7 | class _IntMixin: 8 | def __init__(self, *args, **kwargs): 9 | super().__init__(*args, **kwargs) 10 | self._singleStep = 1 11 | 12 | def _type_cast(self, value) -> int: 13 | return int(round(value)) 14 | 15 | 16 | class _FloatMixin: 17 | _fvalueChanged = Signal(float) 18 | _fsliderMoved = Signal(float) 19 | _frangeChanged = Signal(float, float) 20 | 21 | def __init__(self, *args, **kwargs): 22 | super().__init__(*args, **kwargs) 23 | self._singleStep = 0.01 24 | self._pageStep = 0.1 25 | 26 | def _type_cast(self, value) -> float: 27 | return float(value) 28 | 29 | 30 | class QDoubleSlider(_FloatMixin, _GenericSlider): 31 | pass 32 | 33 | 34 | class QIntSlider(_IntMixin, _GenericSlider): 35 | # mostly just an example... use QSlider instead. 36 | valueChanged = Signal(int) 37 | 38 | 39 | class QRangeSlider(_IntMixin, _GenericRangeSlider): 40 | pass 41 | 42 | 43 | class QDoubleRangeSlider(_FloatMixin, QRangeSlider): 44 | pass 45 | 46 | 47 | # QRangeSlider.__doc__ += "\n" + textwrap.indent(QSlider.__doc__, " ") 48 | -------------------------------------------------------------------------------- /plotpy/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # pylint: disable=unused-import 4 | # flake8: noqa 5 | 6 | from .items import ( 7 | IBaseImageItem, 8 | IBasePlotItem, 9 | IColormapImageItemType, 10 | ICSImageItemType, 11 | ICurveItemType, 12 | IDecoratorItemType, 13 | IExportROIImageItemType, 14 | IHistDataSource, 15 | IImageItemType, 16 | IItemType, 17 | ISerializableType, 18 | IShapeItemType, 19 | ITrackableItemType, 20 | IVoiImageItemType, 21 | ) 22 | from .panel import IPanel 23 | from .plotmanager import IPlotManager 24 | -------------------------------------------------------------------------------- /plotpy/interfaces/panel.py: -------------------------------------------------------------------------------- 1 | class IPanel: 2 | """Interface for panels controlled by PlotManager""" 3 | 4 | @staticmethod 5 | def __inherits__(): 6 | # Avoid circular import 7 | # pylint: disable=import-outside-toplevel 8 | from plotpy.panels import PanelWidget 9 | 10 | return PanelWidget 11 | 12 | def register_panel(self, manager): 13 | """Register panel to plot manager""" 14 | pass 15 | 16 | def configure_panel(self): 17 | """Configure panel""" 18 | pass 19 | -------------------------------------------------------------------------------- /plotpy/interfaces/plotmanager.py: -------------------------------------------------------------------------------- 1 | class IPlotManager: 2 | """A 'controller' that organizes relations between 3 | plots (BasePlot), panels, tools (GuiTool) and toolbar 4 | """ 5 | 6 | def add_plot(self, plot, plot_id="default"): 7 | """ 8 | 9 | :param plot: 10 | :param plot_id: 11 | """ 12 | # Avoid circular import 13 | # pylint: disable=import-outside-toplevel 14 | from plotpy.plot.base import BasePlot 15 | 16 | assert id not in self.plots # pylint: disable=no-member 17 | assert isinstance(plot, BasePlot) 18 | 19 | def add_panel(self, panel): 20 | """ 21 | 22 | :param panel: 23 | """ 24 | assert id not in self.panels # pylint: disable=no-member 25 | 26 | def add_toolbar(self, toolbar, toolbar_id="default"): 27 | """ 28 | 29 | :param toolbar: 30 | :param toolbar_id: 31 | """ 32 | assert id not in self.toolbars # pylint: disable=no-member 33 | 34 | def get_active_plot(self): 35 | """The active plot is the plot whose canvas has the focus 36 | otherwise it's the "default" plot 37 | """ 38 | pass 39 | -------------------------------------------------------------------------------- /plotpy/items/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # pylint: disable=unused-import 4 | # flake8: noqa 5 | 6 | from .annotation import ( 7 | AnnotatedCircle, 8 | AnnotatedEllipse, 9 | AnnotatedObliqueRectangle, 10 | AnnotatedPoint, 11 | AnnotatedRectangle, 12 | AnnotatedPolygon, 13 | AnnotatedSegment, 14 | AnnotatedShape, 15 | ) 16 | from .contour import ContourItem, create_contour_items 17 | from .curve import CurveItem, ErrorBarCurveItem 18 | from .grid import GridItem 19 | from .histogram import HistogramItem 20 | from .image import ( 21 | BaseImageItem, 22 | Histogram2DItem, 23 | ImageFilterItem, 24 | ImageItem, 25 | MaskedImageItem, 26 | MaskedXYImageItem, 27 | QuadGridItem, 28 | RawImageItem, 29 | RGBImageItem, 30 | TrImageItem, 31 | XYImageFilterItem, 32 | XYImageItem, 33 | assemble_imageitems, 34 | compute_trimageitems_original_size, 35 | get_image_from_plot, 36 | get_image_from_qrect, 37 | get_image_in_shape, 38 | get_items_in_rectangle, 39 | get_plot_qrect, 40 | ) 41 | from .image.masked import MaskedArea, MaskedImageItem, MaskedXYImageItem 42 | from .label import ( 43 | AbstractLabelItem, 44 | DataInfoLabel, 45 | LabelItem, 46 | LegendBoxItem, 47 | ObjectInfo, 48 | RangeComputation, 49 | RangeComputation2d, 50 | RangeInfo, 51 | SelectedLegendBoxItem, 52 | ) 53 | from .polygonmap import PolygonMapItem 54 | from .shape import ( 55 | AbstractShape, 56 | Axes, 57 | CircleSVGShape, 58 | EllipseShape, 59 | Marker, 60 | ObliqueRectangleShape, 61 | PointShape, 62 | PolygonShape, 63 | RectangleShape, 64 | RectangleSVGShape, 65 | SegmentShape, 66 | SquareSVGShape, 67 | XRangeSelection, 68 | ) 69 | -------------------------------------------------------------------------------- /plotpy/items/curve/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # pylint: disable=W0611 4 | # flake8: noqa 5 | 6 | from plotpy.items.curve.base import CurveItem 7 | from plotpy.items.curve.errorbar import ErrorBarCurveItem 8 | -------------------------------------------------------------------------------- /plotpy/items/image/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # pylint: disable=unused-import 4 | # flake8: noqa 5 | 6 | from .base import BaseImageItem, RawImageItem 7 | from .filter import ImageFilterItem, XYImageFilterItem 8 | from .image_items import ImageItem, RGBImageItem, XYImageItem 9 | from .masked import MaskedArea, MaskedImageItem, MaskedXYImageItem 10 | from .misc import ( 11 | Histogram2DItem, 12 | QuadGridItem, 13 | assemble_imageitems, 14 | compute_trimageitems_original_size, 15 | get_image_from_plot, 16 | get_image_from_qrect, 17 | get_image_in_shape, 18 | get_items_in_rectangle, 19 | get_plot_qrect, 20 | ) 21 | from .transform import TrImageItem 22 | -------------------------------------------------------------------------------- /plotpy/items/shape/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # pylint: disable=W0611 4 | # flake8: noqa 5 | 6 | from .axis import Axes 7 | from .base import AbstractShape 8 | from .ellipse import EllipseShape 9 | from .marker import Marker 10 | from .point import PointShape 11 | from .polygon import PolygonShape 12 | from .range import XRangeSelection 13 | from .rectangle import ObliqueRectangleShape, RectangleShape 14 | from .segment import SegmentShape 15 | from .svg import CircleSVGShape, RectangleSVGShape, SquareSVGShape 16 | -------------------------------------------------------------------------------- /plotpy/locale/fr/LC_MESSAGES/plotpy.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/locale/fr/LC_MESSAGES/plotpy.mo -------------------------------------------------------------------------------- /plotpy/mathutils/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /plotpy/mathutils/arrayfuncs.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Array functions 5 | --------------- 6 | 7 | Overview 8 | ^^^^^^^^ 9 | 10 | The :py:mod:`.arrayfuncs` module provides miscellaneous array functions. 11 | 12 | The following functions are available: 13 | 14 | * :py:func:`.get_nan_min` 15 | * :py:func:`.get_nan_max` 16 | * :py:func:`.get_nan_range` 17 | 18 | Reference 19 | ^^^^^^^^^ 20 | 21 | .. autofunction:: get_nan_min 22 | .. autofunction:: get_nan_max 23 | .. autofunction:: get_nan_range 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | import numpy as np 29 | 30 | 31 | def get_nan_min(data: np.ndarray | np.ma.MaskedArray) -> float: 32 | """Return minimum value of data, ignoring NaNs 33 | 34 | Args: 35 | data: Data array (or masked array) 36 | 37 | Returns: 38 | float: Minimum value of data, ignoring NaNs 39 | """ 40 | if isinstance(data, np.ma.MaskedArray): 41 | data = data.data 42 | if data.dtype.name in ("float32", "float64", "float128"): 43 | return np.nanmin(data) 44 | else: 45 | return data.min() 46 | 47 | 48 | def get_nan_max(data: np.ndarray | np.ma.MaskedArray) -> float: 49 | """Return maximum value of data, ignoring NaNs 50 | 51 | Args: 52 | data: Data array (or masked array) 53 | 54 | Returns: 55 | float: Maximum value of data, ignoring NaNs 56 | """ 57 | if isinstance(data, np.ma.MaskedArray): 58 | data = data.data 59 | if data.dtype.name in ("float32", "float64", "float128"): 60 | return np.nanmax(data) 61 | else: 62 | return data.max() 63 | 64 | 65 | def get_nan_range(data: np.ndarray | np.ma.MaskedArray) -> tuple[float, float]: 66 | """Return range of data, i.e. (min, max), ignoring NaNs 67 | 68 | Args: 69 | data: Data array (or masked array) 70 | 71 | Returns: 72 | tuple: Minimum and maximum value of data, ignoring NaNs 73 | """ 74 | return get_nan_min(data), get_nan_max(data) 75 | -------------------------------------------------------------------------------- /plotpy/mathutils/scaler.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | # pylint: disable=C0103 7 | 8 | """ 9 | Scaling functions 10 | ----------------- 11 | 12 | Overview 13 | ^^^^^^^^ 14 | 15 | The :py:mod:`.scaler` module provides scaling functions for images, thanks to 16 | the C++ scaler engine (`_scaler` extension). 17 | 18 | The following functions are available: 19 | 20 | * :py:func:`.resize`: resize an image using the scaler engine 21 | 22 | Reference 23 | ^^^^^^^^^ 24 | 25 | .. autofunction:: resize 26 | """ 27 | 28 | # TODO: Move all _scaler imports in this module and do something to avoid 29 | # the need to import INTERP_LINEAR, INTERP_AA, ... in all modules using the 30 | # scaler (code refactoring between pyplot.imshow, 31 | # styles.BaseImageParam.update_item) 32 | 33 | # TODO: Other functions like resize could be written in the future 34 | 35 | import numpy as np 36 | 37 | from plotpy._scaler import INTERP_AA, INTERP_LINEAR, INTERP_NEAREST, _scale_rect 38 | 39 | 40 | def resize(data, shape, interpolation=None): 41 | """Resize array *data* to *shape* (tuple) 42 | interpolation: 'nearest', 'linear' (default), 'antialiasing'""" 43 | interpolate = (INTERP_NEAREST,) 44 | if interpolation is not None: 45 | interp_dict = { 46 | "nearest": INTERP_NEAREST, 47 | "linear": INTERP_LINEAR, 48 | "antialiasing": INTERP_AA, 49 | } 50 | assert interpolation in interp_dict, "invalid interpolation option" 51 | interp_mode = interp_dict[interpolation] 52 | if interp_mode in (INTERP_NEAREST, INTERP_LINEAR): 53 | interpolate = (interp_mode,) 54 | if interp_mode == INTERP_AA: 55 | aa = np.ones((5, 5), data.dtype) 56 | interpolate = (interp_mode, aa) 57 | out = np.empty(shape) 58 | src_rect = (0, 0, data.shape[1], data.shape[0]) 59 | dst_rect = (0, 0, out.shape[1], out.shape[0]) 60 | _scale_rect(data, src_rect, out, dst_rect, (1.0, 0.0, None), interpolate) 61 | return out 62 | -------------------------------------------------------------------------------- /plotpy/panels/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # pylint: disable=unused-import 4 | # flake8: noqa 5 | 6 | from .base import PanelWidget 7 | from .contrastadjustment import ContrastAdjustment 8 | from .csection import ( 9 | ObliqueCrossSection, 10 | XCrossSection, 11 | YCrossSection, 12 | LineCrossSection, 13 | ) 14 | from .itemlist import PlotItemList 15 | -------------------------------------------------------------------------------- /plotpy/panels/csection/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Cross-sections 5 | ^^^^^^^^^^^^^^ 6 | 7 | The cross-section panels are used to display cross-sections of 2D data, either 8 | along the X or Y axis, or along an oblique rectangle (average of the data along 9 | an oblique rectangle). 10 | 11 | .. autoclass:: XCrossSection 12 | .. autoclass:: YCrossSection 13 | .. autoclass:: ObliqueCrossSection 14 | .. autoclass:: LineCrossSection 15 | """ 16 | 17 | # pylint: disable=unused-import 18 | # flake8: noqa 19 | 20 | from .cswidget import ( 21 | ObliqueCrossSection, 22 | XCrossSection, 23 | YCrossSection, 24 | LineCrossSection, 25 | ) 26 | -------------------------------------------------------------------------------- /plotpy/plot/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # pylint: disable=unused-import 4 | # flake8: noqa 5 | 6 | from .base import BasePlot, BasePlotOptions 7 | from .manager import PlotManager 8 | from .plotwidget import ( 9 | PlotDialog, 10 | PlotOptions, 11 | PlotWidget, 12 | PlotWindow, 13 | SubplotWidget, 14 | SyncPlotWindow, 15 | set_widget_title_icon, 16 | ) 17 | -------------------------------------------------------------------------------- /plotpy/styles/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # pylint: disable=W0611 4 | # flake8: noqa 5 | 6 | from plotpy.styles.axes import ( 7 | AxesParam, 8 | AxeStyleParam, 9 | AxisItem, 10 | AxisItemWidget, 11 | AxisParam, 12 | ImageAxesParam, 13 | ) 14 | from plotpy.styles.base import ( 15 | COLORS, 16 | LINESTYLES, 17 | MARKERS, 18 | BrushStyleItem, 19 | BrushStyleItemWidget, 20 | BrushStyleParam, 21 | FontItem, 22 | FontItemWidget, 23 | FontParam, 24 | GridParam, 25 | ItemParameters, 26 | LineStyleItem, 27 | LineStyleItemWidget, 28 | LineStyleParam, 29 | SymbolItem, 30 | SymbolItemWidget, 31 | SymbolParam, 32 | TextStyleItem, 33 | TextStyleItemWidget, 34 | TextStyleParam, 35 | style_generator, 36 | update_style_attr, 37 | ) 38 | from plotpy.styles.curve import CurveParam, CurveParam_MS 39 | from plotpy.styles.errorbar import ErrorBarParam 40 | from plotpy.styles.histogram import ( 41 | Histogram2DParam, 42 | Histogram2DParam_MS, 43 | HistogramParam, 44 | ) 45 | from plotpy.styles.image import ( 46 | BaseImageParam, 47 | ImageFilterParam, 48 | ImageParam, 49 | ImageParam_MS, 50 | MaskedImageParam, 51 | MaskedImageParam_MS, 52 | MaskedImageParamMixin, 53 | MaskedXYImageParam, 54 | MaskedXYImageParam_MS, 55 | QuadGridParam, 56 | RawImageParam, 57 | RawImageParam_MS, 58 | RGBImageParam, 59 | TrImageParam, 60 | TrImageParam_MS, 61 | XYImageParam, 62 | XYImageParam_MS, 63 | ) 64 | from plotpy.styles.label import ( 65 | LabelParam, 66 | LabelParam_MS, 67 | LabelParamWithContents, 68 | LabelParamWithContents_MS, 69 | LegendParam, 70 | LegendParam_MS, 71 | ) 72 | from plotpy.styles.polygonmap import PolygonMapParam, PolygonParam_MS 73 | from plotpy.styles.shape import ( 74 | AnnotationParam, 75 | AnnotationParam_MS, 76 | AxesShapeParam, 77 | MarkerParam, 78 | RangeShapeParam, 79 | ShapeParam, 80 | ) 81 | -------------------------------------------------------------------------------- /plotpy/styles/polygonmap.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from guidata.dataset import DataSet, GetAttrProp, StringItem 8 | 9 | from plotpy.config import _ 10 | from plotpy.styles.base import ItemParameters 11 | 12 | if TYPE_CHECKING: 13 | from plotpy.items import PolygonMapItem 14 | 15 | 16 | class PolygonMapParam(DataSet): 17 | """Dataset defining the parameters of a PolygonMapItem instance""" 18 | 19 | _multiselection = False 20 | label = StringItem(_("Title"), default="").set_prop( 21 | "display", hide=GetAttrProp("_multiselection") 22 | ) 23 | 24 | def update_param(self, item: PolygonMapItem) -> None: 25 | """Updates the parameters using values from a given PolygonMapItem 26 | 27 | Args: 28 | item: reference PolygonMapItem instance 29 | """ 30 | self.label = str(item.title().text()) 31 | 32 | def update_item(self, item: PolygonMapItem) -> None: 33 | """Updates a given PolygonMapItem using the current parameters 34 | 35 | Args: 36 | item: instance of PolygonMapItem to update 37 | """ 38 | plot = item.plot() 39 | if plot is not None: 40 | plot.blockSignals(True) # Avoid unwanted calls of update_param 41 | # triggered by the setter methods below 42 | if not self._multiselection: 43 | # Non common parameters 44 | item.setTitle(self.label) 45 | if plot is not None: 46 | plot.blockSignals(False) 47 | 48 | 49 | class PolygonParam_MS(PolygonMapParam): 50 | """Same as PolygonParam but for multiselection""" 51 | 52 | _multiselection = True 53 | 54 | 55 | ItemParameters.register_multiselection(PolygonMapParam, PolygonParam_MS) 56 | -------------------------------------------------------------------------------- /plotpy/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ 7 | plotpy test package 8 | =================== 9 | """ 10 | 11 | import os.path as osp 12 | 13 | from guidata.configtools import get_module_data_path 14 | 15 | import plotpy # noqa: F401 16 | 17 | TESTDATAPATH = get_module_data_path("plotpy", osp.join("tests", "data")) 18 | 19 | 20 | def get_path(filename: str) -> str: 21 | """Return absolute path of test file""" 22 | return osp.join(TESTDATAPATH, filename) 23 | 24 | 25 | def run() -> None: 26 | """Run plotpy test launcher""" 27 | from guidata.guitest import run_testlauncher 28 | 29 | import plotpy.config # load icons 30 | 31 | run_testlauncher(plotpy) 32 | 33 | 34 | if __name__ == "__main__": 35 | run() 36 | -------------------------------------------------------------------------------- /plotpy/tests/benchmarks/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ 7 | plotpy benchmarks 8 | ================= 9 | """ 10 | 11 | from .test_benchmarks import test_benchmarks 12 | 13 | 14 | def run() -> None: 15 | """Run plotpy benchmarks""" 16 | test_benchmarks() 17 | 18 | 19 | if __name__ == "__main__": 20 | run() 21 | -------------------------------------------------------------------------------- /plotpy/tests/benchmarks/test_bigimages.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Test showing 10 big images""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | import pytest 12 | from guidata.qthelpers import qt_app_context 13 | 14 | from plotpy.builder import make 15 | 16 | 17 | def imshow(): 18 | win = make.dialog( 19 | toolbar=True, title="Displaying 10 big images test", size=(800, 600) 20 | ) 21 | plot = win.manager.get_plot() 22 | for i in range(10): 23 | plot.add_item(make.image(compute_image(i))) 24 | win.show() 25 | return win 26 | 27 | 28 | def compute_image(i, N=7500, M=1750): 29 | if i % 2 == 0: 30 | N, M = M, N 31 | return (np.random.rand(N, M) * 65536).astype(np.int16) 32 | 33 | 34 | @pytest.mark.skip(reason="Not relevant in automated test suite") 35 | def test_bigimages(): 36 | """Test Bigimages""" 37 | with qt_app_context(exec_loop=True): 38 | _persist_obj = imshow() 39 | 40 | 41 | if __name__ == "__main__": 42 | test_bigimages() 43 | -------------------------------------------------------------------------------- /plotpy/tests/conftest.py: -------------------------------------------------------------------------------- 1 | # content of conftest.py 2 | 3 | import gc 4 | 5 | import guidata 6 | import h5py 7 | import numpy 8 | import PIL 9 | import pytest 10 | import qtpy 11 | import qwt 12 | import scipy 13 | import tifffile 14 | from guidata.env import execenv 15 | 16 | import plotpy 17 | 18 | # Turn on unattended mode for executing tests without user interaction 19 | execenv.unattended = True 20 | execenv.verbose = "quiet" 21 | 22 | 23 | @pytest.fixture(scope="session", autouse=True) 24 | def disable_gc_for_tests(): 25 | """Disable garbage collection for all tests in the session.""" 26 | # Important note: 27 | # --------------- 28 | # We need to disable garbage collection for all tests in the session because 29 | # this test suite is not representative of a typical application. 30 | # The high level of stress on the garbage collector can lead to false positives 31 | # in tests that rely on reference counting or finalization. 32 | # In a typical application, the garbage collector should be left enabled. 33 | 34 | gc.disable() 35 | yield 36 | gc.enable() 37 | 38 | 39 | def pytest_report_header(config): 40 | """Add additional information to the pytest report header.""" 41 | qtbindings_version = qtpy.PYSIDE_VERSION 42 | if qtbindings_version is None: 43 | qtbindings_version = qtpy.PYQT_VERSION 44 | return [ 45 | f"PlotPy {plotpy.__version__}, guidata {guidata.__version__}, " 46 | f"PythonQwt {qwt.__version__}, " 47 | f"{qtpy.API_NAME} {qtbindings_version} [Qt version: {qtpy.QT_VERSION}]", 48 | f"NumPy {numpy.__version__}, SciPy {scipy.__version__}, " 49 | f"h5py {h5py.__version__}, " 50 | f"Pillow {PIL.__version__}, tifffile {tifffile.__version__}", 51 | ] 52 | -------------------------------------------------------------------------------- /plotpy/tests/data/brain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/tests/data/brain.png -------------------------------------------------------------------------------- /plotpy/tests/data/brain_cylinder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/tests/data/brain_cylinder.png -------------------------------------------------------------------------------- /plotpy/tests/data/mr-brain.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/tests/data/mr-brain.dcm -------------------------------------------------------------------------------- /plotpy/tests/data/svg_target.svg: -------------------------------------------------------------------------------- 1 | 2 | 43 | -------------------------------------------------------------------------------- /plotpy/tests/data/svg_tool.svg: -------------------------------------------------------------------------------- 1 | 2 | 56 | -------------------------------------------------------------------------------- /plotpy/tests/features/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/tests/features/__init__.py -------------------------------------------------------------------------------- /plotpy/tests/features/test_auto_curve_image.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Testing 'auto' plot type""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | from numpy import linspace, sin 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import data as ptd 15 | from plotpy.tests import vistools as ptv 16 | 17 | 18 | def make_curve_image_legend(): 19 | """Make curve, image and legend""" 20 | x = linspace(0, 2000, 20000) 21 | y = (sin(sin(sin(x / 50))) - 1) * -1000 22 | z = ptd.gen_image1() 23 | return [make.image(z), make.curve(x, y, color="w"), make.legend("TR")] 24 | 25 | 26 | def test_auto_curve_image(): 27 | """Test auto curve image""" 28 | with qt_app_context(exec_loop=True): 29 | items = make_curve_image_legend() 30 | _win = ptv.show_items(items, wintitle="Testing 'auto' plot type") 31 | 32 | 33 | if __name__ == "__main__": 34 | test_auto_curve_image() 35 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Builder tests""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import data as ptd 15 | from plotpy.tests import vistools as ptv 16 | 17 | 18 | def test_builder(): 19 | """Testing plot builder""" 20 | data = ptd.gen_image1() 21 | show = ptv.show_items 22 | with qt_app_context(exec_loop=True): 23 | _win0 = show([make.image(data, colormap="pink")], wintitle="Pink colormap test") 24 | _win1 = show([make.image(data)], wintitle="Default LUT range") 25 | img1 = make.image(data) 26 | img1.set_lut_range([0, 1]) 27 | _win2 = show([img1], wintitle="0->1 LUT range through item") 28 | img2 = make.image(data, lut_range=[0, 1]) 29 | _win3 = show([img2], wintitle="0->1 LUT range through builder") 30 | x = np.linspace(1, 10, 200) 31 | y = np.sin(x) 32 | 33 | crv1 = make.curve(x, y, dx=x * 0.1, dy=y * 0.23) 34 | crv2 = make.curve(x, np.cos(x), color="#FF0000") 35 | _win4 = show([crv1, crv2], wintitle="Error bars with make.curve()") 36 | 37 | dat22 = np.zeros((2, 2), np.float32) 38 | dat22[0, 0] = 1 39 | dat22[0, 1] = 2 40 | dat22[1, 0] = 3 41 | dat22[1, 1] = 4 42 | img3 = make.image(dat22, xdata=[-1, 3], ydata=[-1, 3], interpolation="nearest") 43 | _win5 = show([img3], wintitle="2x2 image") 44 | 45 | img4 = make.image(dat22, x=[0, 2], y=[0, 2], interpolation="nearest") 46 | _win6 = show([img4], wintitle="Equivalent 2x2 XY image") 47 | 48 | 49 | if __name__ == "__main__": 50 | test_builder() 51 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_computations.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Plot computations test""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | import scipy.integrate as spt 12 | from guidata.qthelpers import qt_app_context 13 | 14 | from plotpy.builder import make 15 | from plotpy.tests import vistools as ptv 16 | 17 | 18 | def test_computations(): 19 | """Test computations""" 20 | x = np.linspace(-10, 10, 1000) 21 | y = np.sin(np.sin(np.sin(x))) 22 | with qt_app_context(exec_loop=True): 23 | curve = make.curve(x, y, "ab", "b") 24 | range = make.range(-2, 2) 25 | disp0 = make.range_info_label( 26 | range, "BR", "x = %.1f ± %.1f cm", title="Range infos" 27 | ) 28 | 29 | disp1 = make.computation( 30 | range, "BL", "trapz=%g", curve, lambda x, y: spt.trapezoid(y, x) 31 | ) 32 | 33 | disp2 = make.computations( 34 | range, 35 | "TL", 36 | [ 37 | (curve, "min=%.5f", lambda x, y: y.min()), 38 | (curve, "max=%.5f", lambda x, y: y.max()), 39 | (curve, "avg=%.5f", lambda x, y: y.mean()), 40 | ], 41 | ) 42 | legend = make.legend("TR") 43 | _win = ptv.show_items( 44 | wintitle="Plot computations", 45 | items=[curve, range, disp0, disp1, disp2, legend], 46 | plot_type="curve", 47 | ) 48 | 49 | 50 | if __name__ == "__main__": 51 | test_computations() 52 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_cursors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Horizontal/vertical cursors test""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | from numpy import linspace, sin 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_cursor(): 18 | """Test cursor""" 19 | x = linspace(-10, 10, 1000) + 1 20 | y = sin(sin(sin(x))) + 3 21 | with qt_app_context(exec_loop=True): 22 | curve = make.curve(x, y, "ab", "b") 23 | hcursor = make.hcursor(3.2, label="y = %.2f") 24 | vcursor = make.vcursor(7, label="x = %.2f") 25 | vcursor2 = make.vcursor(-1, label="NOT MOVABLE = %.2f", movable=False) 26 | xcursor = make.xcursor(-4, 2.5, label="x = %.2f
y = %.2f") 27 | legend = make.legend("TR") 28 | _win = ptv.show_items( 29 | wintitle="Plot cursors", 30 | items=[curve, hcursor, vcursor, vcursor2, xcursor, legend], 31 | plot_type="curve", 32 | ) 33 | 34 | 35 | if __name__ == "__main__": 36 | test_cursor() 37 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_dicom_image.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """DICOM image test 7 | 8 | Requires pydicom (>=0.9.3)""" 9 | 10 | # guitest: show 11 | 12 | import pytest 13 | from guidata.qthelpers import qt_app_context 14 | 15 | from plotpy.builder import make 16 | from plotpy.tests import get_path 17 | 18 | try: 19 | import pydicom # type:ignore 20 | except ImportError: 21 | pydicom = None 22 | 23 | 24 | @pytest.mark.skipif(pydicom is None, reason="pydicom not installed") 25 | def test_dicom_image(): 26 | with qt_app_context(exec_loop=True): 27 | win = make.dialog( 28 | edit=False, 29 | toolbar=True, 30 | wintitle="DICOM I/O test", 31 | show_contrast=True, 32 | type="image", 33 | size=(600, 700), 34 | ) 35 | filename = get_path("mr-brain.dcm") 36 | image = make.image(filename=filename, title="DICOM img", colormap="gray") 37 | plot = win.manager.get_plot() 38 | plot.add_item(image) 39 | plot.select_item(image) 40 | contrast = win.manager.get_contrast_panel() 41 | contrast.histogram.eliminate_outliers(54.0) 42 | 43 | 44 | if __name__ == "__main__": 45 | win = test_dicom_image() 46 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_fit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Curve fitting tools""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | 12 | from plotpy.widgets.fit import FitParam, guifit 13 | 14 | 15 | def test_fit(): 16 | """Test the curve fitting tool""" 17 | x = np.linspace(-10, 10, 1000) 18 | y = np.cos(1.5 * x) + np.random.rand(x.shape[0]) * 0.2 19 | 20 | def fit(x, params): 21 | a, b = params 22 | return np.cos(b * x) + a 23 | 24 | a = FitParam("Offset", 0.7, -1.0, 1.0) 25 | b = FitParam("Frequency", 1.2, 0.3, 3.0, logscale=True) 26 | params = [a, b] 27 | values = guifit(x, y, fit, params, xlabel="Time (s)", ylabel="Power (a.u.)") 28 | 29 | print(values) 30 | print([param.value for param in params]) 31 | 32 | 33 | if __name__ == "__main__": 34 | test_fit() 35 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_image_coords.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ 7 | Testing image coordinates issues 8 | 9 | Check that the first image pixel is centered on (0, 0) coordinates. 10 | 11 | See https://github.com/PlotPyStack/guiqwt/issues/90 12 | """ 13 | 14 | # guitest: show 15 | 16 | import numpy as np 17 | from guidata.qthelpers import qt_app_context 18 | 19 | from plotpy.builder import make 20 | from plotpy.tests import data as ptd 21 | from plotpy.tests import vistools as ptv 22 | from plotpy.tools import DisplayCoordsTool 23 | 24 | 25 | def test_pixel_coords(): 26 | """Testing image pixel coordinates""" 27 | title = test_pixel_coords.__doc__ 28 | data = ptd.gen_2d_gaussian(20, np.uint8, x0=-10, y0=-10, mu=7, sigma=10.0) 29 | with qt_app_context(exec_loop=True): 30 | image = make.image(data, interpolation="nearest") 31 | text = "First pixel should be centered on (0, 0) coordinates" 32 | label = make.label(text, (1, 1), (0, 0), "L") 33 | rect = make.rectangle(5, 5, 10, 10, "Rectangle") 34 | cursors = [] 35 | for i_cursor in range(0, 21, 10): 36 | cursors.append(make.vcursor(i_cursor, movable=False)) 37 | cursors.append(make.hcursor(i_cursor, movable=False)) 38 | win = ptv.show_items([image, label, rect] + cursors, wintitle=title) 39 | plot = win.get_plot() 40 | plot.select_item(image) 41 | win.manager.get_tool(DisplayCoordsTool).activate_curve_pointer(True) 42 | 43 | 44 | if __name__ == "__main__": 45 | test_pixel_coords() 46 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_image_filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Image filter demo""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | from scipy.ndimage import gaussian_filter 13 | 14 | from plotpy import io 15 | from plotpy.builder import make 16 | from plotpy.tests import data as ptd 17 | from plotpy.tests import get_path 18 | 19 | 20 | def imshow(x, y, data, filter_area, yreverse=True): 21 | with qt_app_context(exec_loop=True): 22 | win = make.dialog( 23 | edit=False, 24 | toolbar=True, 25 | wintitle="Image filter demo", 26 | xlabel="x (cm)", 27 | ylabel="y (cm)", 28 | yreverse=yreverse, 29 | type="image", 30 | size=(800, 600), 31 | ) 32 | image = make.xyimage(x, y, data) 33 | plot = win.manager.get_plot() 34 | plot.add_item(image) 35 | xmin, xmax, ymin, ymax = filter_area 36 | 37 | def ifilter(x, y, data): 38 | """Image filter function""" 39 | return gaussian_filter(data, 5) 40 | 41 | flt = make.imagefilter(xmin, xmax, ymin, ymax, image, filter=ifilter) 42 | plot.add_item(flt, z=1) 43 | plot.replot() 44 | win.show() 45 | 46 | 47 | def test_imagefilter(): 48 | """Test image filter""" 49 | x, y, data = ptd.gen_xyimage() 50 | imshow(x, y, data, filter_area=(-3.0, -1.0, 0.0, 2.0), yreverse=False) 51 | 52 | filename = get_path("brain.png") 53 | data = io.imread(filename, to_grayscale=True) 54 | x = np.linspace(0, 30.0, data.shape[1]) 55 | y = np.linspace(0, 30.0, data.shape[0]) 56 | imshow(x, y, data, filter_area=(10, 20, 5, 15)) 57 | 58 | 59 | if __name__ == "__main__": 60 | test_imagefilter() 61 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_image_superp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Image superposition test""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import get_path 15 | from plotpy.tools import EllipseTool, PlaceAxesTool, PolygonTool, RectangleTool 16 | 17 | 18 | def create_window(): 19 | gridparam = make.gridparam( 20 | background="black", minor_enabled=(False, False), major_style=(".", "gray", 1) 21 | ) 22 | win = make.dialog( 23 | toolbar=True, 24 | wintitle="Image superposition test", 25 | gridparam=gridparam, 26 | type="image", 27 | size=(800, 600), 28 | ) 29 | for toolklass in (RectangleTool, EllipseTool, PolygonTool, PlaceAxesTool): 30 | win.manager.add_tool(toolklass) 31 | return win 32 | 33 | 34 | def test_imagesuperp(): 35 | """Test image superposition""" 36 | filename = get_path("brain.png") 37 | with qt_app_context(exec_loop=True): 38 | win = create_window() 39 | image1 = make.image(filename=filename, title="Original", colormap="gray") 40 | data2 = np.array(image1.data[:, :150], copy=True) 41 | data2[:100] = data2[-100:] = 0 42 | image2 = make.image(data2, title="Modified", alpha_function="step") 43 | plot = win.manager.get_plot() 44 | plot.add_item(image1, z=0) 45 | plot.add_item(image2, z=1) 46 | plot.set_items_readonly(False) 47 | image2.set_readonly(True) 48 | win.manager.get_itemlist_panel().show() 49 | win.show() 50 | 51 | 52 | if __name__ == "__main__": 53 | test_imagesuperp() 54 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_loadsaveitems_hdf5.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Load/save items from/to HDF5 file""" 7 | 8 | # guitest: show 9 | 10 | # WARNING: 11 | # This script requires read/write permissions on current directory 12 | 13 | from __future__ import annotations 14 | 15 | from guidata.io import HDF5Reader, HDF5Writer 16 | 17 | from plotpy.tests.features.test_loadsaveitems_pickle import IOTest 18 | 19 | 20 | class HDF5Test(IOTest): 21 | """Test load/save items from/to HDF5 file""" 22 | 23 | FNAME = "loadsavecanvas.h5" 24 | 25 | def restore_items(self) -> None: 26 | """Restore items from HDF5 file""" 27 | reader = HDF5Reader(self.FNAME) 28 | self.plot.deserialize(reader) 29 | reader.close() 30 | 31 | def save_items(self) -> None: 32 | """Save items to HDF5 file""" 33 | writer = HDF5Writer(self.FNAME) 34 | self.plot.serialize(writer) 35 | writer.close() 36 | 37 | 38 | def test_loadsaveitems_hdf5(): 39 | """Test load/save items from/to HDF5 file""" 40 | test = HDF5Test("Load/save items from/to HDF5 file") 41 | test.run() 42 | 43 | 44 | if __name__ == "__main__": 45 | test_loadsaveitems_hdf5() 46 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_loadsaveitems_json.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of CodraFT Project 4 | # https://codra-ingenierie-informatique.github.io/CodraFT/ 5 | # 6 | # Licensed under the terms of the BSD 3-Clause or the CeCILL-B License 7 | # (see codraft/__init__.py for details) 8 | 9 | """ 10 | Unit test for plot items <--> JSON serialization/deserialization 11 | 12 | How to save/restore items to/from a JSON string? 13 | 14 | # Plot items --> JSON: 15 | writer = JSONWriter(None) 16 | save_items(writer, items) 17 | text = writer.get_json() 18 | 19 | # JSON --> Plot items: 20 | items = load_items(JSONReader(text)) 21 | 22 | """ 23 | 24 | # guitest: show 25 | 26 | # WARNING: 27 | # This script requires read/write permissions on current directory 28 | 29 | from __future__ import annotations 30 | 31 | from guidata.io import JSONReader, JSONWriter 32 | 33 | from plotpy.tests.features.test_loadsaveitems_pickle import IOTest 34 | 35 | 36 | class JSONTest(IOTest): 37 | """Class for JSON I/O testing""" 38 | 39 | FNAME = "loadsavecanvas.json" 40 | 41 | def restore_items(self) -> None: 42 | """Restore plot items""" 43 | self.plot.deserialize(JSONReader(self.FNAME)) 44 | 45 | def save_items(self) -> None: 46 | """Save plot items""" 47 | writer = JSONWriter(self.FNAME) 48 | self.plot.serialize(writer) 49 | writer.save() 50 | 51 | 52 | def test_loadsaveitems_json(): 53 | """Test load/save items from/to JSON file""" 54 | test = JSONTest("Load/save items from/to JSON file") 55 | test.run() 56 | 57 | 58 | if __name__ == "__main__": 59 | test_loadsaveitems_json() 60 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_no_auto_tools.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Testing `auto_tools` plot option""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | from numpy import linspace, sin 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_no_auto_tools(): 18 | """Test no auto tools""" 19 | x = linspace(-10, 10, 200) 20 | y = sin(sin(sin(x))) 21 | with qt_app_context(exec_loop=True): 22 | _win = ptv.show_items( 23 | [make.curve(x, y, color="b")], 24 | auto_tools=False, 25 | wintitle=test_no_auto_tools.__doc__, 26 | ) 27 | 28 | 29 | if __name__ == "__main__": 30 | test_no_auto_tools() 31 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_plot_log.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Logarithmic scale test for curve plotting""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_plot_log(): 18 | """Test plot log""" 19 | with qt_app_context(exec_loop=True): 20 | x = np.linspace(1, 10, 200) 21 | y = np.exp(-x) 22 | y[0] = 0 23 | items = [make.curve(x, y, color="b"), make.error(x, y, None, y * 0.23)] 24 | win = ptv.show_items(items, plot_type="curve", wintitle=test_plot_log.__doc__) 25 | plot = win.manager.get_plot() 26 | plot.set_axis_scale("left", "log") 27 | plot.set_axis_scale("bottom", "log") 28 | # plot.set_axis_limits("left", 4.53999297625e-05, 22026.4657948) 29 | 30 | 31 | if __name__ == "__main__": 32 | test_plot_log() 33 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_plot_types.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """PlotTypes test""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | from numpy import linspace, sin 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import data as ptd 15 | from plotpy.tests import vistools as ptv 16 | 17 | 18 | def test_plot_types(): 19 | """Test plot types""" 20 | _persist = [] 21 | with qt_app_context(exec_loop=True): 22 | x = linspace(-10, 10, 200) 23 | y = sin(sin(sin(x))) 24 | for plot_type in ("curve", "image", "auto", "manual"): 25 | for reverse in (True, False): 26 | revtxt = f"{'image' if reverse else 'curve'} added first" 27 | items = [ 28 | make.curve(x, y, color="b"), 29 | make.image(ptd.gen_image1()), 30 | ] 31 | _persist.append( 32 | ptv.show_items( 33 | reversed(items) if reverse else items, 34 | plot_type=plot_type, 35 | wintitle=f"Plot type: '{plot_type}' ({revtxt})", 36 | ) 37 | ) 38 | 39 | 40 | if __name__ == "__main__": 41 | test_plot_types() 42 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_plot_yreverse.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Reverse y-axis test for curve plotting""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_plot_yreverse(): 18 | """Testing reverse x/y axes""" 19 | with qt_app_context(exec_loop=True): 20 | x = np.linspace(-10, 10, 200) 21 | win = ptv.show_items( 22 | [make.curve(x, x * np.exp(-x), color="b")], 23 | plot_type="curve", 24 | wintitle=test_plot_yreverse.__doc__, 25 | ) 26 | plot = win.manager.get_plot() 27 | plot.set_axis_direction("left", True) 28 | plot.set_axis_direction("bottom", True) 29 | 30 | 31 | if __name__ == "__main__": 32 | test_plot_yreverse() 33 | -------------------------------------------------------------------------------- /plotpy/tests/features/test_resize.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Resize test: using the scaler C++ engine to resize images""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | 12 | from plotpy import io 13 | from plotpy.mathutils import scaler 14 | from plotpy.tests import get_path 15 | from plotpy.tests.widgets.test_rotatecrop import imshow 16 | 17 | 18 | def test_resize(): 19 | """Test""" 20 | with qt_app_context(exec_loop=False): 21 | filename = get_path("brain.png") 22 | data = io.imread(filename) 23 | dst_image = scaler.resize(data, (2000, 3000)) 24 | imshow(dst_image) 25 | 26 | 27 | if __name__ == "__main__": 28 | test_resize() 29 | -------------------------------------------------------------------------------- /plotpy/tests/items/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/tests/items/__init__.py -------------------------------------------------------------------------------- /plotpy/tests/items/test_annotations.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Annotation test""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | from numpy import linspace, sin 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import data as ptd 15 | from plotpy.tests import vistools as ptv 16 | 17 | 18 | def plot(*items, plot_type="auto"): 19 | title = "All annotation tools" 20 | if plot_type in ("curve", "image"): 21 | title = f"{plot_type.capitalize()} specialized plot annotation tools" 22 | win = ptv.show_items(items, plot_type=plot_type, wintitle=title, title=title) 23 | win.register_annotation_tools() 24 | return win 25 | 26 | 27 | def test_annotation(): 28 | """Test annotation""" 29 | x = linspace(-10, 10, 200) 30 | y = sin(sin(sin(x))) 31 | persist = [] 32 | with qt_app_context(exec_loop=True): 33 | persist.append(plot(make.curve(x, y, color="b"), plot_type="curve")) 34 | item = make.image(ptd.gen_image1()) 35 | item.set_readonly(True) 36 | item.set_selectable(False) 37 | persist.append(plot(item, plot_type="image")) 38 | persist.append(plot(make.curve(x, y, color="b"), make.image(ptd.gen_image1()))) 39 | 40 | 41 | if __name__ == "__main__": 42 | test_annotation() 43 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_curves.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Curve plotting test""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_plot(): 18 | """Curve plotting test""" 19 | x = np.linspace(-10, 10, 200) 20 | dy = x / 100.0 21 | y = np.sin(np.sin(np.sin(x))) 22 | x2 = np.linspace(-10, 10, 20) 23 | y2 = np.sin(np.sin(np.sin(x2))) 24 | with qt_app_context(exec_loop=True): 25 | items = [ 26 | make.curve(x, y, color="b"), 27 | make.curve(x2, y2, color="g", curvestyle="Sticks", title="toto"), 28 | make.curve(x, np.sin(2 * y), color="r"), 29 | make.merror(x, y / 2, dy), 30 | make.label( 31 | "Relative position outside", (x[0], y[0]), (-10, -10), "BR" 32 | ), 33 | make.label("Relative position inside", (x[0], y[0]), (10, 10), "TL"), 34 | make.label("Absolute position", "R", (0, 0), "R"), 35 | make.legend("TR"), 36 | make.marker( 37 | position=(5.0, 0.8), 38 | label_cb=lambda x, y: "A = %.2f" % x, 39 | markerstyle="|", 40 | movable=False, 41 | ), 42 | ] 43 | _win = ptv.show_items( 44 | items, wintitle=test_plot.__doc__, title="Curves", plot_type="curve" 45 | ) 46 | 47 | 48 | if __name__ == "__main__": 49 | test_plot() 50 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_curves_highdpi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Curve plotting test with high DPI""" 7 | 8 | # guitest: show,skip 9 | 10 | import os 11 | 12 | import numpy as np 13 | import pytest 14 | from guidata.qthelpers import qt_app_context 15 | 16 | from plotpy.builder import make 17 | from plotpy.tests import vistools as ptv 18 | 19 | 20 | @pytest.mark.skip(reason="This test is not relevant for the automated test suite") 21 | def test_plot_highdpi(): 22 | """Curve plotting test with high DPI""" 23 | 24 | # When setting the QT_SCALE_FACTOR to "2", performance is degraded, due to the 25 | # increased number of points to be drawn. As a workaround, we use the downsampling 26 | # feature to reduce the number of points to be drawn. 27 | # We also enable the antialiasing feature to improve the rendering of the curves, 28 | # which is also affected by the high DPI setting. 29 | # See https://github.com/PlotPyStack/PlotPy/issues/10 30 | os.environ["QT_SCALE_FACTOR"] = "2" 31 | 32 | npoints = 5000000 # 5M points are needed to see the difference 33 | dsamp_factor = npoints // 50000 # Max 50000 points to be drawn 34 | x = np.linspace(-10, 10, npoints) 35 | y = np.sin(np.sin(np.sin(x))) 36 | with qt_app_context(exec_loop=True): 37 | _win = ptv.show_items( 38 | [ 39 | make.curve(x, y, color="b", dsamp_factor=dsamp_factor, use_dsamp=True), 40 | make.legend("TR"), 41 | ], 42 | curve_antialiasing=True, 43 | wintitle=test_plot_highdpi.__doc__, 44 | title="Curves with high DPI", 45 | plot_type="curve", 46 | ) 47 | 48 | 49 | if __name__ == "__main__": 50 | test_plot_highdpi() 51 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_histogram.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Histogram test""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | from numpy.random import normal 12 | 13 | from plotpy.builder import make 14 | 15 | 16 | def test_histogram(): 17 | """Test""" 18 | with qt_app_context(exec_loop=True): 19 | data = normal(0, 1, (2000,)) 20 | win = make.dialog( 21 | edit=False, 22 | toolbar=True, 23 | wintitle="Histogram test", 24 | type="curve", 25 | ) 26 | plot = win.manager.get_plot() 27 | plot.add_item(make.histogram(data)) 28 | win.show() 29 | 30 | 31 | if __name__ == "__main__": 32 | test_histogram() 33 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_image.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Test showing an image""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | 12 | from plotpy.builder import make 13 | from plotpy.tests import data as ptd 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_image(): 18 | """Testing ImageItem object""" 19 | for index, func in enumerate((ptd.gen_image1, ptd.gen_image2, ptd.gen_image3)): 20 | title = test_image.__doc__ + f" #{index+1}" 21 | data = func() 22 | with qt_app_context(exec_loop=True): 23 | _win = ptv.show_items([make.image(data)], wintitle=title) 24 | 25 | 26 | if __name__ == "__main__": 27 | test_image() 28 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_image_contour.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Contour test""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import vistools as ptv 15 | from plotpy.tests.data import gen_xyz_data 16 | 17 | 18 | def test_contour(): 19 | """Contour plotting test""" 20 | with qt_app_context(exec_loop=True): 21 | _x, _y, z = gen_xyz_data() 22 | _win = ptv.show_items( 23 | [make.image(z)] + make.contours(z, np.arange(-2, 2, 0.5)), 24 | wintitle=test_contour.__doc__, 25 | curve_antialiasing=False, 26 | lock_aspect_ratio=True, 27 | ) 28 | 29 | 30 | if __name__ == "__main__": 31 | test_contour() 32 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_image_masked.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ 7 | Masked Image test, creating the MaskedImageItem object via make.maskedimage 8 | 9 | Masked image items are constructed using a masked array item. Masked data is 10 | ignored in computations, like the average cross sections. 11 | """ 12 | 13 | # guitest: show 14 | 15 | from __future__ import annotations 16 | 17 | import os.path as osp 18 | 19 | from plotpy.builder import make 20 | from plotpy.tests import get_path 21 | from plotpy.tests.features.test_loadsaveitems_pickle import PickleTest 22 | 23 | 24 | class MaskedImageTest(PickleTest): 25 | """Test class for MaskedImageItem tests""" 26 | 27 | FNAME = f"{osp.splitext(osp.basename(__file__))[0]}.pickle" 28 | IMAGE_FN = get_path("brain.png") 29 | 30 | def build_items(self) -> list: 31 | """Build items""" 32 | image = make.maskedimage( 33 | filename=self.IMAGE_FN, 34 | colormap="gray", 35 | show_mask=True, 36 | xdata=[0, 20], 37 | ydata=[0, 25], 38 | ) 39 | return [image] 40 | 41 | 42 | def test_image_masked(): 43 | """Test MaskedImageItem""" 44 | test = MaskedImageTest("MaskedImageItem test") 45 | test.run() 46 | 47 | 48 | if __name__ == "__main__": 49 | test_image_masked() 50 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_image_masked_xy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ 7 | Masked Image test, creating the MaskedXYImageItem object via make.maskedxyimage 8 | 9 | Masked image XY items are constructed using a masked array item. Masked data is 10 | ignored in computations, like the average cross sections. 11 | """ 12 | 13 | # guitest: show 14 | 15 | from __future__ import annotations 16 | 17 | from plotpy import io 18 | from plotpy.builder import make 19 | from plotpy.tests.items.test_image_masked import MaskedImageTest 20 | 21 | 22 | class XYMaskedImageTest(MaskedImageTest): 23 | """XYMaskedImageItem test class""" 24 | 25 | def build_items(self) -> list: 26 | """Build items""" 27 | data = io.imread(self.IMAGE_FN, to_grayscale=True) 28 | x = [0] 29 | delta = 1 30 | for x_val in range(data.shape[0] - 1): 31 | delta = delta + 0.1 32 | x.append(x[-1] + delta) 33 | y = [0] 34 | for y_val in range(data.shape[1] - 1): 35 | delta = delta + 0.1 36 | y.append(y[-1] + delta) 37 | image = make.maskedimage(data=data, colormap="gray", show_mask=True, x=x, y=y) 38 | return [image] 39 | 40 | 41 | def test_image_masked_xy(): 42 | """Test MaskedImageItem""" 43 | test = XYMaskedImageTest("MaskedImageItem test") 44 | test.run() 45 | 46 | 47 | if __name__ == "__main__": 48 | test_image_masked_xy() 49 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_image_rgb.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """RGB Image test, creating the RGBImageItem object via make.rgbimage""" 7 | 8 | # guitest: show 9 | 10 | from guidata.configtools import get_image_file_path 11 | from guidata.qthelpers import qt_app_context 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_image_rgb(): 18 | """Testing RGB image item""" 19 | with qt_app_context(exec_loop=True): 20 | item = make.rgbimage( 21 | filename=get_image_file_path("image.png"), xdata=[-1, 1], ydata=[-1, 1] 22 | ) 23 | _wn = ptv.show_items([item], plot_type="image", wintitle=test_image_rgb.__doc__) 24 | 25 | 26 | if __name__ == "__main__": 27 | test_image_rgb() 28 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_image_xy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Image with custom X/Y axes linear scales""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | 12 | from plotpy.builder import make 13 | from plotpy.tests import data as ptd 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_imagexy(): 18 | """Testing XYImageItem""" 19 | with qt_app_context(exec_loop=True): 20 | x, y, data = ptd.gen_xyimage() 21 | _win = ptv.show_items( 22 | [make.xyimage(x, y, data)], 23 | plot_type="image", 24 | xlabel="x (a.u.)", 25 | ylabel="y (a.u.)", 26 | wintitle=test_imagexy.__doc__, 27 | ) 28 | 29 | 30 | if __name__ == "__main__": 31 | test_imagexy() 32 | -------------------------------------------------------------------------------- /plotpy/tests/items/test_svgshapes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Test showing SVG shapes""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | 12 | from plotpy.builder import make 13 | from plotpy.tests import get_path 14 | from plotpy.tests import vistools as ptv 15 | 16 | 17 | def test_svg(): 18 | """Test showing SVG shapes""" 19 | with qt_app_context(exec_loop=True): 20 | path1, path2 = get_path("svg_tool.svg"), get_path("svg_target.svg") 21 | csvg = make.svg("circle", path2, 0, 0, 100, 100, "Circle") 22 | rsvg = make.svg("rectangle", path1, 150, 0, 200, 100, "Rect") 23 | ssvg = make.svg("square", path1, 0, 150, 100, 250, "Square") 24 | items = [csvg, rsvg, ssvg] 25 | _win = ptv.show_items(items, wintitle=test_svg.__doc__, lock_aspect_ratio=True) 26 | 27 | 28 | if __name__ == "__main__": 29 | test_svg() 30 | -------------------------------------------------------------------------------- /plotpy/tests/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/tests/tools/__init__.py -------------------------------------------------------------------------------- /plotpy/tests/tools/test_actiontool.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ActionTool test""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import create_action, qt_app_context 11 | from qtpy import QtWidgets as QW 12 | 13 | from plotpy.builder import make 14 | from plotpy.items import ImageItem 15 | from plotpy.plot import PlotDialog, PlotOptions 16 | from plotpy.tests.data import gen_image4 17 | from plotpy.tools import ActionTool 18 | 19 | 20 | class MyPlotDialog(PlotDialog): 21 | def __init__(self): 22 | """Reimplement PlotDialog method""" 23 | super().__init__( 24 | title="ActionTool test", toolbar=True, options=PlotOptions(type="image") 25 | ) 26 | self.info_action = create_action(self, "Show infos", triggered=self.show_info) 27 | self.manager.add_tool(ActionTool, self.info_action, item_types=(ImageItem,)) 28 | 29 | def show_info(self): 30 | """Show infos on selected item(s)""" 31 | # This is just a demo of what can be done with ActionTool 32 | plot = self.get_plot() 33 | for item in plot.get_selected_items(): 34 | QW.QMessageBox.information(self, "Item infos", str(item)) 35 | 36 | 37 | def test_image_plot_tools(): 38 | """Test""" 39 | with qt_app_context(exec_loop=True): 40 | win = MyPlotDialog() 41 | win.show() 42 | image = make.image(gen_image4(500, 500), colormap="Spectral") 43 | plot = win.manager.get_plot() 44 | plot.add_item(image) 45 | 46 | 47 | if __name__ == "__main__": 48 | test_image_plot_tools() 49 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_cross_section.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Renders a cross section chosen by a cross marker""" 7 | 8 | # guitest: show 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | 13 | from plotpy.builder import make 14 | from plotpy.tests import get_path 15 | 16 | 17 | def create_window(): 18 | win = make.dialog( 19 | edit=False, 20 | toolbar=True, 21 | wintitle="Cross sections test", 22 | show_xsection=True, 23 | show_ysection=True, 24 | type="image", 25 | size=(640, 600), 26 | ) 27 | return win 28 | 29 | 30 | def test_cross_section(): 31 | """Test cross section""" 32 | with qt_app_context(exec_loop=True): 33 | filename = get_path("brain.png") 34 | win = create_window() 35 | win.show() 36 | image = make.image(filename=filename, colormap="bone") 37 | data2 = np.array(image.data.T[200:], copy=True) 38 | image2 = make.image(data2, title="Modified", alpha_function="linear") 39 | plot = win.manager.get_plot() 40 | plot.add_item(image) 41 | plot.add_item(image2, z=1) 42 | 43 | 44 | if __name__ == "__main__": 45 | test_cross_section() 46 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_cross_section_oblique.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Oblique averaged cross section test""" 7 | 8 | # guitest: show 9 | 10 | from __future__ import annotations 11 | 12 | from plotpy.panels.csection.csitem import ObliqueCrossSectionItem 13 | from plotpy.panels.csection.cswidget import ObliqueCrossSection 14 | from plotpy.tests.tools import test_cross_section_line 15 | from plotpy.tools import ImageMaskTool, ObliqueCrossSectionTool, OCSPanelTool 16 | 17 | # debug mode shows the ROI in the top-left corner of the image plot: 18 | ObliqueCrossSectionItem.DEBUG = False 19 | 20 | 21 | class OCSImageDialog(test_cross_section_line.BaseCSImageDialog): 22 | """Oblique averaged cross section test""" 23 | 24 | TOOLCLASSES = (ObliqueCrossSectionTool, OCSPanelTool, ImageMaskTool) 25 | PANELCLASS = ObliqueCrossSection 26 | 27 | 28 | def test_cross_section_oblique(): 29 | """Test cross section oblique""" 30 | test_cross_section_line.generic_cross_section_dialog( 31 | "Oblique averaged cross section test", OCSImageDialog 32 | ) 33 | 34 | 35 | if __name__ == "__main__": 36 | test_cross_section_oblique() 37 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_customize_shape_tool.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Shows how to customize a shape created with a tool like RectangleTool""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import qt_app_context 11 | 12 | from plotpy.builder import make 13 | from plotpy.constants import LUTAlpha 14 | from plotpy.styles import style_generator, update_style_attr 15 | from plotpy.tests import get_path 16 | from plotpy.tools import ( 17 | EllipseTool, 18 | MultiLineTool, 19 | PolygonTool, 20 | RectangleTool, 21 | SegmentTool, 22 | ) 23 | 24 | STYLE = style_generator() 25 | 26 | 27 | def customize_shape(shape): 28 | global STYLE 29 | param = shape.shapeparam 30 | style = next(STYLE) 31 | update_style_attr(style, param) 32 | param.update_item(shape) 33 | shape.plot().replot() 34 | 35 | 36 | def create_window(): 37 | gridparam = make.gridparam( 38 | background="black", minor_enabled=(False, False), major_style=(".", "gray", 1) 39 | ) 40 | win = make.dialog( 41 | edit=False, 42 | toolbar=True, 43 | wintitle="All image and plot tools test", 44 | gridparam=gridparam, 45 | type="image", 46 | size=(800, 600), 47 | ) 48 | for toolklass in ( 49 | RectangleTool, 50 | EllipseTool, 51 | SegmentTool, 52 | MultiLineTool, 53 | PolygonTool, 54 | ): 55 | win.manager.add_tool(toolklass, handle_final_shape_cb=customize_shape) 56 | return win 57 | 58 | 59 | def test_customize_shape_tool(): 60 | """Test""" 61 | with qt_app_context(exec_loop=True): 62 | filename = get_path("brain.png") 63 | win = create_window() 64 | image = make.image( 65 | filename=filename, colormap="bone", alpha_function=LUTAlpha.LINEAR 66 | ) 67 | plot = win.manager.get_plot() 68 | plot.add_item(image) 69 | win.show() 70 | 71 | 72 | if __name__ == "__main__": 73 | test_customize_shape_tool() 74 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_cyclic_import.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Test cyclic import issue""" 7 | 8 | # pylint: disable=import-outside-toplevel 9 | # pylint: disable=unused-import 10 | 11 | 12 | def test_tools_cyclic_import(): 13 | """Test cyclic import issue""" 14 | # Importing one tool from each module to check if there is a cyclic import issue 15 | from plotpy.tools import ( 16 | AnnotatedPointTool, # noqa: F401 17 | AverageCrossSectionTool, # noqa: F401 18 | CurveStatsTool, # noqa: F401 19 | DoAutoscaleTool, # noqa: F401 20 | ItemCenterTool, # noqa: F401 21 | OpenImageTool, # noqa: F401 22 | PointTool, # noqa: F401 23 | PrintTool, # noqa: F401 24 | RectangularActionTool, # noqa: F401 25 | SelectTool, # noqa: F401 26 | ) 27 | 28 | 29 | if __name__ == "__main__": 30 | test_tools_cyclic_import() 31 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_downsample_curve.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ 7 | DownSampleCurveTool test 8 | 9 | This plotpy tool provides a toggle to downsample the current curve with a given factor. 10 | """ 11 | 12 | # guitest: show 13 | 14 | from __future__ import annotations 15 | 16 | from guidata.qthelpers import exec_dialog, qt_app_context 17 | from numpy import linspace, sin 18 | 19 | from plotpy.builder import make 20 | from plotpy.config import _ 21 | 22 | 23 | def edit_downsampled_curve( 24 | cdata: tuple[tuple[float, float], ...], dsamp_factor: int 25 | ) -> None: 26 | """ 27 | Plot curves and return selected point(s) coordinates 28 | 29 | Args: 30 | cdata: tuple of curves to plot 31 | dsamp_factor: downsampling factor 32 | """ 33 | win = make.dialog( 34 | wintitle=_("Right-click on the curve to enable/disable downsampling"), 35 | edit=True, 36 | type="curve", 37 | size=(800, 600), 38 | ) 39 | plot = win.manager.get_plot() 40 | for cx, cy in cdata[:-1]: 41 | item = make.mcurve(cx, cy) 42 | plot.add_item(item) 43 | item = make.mcurve(*cdata[-1], "r-+", dsamp_factor=dsamp_factor, use_dsamp=True) 44 | plot.add_item(item) 45 | plot.set_active_item(item) 46 | plot.unselect_item(item) 47 | exec_dialog(win) 48 | 49 | 50 | def test_edit_curve(): 51 | """Test""" 52 | with qt_app_context(exec_loop=False): 53 | nlines = 1000 54 | x = linspace(-10, 10, num=nlines) 55 | y = 0.25 * sin(sin(sin(x * 0.5))) 56 | x2 = linspace(-10, 10, num=nlines) 57 | y2 = sin(sin(sin(x2))) 58 | cdata = ((x, y), (x2, y2), (x, sin(2 * y))) 59 | for dsamp_factor in (10, 50): 60 | edit_downsampled_curve(cdata, dsamp_factor) 61 | 62 | 63 | if __name__ == "__main__": 64 | test_edit_curve() 65 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_get_point.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ 7 | SelectPointTool test 8 | 9 | This plotpy tool provide a MATLAB-like "ginput" feature. 10 | """ 11 | 12 | # guitest: show 13 | 14 | from __future__ import annotations 15 | 16 | from guidata.qthelpers import exec_dialog, qt_app_context 17 | from numpy import linspace, sin 18 | 19 | from plotpy.builder import make 20 | from plotpy.config import _ 21 | from plotpy.tools import SelectPointTool 22 | 23 | 24 | def callback_function(tool: SelectPointTool) -> None: 25 | print("Current coordinates:", tool.get_coordinates()) 26 | 27 | 28 | def get_point(cdata: tuple[tuple[float, float], ...]) -> None: 29 | """ 30 | Plot curves and return selected point(s) coordinates 31 | 32 | Args: 33 | cdata: A tuple of curves to plot 34 | """ 35 | win = make.dialog( 36 | wintitle=_("Select one point then press OK to accept"), 37 | edit=True, 38 | type="curve", 39 | size=(800, 600), 40 | ) 41 | default = win.manager.add_tool( 42 | SelectPointTool, 43 | title="Test", 44 | on_active_item=True, 45 | mode="reuse", 46 | end_callback=callback_function, 47 | ) 48 | default.activate() 49 | plot = win.manager.get_plot() 50 | for cx, cy in cdata[:-1]: 51 | item = make.mcurve(cx, cy) 52 | plot.add_item(item) 53 | item = make.mcurve(*cdata[-1], "r-+") 54 | plot.add_item(item) 55 | plot.set_active_item(item) 56 | plot.unselect_item(item) 57 | exec_dialog(win) 58 | 59 | 60 | def test_get_point(): 61 | """Test""" 62 | with qt_app_context(exec_loop=False): 63 | x = linspace(-10, 10, 200) 64 | y = 0.25 * sin(sin(sin(x * 0.5))) 65 | x2 = linspace(-10, 10, 200) 66 | y2 = sin(sin(sin(x2))) 67 | get_point(((x, y), (x2, y2), (x, sin(2 * y)))) 68 | 69 | 70 | if __name__ == "__main__": 71 | test_get_point() 72 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_get_rectangle.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # For licensing and distribution details, please read carefully xgrid/__init__.py 4 | 5 | """ 6 | Get rectangular selection from image 7 | """ 8 | 9 | # guitest: show 10 | 11 | import numpy as np 12 | from guidata.env import execenv 13 | from guidata.qthelpers import qt_app_context 14 | 15 | from plotpy.builder import make 16 | from plotpy.tests.tools.test_get_segment import SEG_AXES_COORDS, PatchedSelectDialog 17 | from plotpy.tools import RectangleTool 18 | from plotpy.widgets.selectdialog import select_with_shape_tool 19 | 20 | 21 | def test_get_rectangle(): 22 | """Test get_rectangle""" 23 | with qt_app_context(): 24 | image = make.image(data=np.random.rand(200, 200), colormap="gray") 25 | shape = select_with_shape_tool( 26 | None, RectangleTool, image, "Test", tooldialogclass=PatchedSelectDialog 27 | ) 28 | if shape is not None: 29 | rect = shape.get_rect() 30 | if execenv.unattended: 31 | assert [round(i) for i in list(rect)] == SEG_AXES_COORDS 32 | elif rect is not None: 33 | print("Area:", rect) 34 | 35 | 36 | if __name__ == "__main__": 37 | test_get_rectangle() 38 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_get_rectangle_with_svg.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # For licensing and distribution details, please read carefully xgrid/__init__.py 4 | 5 | """ 6 | Get rectangular selection from image with SVG shape 7 | """ 8 | 9 | # guitest: show 10 | 11 | from guidata.env import execenv 12 | from guidata.qthelpers import qt_app_context 13 | 14 | from plotpy.builder import make 15 | from plotpy.tests import get_path 16 | from plotpy.tests.data import gen_image4 17 | from plotpy.tests.tools.test_get_segment import SEG_AXES_COORDS, PatchedSelectDialog 18 | from plotpy.tools import RectangularShapeTool 19 | from plotpy.widgets.selectdialog import select_with_shape_tool 20 | 21 | 22 | class SVGToolExample(RectangularShapeTool): 23 | """Tool to select a rectangular area and create a pattern from it""" 24 | 25 | TITLE = "Pattern selection tool" 26 | ICON = "your_icon.svg" 27 | AVOID_NULL_SHAPE = True 28 | SVG_FNAME = get_path("svg_tool.svg") 29 | 30 | def create_shape(self): 31 | """Create shape to be drawn""" 32 | with open(self.SVG_FNAME, "rb") as svg_file: 33 | svg_data = svg_file.read() 34 | shape = make.svg("rectangle", svg_data, 0, 0, 1, 1, "SVG") 35 | self.set_shape_style(shape) 36 | return shape, 0, 2 37 | 38 | 39 | def test_get_rectangle_with_svg(): 40 | """Test get_rectangle_with_svg""" 41 | with qt_app_context(): 42 | image = make.image(data=gen_image4(200, 200), colormap="gray") 43 | shape = select_with_shape_tool( 44 | None, SVGToolExample, image, "Test", tooldialogclass=PatchedSelectDialog 45 | ) 46 | if shape is not None: 47 | rect = shape.get_rect() 48 | if execenv.unattended: 49 | assert [round(i) for i in list(rect)] == SEG_AXES_COORDS 50 | elif rect is not None: 51 | print("Area:", rect) 52 | 53 | 54 | if __name__ == "__main__": 55 | test_get_rectangle_with_svg() 56 | -------------------------------------------------------------------------------- /plotpy/tests/tools/test_zaxislog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Z-axis log scale tool test""" 7 | 8 | # guitest: show 9 | 10 | from __future__ import annotations 11 | 12 | import numpy as np 13 | from guidata.qthelpers import qt_app_context, qt_wait 14 | 15 | from plotpy.builder import make 16 | from plotpy.plot import PlotDialog, PlotOptions 17 | from plotpy.tests.data import gen_2d_gaussian 18 | from plotpy.tools import ZAxisLogTool 19 | 20 | 21 | class MyPlotDialog(PlotDialog): 22 | def __init__(self) -> None: 23 | """Reimplement PlotDialog method""" 24 | super().__init__( 25 | title="Z-axis log scale tool test", 26 | toolbar=True, 27 | options=PlotOptions(type="image"), 28 | ) 29 | # No need to add the tools to the manager, they are automatically added 30 | # when the `register_curve_tools` or `register_image_tools` method is called 31 | self.setup_items() 32 | 33 | def setup_items(self) -> None: 34 | """Setup items""" 35 | plot = self.get_plot() 36 | data = gen_2d_gaussian(512, np.uint16) 37 | item = make.image(data, title="Image", colormap="plasma") 38 | plot.add_item(item) 39 | plot.set_active_item(item) 40 | item.unselect() 41 | 42 | 43 | def test_zaxislogtool() -> None: 44 | """Test the Z-axis log scale tool""" 45 | with qt_app_context(exec_loop=True): 46 | win = MyPlotDialog() 47 | win.show() 48 | tool = win.manager.get_tool(ZAxisLogTool) 49 | qt_wait(1, except_unattended=True) 50 | for _index in range(2): 51 | tool.activate() 52 | qt_wait(1, except_unattended=True) 53 | 54 | 55 | if __name__ == "__main__": 56 | test_zaxislogtool() 57 | -------------------------------------------------------------------------------- /plotpy/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/tests/unit/__init__.py -------------------------------------------------------------------------------- /plotpy/tests/unit/test_aspect_ratio_tool.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from guidata.qthelpers import exec_dialog, qt_app_context 4 | 5 | from plotpy.interfaces.items import IImageItemType 6 | from plotpy.tests.unit.utils import create_window 7 | from plotpy.tools import AspectRatioTool 8 | 9 | 10 | def test_aspect_ratio_tool(): 11 | """Test the aspect ratio tool.""" 12 | with qt_app_context(exec_loop=False): 13 | win, tool = create_window(AspectRatioTool, active_item_type=IImageItemType) 14 | plot = win.manager.get_plot() 15 | 16 | initial_aspect_ratio: float = plot.get_aspect_ratio() 17 | 18 | new_ratio = 0.5 19 | 20 | plot.set_aspect_ratio(new_ratio) 21 | tool.edit_aspect_ratio() 22 | assert plot.get_aspect_ratio() == new_ratio 23 | 24 | plot.set_aspect_ratio(initial_aspect_ratio) 25 | tool.edit_aspect_ratio() 26 | assert plot.get_aspect_ratio() == initial_aspect_ratio 27 | 28 | tool.lock_aspect_ratio(True) 29 | assert plot.lock_aspect_ratio is True 30 | tool.lock_aspect_ratio(False) 31 | assert plot.lock_aspect_ratio is False 32 | 33 | exec_dialog(win) 34 | 35 | 36 | if __name__ == "__main__": 37 | test_aspect_ratio_tool() 38 | -------------------------------------------------------------------------------- /plotpy/tests/unit/test_cursor_tools.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import numpy as np 6 | import pytest 7 | from guidata.qthelpers import exec_dialog, qt_app_context 8 | 9 | from plotpy.tests.unit.utils import ( 10 | create_window, 11 | drag_mouse, 12 | ) 13 | from plotpy.tools import ( 14 | HCursorTool, 15 | HRangeTool, 16 | VCursorTool, 17 | XCursorTool, 18 | ) 19 | 20 | if TYPE_CHECKING: 21 | from plotpy.tools.cursor import BaseCursorTool 22 | 23 | 24 | @pytest.mark.parametrize( 25 | "cursor_tool", [HCursorTool, VCursorTool, XCursorTool, HRangeTool] 26 | ) 27 | def test_cursor_tool(cursor_tool: type[BaseCursorTool]): 28 | """Test the cursor tools. by simulating a mouse drag and checking if the tool 29 | shape is created. 30 | 31 | Args: 32 | cursor_tool: Cursor tool class to test. 33 | """ 34 | with qt_app_context(): 35 | win, _tool = create_window(cursor_tool) 36 | win.show() 37 | plot = win.manager.get_plot() 38 | 39 | active_tool = win.manager.get_active_tool() 40 | assert isinstance(active_tool, cursor_tool) 41 | tool_shape_type = type(active_tool.create_shape()) 42 | assert tool_shape_type not in (type(item) for item in plot.get_items()) 43 | 44 | drag_mouse(win, np.array([0.5, 0.6, 0.7]), np.array([0.5, 0.6, 0.7])) 45 | assert tool_shape_type in (type(item) for item in plot.get_items()) 46 | 47 | exec_dialog(win) 48 | 49 | 50 | if __name__ == "__main__": 51 | for tool in (HCursorTool, VCursorTool, XCursorTool, HRangeTool): 52 | test_cursor_tool(tool) 53 | -------------------------------------------------------------------------------- /plotpy/tests/unit/test_fontparam.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """FontParam test""" 7 | 8 | from guidata.qthelpers import qt_app_context 9 | 10 | from plotpy.styles.base import FontParam 11 | 12 | 13 | def test_fontparam(): 14 | with qt_app_context(exec_loop=True): 15 | fp = FontParam() 16 | fp.edit() 17 | fp.edit() 18 | 19 | 20 | if __name__ == "__main__": 21 | test_fontparam() 22 | -------------------------------------------------------------------------------- /plotpy/tests/unit/test_line.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Internal test related to pcolor feature""" 7 | 8 | import numpy as np 9 | import pytest 10 | 11 | from plotpy._scaler import _line_test as line 12 | 13 | N = 10 14 | TEST_LINE_DATA = [(0, 0, 9, 9), (9, 9, 0, 0), (0, 5, 0, 9), (2, 5, 7, 5), (0, 1, 2, 9)] 15 | TEST_TRI_DATA = [(0, 1, 2, 9, 8, 7)] 16 | 17 | 18 | def print_tri(imin, imax): 19 | """Print triangle""" 20 | for i in range(N): 21 | for j in range(N): 22 | if j < imin[i] or j > imax[i]: 23 | print(".", end=" ") 24 | else: 25 | print("*", end=" ") 26 | print() 27 | 28 | 29 | @pytest.mark.parametrize("x0,y0,x1,y1", TEST_LINE_DATA) 30 | def test_line(x0, y0, x1, y1): 31 | """Test line""" 32 | print(x0, ",", y0, "->", x1, ",", y1) 33 | imin = np.full((N,), N, dtype=np.int32) 34 | imax = np.full((N,), 0, dtype=np.int32) 35 | print("imin:", repr(imin), imin.dtype) 36 | print("imax:", repr(imax), imax.dtype) 37 | line(x0, y0, x1, y1, N, imin, imax) 38 | print_tri(imin, imax) 39 | 40 | 41 | @pytest.mark.parametrize("x0,y0,x1,y1,x2,y2", TEST_TRI_DATA) 42 | def test_tri(x0, y0, x1, y1, x2, y2): 43 | """Test triangle""" 44 | print(x0, ",", y0, "->", x1, ",", y1) 45 | imin = np.full((N,), N, dtype=np.int32) 46 | imax = np.full((N,), 0, dtype=np.int32) 47 | imin[:] = N + 1 48 | imax[:] = -1 49 | line(x0, y0, x1, y1, N, imin, imax) 50 | line(x0, y0, x2, y2, N, imin, imax) 51 | line(x1, y1, x2, y2, N, imin, imax) 52 | print_tri(imin, imax) 53 | 54 | 55 | if __name__ == "__main__": 56 | test_tri(0, 1, 2, 9, 8, 7) 57 | test_line(0, 0, 9, 9) 58 | test_line(9, 9, 0, 0) 59 | test_line(0, 5, 0, 9) 60 | test_line(2, 5, 7, 5) 61 | test_line(0, 1, 2, 9) 62 | -------------------------------------------------------------------------------- /plotpy/tests/unit/test_line_cross_section_tool.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import numpy as np 4 | from guidata.qthelpers import exec_dialog, qt_app_context 5 | 6 | from plotpy.interfaces.items import IImageItemType 7 | from plotpy.panels.csection.cswidget import LineCrossSection 8 | from plotpy.tests.unit.utils import create_window, drag_mouse 9 | from plotpy.tools import LineCrossSectionTool 10 | 11 | 12 | def test_line_cross_section(): 13 | """Test the line cross section tool.""" 14 | with qt_app_context(exec_loop=False): 15 | win, _tool = create_window( 16 | LineCrossSectionTool, 17 | active_item_type=IImageItemType, 18 | panels=[LineCrossSection], 19 | ) 20 | n = 100 21 | drag_mouse(win, np.linspace(0.25, 0.75, n), np.linspace(0.25, 0.75, n)) 22 | exec_dialog(win) 23 | 24 | 25 | if __name__ == "__main__": 26 | test_line_cross_section() 27 | -------------------------------------------------------------------------------- /plotpy/tests/unit/test_oblique_cross_section_tool.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import numpy as np 4 | from guidata.qthelpers import exec_dialog, qt_app_context 5 | 6 | from plotpy.interfaces.items import IImageItemType 7 | from plotpy.panels.csection.cswidget import ObliqueCrossSection 8 | from plotpy.tests.unit.utils import create_window, drag_mouse 9 | from plotpy.tools import ObliqueCrossSectionTool 10 | 11 | 12 | def test_oblique_cross_section(): 13 | """Test the oblique cross section tool.""" 14 | with qt_app_context(exec_loop=False): 15 | win, _tool = create_window( 16 | ObliqueCrossSectionTool, 17 | active_item_type=IImageItemType, 18 | panels=[ObliqueCrossSection], 19 | ) 20 | n = 100 21 | drag_mouse(win, np.linspace(0.25, 0.75, n), np.linspace(0.25, 0.75, n)) 22 | 23 | exec_dialog(win) 24 | 25 | 26 | if __name__ == "__main__": 27 | test_oblique_cross_section() 28 | -------------------------------------------------------------------------------- /plotpy/tests/unit/test_seg_dist.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | import qtpy.QtCore as QC 4 | 5 | from plotpy.items.curve.base import seg_dist, seg_dist_v 6 | 7 | param_list = [ 8 | ((200, 100), (150, 196), (250, 180), 86), 9 | ((200, 100), (190, 196), (210, 180), 80), 10 | ((201, 105), (201, 196), (201, 180), 75), 11 | ] 12 | 13 | 14 | @pytest.mark.parametrize("point_1,point_2,point_3,output", param_list) 15 | def test_seg_dist(point_1, point_2, point_3, output): 16 | """ """ 17 | ret = seg_dist(QC.QPointF(*point_1), QC.QPointF(*point_2), QC.QPointF(*point_3)) 18 | assert int(ret) == output 19 | 20 | 21 | def test_seg_dist_v(): 22 | """Test de seg_dist_v""" 23 | a = (np.arange(10.0) ** 2).reshape(5, 2) 24 | ix, dist = seg_dist_v((2.1, 3.3), a[:-1, 0], a[:-1, 1], a[1:, 0], a[1:, 1]) 25 | assert ix == 0 26 | assert round(dist, 2) == 0.85 27 | 28 | 29 | if __name__ == "__main__": 30 | test_seg_dist_v() 31 | -------------------------------------------------------------------------------- /plotpy/tests/unit/test_tools_export.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Export tools unit tests""" 7 | 8 | from unittest.mock import patch 9 | 10 | import numpy as np 11 | from guidata.qthelpers import qt_app_context 12 | from qtpy import QtWidgets as QW 13 | 14 | from plotpy.builder import make 15 | from plotpy.tools.curve import export_curve_data 16 | 17 | 18 | def test_export_curve(tmpdir): 19 | """Test export of a curve""" 20 | x = np.linspace(-10, 10, 200) 21 | y = x + 1 22 | 23 | with qt_app_context(exec_loop=False): 24 | curve = make.curve(x, y, color="g") 25 | 26 | dest = tmpdir / "output.txt" 27 | with patch.object(QW.QFileDialog, "getSaveFileName") as gsf_mock: 28 | gsf_mock.return_value = (str(dest), "") 29 | export_curve_data(curve) 30 | 31 | assert dest.exists() 32 | data = dest.readlines() 33 | assert len(data) == 200 34 | for line in data: 35 | x, y = line.split(",") 36 | assert float(y) == float(x) + 1 37 | -------------------------------------------------------------------------------- /plotpy/tests/vistools.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Visualisation tools for plotpy tests""" 7 | 8 | from __future__ import annotations 9 | 10 | from typing import TYPE_CHECKING 11 | 12 | from plotpy.builder import make 13 | 14 | if TYPE_CHECKING: 15 | from plotpy.items import BaseImageItem, CurveItem 16 | from plotpy.plot import PlotDialog 17 | 18 | 19 | def show_items( 20 | items: list[CurveItem | BaseImageItem], 21 | plot_type: str = "auto", 22 | wintitle: str = "Plot items", 23 | title: str = "Title", 24 | xlabel: str = "X", 25 | ylabel: str = "Y", 26 | auto_tools: bool = True, 27 | lock_aspect_ratio: bool | None = None, 28 | curve_antialiasing: bool | None = None, 29 | show_itemlist: bool = True, 30 | show_contrast: bool = False, 31 | winsize: tuple[int, int] | None = None, 32 | ) -> PlotDialog: 33 | """Show plot items in a dialog box""" 34 | winsize = (640, 480) if winsize is None else winsize 35 | win = make.dialog( 36 | edit=False, 37 | toolbar=True, 38 | wintitle=wintitle, 39 | title=title, 40 | xlabel=xlabel, 41 | ylabel=ylabel, 42 | type=plot_type, 43 | auto_tools=auto_tools, 44 | lock_aspect_ratio=lock_aspect_ratio, 45 | curve_antialiasing=curve_antialiasing, 46 | show_itemlist=show_itemlist, 47 | show_contrast=show_contrast, 48 | size=winsize, 49 | ) 50 | plot = win.manager.get_plot() 51 | for item in items: 52 | plot.add_item(item) 53 | plot.set_items_readonly(False) 54 | win.show() 55 | return win 56 | -------------------------------------------------------------------------------- /plotpy/tests/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlotPyStack/PlotPy/f4c27a2bcba082086375a62391fccfb80859c0a4/plotpy/tests/widgets/__init__.py -------------------------------------------------------------------------------- /plotpy/tests/widgets/test_fliprotate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """Flip/rotate test""" 7 | 8 | # guitest: show 9 | 10 | from guidata.qthelpers import exec_dialog, qt_app_context 11 | from qtpy import QtWidgets as QW 12 | 13 | from plotpy.tests.widgets.test_rotatecrop import create_test_data, imshow 14 | from plotpy.tools import RotationCenterTool 15 | from plotpy.widgets.fliprotate import FlipRotateDialog, FlipRotateWidget 16 | 17 | 18 | def widget_test(fname): 19 | """Test the flip/rotate widget""" 20 | array0, item = create_test_data(fname) 21 | widget = FlipRotateWidget(None, toolbar=True) 22 | widget.transform.set_item(item) 23 | widget.set_parameters(-90, True, False) 24 | widget.show() 25 | return widget 26 | 27 | 28 | def dialog_test(fname): 29 | """Test the flip/rotate dialog with rotation point changeable""" 30 | array0, item = create_test_data(fname) 31 | dlg = FlipRotateDialog(None, toolbar=True) 32 | dlg.manager.add_tool( 33 | RotationCenterTool, 34 | rotation_center=False, 35 | rotation_point_move_with_shape=True, 36 | on_all_items=True, 37 | ) 38 | dlg.transform.set_item(item) 39 | if exec_dialog(dlg) == QW.QDialog.Accepted: 40 | array1 = dlg.transform.get_result() 41 | dlg1 = imshow(array0, title="array0") 42 | dlg2 = imshow(array1, title="array1") 43 | return dlg, dlg1, dlg2 44 | 45 | 46 | def test_flip_rotate(): 47 | """Test the flip/rotate widget and dialog""" 48 | persist_list = [] 49 | with qt_app_context(exec_loop=True): 50 | persist_list.append(widget_test("brain.png")) 51 | with qt_app_context(exec_loop=False): 52 | persist_list.append(dialog_test("brain.png")) 53 | 54 | 55 | if __name__ == "__main__": 56 | test_flip_rotate() 57 | -------------------------------------------------------------------------------- /plotpy/tests/widgets/test_qtdesigner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | # -*- coding: utf-8 -*- 7 | """ 8 | Testing plotpy QtDesigner plugins 9 | 10 | These plugins provide PlotWidget objects 11 | embedding in GUI layouts directly from QtDesigner. 12 | """ 13 | 14 | # guitest: show 15 | 16 | import os 17 | 18 | import pytest 19 | from guidata.qthelpers import qt_app_context 20 | 21 | from plotpy.builder import make 22 | from plotpy.tests import data as ptd 23 | 24 | try: 25 | from plotpy.widgets.qtdesigner import loadui 26 | except ImportError: 27 | # PySide6 known to fail 28 | pytest.skip( 29 | "PySide6 does not support QPyDesignerCustomWidgetPlugin", 30 | allow_module_level=True, 31 | ) 32 | 33 | FormClass = loadui(os.path.splitext(__file__)[0] + ".ui") 34 | 35 | 36 | class WindowTest(FormClass): 37 | def __init__(self, image_data): 38 | super().__init__() 39 | plot = self.imagewidget.plot 40 | plot.add_item(make.image(image_data)) 41 | self.setWindowTitle("QtDesigner plugins example") 42 | 43 | 44 | def test_qtdesigner(): 45 | with qt_app_context(exec_loop=True): 46 | form = WindowTest(ptd.gen_image4(200, 200)) 47 | form.show() 48 | 49 | 50 | if __name__ == "__main__": 51 | test_qtdesigner() 52 | -------------------------------------------------------------------------------- /plotpy/tests/widgets/test_qtdesigner.ui: -------------------------------------------------------------------------------- 1 | 2 | Dialog 3 | 4 | 5 | 6 | 0 7 | 0 8 | 500 9 | 800 10 | 11 | 12 | 13 | Dialog 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | PlotWidget 27 | QwtPlot 28 |
plotpy.plot.plotwidget
29 |
30 |
31 | 32 | 33 |
34 | -------------------------------------------------------------------------------- /plotpy/widgets/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /plotpy/widgets/about.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | about 4 | ===== 5 | 6 | """ 7 | 8 | from __future__ import annotations 9 | 10 | import guidata 11 | import qwt 12 | from guidata.configtools import get_icon 13 | from guidata.widgets import about as guidata_about 14 | from qtpy.QtCore import Qt 15 | from qtpy.QtWidgets import QMainWindow, QMessageBox 16 | 17 | import plotpy 18 | from plotpy.config import _ 19 | 20 | 21 | def get_python_libs_infos(addinfos: str = "") -> str: 22 | """Get Python and libraries information 23 | 24 | Args: 25 | addinfos: additional information to be displayed 26 | 27 | Returns: 28 | str: Python and libraries information 29 | """ 30 | if addinfos: 31 | addinfos = ", " + addinfos 32 | addinfos = f"PlotPy {plotpy.__version__}{addinfos}" 33 | return guidata_about.get_python_libs_infos(addinfos) 34 | 35 | 36 | def about(html: bool = True, copyright_only: bool = False) -> str: 37 | """Return text about this package 38 | 39 | Args: 40 | html: return html text. Defaults to True. 41 | copyright_only: if True, return only copyright 42 | 43 | Returns: 44 | str: text about this package 45 | """ 46 | info = guidata_about.AboutInfo( 47 | name="PlotPy", 48 | version=plotpy.__version__, 49 | description=_("Set of tools for curve and image plotting"), 50 | author="Pierre Raybaut", 51 | year=2016, 52 | organization="PlotPyStack", 53 | ) 54 | addinfos = f"guidata {guidata.__version__}, PythonQwt {qwt.__version__}" 55 | return info.about(html=html, copyright_only=copyright_only, addinfos=addinfos) 56 | 57 | 58 | def show_about_dialog() -> None: 59 | """Show ``plotpy`` about dialog""" 60 | win = QMainWindow(None) 61 | win.setAttribute(Qt.WA_DeleteOnClose) 62 | win.hide() 63 | win.setWindowIcon(get_icon("plotpy.svg")) 64 | QMessageBox.about(win, _("About") + " PlotPy", about(html=True)) 65 | win.close() 66 | -------------------------------------------------------------------------------- /plotpy/widgets/colormap/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Colormaps 5 | ========= 6 | 7 | The `colormap` module contains definition of common colormaps and tools 8 | to manipulate and create them. 9 | 10 | .. automodule:: plotpy.widgets.colormap.widget 11 | :members: 12 | .. automodule:: plotpy.widgets.colormap.editor 13 | :members: 14 | .. automodule:: plotpy.widgets.colormap.manager 15 | :members: 16 | """ 17 | -------------------------------------------------------------------------------- /qtdesigner/plotplugin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed under the terms of the BSD 3-Clause 4 | # (see plotpy/LICENSE for details) 5 | 6 | """ 7 | plotplugin 8 | ========== 9 | 10 | A plotpy plot widget plugin for Qt Designer 11 | """ 12 | from plotpy.widgets.qtdesigner import create_qtdesigner_plugin 13 | 14 | Plugin = create_qtdesigner_plugin( 15 | "plotpy", "plotpy.plot", "PlotWidget", icon="curve.png" 16 | ) 17 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Coverage 2 | Cython>=3.0 3 | NumPy>=1.17 4 | scikit-image>=0.18 5 | Pillow 6 | tifffile 7 | PyQt5 8 | PythonQwt>=0.12.1 9 | SciPy>=1.3 10 | guidata>=3.6.2 11 | pylint 12 | ruff 13 | pytest 14 | pytest-xvfb 15 | python-docs-theme 16 | sphinx 17 | myst_parser 18 | sphinx-copybutton 19 | sphinx_qt_documentation 20 | -------------------------------------------------------------------------------- /scripts/build-wheels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -u -x 3 | 4 | ARCH=$(uname -m) 5 | export PLAT=manylinux_2_24_$ARCH 6 | 7 | # Accurately check if Python version is 3.9 or greater 8 | function is_python_version_ge_39 { 9 | local pydir="$1" 10 | if [[ $pydir =~ cp([0-9]+)([0-9]+)-cp ]]; then 11 | local version="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" 12 | # Use sort with version sort flag to compare version against 3.9 13 | if [[ $(echo -e "3.9\n$version" | sort -V | head -n1) == "3.9" ]]; then 14 | return 0 # True, version is >= 3.9 15 | fi 16 | fi 17 | return 1 # False, version is < 3.9 18 | } 19 | 20 | # Compile wheels, only for CPython 3.9+ 21 | for PYDIR in /opt/python/*; do 22 | if is_python_version_ge_39 "$PYDIR"; then 23 | PYBIN="$PYDIR/bin" 24 | "${PYBIN}/pip" install -r /io/requirements.txt 25 | "${PYBIN}/pip" wheel /io/ --no-deps -w wheelhouse/ 26 | fi 27 | done 28 | 29 | # Bundle external shared libraries into the wheels 30 | for wheel in wheelhouse/*.whl; do 31 | if auditwheel show "$wheel"; then 32 | auditwheel repair "$wheel" --plat "$PLAT" -w /io/wheelhouse/ 33 | fi 34 | done 35 | 36 | # Install packages and test, only for CPython 3.9+ 37 | for PYDIR in /opt/python/*; do 38 | if is_python_version_ge_39 "$PYDIR"; then 39 | PYBIN="$PYDIR/bin" 40 | "${PYBIN}/pip" install plotpy --no-index -f /io/wheelhouse 41 | (cd "$HOME"; INSTDIR=$("${PYBIN}/python" -c "import plotpy, os.path as osp; print(osp.dirname(plotpy.__file__))"); export QT_QPA_PLATFORM=offscreen; "${PYBIN}/pytest" "$INSTDIR") 42 | fi 43 | done 44 | -------------------------------------------------------------------------------- /scripts/build_dist.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was copied from PythonQwt project 3 | REM ====================================================== 4 | REM Package build script 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | call %~dp0utils GetScriptPath SCRIPTPATH 11 | call %FUNC% GetLibName LIBNAME 12 | call %FUNC% GetModName MODNAME 13 | call %FUNC% SetPythonPath 14 | call %FUNC% UsePython 15 | if exist MANIFEST ( del /q MANIFEST ) 16 | %PYTHON% -m build 17 | rmdir /s /q %LIBNAME%.egg-info 18 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /scripts/build_doc.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was copied from PythonQwt project 3 | REM ====================================================== 4 | REM Documentation build script 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | call %FUNC% GetLibName LIBNAME 13 | call %FUNC% GetModName MODNAME 14 | call %FUNC% SetPythonPath 15 | call %FUNC% UsePython 16 | cd %SCRIPTPATH%\.. 17 | %PYTHON% doc\update_requirements.py 18 | sphinx-build -b html doc build\doc 19 | start build\doc\index.html 20 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /scripts/build_inplace.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was copied from PythonQwt project 3 | REM ====================================================== 4 | REM Package build script 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal enabledelayedexpansion 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | call %FUNC% GetModName MODNAME 13 | call %FUNC% SetPythonPath 14 | 15 | if exist MANIFEST ( del /q MANIFEST ) 16 | :: Iterate over all directories in the grandparent directory 17 | :: (WinPython base directories) 18 | call %FUNC% GetPythonExeGrandParentDir DIR0 19 | for /D %%d in ("%DIR0%*") do ( 20 | :: Get the directory name without the path 21 | for %%n in (%%d) do set "DIRNAME=%%~nxn" 22 | 23 | :: Check if the directory ends with "-PyQt6" or "-PySide6" 24 | if not "!DIRNAME:~-6!"=="-PyQt6" ( 25 | if not "!DIRNAME:~-8!"=="-PySide6" ( 26 | set WINPYDIRBASE=%%d 27 | call !WINPYDIRBASE!\scripts\env.bat 28 | echo ****************************************************************************** 29 | echo Building %MODNAME% from "%%d" 30 | echo ****************************************************************************** 31 | python setup.py build_ext --inplace 32 | echo ---- 33 | ) 34 | ) 35 | ) 36 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /scripts/build_wheels.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was copied from PythonQwt project 3 | REM ====================================================== 4 | REM Package build script 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal enabledelayedexpansion 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | call %FUNC% GetModName MODNAME 13 | call %FUNC% SetPythonPath 14 | 15 | if exist MANIFEST ( del /q MANIFEST ) 16 | :: Iterate over all directories in the grandparent directory 17 | :: (WinPython base directories) 18 | call %FUNC% GetPythonExeGrandParentDir DIR0 19 | for /D %%d in ("%DIR0%*") do ( 20 | :: Get the directory name without the path 21 | for %%n in (%%d) do set "DIRNAME=%%~nxn" 22 | 23 | :: Check if the directory ends with "-PyQt6" or "-PySide6" 24 | if not "!DIRNAME:~-6!"=="-PyQt6" ( 25 | if not "!DIRNAME:~-8!"=="-PySide6" ( 26 | set WINPYDIRBASE=%%d 27 | set OLD_PATH=!PATH! 28 | call !WINPYDIRBASE!\scripts\env.bat 29 | echo ****************************************************************************** 30 | echo Building %MODNAME% from "%%d" 31 | echo ****************************************************************************** 32 | python -m build 33 | echo ---- 34 | set PATH=!OLD_PATH! 35 | ) 36 | ) 37 | ) 38 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /scripts/clean_up.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was copied from PythonQwt project 3 | REM ====================================================== 4 | REM Clean up repository 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | call %~dp0utils GetScriptPath SCRIPTPATH 11 | call %FUNC% GetLibName LIBNAME 12 | call %FUNC% GetModName MODNAME 13 | cd %SCRIPTPATH%\..\ 14 | 15 | @REM Removing files/directories related to Python/doc build process 16 | if exist %LIBNAME%.egg-info ( rmdir /s /q %LIBNAME%.egg-info ) 17 | if exist %MODNAME%.egg-info ( rmdir /s /q %MODNAME%.egg-info ) 18 | if exist MANIFEST ( del /q MANIFEST ) 19 | if exist build ( rmdir /s /q build ) 20 | if exist dist ( rmdir /s /q dist ) 21 | if exist doc\_build ( rmdir /s /q doc\_build ) 22 | 23 | @REM Removing cache files/directories related to Python execution 24 | del /s /q *.pyc 1>nul 2>&1 25 | del /s /q *.pyo 1>nul 2>&1 26 | FOR /d /r %%d IN ("__pycache__") DO @IF EXIST "%%d" rd /s /q "%%d" 27 | 28 | @REM Removing directories related to public repository upload 29 | set TEMP=%SCRIPTPATH%\..\..\%LIBNAME%_temp 30 | set PUBLIC=%SCRIPTPATH%\..\..\%LIBNAME%_public 31 | if exist %TEMP% ( rmdir /s /q %TEMP% ) 32 | if exist %PUBLIC% ( rmdir /s /q %PUBLIC% ) 33 | 34 | @REM Removing files/directories related to Coverage 35 | if exist .coverage ( del /q .coverage ) 36 | if exist coverage.xml ( del /q coverage.xml ) 37 | if exist htmlcov ( rmdir /s /q htmlcov ) 38 | del /q .coverage.* 1>nul 2>&1 39 | if exist sitecustomize.py ( del /q sitecustomize.py ) 40 | -------------------------------------------------------------------------------- /scripts/display_cov.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | start "" "..\htmlcov\index.html" -------------------------------------------------------------------------------- /scripts/gettext.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was derived from PythonQwt project 3 | REM ====================================================== 4 | REM Run gettext translation tool 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | call %FUNC% SetPythonPath 13 | call %FUNC% UsePython 14 | call %FUNC% GetModName MODNAME 15 | %PYTHON% -c "from guidata.utils.gettext_helpers import do_%1; do_%1('%MODNAME%')" 16 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /scripts/run_coverage.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was derived from PythonQwt project 3 | REM ====================================================== 4 | REM Run coverage tests 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | call %FUNC% GetModName MODNAME 13 | call %FUNC% SetPythonPath 14 | call %FUNC% UsePython 15 | coverage run -m pytest 16 | coverage combine 17 | coverage html 18 | start .\htmlcov\index.html 19 | call %FUNC% EndOfScript 20 | -------------------------------------------------------------------------------- /scripts/run_pylint.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was derived from PythonQwt project 3 | REM ====================================================== 4 | REM Run pylint analysis 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | call %FUNC% GetModName MODNAME 13 | call %FUNC% SetPythonPath 14 | set PYLINT_ARG=%* 15 | if "%PYLINT_ARG%"=="" set PYLINT_ARG=--disable=fixme 16 | %PYTHON% -m pylint --rcfile=%SCRIPTPATH%\..\.pylintrc %PYLINT_ARG% %MODNAME% 17 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /scripts/run_pytest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was derived from PythonQwt project 3 | REM ====================================================== 4 | REM Run pytest script 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal enabledelayedexpansion 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | call %FUNC% GetModName MODNAME 13 | call %FUNC% SetPythonPath 14 | 15 | :: Iterate over all directories in the grandparent directory 16 | :: (WinPython base directories) 17 | call %FUNC% GetPythonExeGrandParentDir DIR0 18 | for /D %%d in ("%DIR0%*") do ( 19 | set WINPYDIRBASE=%%d 20 | call !WINPYDIRBASE!\scripts\env.bat 21 | echo Running pytest from "%%d": 22 | pytest --ff -q %MODNAME% 23 | echo ---- 24 | ) 25 | call %FUNC% EndOfScript 26 | -------------------------------------------------------------------------------- /scripts/run_ruff.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was derived from PythonQwt project 3 | REM ====================================================== 4 | REM Run Ruff analysis 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | call %FUNC% GetModName MODNAME 13 | call %FUNC% SetPythonPath 14 | call %FUNC% UsePython 15 | ruff check 16 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /scripts/upgrade_env.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was derived from PythonQwt project 3 | REM ====================================================== 4 | REM Upgrade environment 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal enabledelayedexpansion 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | cd %SCRIPTPATH%\.. 13 | 14 | :: Iterate over all directories in the grandparent directory 15 | :: (WinPython base directories) 16 | call %FUNC% GetPythonExeGrandParentDir DIR0 17 | for /D %%d in ("%DIR0%*") do ( 18 | set WINPYDIRBASE=%%d 19 | call !WINPYDIRBASE!\scripts\env.bat 20 | echo Upgrading environment for "%%d": 21 | python -m pip install --upgrade pip 22 | python -m pip install --upgrade -r requirements.txt 23 | echo ---- 24 | ) 25 | 26 | %PYTHON% -m pip list > dev\pip_list.txt 27 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /scripts/upgrade_stack.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This script was derived from PythonQwt project 3 | REM ====================================================== 4 | REM Upgrade environment, but only PlotPyStack packages 5 | REM ====================================================== 6 | REM Licensed under the terms of the MIT License 7 | REM Copyright (c) 2020 Pierre Raybaut 8 | REM (see PythonQwt LICENSE file for more details) 9 | REM ====================================================== 10 | setlocal enabledelayedexpansion 11 | call %~dp0utils GetScriptPath SCRIPTPATH 12 | cd %SCRIPTPATH%\.. 13 | 14 | :: Iterate over all directories in the grandparent directory 15 | :: (WinPython base directories) 16 | call %FUNC% GetPythonExeGrandParentDir DIR0 17 | for /D %%d in ("%DIR0%*") do ( 18 | set WINPYDIRBASE=%%d 19 | call !WINPYDIRBASE!\scripts\env.bat 20 | echo Upgrading environment for "%%d": 21 | python -m pip install --upgrade pip 22 | python -m pip install --upgrade PythonQwt guidata 23 | echo ---- 24 | ) 25 | 26 | %PYTHON% -m pip list > dev\pip_list.txt 27 | call %FUNC% EndOfScript -------------------------------------------------------------------------------- /src/debug.hpp: -------------------------------------------------------------------------------- 1 | /* -*- coding: utf-8;mode:c++;c-file-style:"stroustrup" -*- */ 2 | /* 3 | Licensed under the terms of the BSD 3-Clause 4 | (see plotpy/__init__.py for details) 5 | */ 6 | #ifndef __DEBUG_HPP__ 7 | #define __DEBUG_HPP__ 8 | 9 | #define DEBUG 0 10 | 11 | #if DEBUG 12 | 13 | #define check(msg, x, n, r) \ 14 | if (x < 0 || x >= n) \ 15 | { \ 16 | printf(msg "%d out of bound (%d)\n", x, n); \ 17 | return r; \ 18 | } 19 | #define check_img_ptr(msg, p, r, img) \ 20 | if (p < img.base || p > (img.base + (img.ni - 1) * img.si + (img.nj - 1) * img.sj)) \ 21 | { \ 22 | printf(msg "%p out of bound (%p,%dx%d, %dx%d\n", p, img.base, img.ni, img.si, img.nj, img.sj); \ 23 | return r; \ 24 | } 25 | 26 | #else 27 | 28 | #define check(msg, x, n, r) ; 29 | #define check_img_ptr(msg, p, r, img) ; 30 | 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/mandelbrot.pyx: -------------------------------------------------------------------------------- 1 | # cython: language_level=3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Licensed under the terms of the BSD 3-Clause 5 | # (see plotpy/__init__.py for details) 6 | 7 | """Mandelbrot algorithm""" 8 | 9 | cimport cython 10 | cimport numpy as np 11 | 12 | @cython.profile(False) 13 | cdef inline int mandel(double real, double imag, int nmax): 14 | cdef double z_real=0., z_imag=0. 15 | cdef int i 16 | for i in range(nmax): 17 | z_real, z_imag = (z_real*z_real - z_imag*z_imag + real, 18 | 2*z_real*z_imag + imag) 19 | if z_real*z_real + z_imag*z_imag > 4: 20 | return i 21 | return -1 22 | 23 | @cython.boundscheck(False) 24 | def mandelbrot(double x1, double y1, double x2, double y2, 25 | data, unsigned int nmax): 26 | """Compute Mandelbrot fractal""" 27 | cdef double dx, dy, real, imag 28 | cdef unsigned int row, col 29 | cdef unsigned int rows = data.shape[0] 30 | cdef unsigned int cols = data.shape[1] 31 | 32 | dx = (x2-x1)/(cols-1) 33 | dy = (y2-y1)/(rows-1) 34 | 35 | for col in range(cols): 36 | real = x1 + col*dx 37 | for row in range(rows): 38 | imag = y1 + row*dy 39 | data[row, col] = mandel(real, imag, nmax) 40 | --------------------------------------------------------------------------------