vispy 0.15.0__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of vispy might be problematic. Click here for more details.
- vispy/__init__.py +33 -0
- vispy/app/__init__.py +15 -0
- vispy/app/_default_app.py +76 -0
- vispy/app/_detect_eventloop.py +148 -0
- vispy/app/application.py +263 -0
- vispy/app/backends/__init__.py +52 -0
- vispy/app/backends/_egl.py +264 -0
- vispy/app/backends/_glfw.py +513 -0
- vispy/app/backends/_jupyter_rfb.py +278 -0
- vispy/app/backends/_offscreen_util.py +121 -0
- vispy/app/backends/_osmesa.py +235 -0
- vispy/app/backends/_pyglet.py +451 -0
- vispy/app/backends/_pyqt4.py +36 -0
- vispy/app/backends/_pyqt5.py +36 -0
- vispy/app/backends/_pyqt6.py +40 -0
- vispy/app/backends/_pyside.py +37 -0
- vispy/app/backends/_pyside2.py +52 -0
- vispy/app/backends/_pyside6.py +53 -0
- vispy/app/backends/_qt.py +1003 -0
- vispy/app/backends/_sdl2.py +444 -0
- vispy/app/backends/_template.py +244 -0
- vispy/app/backends/_test.py +8 -0
- vispy/app/backends/_tk.py +800 -0
- vispy/app/backends/_wx.py +476 -0
- vispy/app/backends/tests/__init__.py +0 -0
- vispy/app/backends/tests/test_offscreen_util.py +52 -0
- vispy/app/backends/tests/test_rfb.py +77 -0
- vispy/app/base.py +294 -0
- vispy/app/canvas.py +828 -0
- vispy/app/qt.py +92 -0
- vispy/app/tests/__init__.py +0 -0
- vispy/app/tests/qt-designer.ui +58 -0
- vispy/app/tests/test_app.py +442 -0
- vispy/app/tests/test_backends.py +164 -0
- vispy/app/tests/test_canvas.py +122 -0
- vispy/app/tests/test_context.py +92 -0
- vispy/app/tests/test_qt.py +47 -0
- vispy/app/tests/test_simultaneous.py +134 -0
- vispy/app/timer.py +174 -0
- vispy/color/__init__.py +17 -0
- vispy/color/_color_dict.py +193 -0
- vispy/color/color_array.py +447 -0
- vispy/color/color_space.py +181 -0
- vispy/color/colormap.py +1213 -0
- vispy/color/tests/__init__.py +0 -0
- vispy/color/tests/test_color.py +378 -0
- vispy/conftest.py +12 -0
- vispy/ext/__init__.py +0 -0
- vispy/ext/cocoapy.py +1522 -0
- vispy/ext/cubehelix.py +138 -0
- vispy/ext/egl.py +375 -0
- vispy/ext/fontconfig.py +118 -0
- vispy/ext/gdi32plus.py +206 -0
- vispy/ext/osmesa.py +105 -0
- vispy/geometry/__init__.py +23 -0
- vispy/geometry/_triangulation_debugger.py +171 -0
- vispy/geometry/calculations.py +162 -0
- vispy/geometry/curves.py +399 -0
- vispy/geometry/generation.py +643 -0
- vispy/geometry/isocurve.py +175 -0
- vispy/geometry/isosurface.py +465 -0
- vispy/geometry/meshdata.py +700 -0
- vispy/geometry/normals.py +78 -0
- vispy/geometry/parametric.py +56 -0
- vispy/geometry/polygon.py +137 -0
- vispy/geometry/rect.py +210 -0
- vispy/geometry/tests/__init__.py +0 -0
- vispy/geometry/tests/test_calculations.py +23 -0
- vispy/geometry/tests/test_generation.py +56 -0
- vispy/geometry/tests/test_meshdata.py +106 -0
- vispy/geometry/tests/test_triangulation.py +594 -0
- vispy/geometry/torusknot.py +142 -0
- vispy/geometry/triangulation.py +876 -0
- vispy/gloo/__init__.py +56 -0
- vispy/gloo/buffer.py +505 -0
- vispy/gloo/context.py +272 -0
- vispy/gloo/framebuffer.py +257 -0
- vispy/gloo/gl/__init__.py +234 -0
- vispy/gloo/gl/_constants.py +332 -0
- vispy/gloo/gl/_es2.py +986 -0
- vispy/gloo/gl/_gl2.py +1365 -0
- vispy/gloo/gl/_proxy.py +499 -0
- vispy/gloo/gl/_pyopengl2.py +362 -0
- vispy/gloo/gl/dummy.py +24 -0
- vispy/gloo/gl/es2.py +62 -0
- vispy/gloo/gl/gl2.py +98 -0
- vispy/gloo/gl/glplus.py +168 -0
- vispy/gloo/gl/pyopengl2.py +97 -0
- vispy/gloo/gl/tests/__init__.py +0 -0
- vispy/gloo/gl/tests/test_basics.py +282 -0
- vispy/gloo/gl/tests/test_functionality.py +568 -0
- vispy/gloo/gl/tests/test_names.py +246 -0
- vispy/gloo/gl/tests/test_use.py +71 -0
- vispy/gloo/glir.py +1824 -0
- vispy/gloo/globject.py +101 -0
- vispy/gloo/preprocessor.py +67 -0
- vispy/gloo/program.py +543 -0
- vispy/gloo/tests/__init__.py +0 -0
- vispy/gloo/tests/test_buffer.py +558 -0
- vispy/gloo/tests/test_context.py +119 -0
- vispy/gloo/tests/test_framebuffer.py +195 -0
- vispy/gloo/tests/test_glir.py +307 -0
- vispy/gloo/tests/test_globject.py +35 -0
- vispy/gloo/tests/test_program.py +302 -0
- vispy/gloo/tests/test_texture.py +732 -0
- vispy/gloo/tests/test_use_gloo.py +187 -0
- vispy/gloo/tests/test_util.py +60 -0
- vispy/gloo/tests/test_wrappers.py +261 -0
- vispy/gloo/texture.py +1046 -0
- vispy/gloo/util.py +129 -0
- vispy/gloo/wrappers.py +762 -0
- vispy/glsl/__init__.py +42 -0
- vispy/glsl/antialias/antialias.glsl +7 -0
- vispy/glsl/antialias/cap-butt.glsl +31 -0
- vispy/glsl/antialias/cap-round.glsl +29 -0
- vispy/glsl/antialias/cap-square.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
- vispy/glsl/antialias/cap.glsl +67 -0
- vispy/glsl/antialias/caps.glsl +67 -0
- vispy/glsl/antialias/filled.glsl +50 -0
- vispy/glsl/antialias/outline.glsl +40 -0
- vispy/glsl/antialias/stroke.glsl +43 -0
- vispy/glsl/arrowheads/angle.glsl +99 -0
- vispy/glsl/arrowheads/arrowheads.frag +60 -0
- vispy/glsl/arrowheads/arrowheads.glsl +12 -0
- vispy/glsl/arrowheads/arrowheads.vert +83 -0
- vispy/glsl/arrowheads/curved.glsl +48 -0
- vispy/glsl/arrowheads/inhibitor.glsl +26 -0
- vispy/glsl/arrowheads/stealth.glsl +46 -0
- vispy/glsl/arrowheads/triangle.glsl +97 -0
- vispy/glsl/arrowheads/util.glsl +13 -0
- vispy/glsl/arrows/angle-30.glsl +12 -0
- vispy/glsl/arrows/angle-60.glsl +12 -0
- vispy/glsl/arrows/angle-90.glsl +12 -0
- vispy/glsl/arrows/arrow.frag +39 -0
- vispy/glsl/arrows/arrow.vert +49 -0
- vispy/glsl/arrows/arrows.glsl +17 -0
- vispy/glsl/arrows/common.glsl +187 -0
- vispy/glsl/arrows/curved.glsl +63 -0
- vispy/glsl/arrows/stealth.glsl +50 -0
- vispy/glsl/arrows/triangle-30.glsl +12 -0
- vispy/glsl/arrows/triangle-60.glsl +12 -0
- vispy/glsl/arrows/triangle-90.glsl +12 -0
- vispy/glsl/arrows/util.glsl +98 -0
- vispy/glsl/build_spatial_filters.py +660 -0
- vispy/glsl/collections/agg-fast-path.frag +20 -0
- vispy/glsl/collections/agg-fast-path.vert +78 -0
- vispy/glsl/collections/agg-glyph.frag +60 -0
- vispy/glsl/collections/agg-glyph.vert +33 -0
- vispy/glsl/collections/agg-marker.frag +35 -0
- vispy/glsl/collections/agg-marker.vert +48 -0
- vispy/glsl/collections/agg-path.frag +55 -0
- vispy/glsl/collections/agg-path.vert +166 -0
- vispy/glsl/collections/agg-point.frag +21 -0
- vispy/glsl/collections/agg-point.vert +35 -0
- vispy/glsl/collections/agg-segment.frag +32 -0
- vispy/glsl/collections/agg-segment.vert +75 -0
- vispy/glsl/collections/marker.frag +38 -0
- vispy/glsl/collections/marker.vert +48 -0
- vispy/glsl/collections/raw-path.frag +15 -0
- vispy/glsl/collections/raw-path.vert +24 -0
- vispy/glsl/collections/raw-point.frag +14 -0
- vispy/glsl/collections/raw-point.vert +31 -0
- vispy/glsl/collections/raw-segment.frag +18 -0
- vispy/glsl/collections/raw-segment.vert +26 -0
- vispy/glsl/collections/raw-triangle.frag +13 -0
- vispy/glsl/collections/raw-triangle.vert +26 -0
- vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
- vispy/glsl/collections/sdf-glyph.frag +80 -0
- vispy/glsl/collections/sdf-glyph.vert +59 -0
- vispy/glsl/collections/tick-labels.vert +71 -0
- vispy/glsl/colormaps/autumn.glsl +20 -0
- vispy/glsl/colormaps/blues.glsl +20 -0
- vispy/glsl/colormaps/color-space.glsl +17 -0
- vispy/glsl/colormaps/colormaps.glsl +24 -0
- vispy/glsl/colormaps/cool.glsl +20 -0
- vispy/glsl/colormaps/fire.glsl +21 -0
- vispy/glsl/colormaps/gray.glsl +20 -0
- vispy/glsl/colormaps/greens.glsl +20 -0
- vispy/glsl/colormaps/hot.glsl +22 -0
- vispy/glsl/colormaps/ice.glsl +20 -0
- vispy/glsl/colormaps/icefire.glsl +23 -0
- vispy/glsl/colormaps/parse.py +40 -0
- vispy/glsl/colormaps/reds.glsl +20 -0
- vispy/glsl/colormaps/spring.glsl +20 -0
- vispy/glsl/colormaps/summer.glsl +20 -0
- vispy/glsl/colormaps/user.glsl +22 -0
- vispy/glsl/colormaps/util.glsl +41 -0
- vispy/glsl/colormaps/wheel.glsl +21 -0
- vispy/glsl/colormaps/winter.glsl +20 -0
- vispy/glsl/lines/agg.frag +320 -0
- vispy/glsl/lines/agg.vert +241 -0
- vispy/glsl/markers/arrow.glsl +12 -0
- vispy/glsl/markers/asterisk.glsl +16 -0
- vispy/glsl/markers/chevron.glsl +14 -0
- vispy/glsl/markers/clover.glsl +20 -0
- vispy/glsl/markers/club.glsl +31 -0
- vispy/glsl/markers/cross.glsl +17 -0
- vispy/glsl/markers/diamond.glsl +12 -0
- vispy/glsl/markers/disc.glsl +9 -0
- vispy/glsl/markers/ellipse.glsl +67 -0
- vispy/glsl/markers/hbar.glsl +9 -0
- vispy/glsl/markers/heart.glsl +15 -0
- vispy/glsl/markers/infinity.glsl +15 -0
- vispy/glsl/markers/marker-sdf.frag +74 -0
- vispy/glsl/markers/marker-sdf.vert +41 -0
- vispy/glsl/markers/marker.frag +36 -0
- vispy/glsl/markers/marker.vert +46 -0
- vispy/glsl/markers/markers.glsl +24 -0
- vispy/glsl/markers/pin.glsl +18 -0
- vispy/glsl/markers/ring.glsl +11 -0
- vispy/glsl/markers/spade.glsl +28 -0
- vispy/glsl/markers/square.glsl +10 -0
- vispy/glsl/markers/tag.glsl +11 -0
- vispy/glsl/markers/triangle.glsl +14 -0
- vispy/glsl/markers/vbar.glsl +9 -0
- vispy/glsl/math/circle-through-2-points.glsl +30 -0
- vispy/glsl/math/constants.glsl +48 -0
- vispy/glsl/math/double.glsl +114 -0
- vispy/glsl/math/functions.glsl +20 -0
- vispy/glsl/math/point-to-line-distance.glsl +31 -0
- vispy/glsl/math/point-to-line-projection.glsl +29 -0
- vispy/glsl/math/signed-line-distance.glsl +27 -0
- vispy/glsl/math/signed-segment-distance.glsl +30 -0
- vispy/glsl/misc/regular-grid.frag +244 -0
- vispy/glsl/misc/spatial-filters.frag +1407 -0
- vispy/glsl/misc/viewport-NDC.glsl +20 -0
- vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
- vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
- vispy/glsl/transforms/hammer.glsl +44 -0
- vispy/glsl/transforms/identity.glsl +6 -0
- vispy/glsl/transforms/identity_forward.glsl +23 -0
- vispy/glsl/transforms/identity_inverse.glsl +23 -0
- vispy/glsl/transforms/linear-scale.glsl +127 -0
- vispy/glsl/transforms/log-scale.glsl +126 -0
- vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
- vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
- vispy/glsl/transforms/panzoom.glsl +10 -0
- vispy/glsl/transforms/polar.glsl +41 -0
- vispy/glsl/transforms/position.glsl +44 -0
- vispy/glsl/transforms/power-scale.glsl +139 -0
- vispy/glsl/transforms/projection.glsl +7 -0
- vispy/glsl/transforms/pvm.glsl +13 -0
- vispy/glsl/transforms/rotate.glsl +45 -0
- vispy/glsl/transforms/trackball.glsl +15 -0
- vispy/glsl/transforms/translate.glsl +35 -0
- vispy/glsl/transforms/transverse_mercator.glsl +38 -0
- vispy/glsl/transforms/viewport-clipping.glsl +14 -0
- vispy/glsl/transforms/viewport-transform.glsl +16 -0
- vispy/glsl/transforms/viewport.glsl +50 -0
- vispy/glsl/transforms/x.glsl +24 -0
- vispy/glsl/transforms/y.glsl +19 -0
- vispy/glsl/transforms/z.glsl +14 -0
- vispy/io/__init__.py +20 -0
- vispy/io/_data/spatial-filters.npy +0 -0
- vispy/io/datasets.py +94 -0
- vispy/io/image.py +231 -0
- vispy/io/mesh.py +122 -0
- vispy/io/stl.py +167 -0
- vispy/io/tests/__init__.py +0 -0
- vispy/io/tests/test_image.py +47 -0
- vispy/io/tests/test_io.py +121 -0
- vispy/io/wavefront.py +350 -0
- vispy/plot/__init__.py +36 -0
- vispy/plot/fig.py +58 -0
- vispy/plot/plotwidget.py +522 -0
- vispy/plot/tests/__init__.py +0 -0
- vispy/plot/tests/test_plot.py +46 -0
- vispy/scene/__init__.py +43 -0
- vispy/scene/cameras/__init__.py +27 -0
- vispy/scene/cameras/_base.py +38 -0
- vispy/scene/cameras/arcball.py +105 -0
- vispy/scene/cameras/base_camera.py +551 -0
- vispy/scene/cameras/fly.py +474 -0
- vispy/scene/cameras/magnify.py +163 -0
- vispy/scene/cameras/panzoom.py +311 -0
- vispy/scene/cameras/perspective.py +338 -0
- vispy/scene/cameras/tests/__init__.py +0 -0
- vispy/scene/cameras/tests/test_cameras.py +27 -0
- vispy/scene/cameras/tests/test_link.py +53 -0
- vispy/scene/cameras/tests/test_perspective.py +122 -0
- vispy/scene/cameras/turntable.py +183 -0
- vispy/scene/canvas.py +639 -0
- vispy/scene/events.py +85 -0
- vispy/scene/node.py +644 -0
- vispy/scene/subscene.py +20 -0
- vispy/scene/tests/__init__.py +0 -0
- vispy/scene/tests/test_canvas.py +119 -0
- vispy/scene/tests/test_node.py +142 -0
- vispy/scene/tests/test_visuals.py +141 -0
- vispy/scene/visuals.py +276 -0
- vispy/scene/widgets/__init__.py +18 -0
- vispy/scene/widgets/anchor.py +25 -0
- vispy/scene/widgets/axis.py +88 -0
- vispy/scene/widgets/colorbar.py +176 -0
- vispy/scene/widgets/console.py +351 -0
- vispy/scene/widgets/grid.py +509 -0
- vispy/scene/widgets/label.py +50 -0
- vispy/scene/widgets/tests/__init__.py +0 -0
- vispy/scene/widgets/tests/test_colorbar.py +47 -0
- vispy/scene/widgets/viewbox.py +199 -0
- vispy/scene/widgets/widget.py +478 -0
- vispy/testing/__init__.py +51 -0
- vispy/testing/_runners.py +448 -0
- vispy/testing/_testing.py +416 -0
- vispy/testing/image_tester.py +494 -0
- vispy/testing/rendered_array_tester.py +85 -0
- vispy/testing/tests/__init__.py +0 -0
- vispy/testing/tests/test_testing.py +20 -0
- vispy/util/__init__.py +32 -0
- vispy/util/bunch.py +15 -0
- vispy/util/check_environment.py +57 -0
- vispy/util/config.py +490 -0
- vispy/util/dpi/__init__.py +19 -0
- vispy/util/dpi/_linux.py +69 -0
- vispy/util/dpi/_quartz.py +26 -0
- vispy/util/dpi/_win32.py +34 -0
- vispy/util/dpi/tests/__init__.py +0 -0
- vispy/util/dpi/tests/test_dpi.py +16 -0
- vispy/util/eq.py +41 -0
- vispy/util/event.py +774 -0
- vispy/util/fetching.py +276 -0
- vispy/util/filter.py +44 -0
- vispy/util/fonts/__init__.py +14 -0
- vispy/util/fonts/_freetype.py +73 -0
- vispy/util/fonts/_quartz.py +192 -0
- vispy/util/fonts/_triage.py +36 -0
- vispy/util/fonts/_vispy_fonts.py +20 -0
- vispy/util/fonts/_win32.py +105 -0
- vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
- vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
- vispy/util/fonts/tests/__init__.py +0 -0
- vispy/util/fonts/tests/test_font.py +45 -0
- vispy/util/fourier.py +69 -0
- vispy/util/frozen.py +25 -0
- vispy/util/gallery_scraper.py +268 -0
- vispy/util/keys.py +91 -0
- vispy/util/logs.py +358 -0
- vispy/util/osmesa_gl.py +17 -0
- vispy/util/profiler.py +135 -0
- vispy/util/ptime.py +16 -0
- vispy/util/quaternion.py +229 -0
- vispy/util/svg/__init__.py +18 -0
- vispy/util/svg/base.py +20 -0
- vispy/util/svg/color.py +219 -0
- vispy/util/svg/element.py +51 -0
- vispy/util/svg/geometry.py +478 -0
- vispy/util/svg/group.py +66 -0
- vispy/util/svg/length.py +81 -0
- vispy/util/svg/number.py +25 -0
- vispy/util/svg/path.py +332 -0
- vispy/util/svg/shapes.py +57 -0
- vispy/util/svg/style.py +59 -0
- vispy/util/svg/svg.py +40 -0
- vispy/util/svg/transform.py +223 -0
- vispy/util/svg/transformable.py +28 -0
- vispy/util/svg/viewport.py +73 -0
- vispy/util/tests/__init__.py +0 -0
- vispy/util/tests/test_config.py +58 -0
- vispy/util/tests/test_docstring_parameters.py +123 -0
- vispy/util/tests/test_emitter_group.py +262 -0
- vispy/util/tests/test_event_emitter.py +743 -0
- vispy/util/tests/test_fourier.py +35 -0
- vispy/util/tests/test_gallery_scraper.py +112 -0
- vispy/util/tests/test_import.py +127 -0
- vispy/util/tests/test_key.py +22 -0
- vispy/util/tests/test_logging.py +45 -0
- vispy/util/tests/test_run.py +14 -0
- vispy/util/tests/test_transforms.py +42 -0
- vispy/util/tests/test_vispy.py +48 -0
- vispy/util/transforms.py +201 -0
- vispy/util/wrappers.py +155 -0
- vispy/version.py +21 -0
- vispy/visuals/__init__.py +50 -0
- vispy/visuals/_scalable_textures.py +487 -0
- vispy/visuals/axis.py +678 -0
- vispy/visuals/border.py +208 -0
- vispy/visuals/box.py +79 -0
- vispy/visuals/collections/__init__.py +30 -0
- vispy/visuals/collections/agg_fast_path_collection.py +219 -0
- vispy/visuals/collections/agg_path_collection.py +197 -0
- vispy/visuals/collections/agg_point_collection.py +52 -0
- vispy/visuals/collections/agg_segment_collection.py +142 -0
- vispy/visuals/collections/array_list.py +401 -0
- vispy/visuals/collections/base_collection.py +482 -0
- vispy/visuals/collections/collection.py +253 -0
- vispy/visuals/collections/path_collection.py +23 -0
- vispy/visuals/collections/point_collection.py +19 -0
- vispy/visuals/collections/polygon_collection.py +25 -0
- vispy/visuals/collections/raw_path_collection.py +119 -0
- vispy/visuals/collections/raw_point_collection.py +113 -0
- vispy/visuals/collections/raw_polygon_collection.py +77 -0
- vispy/visuals/collections/raw_segment_collection.py +112 -0
- vispy/visuals/collections/raw_triangle_collection.py +78 -0
- vispy/visuals/collections/segment_collection.py +19 -0
- vispy/visuals/collections/triangle_collection.py +16 -0
- vispy/visuals/collections/util.py +168 -0
- vispy/visuals/colorbar.py +699 -0
- vispy/visuals/cube.py +41 -0
- vispy/visuals/ellipse.py +162 -0
- vispy/visuals/filters/__init__.py +10 -0
- vispy/visuals/filters/base_filter.py +242 -0
- vispy/visuals/filters/clipper.py +60 -0
- vispy/visuals/filters/clipping_planes.py +122 -0
- vispy/visuals/filters/color.py +181 -0
- vispy/visuals/filters/markers.py +28 -0
- vispy/visuals/filters/mesh.py +801 -0
- vispy/visuals/filters/picking.py +60 -0
- vispy/visuals/filters/tests/__init__.py +3 -0
- vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
- vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
- vispy/visuals/glsl/__init__.py +1 -0
- vispy/visuals/glsl/antialiasing.py +133 -0
- vispy/visuals/glsl/color.py +63 -0
- vispy/visuals/graphs/__init__.py +1 -0
- vispy/visuals/graphs/graph.py +240 -0
- vispy/visuals/graphs/layouts/__init__.py +55 -0
- vispy/visuals/graphs/layouts/circular.py +49 -0
- vispy/visuals/graphs/layouts/force_directed.py +211 -0
- vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
- vispy/visuals/graphs/layouts/random.py +52 -0
- vispy/visuals/graphs/tests/__init__.py +1 -0
- vispy/visuals/graphs/tests/test_layouts.py +139 -0
- vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
- vispy/visuals/graphs/util.py +120 -0
- vispy/visuals/gridlines.py +161 -0
- vispy/visuals/gridmesh.py +98 -0
- vispy/visuals/histogram.py +58 -0
- vispy/visuals/image.py +701 -0
- vispy/visuals/image_complex.py +130 -0
- vispy/visuals/infinite_line.py +199 -0
- vispy/visuals/instanced_mesh.py +152 -0
- vispy/visuals/isocurve.py +213 -0
- vispy/visuals/isoline.py +241 -0
- vispy/visuals/isosurface.py +113 -0
- vispy/visuals/line/__init__.py +6 -0
- vispy/visuals/line/arrow.py +289 -0
- vispy/visuals/line/dash_atlas.py +90 -0
- vispy/visuals/line/line.py +545 -0
- vispy/visuals/line_plot.py +135 -0
- vispy/visuals/linear_region.py +199 -0
- vispy/visuals/markers.py +819 -0
- vispy/visuals/mesh.py +373 -0
- vispy/visuals/mesh_normals.py +159 -0
- vispy/visuals/plane.py +54 -0
- vispy/visuals/polygon.py +145 -0
- vispy/visuals/rectangle.py +196 -0
- vispy/visuals/regular_polygon.py +56 -0
- vispy/visuals/scrolling_lines.py +197 -0
- vispy/visuals/shaders/__init__.py +17 -0
- vispy/visuals/shaders/compiler.py +206 -0
- vispy/visuals/shaders/expression.py +99 -0
- vispy/visuals/shaders/function.py +788 -0
- vispy/visuals/shaders/multiprogram.py +145 -0
- vispy/visuals/shaders/parsing.py +140 -0
- vispy/visuals/shaders/program.py +161 -0
- vispy/visuals/shaders/shader_object.py +162 -0
- vispy/visuals/shaders/tests/__init__.py +0 -0
- vispy/visuals/shaders/tests/test_function.py +486 -0
- vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
- vispy/visuals/shaders/tests/test_parsing.py +57 -0
- vispy/visuals/shaders/variable.py +272 -0
- vispy/visuals/spectrogram.py +169 -0
- vispy/visuals/sphere.py +80 -0
- vispy/visuals/surface_plot.py +192 -0
- vispy/visuals/tests/__init__.py +0 -0
- vispy/visuals/tests/test_arrows.py +109 -0
- vispy/visuals/tests/test_axis.py +120 -0
- vispy/visuals/tests/test_collections.py +15 -0
- vispy/visuals/tests/test_colorbar.py +179 -0
- vispy/visuals/tests/test_colormap.py +97 -0
- vispy/visuals/tests/test_ellipse.py +122 -0
- vispy/visuals/tests/test_gridlines.py +30 -0
- vispy/visuals/tests/test_histogram.py +24 -0
- vispy/visuals/tests/test_image.py +392 -0
- vispy/visuals/tests/test_image_complex.py +36 -0
- vispy/visuals/tests/test_infinite_line.py +53 -0
- vispy/visuals/tests/test_instanced_mesh.py +50 -0
- vispy/visuals/tests/test_isosurface.py +22 -0
- vispy/visuals/tests/test_linear_region.py +152 -0
- vispy/visuals/tests/test_markers.py +54 -0
- vispy/visuals/tests/test_mesh.py +261 -0
- vispy/visuals/tests/test_mesh_normals.py +218 -0
- vispy/visuals/tests/test_polygon.py +112 -0
- vispy/visuals/tests/test_rectangle.py +163 -0
- vispy/visuals/tests/test_regular_polygon.py +111 -0
- vispy/visuals/tests/test_scalable_textures.py +196 -0
- vispy/visuals/tests/test_sdf.py +73 -0
- vispy/visuals/tests/test_spectrogram.py +42 -0
- vispy/visuals/tests/test_surface_plot.py +57 -0
- vispy/visuals/tests/test_text.py +95 -0
- vispy/visuals/tests/test_volume.py +542 -0
- vispy/visuals/tests/test_windbarb.py +33 -0
- vispy/visuals/text/__init__.py +7 -0
- vispy/visuals/text/_sdf_cpu.cpython-313-x86_64-linux-gnu.so +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +112 -0
- vispy/visuals/text/_sdf_gpu.py +316 -0
- vispy/visuals/text/text.py +675 -0
- vispy/visuals/transforms/__init__.py +34 -0
- vispy/visuals/transforms/_util.py +191 -0
- vispy/visuals/transforms/base_transform.py +233 -0
- vispy/visuals/transforms/chain.py +300 -0
- vispy/visuals/transforms/interactive.py +98 -0
- vispy/visuals/transforms/linear.py +564 -0
- vispy/visuals/transforms/nonlinear.py +398 -0
- vispy/visuals/transforms/tests/__init__.py +0 -0
- vispy/visuals/transforms/tests/test_transforms.py +243 -0
- vispy/visuals/transforms/transform_system.py +339 -0
- vispy/visuals/tube.py +173 -0
- vispy/visuals/visual.py +923 -0
- vispy/visuals/volume.py +1366 -0
- vispy/visuals/windbarb.py +291 -0
- vispy/visuals/xyz_axis.py +34 -0
- vispy-0.15.0.dist-info/METADATA +243 -0
- vispy-0.15.0.dist-info/RECORD +521 -0
- vispy-0.15.0.dist-info/WHEEL +6 -0
- vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
- vispy-0.15.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
import numpy as np
|
|
5
|
+
from vispy import scene
|
|
6
|
+
|
|
7
|
+
from vispy.testing import (TestingCanvas, requires_application,
|
|
8
|
+
run_tests_if_main, requires_pyopengl,
|
|
9
|
+
raises)
|
|
10
|
+
from vispy.testing.image_tester import assert_image_approved, downsample
|
|
11
|
+
from vispy.testing.rendered_array_tester import compare_render, max_for_dtype
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@requires_pyopengl()
|
|
15
|
+
def test_volume():
|
|
16
|
+
vol = np.zeros((20, 20, 20), 'float32')
|
|
17
|
+
vol[8:16, 8:16, :] = 1.0
|
|
18
|
+
|
|
19
|
+
# Create
|
|
20
|
+
V = scene.visuals.Volume(vol)
|
|
21
|
+
assert V.clim == (0, 1)
|
|
22
|
+
assert V.method == 'mip'
|
|
23
|
+
assert V.interpolation == 'linear'
|
|
24
|
+
|
|
25
|
+
# Set wrong data
|
|
26
|
+
with raises(ValueError):
|
|
27
|
+
V.set_data(np.zeros((20, 20), 'float32'))
|
|
28
|
+
|
|
29
|
+
# Clim
|
|
30
|
+
V.set_data(vol, (0.5, 0.8))
|
|
31
|
+
assert V.clim == (0.5, 0.8)
|
|
32
|
+
with raises(ValueError):
|
|
33
|
+
V.set_data((0.5, 0.8, 1.0))
|
|
34
|
+
|
|
35
|
+
# Method
|
|
36
|
+
V.method = 'iso'
|
|
37
|
+
assert V.method == 'iso'
|
|
38
|
+
|
|
39
|
+
# Interpolation
|
|
40
|
+
V.interpolation = 'nearest'
|
|
41
|
+
assert V.interpolation == 'nearest'
|
|
42
|
+
|
|
43
|
+
# Step size
|
|
44
|
+
V.relative_step_size = 1.1
|
|
45
|
+
assert V.relative_step_size == 1.1
|
|
46
|
+
# Disallow 0 step size to avoid GPU stalling
|
|
47
|
+
with raises(ValueError):
|
|
48
|
+
V.relative_step_size = 0
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@requires_pyopengl()
|
|
52
|
+
def test_volume_bounds():
|
|
53
|
+
vol = np.zeros((20, 30, 40), 'float32')
|
|
54
|
+
vol[8:16, 8:16, :] = 1.0
|
|
55
|
+
|
|
56
|
+
# Create
|
|
57
|
+
V = scene.visuals.Volume(vol)
|
|
58
|
+
assert V._compute_bounds(0, V) == (0, 40) # x
|
|
59
|
+
assert V._compute_bounds(1, V) == (0, 30) # y
|
|
60
|
+
assert V._compute_bounds(2, V) == (0, 20) # z
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@requires_pyopengl()
|
|
64
|
+
@requires_application()
|
|
65
|
+
def test_volume_draw():
|
|
66
|
+
with TestingCanvas(bgcolor='k', size=(100, 100)) as c:
|
|
67
|
+
v = c.central_widget.add_view()
|
|
68
|
+
v.camera = 'turntable'
|
|
69
|
+
v.camera.fov = 70
|
|
70
|
+
# Create
|
|
71
|
+
np.random.seed(2376)
|
|
72
|
+
vol = np.random.normal(size=(20, 20, 20), loc=0.5, scale=0.2)
|
|
73
|
+
vol[8:16, 8:16, :] += 1.0
|
|
74
|
+
scene.visuals.Volume(vol, parent=v.scene) # noqa
|
|
75
|
+
v.camera.set_range()
|
|
76
|
+
assert_image_approved(c.render(), 'visuals/volume.png')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@requires_pyopengl()
|
|
80
|
+
@requires_application()
|
|
81
|
+
@pytest.mark.parametrize('clim_on_init', [False, True])
|
|
82
|
+
@pytest.mark.parametrize('texture_format', [None, '__dtype__', 'auto'])
|
|
83
|
+
@pytest.mark.parametrize('input_dtype', [np.uint8, np.uint16, np.float32, np.float64])
|
|
84
|
+
def test_volume_clims_and_gamma(texture_format, input_dtype, clim_on_init):
|
|
85
|
+
"""Test volume visual with clims and gamma on shader.
|
|
86
|
+
|
|
87
|
+
Test is parameterized based on ``texture_format`` and should produce
|
|
88
|
+
relatively the same results for each format.
|
|
89
|
+
|
|
90
|
+
Currently just using np.ones since the angle of view made more complicated samples
|
|
91
|
+
challenging, but this confirms gamma and clims works in the shader.
|
|
92
|
+
The VolumeVisual defaults to the "grays" colormap so although we compare
|
|
93
|
+
data using RGBA arrays, each R/G/B channel should be the same.
|
|
94
|
+
|
|
95
|
+
"""
|
|
96
|
+
size = (40, 40)
|
|
97
|
+
if texture_format == '__dtype__':
|
|
98
|
+
texture_format = input_dtype
|
|
99
|
+
np.random.seed(0) # make tests the same every time
|
|
100
|
+
data = _make_test_data(size[:1] * 3, input_dtype)
|
|
101
|
+
clim = (0, 1)
|
|
102
|
+
new_clim = (0.3, 0.8)
|
|
103
|
+
max = max_for_dtype(input_dtype)
|
|
104
|
+
if max != 1:
|
|
105
|
+
clim = (clim[0] * max, clim[1] * max)
|
|
106
|
+
new_clim = (new_clim[0] * max, new_clim[1] * max)
|
|
107
|
+
|
|
108
|
+
kwargs = {}
|
|
109
|
+
if clim_on_init:
|
|
110
|
+
kwargs['clim'] = clim
|
|
111
|
+
with TestingCanvas(size=size, bgcolor="k") as c:
|
|
112
|
+
v = c.central_widget.add_view(border_width=0)
|
|
113
|
+
volume = scene.visuals.Volume(
|
|
114
|
+
data,
|
|
115
|
+
interpolation='nearest',
|
|
116
|
+
parent=v.scene,
|
|
117
|
+
method='mip',
|
|
118
|
+
texture_format=texture_format,
|
|
119
|
+
**kwargs
|
|
120
|
+
)
|
|
121
|
+
v.camera = 'arcball'
|
|
122
|
+
v.camera.fov = 0
|
|
123
|
+
v.camera.scale_factor = 40.0
|
|
124
|
+
v.camera.center = (19.5, 19.5, 19.5)
|
|
125
|
+
|
|
126
|
+
rendered = c.render()
|
|
127
|
+
_dtype = rendered.dtype
|
|
128
|
+
shape_ratio = rendered.shape[0] // data.shape[0]
|
|
129
|
+
rendered1 = downsample(rendered, shape_ratio, axis=(0, 1)).astype(_dtype)
|
|
130
|
+
predicted = data.max(axis=1)
|
|
131
|
+
compare_render(predicted, rendered1)
|
|
132
|
+
|
|
133
|
+
# adjust contrast limits
|
|
134
|
+
volume.clim = new_clim
|
|
135
|
+
rendered2 = downsample(c.render(), shape_ratio, axis=(0, 1)).astype(_dtype)
|
|
136
|
+
scaled_data = (np.clip(data, new_clim[0], new_clim[1]) - new_clim[0]) / (new_clim[1] - new_clim[0])
|
|
137
|
+
predicted = scaled_data.max(axis=1)
|
|
138
|
+
compare_render(predicted, rendered2, previous_render=rendered)
|
|
139
|
+
|
|
140
|
+
# adjust gamma
|
|
141
|
+
volume.gamma = 2
|
|
142
|
+
rendered3 = downsample(c.render(), shape_ratio, axis=(0, 1)).astype(_dtype)
|
|
143
|
+
predicted = (scaled_data ** 2).max(axis=1)
|
|
144
|
+
compare_render(predicted, rendered3, previous_render=rendered2)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@requires_pyopengl()
|
|
148
|
+
@requires_application()
|
|
149
|
+
@pytest.mark.parametrize('method_name', scene.visuals.Volume._rendering_methods.keys())
|
|
150
|
+
def test_all_render_methods(method_name):
|
|
151
|
+
"""Test that render methods don't produce any errors."""
|
|
152
|
+
size = (40, 40)
|
|
153
|
+
np.random.seed(0) # make tests the same every time
|
|
154
|
+
data = _make_test_data(size[:1] * 3, np.float32)
|
|
155
|
+
# modify the data for 'minip' method so that there is at least one segment
|
|
156
|
+
# of the volume with no 'empty'/zero space
|
|
157
|
+
data[:, :, 40 // 3: 2 * 40 // 3] = 1.0
|
|
158
|
+
clim = (0, 1)
|
|
159
|
+
kwargs = {}
|
|
160
|
+
with TestingCanvas(size=size, bgcolor="k") as c:
|
|
161
|
+
v = c.central_widget.add_view(border_width=0)
|
|
162
|
+
volume = scene.visuals.Volume(
|
|
163
|
+
data,
|
|
164
|
+
interpolation='nearest',
|
|
165
|
+
clim=clim,
|
|
166
|
+
parent=v.scene,
|
|
167
|
+
method=method_name,
|
|
168
|
+
**kwargs
|
|
169
|
+
)
|
|
170
|
+
v.camera = 'arcball'
|
|
171
|
+
v.camera.fov = 0
|
|
172
|
+
v.camera.scale_factor = 40.0
|
|
173
|
+
v.camera.center = (19.5, 19.5, 19.5)
|
|
174
|
+
|
|
175
|
+
assert volume.method == method_name
|
|
176
|
+
rendered = c.render()[..., :3]
|
|
177
|
+
# not all black
|
|
178
|
+
assert rendered.sum() != 0
|
|
179
|
+
# not all white
|
|
180
|
+
assert rendered.sum() != 255 * rendered.size
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@requires_pyopengl()
|
|
184
|
+
@requires_application()
|
|
185
|
+
@pytest.mark.parametrize('texture_format', [None, 'auto'])
|
|
186
|
+
def test_equal_clims(texture_format):
|
|
187
|
+
"""Test that equal clims produce a min cmap value."""
|
|
188
|
+
size = (40, 40)
|
|
189
|
+
np.random.seed(0) # make tests the same every time
|
|
190
|
+
data = _make_test_data(size[:1] * 3, np.float32)
|
|
191
|
+
with TestingCanvas(size=size, bgcolor="k") as c:
|
|
192
|
+
v = c.central_widget.add_view(border_width=0)
|
|
193
|
+
scene.visuals.Volume(
|
|
194
|
+
data,
|
|
195
|
+
interpolation='nearest',
|
|
196
|
+
clim=(128.0, 128.0), # equal clims
|
|
197
|
+
cmap='viridis', # something with a non-black min value
|
|
198
|
+
parent=v.scene,
|
|
199
|
+
method='mip',
|
|
200
|
+
texture_format=texture_format,
|
|
201
|
+
)
|
|
202
|
+
v.camera = 'arcball'
|
|
203
|
+
v.camera.fov = 0
|
|
204
|
+
v.camera.scale_factor = 40.0
|
|
205
|
+
v.camera.center = (19.5, 19.5, 19.5)
|
|
206
|
+
|
|
207
|
+
rendered = c.render()[..., :3]
|
|
208
|
+
# not all black
|
|
209
|
+
assert rendered.sum() != 0
|
|
210
|
+
# not all white
|
|
211
|
+
assert rendered.sum() != 255 * rendered.size
|
|
212
|
+
# should be all the same value
|
|
213
|
+
r_unique = np.unique(rendered[..., 0])
|
|
214
|
+
g_unique = np.unique(rendered[..., 1])
|
|
215
|
+
b_unique = np.unique(rendered[..., 2])
|
|
216
|
+
assert r_unique.size == 1
|
|
217
|
+
assert g_unique.size == 1
|
|
218
|
+
assert b_unique.size == 1
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _make_test_data(shape, input_dtype):
|
|
222
|
+
one_third = shape[0] // 3
|
|
223
|
+
two_third = 2 * one_third
|
|
224
|
+
data = np.zeros(shape, dtype=np.float64)
|
|
225
|
+
# 0.00 | 1.00 | 0.00
|
|
226
|
+
# 0.50 | 0.00 | 0.25
|
|
227
|
+
# 0.00 | 0.00 | 0.00
|
|
228
|
+
data[:, :one_third, one_third:two_third] = 1.0
|
|
229
|
+
data[:, one_third:two_third, :one_third] = 0.5
|
|
230
|
+
data[:, one_third:two_third, two_third:] = 0.25
|
|
231
|
+
max_val = max_for_dtype(input_dtype)
|
|
232
|
+
if max_val != 1:
|
|
233
|
+
data *= max_val
|
|
234
|
+
data = data.astype(input_dtype)
|
|
235
|
+
return data
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@requires_pyopengl()
|
|
239
|
+
def test_set_data_does_not_change_input():
|
|
240
|
+
# Create volume
|
|
241
|
+
V = scene.visuals.Volume(np.zeros((20, 20, 20), dtype=np.float32))
|
|
242
|
+
|
|
243
|
+
# calling Volume.set_data() should NOT alter the values of the input array
|
|
244
|
+
# regardless of data type
|
|
245
|
+
vol = np.random.randint(0, 200, (20, 20, 20))
|
|
246
|
+
for dtype in ['uint8', 'int16', 'uint16', 'float32', 'float64']:
|
|
247
|
+
vol_copy = np.array(vol, dtype=dtype, copy=True)
|
|
248
|
+
# setting clim so that normalization would otherwise change the data
|
|
249
|
+
V.set_data(vol_copy, clim=(0, 200))
|
|
250
|
+
assert np.allclose(vol, vol_copy)
|
|
251
|
+
|
|
252
|
+
# dtype has to be the same as the one used to init the texture, or it will
|
|
253
|
+
# be first coerced to the same dtype as the init
|
|
254
|
+
|
|
255
|
+
vol2 = np.array(vol, dtype=np.float32, copy=True)
|
|
256
|
+
assert np.allclose(vol, vol2)
|
|
257
|
+
# we explicitly create a copy when data would be altered by the texture,
|
|
258
|
+
# no matter what the user asks, so the data outside should never change
|
|
259
|
+
V.set_data(vol2, clim=(0, 200), copy=False)
|
|
260
|
+
assert np.allclose(vol, vol2)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@requires_pyopengl()
|
|
264
|
+
def test_set_data_changes_shape():
|
|
265
|
+
dtype = np.float32
|
|
266
|
+
# Create initial volume
|
|
267
|
+
V = scene.visuals.Volume(np.zeros((20, 20, 20), dtype=dtype))
|
|
268
|
+
|
|
269
|
+
# Sending new three dimensional data of different shape should alter volume shape
|
|
270
|
+
vol = np.zeros((25, 25, 10), dtype=dtype)
|
|
271
|
+
V.set_data(vol)
|
|
272
|
+
assert V._vol_shape == (25, 25, 10)
|
|
273
|
+
|
|
274
|
+
# Sending data of dimension other than 3 should raise a ValueError
|
|
275
|
+
vol2 = np.zeros((20, 20), dtype=dtype)
|
|
276
|
+
with pytest.raises(ValueError):
|
|
277
|
+
V.set_data(vol2)
|
|
278
|
+
|
|
279
|
+
vol2 = np.zeros((20, 20, 20, 20), dtype=dtype)
|
|
280
|
+
with pytest.raises(ValueError):
|
|
281
|
+
V.set_data(vol2)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
@requires_pyopengl()
|
|
285
|
+
@requires_application()
|
|
286
|
+
def test_changing_cmap():
|
|
287
|
+
"""Test that changing colormaps updates the display."""
|
|
288
|
+
size = (40, 40)
|
|
289
|
+
np.random.seed(0) # make tests the same every time
|
|
290
|
+
data = _make_test_data(size[:1] * 3, np.float32)
|
|
291
|
+
cmap = 'grays'
|
|
292
|
+
test_cmaps = ('reds', 'greens', 'blues')
|
|
293
|
+
clim = (0, 1)
|
|
294
|
+
kwargs = {}
|
|
295
|
+
with TestingCanvas(size=size, bgcolor="k") as c:
|
|
296
|
+
v = c.central_widget.add_view(border_width=0)
|
|
297
|
+
volume = scene.visuals.Volume(
|
|
298
|
+
data,
|
|
299
|
+
interpolation='nearest',
|
|
300
|
+
clim=clim,
|
|
301
|
+
cmap=cmap,
|
|
302
|
+
parent=v.scene,
|
|
303
|
+
**kwargs
|
|
304
|
+
)
|
|
305
|
+
v.camera = 'arcball'
|
|
306
|
+
v.camera.fov = 0
|
|
307
|
+
v.camera.scale_factor = 40.0
|
|
308
|
+
|
|
309
|
+
# render with grays colormap
|
|
310
|
+
grays = c.render()
|
|
311
|
+
|
|
312
|
+
# update cmap, compare rendered array with the grays cmap render
|
|
313
|
+
for cmap in test_cmaps:
|
|
314
|
+
volume.cmap = cmap
|
|
315
|
+
current_cmap = c.render()
|
|
316
|
+
with pytest.raises(AssertionError):
|
|
317
|
+
np.testing.assert_allclose(grays, current_cmap)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
@requires_pyopengl()
|
|
321
|
+
@requires_application()
|
|
322
|
+
def test_plane_depth():
|
|
323
|
+
with TestingCanvas(size=(80, 80)) as c:
|
|
324
|
+
v = c.central_widget.add_view(border_width=0)
|
|
325
|
+
v.camera = 'arcball'
|
|
326
|
+
v.camera.fov = 0
|
|
327
|
+
v.camera.center = (40, 40, 40)
|
|
328
|
+
v.camera.scale_factor = 80.0
|
|
329
|
+
|
|
330
|
+
# two planes at 45 degrees relative to the camera. If depth is set correctly, we should see one half
|
|
331
|
+
# of the screen red and the other half white
|
|
332
|
+
scene.visuals.Volume(
|
|
333
|
+
np.ones((80, 80, 80), dtype=np.uint8),
|
|
334
|
+
interpolation="nearest",
|
|
335
|
+
clim=(0, 1),
|
|
336
|
+
cmap="grays",
|
|
337
|
+
raycasting_mode="plane",
|
|
338
|
+
plane_normal=(0, 1, 1),
|
|
339
|
+
parent=v.scene,
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
scene.visuals.Volume(
|
|
343
|
+
np.ones((80, 80, 80), dtype=np.uint8),
|
|
344
|
+
interpolation="nearest",
|
|
345
|
+
clim=(0, 1),
|
|
346
|
+
cmap="reds",
|
|
347
|
+
raycasting_mode="plane",
|
|
348
|
+
plane_normal=(0, 1, -1),
|
|
349
|
+
parent=v.scene,
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
# render with grays colormap
|
|
353
|
+
rendered = c.render()
|
|
354
|
+
left = rendered[40, 20]
|
|
355
|
+
right = rendered[40, 60]
|
|
356
|
+
assert np.array_equal(left, [255, 0, 0, 255])
|
|
357
|
+
assert np.array_equal(right, [255, 255, 255, 255])
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@requires_pyopengl()
|
|
361
|
+
@requires_application()
|
|
362
|
+
def test_volume_depth():
|
|
363
|
+
"""Check that depth setting is properly performed for the volume visual
|
|
364
|
+
|
|
365
|
+
Render a volume with a blue ball in front of a red plane in front of a
|
|
366
|
+
blue plane, checking that the output image contains both red and blue pixels.
|
|
367
|
+
"""
|
|
368
|
+
# A blue strip behind a red strip
|
|
369
|
+
# If depth is set correctly, we should see only red pixels
|
|
370
|
+
# the screen
|
|
371
|
+
blue_vol = np.zeros((80, 80, 80), dtype=np.uint8)
|
|
372
|
+
blue_vol[:, -1, :] = 1 # back plane blue
|
|
373
|
+
blue_vol[30:50, 30:50, 30:50] = 1 # blue in center
|
|
374
|
+
|
|
375
|
+
red_vol = np.zeros((80, 80, 80), dtype=np.uint8)
|
|
376
|
+
red_vol[:, -5, :] = 1 # red plane in front of blue plane
|
|
377
|
+
|
|
378
|
+
with TestingCanvas(size=(80, 80)) as c:
|
|
379
|
+
v = c.central_widget.add_view(border_width=0)
|
|
380
|
+
v.camera = 'arcball'
|
|
381
|
+
v.camera.fov = 0
|
|
382
|
+
v.camera.center = (40, 40, 40)
|
|
383
|
+
v.camera.scale_factor = 80.0
|
|
384
|
+
|
|
385
|
+
scene.visuals.Volume(
|
|
386
|
+
red_vol,
|
|
387
|
+
interpolation="nearest",
|
|
388
|
+
clim=(0, 1),
|
|
389
|
+
cmap="reds",
|
|
390
|
+
parent=v.scene,
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
scene.visuals.Volume(
|
|
394
|
+
blue_vol,
|
|
395
|
+
interpolation="nearest",
|
|
396
|
+
clim=(0, 1),
|
|
397
|
+
cmap="blues",
|
|
398
|
+
parent=v.scene,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
# render
|
|
402
|
+
rendered = c.render()
|
|
403
|
+
reds = np.sum(rendered[:, :, 0])
|
|
404
|
+
greens = np.sum(rendered[:, :, 1])
|
|
405
|
+
blues = np.sum(rendered[:, :, 2])
|
|
406
|
+
assert reds > 0
|
|
407
|
+
np.testing.assert_allclose(greens, 0)
|
|
408
|
+
assert blues > 0
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@requires_pyopengl()
|
|
412
|
+
@requires_application()
|
|
413
|
+
def test_mip_cutoff():
|
|
414
|
+
"""
|
|
415
|
+
Ensure fragments are properly discarded based on the mip_cutoff
|
|
416
|
+
for the mip and attenuated_mip rendering methods
|
|
417
|
+
"""
|
|
418
|
+
with TestingCanvas(size=(80, 80)) as c:
|
|
419
|
+
v = c.central_widget.add_view(border_width=0)
|
|
420
|
+
v.camera = 'arcball'
|
|
421
|
+
v.camera.fov = 0
|
|
422
|
+
v.camera.center = (40, 40, 40)
|
|
423
|
+
v.camera.scale_factor = 80.0
|
|
424
|
+
|
|
425
|
+
vol = scene.visuals.Volume(
|
|
426
|
+
np.ones((80, 80, 80), dtype=np.uint8),
|
|
427
|
+
interpolation="nearest",
|
|
428
|
+
clim=(0, 1),
|
|
429
|
+
cmap="grays",
|
|
430
|
+
parent=v.scene,
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
# we should see white
|
|
434
|
+
rendered = c.render()
|
|
435
|
+
assert np.array_equal(rendered[40, 40], [255, 255, 255, 255])
|
|
436
|
+
|
|
437
|
+
vol.mip_cutoff = 10
|
|
438
|
+
# we should see black
|
|
439
|
+
rendered = c.render()
|
|
440
|
+
assert np.array_equal(rendered[40, 40], [0, 0, 0, 255])
|
|
441
|
+
|
|
442
|
+
# repeat for attenuated_mip
|
|
443
|
+
vol.method = 'attenuated_mip'
|
|
444
|
+
vol.mip_cutoff = None
|
|
445
|
+
|
|
446
|
+
# we should see white
|
|
447
|
+
rendered = c.render()
|
|
448
|
+
assert np.array_equal(rendered[40, 40], [255, 255, 255, 255])
|
|
449
|
+
|
|
450
|
+
vol.mip_cutoff = 10
|
|
451
|
+
# we should see black
|
|
452
|
+
rendered = c.render()
|
|
453
|
+
assert np.array_equal(rendered[40, 40], [0, 0, 0, 255])
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@requires_pyopengl()
|
|
457
|
+
@requires_application()
|
|
458
|
+
def test_minip_cutoff():
|
|
459
|
+
"""
|
|
460
|
+
Ensure fragments are properly discarded based on the minip_cutoff
|
|
461
|
+
for the minip rendering method
|
|
462
|
+
"""
|
|
463
|
+
with TestingCanvas(size=(80, 80)) as c:
|
|
464
|
+
v = c.central_widget.add_view(border_width=0)
|
|
465
|
+
v.camera = 'arcball'
|
|
466
|
+
v.camera.fov = 0
|
|
467
|
+
v.camera.center = (40, 40, 40)
|
|
468
|
+
v.camera.scale_factor = 120.0
|
|
469
|
+
|
|
470
|
+
# just surface of the cube is ones, but it should win over the twos inside
|
|
471
|
+
data = np.ones((80, 80, 80), dtype=np.uint8)
|
|
472
|
+
data[1:-1, 1:-1, 1:-1] = 2
|
|
473
|
+
|
|
474
|
+
vol = scene.visuals.Volume(
|
|
475
|
+
data,
|
|
476
|
+
interpolation="nearest",
|
|
477
|
+
method='minip',
|
|
478
|
+
clim=(0, 2),
|
|
479
|
+
cmap="grays",
|
|
480
|
+
parent=v.scene,
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
# we should see gray (half of cmap)
|
|
484
|
+
rendered = c.render()
|
|
485
|
+
assert np.array_equal(rendered[40, 40], [128, 128, 128, 255])
|
|
486
|
+
|
|
487
|
+
# discard fragments above -10 (everything)
|
|
488
|
+
vol.minip_cutoff = -10
|
|
489
|
+
# we should see black
|
|
490
|
+
rendered = c.render()
|
|
491
|
+
assert np.array_equal(rendered[40, 40], [0, 0, 0, 255])
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@requires_pyopengl()
|
|
495
|
+
@requires_application()
|
|
496
|
+
def test_volume_set_data_different_dtype():
|
|
497
|
+
size = (80, 80)
|
|
498
|
+
data = np.array([[[0, 127]]], dtype=np.int8)
|
|
499
|
+
left = (40, 10)
|
|
500
|
+
right = (40, 70)
|
|
501
|
+
white = (255, 255, 255, 255)
|
|
502
|
+
black = (0, 0, 0, 255)
|
|
503
|
+
|
|
504
|
+
with TestingCanvas(size=size[::-1], bgcolor="w") as c:
|
|
505
|
+
view = c.central_widget.add_view()
|
|
506
|
+
view.camera = 'arcball'
|
|
507
|
+
view.camera.fov = 0
|
|
508
|
+
view.camera.center = 0.5, 0, 0
|
|
509
|
+
view.camera.scale_factor = 2
|
|
510
|
+
volume = scene.visuals.Volume(
|
|
511
|
+
data,
|
|
512
|
+
cmap='grays',
|
|
513
|
+
clim=[0, 127],
|
|
514
|
+
parent=view.scene
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
render = c.render()
|
|
518
|
+
assert np.allclose(render[left], black)
|
|
519
|
+
assert np.allclose(render[right], white)
|
|
520
|
+
|
|
521
|
+
# same data as float should change nothing
|
|
522
|
+
volume.set_data(data.astype(np.float32))
|
|
523
|
+
render = c.render()
|
|
524
|
+
assert np.allclose(render[left], black)
|
|
525
|
+
assert np.allclose(render[right], white)
|
|
526
|
+
|
|
527
|
+
# something inverted, different dtype
|
|
528
|
+
new_data = np.array([[[127, 0]]], dtype=np.float16)
|
|
529
|
+
volume.set_data(new_data)
|
|
530
|
+
render = c.render()
|
|
531
|
+
assert np.allclose(render[left], white)
|
|
532
|
+
assert np.allclose(render[right], black)
|
|
533
|
+
|
|
534
|
+
# out of bounds should clip (2000 > 127)
|
|
535
|
+
new_data = np.array([[[0, 2000]]], dtype=np.float64)
|
|
536
|
+
volume.set_data(new_data)
|
|
537
|
+
render = c.render()
|
|
538
|
+
assert np.allclose(render[left], black)
|
|
539
|
+
assert np.allclose(render[right], white)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
run_tests_if_main()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
3
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from vispy.scene.visuals import Windbarb
|
|
7
|
+
from vispy.testing import (requires_application, TestingCanvas,
|
|
8
|
+
run_tests_if_main)
|
|
9
|
+
from vispy.testing.image_tester import assert_image_approved
|
|
10
|
+
|
|
11
|
+
length = 15.
|
|
12
|
+
gridx = np.arange(length, 376, length * 2, dtype=np.float32)
|
|
13
|
+
gridy = np.ones_like(gridx) * length
|
|
14
|
+
grid = np.stack((gridx, gridy), axis=-1)
|
|
15
|
+
origin = (length, length)
|
|
16
|
+
vectors = (grid - origin).astype(np.float32)
|
|
17
|
+
vectors[:] /= length // 2
|
|
18
|
+
vectors[:, 1] *= -1
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@requires_application()
|
|
22
|
+
def test_windbarb_draw():
|
|
23
|
+
"""Test drawing arrows without transforms"""
|
|
24
|
+
with TestingCanvas(size=(250, 33), bgcolor='white') as c:
|
|
25
|
+
|
|
26
|
+
Windbarb(pos=grid, wind=vectors,
|
|
27
|
+
trig=False,
|
|
28
|
+
edge_color='black',
|
|
29
|
+
face_color='black',
|
|
30
|
+
size=length, parent=c.scene)
|
|
31
|
+
assert_image_approved(c.render(), 'visuals/windbarb.png')
|
|
32
|
+
|
|
33
|
+
run_tests_if_main()
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# -----------------------------------------------------------------------------
|
|
3
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
4
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
from .text import TextVisual # noqa
|
|
Binary file
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# cython: language_level=3, boundscheck=False, cdivision=True, wraparound=False, initializedcheck=False, nonecheck=False
|
|
2
|
+
# A Cython implementation of the "eight-points signed sequential Euclidean
|
|
3
|
+
# distance transform algorithm" (8SSEDT)
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
cimport numpy as np
|
|
7
|
+
from libc.math cimport sqrt
|
|
8
|
+
cimport cython
|
|
9
|
+
|
|
10
|
+
np.import_array()
|
|
11
|
+
|
|
12
|
+
__all__ = ['_get_distance_field']
|
|
13
|
+
|
|
14
|
+
dtype = np.float32
|
|
15
|
+
dtype_c = np.complex64
|
|
16
|
+
ctypedef np.float32_t DTYPE_t
|
|
17
|
+
ctypedef np.complex64_t DTYPE_ct
|
|
18
|
+
|
|
19
|
+
cdef DTYPE_ct MAX_VAL = (1e6 + 1e6j)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _calc_distance_field(np.ndarray[DTYPE_t, ndim=2] pixels,
|
|
23
|
+
int w, int h, DTYPE_t sp_f):
|
|
24
|
+
# initialize grids
|
|
25
|
+
cdef np.ndarray[DTYPE_ct, ndim=2] g0_arr = np.zeros((h, w), dtype_c)
|
|
26
|
+
cdef np.ndarray[DTYPE_ct, ndim=2] g1_arr = np.zeros((h, w), dtype_c)
|
|
27
|
+
cdef DTYPE_ct[:, ::1] g0 = g0_arr
|
|
28
|
+
cdef DTYPE_ct[:, ::1] g1 = g1_arr
|
|
29
|
+
cdef DTYPE_t[:, :] pixels_view = pixels
|
|
30
|
+
cdef Py_ssize_t y, x
|
|
31
|
+
for y in range(h):
|
|
32
|
+
g0[y, 0] = MAX_VAL
|
|
33
|
+
g0[y, w-1] = MAX_VAL
|
|
34
|
+
g1[y, 0] = MAX_VAL
|
|
35
|
+
g1[y, w-1] = MAX_VAL
|
|
36
|
+
for x in range(1, w-1):
|
|
37
|
+
if pixels_view[y, x] > 0:
|
|
38
|
+
g0[y, x] = MAX_VAL
|
|
39
|
+
if pixels_view[y, x] < 1:
|
|
40
|
+
g1[y, x] = MAX_VAL
|
|
41
|
+
for x in range(w):
|
|
42
|
+
g0[0, x] = MAX_VAL
|
|
43
|
+
g0[h-1, x] = MAX_VAL
|
|
44
|
+
g1[0, x] = MAX_VAL
|
|
45
|
+
g1[h-1, x] = MAX_VAL
|
|
46
|
+
|
|
47
|
+
# Propagate grids
|
|
48
|
+
_propagate(g0)
|
|
49
|
+
_propagate(g1)
|
|
50
|
+
|
|
51
|
+
# Subtracting and normalizing
|
|
52
|
+
cdef DTYPE_t r_sp_f_2 = 1. / (sp_f * 2.)
|
|
53
|
+
for y in range(1, h-1):
|
|
54
|
+
for x in range(1, w-1):
|
|
55
|
+
pixels_view[y, x] = sqrt(dist(g0[y, x])) - sqrt(dist(g1[y, x]))
|
|
56
|
+
if pixels_view[y, x] < 0:
|
|
57
|
+
pixels_view[y, x] = (pixels_view[y, x] + sp_f) * r_sp_f_2
|
|
58
|
+
else:
|
|
59
|
+
pixels_view[y, x] = 0.5 + pixels_view[y, x] * r_sp_f_2
|
|
60
|
+
pixels_view[y, x] = max(min(pixels_view[y, x], 1), 0)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
cdef inline Py_ssize_t compare(DTYPE_ct *cell, DTYPE_ct xy, DTYPE_t *current) noexcept nogil:
|
|
64
|
+
cdef DTYPE_t val = dist(xy)
|
|
65
|
+
if val < current[0]:
|
|
66
|
+
cell[0] = xy
|
|
67
|
+
current[0] = val
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
cdef DTYPE_t dist(DTYPE_ct val) noexcept nogil:
|
|
71
|
+
return val.real*val.real + val.imag*val.imag
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
cdef void _propagate(DTYPE_ct[:, :] grid) noexcept nogil:
|
|
75
|
+
cdef Py_ssize_t height = grid.shape[0]
|
|
76
|
+
cdef Py_ssize_t width = grid.shape[1]
|
|
77
|
+
cdef Py_ssize_t y, x
|
|
78
|
+
cdef DTYPE_t current
|
|
79
|
+
cdef DTYPE_ct a0, a1, a2, a3
|
|
80
|
+
a0 = -1
|
|
81
|
+
a1 = -1j
|
|
82
|
+
a2 = -1 - 1j
|
|
83
|
+
a3 = 1 - 1j
|
|
84
|
+
cdef DTYPE_ct b0=1
|
|
85
|
+
cdef DTYPE_ct c0=1, c1=1j, c2=-1+1j, c3=1+1j
|
|
86
|
+
cdef DTYPE_ct d0=-1
|
|
87
|
+
height -= 1
|
|
88
|
+
width -= 1
|
|
89
|
+
for y in range(1, height):
|
|
90
|
+
for x in range(1, width):
|
|
91
|
+
current = dist(grid[y, x])
|
|
92
|
+
# (-1, +0), (+0, -1), (-1, -1), (+1, -1)
|
|
93
|
+
compare(&grid[y, x], grid[y, x-1] + a0, ¤t)
|
|
94
|
+
compare(&grid[y, x], grid[y-1, x] + a1, ¤t)
|
|
95
|
+
compare(&grid[y, x], grid[y-1, x-1] + a2, ¤t)
|
|
96
|
+
compare(&grid[y, x], grid[y-1, x+1] + a3, ¤t)
|
|
97
|
+
for x in range(width - 1, 0, -1):
|
|
98
|
+
current = dist(grid[y, x])
|
|
99
|
+
# (+1, +0)
|
|
100
|
+
compare(&grid[y, x], grid[y, x+1] + b0, ¤t)
|
|
101
|
+
for y in range(height - 1, 0, -1):
|
|
102
|
+
for x in range(width - 1, 0, -1):
|
|
103
|
+
current = dist(grid[y, x])
|
|
104
|
+
# (+1, +0), (+0, +1), (-1, +1), (+1, +1)
|
|
105
|
+
compare(&grid[y, x], grid[y, x+1] + c0, ¤t)
|
|
106
|
+
compare(&grid[y, x], grid[y+1, x] + c1, ¤t)
|
|
107
|
+
compare(&grid[y, x], grid[y+1, x-1] + c2, ¤t)
|
|
108
|
+
compare(&grid[y, x], grid[y+1, x+1] + c3, ¤t)
|
|
109
|
+
for x in range(1, width):
|
|
110
|
+
current = dist(grid[y, x])
|
|
111
|
+
# (-1, +0)
|
|
112
|
+
compare(&grid[y, x], grid[y, x-1] + d0, ¤t)
|