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,130 @@
|
|
|
1
|
+
from .image import ImageVisual, _APPLY_CLIM_FLOAT, _APPLY_GAMMA_FLOAT
|
|
2
|
+
import numpy as np
|
|
3
|
+
from .shaders import Function, FunctionChain
|
|
4
|
+
|
|
5
|
+
# In a complex Image, the texture will be rg32f, where:
|
|
6
|
+
# data.r contains the real component
|
|
7
|
+
# data.g contains the imaginary component
|
|
8
|
+
COMPLEX_TRANSFORMS = {
|
|
9
|
+
"real": "float cplx2float(vec4 data) { return data.r; }",
|
|
10
|
+
"imaginary": "float cplx2float(vec4 data) { return data.g; }",
|
|
11
|
+
"magnitude": "float cplx2float(vec4 data) { return length(vec2(data)); }",
|
|
12
|
+
"phase": "float cplx2float(vec4 data) { return atan(data.g, data.r); }",
|
|
13
|
+
}
|
|
14
|
+
CPU_COMPLEX_TRANSFORMS = {
|
|
15
|
+
"magnitude": np.abs,
|
|
16
|
+
"phase": np.angle,
|
|
17
|
+
"real": np.real,
|
|
18
|
+
"imaginary": np.imag,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ComplexImageVisual(ImageVisual):
|
|
23
|
+
""":class:`~vispy.visuals.ImageVisual` subclass displaying a complex-valued image.
|
|
24
|
+
|
|
25
|
+
This class handles complex values by using an rg32f float texture behind the scenes,
|
|
26
|
+
storing the real component in the "r" value and the imaginary in the "g" value.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
data : ndarray
|
|
31
|
+
Complex valued ImageVisual data. Should be a two dimensional array with a dtype
|
|
32
|
+
of np.complex64 or np.complex128.
|
|
33
|
+
complex_mode : str
|
|
34
|
+
The mode used to convert the complex value in each pixel into a scalar:
|
|
35
|
+
* 'real': show only the real component.
|
|
36
|
+
* 'imaginary': show only the imaginary component.
|
|
37
|
+
* 'magnitude': show the magnitude (`np.abs`) of the complex value.
|
|
38
|
+
* 'phase': show the phase (`np.angle`) of the complex value.
|
|
39
|
+
"""
|
|
40
|
+
COMPLEX_MODES = set(COMPLEX_TRANSFORMS)
|
|
41
|
+
|
|
42
|
+
def __init__(self, data=None, complex_mode="magnitude", **kwargs):
|
|
43
|
+
if complex_mode not in self.COMPLEX_MODES:
|
|
44
|
+
raise ValueError(
|
|
45
|
+
"complex_mode must be one of %s" % ", ".join(self.COMPLEX_MODES)
|
|
46
|
+
)
|
|
47
|
+
self._data_is_complex = np.iscomplexobj(data)
|
|
48
|
+
self._complex_mode = complex_mode
|
|
49
|
+
|
|
50
|
+
if kwargs.get("clim", "auto") == "auto" and self._data_is_complex:
|
|
51
|
+
kwargs["clim"] = self._calc_complex_clim(data)
|
|
52
|
+
|
|
53
|
+
kwargs["texture_format"] = "r32f" if self._data_is_complex else "r32f"
|
|
54
|
+
if self._data_is_complex:
|
|
55
|
+
data = self._convert_complex_to_float_view(data)
|
|
56
|
+
super().__init__(data=data, **kwargs)
|
|
57
|
+
|
|
58
|
+
def _init_texture(self, data, texture_format, **texture_kwargs):
|
|
59
|
+
texture_kwargs = {}
|
|
60
|
+
if self._data_is_complex:
|
|
61
|
+
texture_kwargs["format"] = "rg"
|
|
62
|
+
return super()._init_texture(data, texture_format, **texture_kwargs)
|
|
63
|
+
|
|
64
|
+
def set_data(self, image):
|
|
65
|
+
data = np.asarray(image)
|
|
66
|
+
if np.iscomplexobj(data):
|
|
67
|
+
# Turn the texture into an rg32f texture
|
|
68
|
+
# where r = 'real' and g = 'imag'
|
|
69
|
+
self._data_is_complex = True
|
|
70
|
+
# FUTURE: Add formal way of defining texture format from set_data
|
|
71
|
+
self._texture._format = "rg"
|
|
72
|
+
data = self._convert_complex_to_float_view(data)
|
|
73
|
+
elif data.ndim == 3 and data.shape[-1] == 2:
|
|
74
|
+
# data was complex but was already converted to 32-bit float
|
|
75
|
+
# should really only occur from __init__
|
|
76
|
+
self._data_is_complex = True
|
|
77
|
+
else:
|
|
78
|
+
self._texture._format = None
|
|
79
|
+
return super().set_data(data)
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def _convert_complex_to_float_view(complex_arr):
|
|
83
|
+
# turn complex128 into complex64 if needed
|
|
84
|
+
complex64_arr = complex_arr.astype(np.complex64, copy=False)
|
|
85
|
+
float_view_arr = complex64_arr.view(dtype=np.float32).reshape((complex64_arr.shape + (2, )))
|
|
86
|
+
return float_view_arr
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def complex_mode(self):
|
|
90
|
+
return self._data_is_complex and self._complex_mode
|
|
91
|
+
|
|
92
|
+
@complex_mode.setter
|
|
93
|
+
def complex_mode(self, value):
|
|
94
|
+
if value not in self.COMPLEX_MODES:
|
|
95
|
+
raise ValueError(
|
|
96
|
+
"complex_mode must be one of %s" % ", ".join(self.COMPLEX_MODES)
|
|
97
|
+
)
|
|
98
|
+
if self._complex_mode != value:
|
|
99
|
+
self._complex_mode = value
|
|
100
|
+
self._need_colortransform_update = True
|
|
101
|
+
self.update()
|
|
102
|
+
|
|
103
|
+
def _build_color_transform(self):
|
|
104
|
+
if self.complex_mode:
|
|
105
|
+
fclim = Function(_APPLY_CLIM_FLOAT)
|
|
106
|
+
fgamma = Function(_APPLY_GAMMA_FLOAT)
|
|
107
|
+
chain = [
|
|
108
|
+
Function(COMPLEX_TRANSFORMS[self.complex_mode]),
|
|
109
|
+
fclim,
|
|
110
|
+
fgamma,
|
|
111
|
+
Function(self.cmap.glsl_map),
|
|
112
|
+
]
|
|
113
|
+
fun = FunctionChain(None, chain)
|
|
114
|
+
fclim["clim"] = self._texture.clim_normalized
|
|
115
|
+
fgamma["gamma"] = self.gamma
|
|
116
|
+
return fun
|
|
117
|
+
return super()._build_color_transform()
|
|
118
|
+
|
|
119
|
+
@ImageVisual.clim.setter
|
|
120
|
+
def clim(self, clim):
|
|
121
|
+
if clim == "auto" and self.complex_mode:
|
|
122
|
+
clim = self._calc_complex_clim()
|
|
123
|
+
super(ComplexImageVisual, type(self)).clim.fset(self, clim)
|
|
124
|
+
|
|
125
|
+
def _calc_complex_clim(self, data=None):
|
|
126
|
+
# it would be nice if this could be done in the scalable texture mixin,
|
|
127
|
+
# but that would require the mixin knowing about the complex mode.
|
|
128
|
+
func = CPU_COMPLEX_TRANSFORMS[self.complex_mode]
|
|
129
|
+
_rendered = func(self._data if data is None else data)
|
|
130
|
+
return (_rendered.min(), _rendered.max())
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from .. import gloo
|
|
4
|
+
from .visual import Visual
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
_VERTEX_SHADER = """
|
|
8
|
+
attribute vec2 a_pos;
|
|
9
|
+
varying vec4 v_color;
|
|
10
|
+
|
|
11
|
+
void main() {
|
|
12
|
+
vec4 pos = vec4(a_pos, 0., 1.);
|
|
13
|
+
|
|
14
|
+
if($is_vertical==1)
|
|
15
|
+
{
|
|
16
|
+
pos.y = $render_to_visual(pos).y;
|
|
17
|
+
}
|
|
18
|
+
else
|
|
19
|
+
{
|
|
20
|
+
pos.x = $render_to_visual(pos).x;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
gl_Position = $transform(pos);
|
|
24
|
+
gl_PointSize = 10.;
|
|
25
|
+
v_color = $color;
|
|
26
|
+
}
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
_FRAGMENT_SHADER = """
|
|
30
|
+
varying vec4 v_color;
|
|
31
|
+
|
|
32
|
+
void main() {
|
|
33
|
+
gl_FragColor = v_color;
|
|
34
|
+
}
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class InfiniteLineVisual(Visual):
|
|
39
|
+
"""Infinite horizontal or vertical line for 2D plots.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
pos : float
|
|
44
|
+
Position of the line along the axis.
|
|
45
|
+
color : list, tuple, or array
|
|
46
|
+
The color to use when drawing the line. If an array is given, it
|
|
47
|
+
must be of shape (1, 4) and provide one rgba color per vertex.
|
|
48
|
+
line_width: float
|
|
49
|
+
The width of the Infinite line, in pixels
|
|
50
|
+
antialias: bool
|
|
51
|
+
If the line is drawn with antialiasing
|
|
52
|
+
vertical:
|
|
53
|
+
True for drawing a vertical line, False for an horizontal line
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
_shaders = {
|
|
57
|
+
'vertex': _VERTEX_SHADER,
|
|
58
|
+
'fragment': _FRAGMENT_SHADER,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
def __init__(self, pos=None, color=(1.0, 1.0, 1.0, 1.0), line_width=1.0, antialias=False,
|
|
62
|
+
vertical=True, **kwargs):
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
Visual.__init__(self, vcode=self._shaders['vertex'], fcode=self._shaders['fragment'])
|
|
67
|
+
|
|
68
|
+
self._changed = {'pos': False, 'color': False}
|
|
69
|
+
|
|
70
|
+
self.pos_buf = gloo.VertexBuffer()
|
|
71
|
+
# The Visual superclass contains a MultiProgram, which is an object
|
|
72
|
+
# that behaves like a normal shader program (you can assign shader
|
|
73
|
+
# code, upload values, set template variables, etc.) but internally
|
|
74
|
+
# manages multiple ModularProgram instances, one per view.
|
|
75
|
+
|
|
76
|
+
# The MultiProgram is accessed via the `shared_program` property, so
|
|
77
|
+
# the following modifications to the program will be applied to all
|
|
78
|
+
# views:
|
|
79
|
+
self.shared_program['a_pos'] = self.pos_buf
|
|
80
|
+
self._program.vert['is_vertical'] = 1 if vertical else 0
|
|
81
|
+
|
|
82
|
+
self._need_upload = False
|
|
83
|
+
self._is_vertical = bool(vertical)
|
|
84
|
+
self._pos = np.zeros((2, 2), dtype=np.float32)
|
|
85
|
+
self._color = np.ones(4, dtype=np.float32)
|
|
86
|
+
self._line_width = line_width
|
|
87
|
+
self._antialias = antialias
|
|
88
|
+
|
|
89
|
+
# Visual keeps track of draw mode, index buffer, and GL state. These
|
|
90
|
+
# are shared between all views.
|
|
91
|
+
self._draw_mode = 'line_strip'
|
|
92
|
+
self.set_gl_state('translucent', depth_test=False)
|
|
93
|
+
|
|
94
|
+
self.set_data(pos=pos, color=color)
|
|
95
|
+
|
|
96
|
+
def set_data(self, pos=None, color=None):
|
|
97
|
+
"""Set the data
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
pos : float
|
|
102
|
+
Position of the line along the axis.
|
|
103
|
+
color : list, tuple, or array
|
|
104
|
+
The color to use when drawing the line. If an array is given, it
|
|
105
|
+
must be of shape (1, 4) and provide one rgba color per vertex.
|
|
106
|
+
"""
|
|
107
|
+
if pos is not None:
|
|
108
|
+
pos = float(pos)
|
|
109
|
+
xy = self._pos
|
|
110
|
+
if self._is_vertical:
|
|
111
|
+
xy[0, 0] = pos
|
|
112
|
+
xy[0, 1] = -1
|
|
113
|
+
xy[1, 0] = pos
|
|
114
|
+
xy[1, 1] = 1
|
|
115
|
+
else:
|
|
116
|
+
xy[0, 0] = -1
|
|
117
|
+
xy[0, 1] = pos
|
|
118
|
+
xy[1, 0] = 1
|
|
119
|
+
xy[1, 1] = pos
|
|
120
|
+
self._changed['pos'] = True
|
|
121
|
+
|
|
122
|
+
if color is not None:
|
|
123
|
+
color = np.array(color, dtype=np.float32)
|
|
124
|
+
if color.ndim != 1 or color.shape[0] != 4:
|
|
125
|
+
raise ValueError('color must be a 4 element float rgba tuple,'
|
|
126
|
+
' list or array')
|
|
127
|
+
self._color = color
|
|
128
|
+
self._changed['color'] = True
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def color(self):
|
|
132
|
+
return self._color
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def pos(self):
|
|
136
|
+
if self._is_vertical:
|
|
137
|
+
return self._pos[0, 0]
|
|
138
|
+
else:
|
|
139
|
+
return self._pos[0, 1]
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def line_width(self):
|
|
143
|
+
return self._line_width
|
|
144
|
+
|
|
145
|
+
@line_width.setter
|
|
146
|
+
def line_width(self, val: float):
|
|
147
|
+
self._line_width = val
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def antialias(self):
|
|
151
|
+
return self._antialias
|
|
152
|
+
|
|
153
|
+
@antialias.setter
|
|
154
|
+
def antialias(self, val: float):
|
|
155
|
+
self._antialias = val
|
|
156
|
+
|
|
157
|
+
def _compute_bounds(self, axis, view):
|
|
158
|
+
"""Return the (min, max) bounding values of this visual along *axis*
|
|
159
|
+
in the local coordinate system.
|
|
160
|
+
"""
|
|
161
|
+
is_vertical = self._is_vertical
|
|
162
|
+
pos = self._pos
|
|
163
|
+
if axis == 0 and is_vertical:
|
|
164
|
+
return (pos[0, 0], pos[0, 0])
|
|
165
|
+
elif axis == 1 and not is_vertical:
|
|
166
|
+
return (self._pos[0, 1], self._pos[0, 1])
|
|
167
|
+
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def is_vertical(self):
|
|
172
|
+
return self._is_vertical
|
|
173
|
+
|
|
174
|
+
def _prepare_transforms(self, view=None):
|
|
175
|
+
program = view.view_program
|
|
176
|
+
transforms = view.transforms
|
|
177
|
+
program.vert['render_to_visual'] = transforms.get_transform('render',
|
|
178
|
+
'visual')
|
|
179
|
+
program.vert['transform'] = transforms.get_transform('visual',
|
|
180
|
+
'render')
|
|
181
|
+
|
|
182
|
+
def _prepare_draw(self, view=None):
|
|
183
|
+
"""This method is called immediately before each draw.
|
|
184
|
+
|
|
185
|
+
The *view* argument indicates which view is about to be drawn.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
self.update_gl_state(line_smooth=self._antialias)
|
|
189
|
+
px_scale = self.transforms.pixel_scale
|
|
190
|
+
width = px_scale * self._line_width
|
|
191
|
+
self.update_gl_state(line_width=max(width, 1.0))
|
|
192
|
+
|
|
193
|
+
if self._changed['pos']:
|
|
194
|
+
self.pos_buf.set_data(self._pos)
|
|
195
|
+
self._changed['pos'] = False
|
|
196
|
+
|
|
197
|
+
if self._changed['color']:
|
|
198
|
+
self._program.vert['color'] = self._color
|
|
199
|
+
self._changed['color'] = False
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
"""An instanced version of MeshVisual with arbitrary shifts, transforms, and colors."""
|
|
8
|
+
|
|
9
|
+
from __future__ import division
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
from ..gloo import VertexBuffer
|
|
14
|
+
from ..gloo.texture import downcast_to_32bit_if_needed
|
|
15
|
+
from ..color import ColorArray
|
|
16
|
+
from .filters import InstancedShadingFilter
|
|
17
|
+
from .shaders import Variable
|
|
18
|
+
|
|
19
|
+
from .mesh import MeshVisual
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
_VERTEX_SHADER = """
|
|
23
|
+
uniform bool use_instance_colors;
|
|
24
|
+
|
|
25
|
+
// these attributes will be defined on an instance basis
|
|
26
|
+
attribute vec3 shift;
|
|
27
|
+
attribute vec3 transform_x;
|
|
28
|
+
attribute vec3 transform_y;
|
|
29
|
+
attribute vec3 transform_z;
|
|
30
|
+
|
|
31
|
+
varying vec4 v_base_color;
|
|
32
|
+
void main() {
|
|
33
|
+
|
|
34
|
+
v_base_color = $color_transform($base_color);
|
|
35
|
+
|
|
36
|
+
// transform is generated from column vectors (new basis vectors)
|
|
37
|
+
// https://en.wikibooks.org/wiki/GLSL_Programming/Vector_and_Matrix_Operations#Constructors
|
|
38
|
+
mat3 instance_transform = mat3(transform_x, transform_y, transform_z);
|
|
39
|
+
vec3 pos_rotated = instance_transform * $to_vec4($position).xyz;
|
|
40
|
+
vec4 pos_shifted = $to_vec4(pos_rotated + shift);
|
|
41
|
+
gl_Position = $transform(pos_shifted);
|
|
42
|
+
}
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class InstancedMeshVisual(MeshVisual):
|
|
47
|
+
"""Instanced Mesh visual.
|
|
48
|
+
|
|
49
|
+
Mostly identical to MeshVisual, but additionally takes arrays of
|
|
50
|
+
of positions and transforms (optionally colors) to create multiple
|
|
51
|
+
instances of the mesh.
|
|
52
|
+
|
|
53
|
+
Instancing is a rendering technique that re-uses the same mesh data
|
|
54
|
+
by applying transformations to vertices and vertex data or textures,
|
|
55
|
+
wich can drastically improve performance compared to having many
|
|
56
|
+
simple MeshVisuals.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
instance_positions : (I, 3) array
|
|
61
|
+
Coordinates for each instance of the mesh.
|
|
62
|
+
instance_transforms : (I, 3, 3) array
|
|
63
|
+
Matrices for the transforms to apply to each instance.
|
|
64
|
+
instance_colors : ColorArray
|
|
65
|
+
Matrices of colors for each instance. Colors
|
|
66
|
+
*args : list
|
|
67
|
+
Positional arguments to pass to :class:`~vispy.visuals.mesh.MeshVisual`.
|
|
68
|
+
**kwargs : dict
|
|
69
|
+
Keyword arguments to pass to :class:`~vispy.visuals.mesh.MeshVisual`.
|
|
70
|
+
|
|
71
|
+
Examples
|
|
72
|
+
--------
|
|
73
|
+
See example `scene/instanced_mesh_visual.py` in the gallery.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
_shaders = {
|
|
77
|
+
'vertex': _VERTEX_SHADER,
|
|
78
|
+
'fragment': MeshVisual._shaders['fragment'],
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
_shading_filter_class = InstancedShadingFilter
|
|
82
|
+
|
|
83
|
+
def __init__(self, *args, instance_positions, instance_transforms, instance_colors=None, **kwargs):
|
|
84
|
+
self._instance_positions = None
|
|
85
|
+
self._instance_positions_vbo = None
|
|
86
|
+
self._instance_transforms = None
|
|
87
|
+
self._instance_transforms_vbos = None
|
|
88
|
+
self._instance_colors = None
|
|
89
|
+
self._instance_colors_vbo = None
|
|
90
|
+
super().__init__(*args, **kwargs)
|
|
91
|
+
self.instance_positions = instance_positions
|
|
92
|
+
self.instance_transforms = instance_transforms
|
|
93
|
+
self.instance_colors = instance_colors
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def instance_positions(self):
|
|
97
|
+
return self._instance_positions
|
|
98
|
+
|
|
99
|
+
@instance_positions.setter
|
|
100
|
+
def instance_positions(self, pos):
|
|
101
|
+
pos = np.reshape(pos, (-1, 3))
|
|
102
|
+
if pos.ndim != 2 or pos.shape[-1] != 3:
|
|
103
|
+
raise ValueError(f'positions must be 3D coordinates, but provided data has shape {pos.shape}')
|
|
104
|
+
self._instance_positions = downcast_to_32bit_if_needed(pos, dtype=np.float32)
|
|
105
|
+
self._instance_positions_vbo = VertexBuffer(self._instance_positions, divisor=1)
|
|
106
|
+
self.mesh_data_changed()
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def instance_transforms(self):
|
|
110
|
+
return self._instance_transforms
|
|
111
|
+
|
|
112
|
+
@instance_transforms.setter
|
|
113
|
+
def instance_transforms(self, matrix):
|
|
114
|
+
matrix = np.reshape(matrix, (-1, 3, 3))
|
|
115
|
+
if matrix.ndim != 3 or matrix.shape[1:] != (3, 3):
|
|
116
|
+
raise ValueError(f'transforms must be an array of 3x3 matrices, but provided data has shape {matrix.shape}')
|
|
117
|
+
self._instance_transforms = downcast_to_32bit_if_needed(matrix, dtype=np.float32)
|
|
118
|
+
# copy if not c contiguous
|
|
119
|
+
self._instance_transforms_vbos = (
|
|
120
|
+
VertexBuffer(np.ascontiguousarray(self._instance_transforms[..., 0]), divisor=1),
|
|
121
|
+
VertexBuffer(np.ascontiguousarray(self._instance_transforms[..., 1]), divisor=1),
|
|
122
|
+
VertexBuffer(np.ascontiguousarray(self._instance_transforms[..., 2]), divisor=1),
|
|
123
|
+
)
|
|
124
|
+
self.mesh_data_changed()
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def instance_colors(self):
|
|
128
|
+
return self._instance_colors
|
|
129
|
+
|
|
130
|
+
@instance_colors.setter
|
|
131
|
+
def instance_colors(self, colors):
|
|
132
|
+
if colors is not None:
|
|
133
|
+
colors = ColorArray(colors)
|
|
134
|
+
self._instance_colors_vbo = VertexBuffer(colors.rgba, divisor=1)
|
|
135
|
+
else:
|
|
136
|
+
self._instance_colors_vbo = Variable('base_color', self._color.rgba)
|
|
137
|
+
|
|
138
|
+
self._instance_colors = colors
|
|
139
|
+
self.mesh_data_changed()
|
|
140
|
+
|
|
141
|
+
def _update_data(self):
|
|
142
|
+
with self.events.data_updated.blocker():
|
|
143
|
+
super()._update_data()
|
|
144
|
+
|
|
145
|
+
# set instance buffers
|
|
146
|
+
self.shared_program.vert['base_color'] = self._instance_colors_vbo
|
|
147
|
+
self.shared_program['transform_x'] = self._instance_transforms_vbos[0]
|
|
148
|
+
self.shared_program['transform_y'] = self._instance_transforms_vbos[1]
|
|
149
|
+
self.shared_program['transform_z'] = self._instance_transforms_vbos[2]
|
|
150
|
+
self.shared_program['shift'] = self._instance_positions_vbo
|
|
151
|
+
|
|
152
|
+
self.events.data_updated()
|
|
@@ -0,0 +1,213 @@
|
|
|
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
|
+
from __future__ import division
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from .line import LineVisual
|
|
10
|
+
from ..color import ColorArray
|
|
11
|
+
from ..color.colormap import _normalize, get_colormap
|
|
12
|
+
from ..geometry.isocurve import isocurve
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class IsocurveVisual(LineVisual):
|
|
16
|
+
"""Displays an isocurve of a 2D scalar array.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
data : ndarray | None
|
|
21
|
+
2D scalar array.
|
|
22
|
+
levels : ndarray, shape (Nlev,) | None
|
|
23
|
+
The levels at which the isocurve is constructed from "*data*".
|
|
24
|
+
color_lev : Color, colormap name, tuple, list or array
|
|
25
|
+
The color to use when drawing the line. If a list is given, it
|
|
26
|
+
must be of shape (Nlev), if an array is given, it must be of
|
|
27
|
+
shape (Nlev, ...). and provide one color per level (rgba, colorname).
|
|
28
|
+
clim : tuple
|
|
29
|
+
(min, max) limits to apply when mapping level values through a
|
|
30
|
+
colormap.
|
|
31
|
+
**kwargs : dict
|
|
32
|
+
Keyword arguments to pass to `LineVisual`.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, data=None, levels=None, color_lev=None, clim=None,
|
|
36
|
+
**kwargs):
|
|
37
|
+
self._data = None
|
|
38
|
+
self._levels = levels
|
|
39
|
+
self._color_lev = color_lev
|
|
40
|
+
self._clim = clim
|
|
41
|
+
self._need_color_update = True
|
|
42
|
+
self._need_level_update = True
|
|
43
|
+
self._need_recompute = True
|
|
44
|
+
self._level_min = None
|
|
45
|
+
self._data_is_uniform = False
|
|
46
|
+
self._lc = None
|
|
47
|
+
self._cl = None
|
|
48
|
+
self._li = None
|
|
49
|
+
self._connect = None
|
|
50
|
+
self._verts = None
|
|
51
|
+
kwargs['method'] = 'gl'
|
|
52
|
+
kwargs['antialias'] = False
|
|
53
|
+
LineVisual.__init__(self, **kwargs)
|
|
54
|
+
if data is not None:
|
|
55
|
+
self.set_data(data)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def levels(self):
|
|
59
|
+
"""The threshold at which the isocurve is constructed from the
|
|
60
|
+
2D data.
|
|
61
|
+
"""
|
|
62
|
+
return self._levels
|
|
63
|
+
|
|
64
|
+
@levels.setter
|
|
65
|
+
def levels(self, levels):
|
|
66
|
+
self._levels = levels
|
|
67
|
+
self._need_level_update = True
|
|
68
|
+
self._need_recompute = True
|
|
69
|
+
self.update()
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def color(self):
|
|
73
|
+
return self._color_lev
|
|
74
|
+
|
|
75
|
+
@color.setter
|
|
76
|
+
def color(self, color):
|
|
77
|
+
self._color_lev = color
|
|
78
|
+
self._need_level_update = True
|
|
79
|
+
self._need_color_update = True
|
|
80
|
+
self.update()
|
|
81
|
+
|
|
82
|
+
def set_data(self, data):
|
|
83
|
+
"""Set the scalar array data
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
data : ndarray
|
|
88
|
+
A 2D array of scalar values. The isocurve is constructed to show
|
|
89
|
+
all locations in the scalar field equal to ``self.levels``.
|
|
90
|
+
"""
|
|
91
|
+
self._data = data
|
|
92
|
+
|
|
93
|
+
if self._clim is None:
|
|
94
|
+
self._clim = (data.min(), data.max())
|
|
95
|
+
|
|
96
|
+
# sanity check,
|
|
97
|
+
# should we raise an error here, since no isolines can be drawn?
|
|
98
|
+
# for now, _prepare_draw returns False if no isoline can be drawn
|
|
99
|
+
if self._data.min() != self._data.max():
|
|
100
|
+
self._data_is_uniform = False
|
|
101
|
+
else:
|
|
102
|
+
self._data_is_uniform = True
|
|
103
|
+
|
|
104
|
+
self._need_recompute = True
|
|
105
|
+
self.update()
|
|
106
|
+
|
|
107
|
+
def _get_verts_and_connect(self, paths):
|
|
108
|
+
"""Retrieve vertices and connects from given paths-list"""
|
|
109
|
+
verts = np.vstack(paths)
|
|
110
|
+
gaps = np.add.accumulate(np.array([len(x) for x in paths])) - 1
|
|
111
|
+
connect = np.ones(gaps[-1], dtype=bool)
|
|
112
|
+
connect[gaps[:-1]] = False
|
|
113
|
+
return verts, connect
|
|
114
|
+
|
|
115
|
+
def _compute_iso_line(self):
|
|
116
|
+
"""Compute LineVisual vertices, connects and color-index"""
|
|
117
|
+
level_index = []
|
|
118
|
+
connects = []
|
|
119
|
+
verts = []
|
|
120
|
+
|
|
121
|
+
# calculate which level are within data range
|
|
122
|
+
# this works for now and the existing examples, but should be tested
|
|
123
|
+
# thoroughly also with the data-sanity check in set_data-function
|
|
124
|
+
choice = np.nonzero((self.levels > self._data.min()) &
|
|
125
|
+
(self.levels < self._data.max()))
|
|
126
|
+
levels_to_calc = np.array(self.levels)[choice]
|
|
127
|
+
|
|
128
|
+
# save minimum level index
|
|
129
|
+
self._level_min = choice[0][0]
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
from skimage.measure import find_contours
|
|
133
|
+
except ImportError:
|
|
134
|
+
find_contours = None
|
|
135
|
+
|
|
136
|
+
for level in levels_to_calc:
|
|
137
|
+
# if we use skimage isoline algorithm we need to add half a
|
|
138
|
+
# pixel in both (x,y) dimensions because isolines are aligned to
|
|
139
|
+
# pixel centers
|
|
140
|
+
if find_contours is not None:
|
|
141
|
+
contours = find_contours(self._data, level,
|
|
142
|
+
positive_orientation='high')
|
|
143
|
+
v, c = self._get_verts_and_connect(contours)
|
|
144
|
+
# swap row, column to column, row (x, y)
|
|
145
|
+
v[:, [0, 1]] = v[:, [1, 0]]
|
|
146
|
+
v += np.array([0.5, 0.5])
|
|
147
|
+
else:
|
|
148
|
+
paths = isocurve(self._data.astype(float).T, level,
|
|
149
|
+
extend_to_edge=True, connected=True)
|
|
150
|
+
v, c = self._get_verts_and_connect(paths)
|
|
151
|
+
|
|
152
|
+
level_index.append(v.shape[0])
|
|
153
|
+
connects.append(np.hstack((c, [False])))
|
|
154
|
+
verts.append(v)
|
|
155
|
+
|
|
156
|
+
self._li = np.hstack(level_index)
|
|
157
|
+
self._connect = np.hstack(connects)
|
|
158
|
+
self._verts = np.vstack(verts)
|
|
159
|
+
|
|
160
|
+
def _compute_iso_color(self):
|
|
161
|
+
"""Compute LineVisual color from level index and corresponding color"""
|
|
162
|
+
level_color = []
|
|
163
|
+
colors = self._lc
|
|
164
|
+
for i, index in enumerate(self._li):
|
|
165
|
+
level_color.append(np.zeros((index, 4)) +
|
|
166
|
+
colors[i+self._level_min])
|
|
167
|
+
self._cl = np.vstack(level_color)
|
|
168
|
+
|
|
169
|
+
def _levels_to_colors(self):
|
|
170
|
+
# computes ColorArrays for given levels
|
|
171
|
+
# try _color_lev as colormap, except as everything else
|
|
172
|
+
try:
|
|
173
|
+
f_color_levs = get_colormap(self._color_lev)
|
|
174
|
+
except (KeyError, TypeError):
|
|
175
|
+
colors = ColorArray(self._color_lev).rgba
|
|
176
|
+
else:
|
|
177
|
+
lev = _normalize(self._levels, self._clim[0], self._clim[1])
|
|
178
|
+
# map function expects (Nlev,1)!
|
|
179
|
+
colors = f_color_levs.map(lev[:, np.newaxis])
|
|
180
|
+
|
|
181
|
+
# broadcast to (nlev, 4) array
|
|
182
|
+
if len(colors) == 1:
|
|
183
|
+
colors = colors * np.ones((len(self._levels), 1))
|
|
184
|
+
|
|
185
|
+
# detect color_lev/levels mismatch and raise error
|
|
186
|
+
if (len(colors) != len(self._levels)):
|
|
187
|
+
raise TypeError("Color/level mismatch. Color must be of shape "
|
|
188
|
+
"(Nlev, ...) and provide one color per level")
|
|
189
|
+
|
|
190
|
+
self._lc = colors
|
|
191
|
+
|
|
192
|
+
def _prepare_draw(self, view):
|
|
193
|
+
if (self._data is None or self._levels is None or
|
|
194
|
+
self._color_lev is None or self._data_is_uniform):
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
if self._need_level_update:
|
|
198
|
+
self._levels_to_colors()
|
|
199
|
+
self._need_level_update = False
|
|
200
|
+
|
|
201
|
+
if self._need_recompute:
|
|
202
|
+
self._compute_iso_line()
|
|
203
|
+
self._compute_iso_color()
|
|
204
|
+
LineVisual.set_data(self, pos=self._verts, connect=self._connect,
|
|
205
|
+
color=self._cl)
|
|
206
|
+
self._need_recompute = False
|
|
207
|
+
|
|
208
|
+
if self._need_color_update:
|
|
209
|
+
self._compute_iso_color()
|
|
210
|
+
LineVisual.set_data(self, color=self._cl)
|
|
211
|
+
self._need_color_update = False
|
|
212
|
+
|
|
213
|
+
return LineVisual._prepare_draw(self, view)
|