├── .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 |
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 |
--------------------------------------------------------------------------------