vispy 0.14.0__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.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 +968 -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 +1134 -0
- vispy/color/tests/__init__.py +0 -0
- vispy/color/tests/test_color.py +352 -0
- vispy/conftest.py +12 -0
- vispy/ext/__init__.py +0 -0
- vispy/ext/cocoapy.py +1542 -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 +134 -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 +698 -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 +506 -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 +566 -0
- vispy/gloo/gl/tests/test_names.py +246 -0
- vispy/gloo/gl/tests/test_use.py +71 -0
- vispy/gloo/glir.py +1816 -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 +1045 -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 +106 -0
- vispy/scene/cameras/base_camera.py +538 -0
- vispy/scene/cameras/fly.py +474 -0
- vispy/scene/cameras/magnify.py +163 -0
- vispy/scene/cameras/panzoom.py +308 -0
- vispy/scene/cameras/perspective.py +333 -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 +173 -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 +446 -0
- vispy/testing/_testing.py +416 -0
- vispy/testing/image_tester.py +473 -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 +17 -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 +4 -0
- vispy/visuals/__init__.py +50 -0
- vispy/visuals/_scalable_textures.py +485 -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 +163 -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 +796 -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 +105 -0
- vispy/visuals/gridmesh.py +98 -0
- vispy/visuals/histogram.py +58 -0
- vispy/visuals/image.py +688 -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 +810 -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_histogram.py +24 -0
- vispy/visuals/tests/test_image.py +390 -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 +180 -0
- vispy/visuals/tests/test_sdf.py +73 -0
- vispy/visuals/tests/test_spectrogram.py +42 -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-312-aarch64-linux-gnu.so +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +110 -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 +1335 -0
- vispy/visuals/windbarb.py +291 -0
- vispy/visuals/xyz_axis.py +34 -0
- vispy-0.14.0.dist-info/LICENSE.txt +36 -0
- vispy-0.14.0.dist-info/METADATA +218 -0
- vispy-0.14.0.dist-info/RECORD +519 -0
- vispy-0.14.0.dist-info/WHEEL +6 -0
- vispy-0.14.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,105 @@
|
|
|
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
|
+
import os
|
|
8
|
+
from os import path as op
|
|
9
|
+
import warnings
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
from ctypes import (cast, byref, sizeof, create_unicode_buffer,
|
|
13
|
+
c_void_p, c_wchar_p)
|
|
14
|
+
from ...ext.gdi32plus import (gdiplus, gdi32, user32, winreg, LOGFONT,
|
|
15
|
+
OUTLINETEXTMETRIC, GM_ADVANCED, FW_NORMAL,
|
|
16
|
+
FW_BOLD, LF_FACESIZE, DEFAULT_CHARSET,
|
|
17
|
+
TRUETYPE_FONTTYPE, FONTENUMPROC, BOOL)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Inspired by:
|
|
21
|
+
# http://forums.codeguru.com/showthread.php?90792-How-to-get-a-system-
|
|
22
|
+
# font-file-name-given-a-LOGFONT-face-name
|
|
23
|
+
|
|
24
|
+
# XXX This isn't perfect, but it should work for now...
|
|
25
|
+
|
|
26
|
+
def find_font(face, bold, italic, orig_face=None):
|
|
27
|
+
style_dict = {'Regular': 0, 'Bold': 1, 'Italic': 2, 'Bold Italic': 3}
|
|
28
|
+
|
|
29
|
+
# Figure out which font to actually use by trying to instantiate by name
|
|
30
|
+
dc = user32.GetDC(0) # noqa, analysis:ignore
|
|
31
|
+
gdi32.SetGraphicsMode(dc, GM_ADVANCED) # only TT and OT fonts
|
|
32
|
+
logfont = LOGFONT()
|
|
33
|
+
logfont.lfHeight = -12 # conv point to pixels
|
|
34
|
+
logfont.lfWeight = FW_BOLD if bold else FW_NORMAL
|
|
35
|
+
logfont.lfItalic = italic
|
|
36
|
+
logfont.lfFaceName = face # logfont needs Unicode
|
|
37
|
+
hfont = gdi32.CreateFontIndirectW(byref(logfont))
|
|
38
|
+
original = gdi32.SelectObject(dc, hfont)
|
|
39
|
+
n_byte = gdi32.GetOutlineTextMetricsW(dc, 0, None)
|
|
40
|
+
assert n_byte > 0
|
|
41
|
+
metrics = OUTLINETEXTMETRIC()
|
|
42
|
+
assert sizeof(metrics) >= n_byte
|
|
43
|
+
assert gdi32.GetOutlineTextMetricsW(dc, n_byte, byref(metrics))
|
|
44
|
+
gdi32.SelectObject(dc, original)
|
|
45
|
+
user32.ReleaseDC(None, dc)
|
|
46
|
+
use_face = cast(byref(metrics, metrics.otmpFamilyName), c_wchar_p).value
|
|
47
|
+
if use_face != face:
|
|
48
|
+
warnings.warn('Could not find face match "%s", falling back to "%s"'
|
|
49
|
+
% (orig_face or face, use_face))
|
|
50
|
+
use_style = cast(byref(metrics, metrics.otmpStyleName), c_wchar_p).value
|
|
51
|
+
use_style = style_dict.get(use_style, 'Regular')
|
|
52
|
+
# AK: I get "Standaard" for use_style, which is Dutch for standard/regular
|
|
53
|
+
|
|
54
|
+
# Now we match by creating private font collections until we find
|
|
55
|
+
# the one that was used
|
|
56
|
+
font_dir = op.join(os.environ['WINDIR'], 'Fonts')
|
|
57
|
+
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
|
58
|
+
key = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts'
|
|
59
|
+
reg_vals = winreg.OpenKey(reg, key)
|
|
60
|
+
n_values = winreg.QueryInfoKey(reg_vals)[1]
|
|
61
|
+
fname = None
|
|
62
|
+
for vi in range(n_values):
|
|
63
|
+
name, ff = winreg.EnumValue(reg_vals, vi)[:2]
|
|
64
|
+
if name.endswith('(TrueType)'):
|
|
65
|
+
ff = op.join(font_dir, ff) if op.basename(ff) == ff else ff
|
|
66
|
+
assert op.isfile(ff)
|
|
67
|
+
pc = c_void_p()
|
|
68
|
+
assert gdiplus.GdipNewPrivateFontCollection(byref(pc)) == 0
|
|
69
|
+
gdiplus.GdipPrivateAddFontFile(pc, ff)
|
|
70
|
+
family = c_void_p()
|
|
71
|
+
if gdiplus.GdipCreateFontFamilyFromName(use_face, pc,
|
|
72
|
+
byref(family)) == 0:
|
|
73
|
+
val = BOOL()
|
|
74
|
+
assert gdiplus.GdipIsStyleAvailable(family, use_style,
|
|
75
|
+
byref(val)) == 0
|
|
76
|
+
if val.value:
|
|
77
|
+
buf = create_unicode_buffer(LF_FACESIZE)
|
|
78
|
+
assert gdiplus.GdipGetFamilyName(family, buf, 0) == 0
|
|
79
|
+
assert buf.value == use_face
|
|
80
|
+
fname = ff
|
|
81
|
+
break
|
|
82
|
+
fname = fname or find_font('', bold, italic, face) # fall back to default
|
|
83
|
+
return fname
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _list_fonts():
|
|
87
|
+
dc = user32.GetDC(0)
|
|
88
|
+
gdi32.SetGraphicsMode(dc, GM_ADVANCED) # only TT and OT fonts
|
|
89
|
+
logfont = LOGFONT()
|
|
90
|
+
logfont.lfCharSet = DEFAULT_CHARSET
|
|
91
|
+
logfont.lfFaceName = ''
|
|
92
|
+
logfont.lfPitchandFamily = 0
|
|
93
|
+
fonts = list()
|
|
94
|
+
|
|
95
|
+
def enum_fun(lp_logfont, lp_text_metric, font_type, l_param):
|
|
96
|
+
# Only support TTF for now (silly Windows shortcomings)
|
|
97
|
+
if font_type == TRUETYPE_FONTTYPE:
|
|
98
|
+
font = lp_logfont.contents.lfFaceName
|
|
99
|
+
if not font.startswith('@') and font not in fonts:
|
|
100
|
+
fonts.append(font)
|
|
101
|
+
return 1
|
|
102
|
+
|
|
103
|
+
gdi32.EnumFontFamiliesExW(dc, byref(logfont), FONTENUMPROC(enum_fun), 0, 0)
|
|
104
|
+
user32.ReleaseDC(None, dc)
|
|
105
|
+
return fonts
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
import warnings
|
|
7
|
+
|
|
8
|
+
from vispy.testing import assert_in, run_tests_if_main
|
|
9
|
+
from vispy.util.fonts import list_fonts, _load_glyph, _vispy_fonts
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
known_bad_fonts = set([
|
|
13
|
+
'Noto Color Emoji', # https://github.com/vispy/vispy/issues/1771
|
|
14
|
+
'Bahnschrift', # https://github.com/vispy/vispy/pull/1974
|
|
15
|
+
])
|
|
16
|
+
|
|
17
|
+
# try both a vispy and system font <--- what does this mean???
|
|
18
|
+
sys_fonts = set(list_fonts()) - set(_vispy_fonts)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_font_list():
|
|
22
|
+
"""Test font listing"""
|
|
23
|
+
f = list_fonts()
|
|
24
|
+
assert len(f) > 0
|
|
25
|
+
for font in _vispy_fonts:
|
|
26
|
+
assert_in(font, f)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.mark.parametrize('face', ['OpenSans'] + sorted(sys_fonts))
|
|
30
|
+
def test_font_glyph(face):
|
|
31
|
+
"""Test loading glyphs"""
|
|
32
|
+
if face in known_bad_fonts or face.split(" ")[0] in known_bad_fonts:
|
|
33
|
+
pytest.xfail()
|
|
34
|
+
font_dict = dict(face=face, size=12, bold=False, italic=False)
|
|
35
|
+
glyphs_dict = dict()
|
|
36
|
+
chars = 'foobar^C&#'
|
|
37
|
+
for char in chars:
|
|
38
|
+
# Warning that Arial might not exist
|
|
39
|
+
with warnings.catch_warnings(record=True):
|
|
40
|
+
warnings.simplefilter('always')
|
|
41
|
+
_load_glyph(font_dict, char, glyphs_dict)
|
|
42
|
+
assert len(glyphs_dict) == np.unique([c for c in chars]).size
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
run_tests_if_main()
|
vispy/util/fourier.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
|
|
7
|
+
|
|
8
|
+
def stft(x, n_fft=1024, step=512, fs=2*np.pi, window='hann'):
|
|
9
|
+
"""Compute the STFT
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
x : array-like
|
|
14
|
+
1D signal to operate on. ``If len(x) < n_fft``, x will be zero-padded
|
|
15
|
+
to length ``n_fft``.
|
|
16
|
+
n_fft : int
|
|
17
|
+
Number of FFT points. Much faster for powers of two.
|
|
18
|
+
step : int | None
|
|
19
|
+
Step size between calculations. If None, ``n_fft // 2``
|
|
20
|
+
will be used.
|
|
21
|
+
fs : float
|
|
22
|
+
The sample rate of the data.
|
|
23
|
+
window : str | None
|
|
24
|
+
Window function to use. Can be ``'hann'`` for Hann window, or None
|
|
25
|
+
for no windowing.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
stft : ndarray
|
|
30
|
+
Spectrogram of the data, shape (n_freqs, n_steps).
|
|
31
|
+
|
|
32
|
+
See also
|
|
33
|
+
--------
|
|
34
|
+
fft_freqs
|
|
35
|
+
"""
|
|
36
|
+
x = np.asarray(x, float)
|
|
37
|
+
if x.ndim != 1:
|
|
38
|
+
raise ValueError('x must be 1D')
|
|
39
|
+
if window is not None:
|
|
40
|
+
if window not in ('hann',):
|
|
41
|
+
raise ValueError('window must be "hann" or None')
|
|
42
|
+
w = np.hanning(n_fft)
|
|
43
|
+
else:
|
|
44
|
+
w = np.ones(n_fft)
|
|
45
|
+
n_fft = int(n_fft)
|
|
46
|
+
step = max(n_fft // 2, 1) if step is None else int(step)
|
|
47
|
+
fs = float(fs)
|
|
48
|
+
zero_pad = n_fft - len(x)
|
|
49
|
+
if zero_pad > 0:
|
|
50
|
+
x = np.concatenate((x, np.zeros(zero_pad, float)))
|
|
51
|
+
n_freqs = n_fft // 2 + 1
|
|
52
|
+
n_estimates = (len(x) - n_fft) // step + 1
|
|
53
|
+
result = np.empty((n_freqs, n_estimates), np.complex128)
|
|
54
|
+
for ii in range(n_estimates):
|
|
55
|
+
result[:, ii] = np.fft.rfft(w * x[ii * step:ii * step + n_fft]) / n_fft
|
|
56
|
+
return result
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def fft_freqs(n_fft, fs):
|
|
60
|
+
"""Return frequencies for DFT
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
n_fft : int
|
|
65
|
+
Number of points in the FFT.
|
|
66
|
+
fs : float
|
|
67
|
+
The sampling rate.
|
|
68
|
+
"""
|
|
69
|
+
return np.arange(0, (n_fft // 2 + 1)) / float(n_fft) * float(fs)
|
vispy/util/frozen.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
|
|
6
|
+
# Class adapted from:
|
|
7
|
+
# http://stackoverflow.com/questions/3603502/
|
|
8
|
+
|
|
9
|
+
class Frozen(object):
|
|
10
|
+
__isfrozen = False
|
|
11
|
+
|
|
12
|
+
def __setattr__(self, key, value):
|
|
13
|
+
if self.__isfrozen and not hasattr(self, key):
|
|
14
|
+
raise AttributeError('%r is not an attribute of class %s. Call '
|
|
15
|
+
'"unfreeze()" to allow addition of new '
|
|
16
|
+
'attributes' % (key, self))
|
|
17
|
+
object.__setattr__(self, key, value)
|
|
18
|
+
|
|
19
|
+
def freeze(self):
|
|
20
|
+
"""Freeze the object so that only existing properties can be set"""
|
|
21
|
+
self.__isfrozen = True
|
|
22
|
+
|
|
23
|
+
def unfreeze(self):
|
|
24
|
+
"""Unfreeze the object so that additional properties can be added"""
|
|
25
|
+
self.__isfrozen = False
|
|
@@ -0,0 +1,268 @@
|
|
|
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
|
+
"""Scraper for sphinx-gallery.
|
|
5
|
+
|
|
6
|
+
This is used to collect screenshots from the examples when executed via
|
|
7
|
+
sphinx-gallery. This can be included in any project wanting to take
|
|
8
|
+
advantage of this by adding the following to your sphinx ``conf.py``:
|
|
9
|
+
|
|
10
|
+
.. code-block:: python
|
|
11
|
+
|
|
12
|
+
sphinx_gallery_conf = {
|
|
13
|
+
...
|
|
14
|
+
'image_scrapers': ('vispy',)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
The scraper is provided to sphinx-gallery via the
|
|
18
|
+
``vispy._get_sg_image_scraper()`` function.
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import os
|
|
25
|
+
import time
|
|
26
|
+
import shutil
|
|
27
|
+
from vispy.io import imsave
|
|
28
|
+
from vispy.gloo.util import _screenshot
|
|
29
|
+
from vispy.scene import SceneCanvas
|
|
30
|
+
|
|
31
|
+
from sphinx_gallery.scrapers import optipng, figure_rst
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class VisPyGalleryScraper:
|
|
35
|
+
"""Custom sphinx-gallery scraper to save the current Canvas to an image."""
|
|
36
|
+
|
|
37
|
+
def __repr__(self):
|
|
38
|
+
return self.__class__.__name__
|
|
39
|
+
|
|
40
|
+
def __call__(self, block, block_vars, gallery_conf):
|
|
41
|
+
"""Scrape VisPy Canvases and applications.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
block : tuple
|
|
46
|
+
A tuple containing the (label, content, line_number) of the block.
|
|
47
|
+
block_vars : dict
|
|
48
|
+
Dict of block variables.
|
|
49
|
+
gallery_conf : dict
|
|
50
|
+
Contains the configuration of Sphinx-Gallery
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
rst : str
|
|
55
|
+
The ReSTructuredText that will be rendered to HTML containing
|
|
56
|
+
the images. This is often produced by
|
|
57
|
+
:func:`sphinx_gallery.scrapers.figure_rst`.
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
example_fn = block_vars["src_file"]
|
|
61
|
+
frame_num_list = self._get_frame_list_from_source(example_fn)
|
|
62
|
+
image_path_iterator = block_vars['image_path_iterator']
|
|
63
|
+
canvas_or_widget = get_canvaslike_from_globals(block_vars["example_globals"])
|
|
64
|
+
if not frame_num_list:
|
|
65
|
+
image_paths = []
|
|
66
|
+
elif isinstance(frame_num_list[0], str):
|
|
67
|
+
# example produces an image/animation as output
|
|
68
|
+
image_paths = []
|
|
69
|
+
for frame_image, image_path in zip(frame_num_list, image_path_iterator):
|
|
70
|
+
image_path = os.path.splitext(image_path)[0] + os.path.splitext(frame_image)[1]
|
|
71
|
+
shutil.move(frame_image, image_path)
|
|
72
|
+
image_paths.append(image_path)
|
|
73
|
+
else:
|
|
74
|
+
image_paths = self._save_example_to_files(
|
|
75
|
+
canvas_or_widget, frame_num_list, gallery_conf, image_path_iterator)
|
|
76
|
+
|
|
77
|
+
fig_titles = "" # alt text
|
|
78
|
+
# FUTURE: Handle non-images (ex. MP4s) with raw HTML
|
|
79
|
+
return figure_rst(image_paths, gallery_conf['src_dir'], fig_titles)
|
|
80
|
+
|
|
81
|
+
def _save_example_to_files(self, canvas_or_widget, frame_num_list, gallery_conf, image_path_iterator):
|
|
82
|
+
image_path = next(image_path_iterator)
|
|
83
|
+
frame_grabber = FrameGrabber(canvas_or_widget, frame_num_list)
|
|
84
|
+
frame_grabber.collect_frames()
|
|
85
|
+
if len(frame_num_list) > 1:
|
|
86
|
+
# let's make an animation
|
|
87
|
+
# FUTURE: mp4 with imageio?
|
|
88
|
+
image_path = os.path.splitext(image_path)[0] + ".gif"
|
|
89
|
+
frame_grabber.save_animation(image_path)
|
|
90
|
+
else:
|
|
91
|
+
frame_grabber.save_frame(image_path)
|
|
92
|
+
frame_grabber.cleanup()
|
|
93
|
+
if 'images' in gallery_conf['compress_images']:
|
|
94
|
+
optipng(image_path, gallery_conf['compress_images_args'])
|
|
95
|
+
return [image_path]
|
|
96
|
+
|
|
97
|
+
def _get_frame_list_from_source(self, filename):
|
|
98
|
+
lines = open(filename, 'rb').read().decode('utf-8').splitlines()
|
|
99
|
+
for line in lines[:10]:
|
|
100
|
+
if not line.startswith("# vispy:"):
|
|
101
|
+
continue
|
|
102
|
+
if "gallery-exports" in line:
|
|
103
|
+
_frames = line.split('gallery-exports')[1].split(',')[0].strip()
|
|
104
|
+
frames = self._frame_exports_to_list(_frames)
|
|
105
|
+
break
|
|
106
|
+
if "gallery " in line:
|
|
107
|
+
# Get what frames to grab
|
|
108
|
+
_frames = line.split('gallery')[1].split(',')[0].strip()
|
|
109
|
+
frames = self._frame_specifier_to_list(_frames)
|
|
110
|
+
break
|
|
111
|
+
else:
|
|
112
|
+
# no frame number hint - don't grab any frames
|
|
113
|
+
frames = []
|
|
114
|
+
return frames
|
|
115
|
+
|
|
116
|
+
def _frame_specifier_to_list(self, frame_specifier):
|
|
117
|
+
_frames = frame_specifier or '0'
|
|
118
|
+
frames = [int(i) for i in _frames.split(':')]
|
|
119
|
+
if not frames:
|
|
120
|
+
frames = [5]
|
|
121
|
+
if len(frames) > 1:
|
|
122
|
+
frames = list(range(*frames))
|
|
123
|
+
return frames
|
|
124
|
+
|
|
125
|
+
def _frame_exports_to_list(self, frame_specifier):
|
|
126
|
+
frames = frame_specifier.split(" ")
|
|
127
|
+
frame_paths = []
|
|
128
|
+
for frame_fn in frames:
|
|
129
|
+
# existing image file created by the example
|
|
130
|
+
if not os.path.isfile(frame_fn):
|
|
131
|
+
raise FileNotFoundError(
|
|
132
|
+
"Example gallery frame specifier must be a frame number, "
|
|
133
|
+
"frame range, or relative filename produced by the example.")
|
|
134
|
+
frame_paths.append(frame_fn)
|
|
135
|
+
return frame_paths
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def get_canvaslike_from_globals(globals_dict):
|
|
139
|
+
qt_widget = _get_qt_top_parent(globals_dict)
|
|
140
|
+
if qt_widget is not None:
|
|
141
|
+
return qt_widget
|
|
142
|
+
|
|
143
|
+
# Get canvas
|
|
144
|
+
if "canvas" in globals_dict:
|
|
145
|
+
return globals_dict["canvas"]
|
|
146
|
+
if "Canvas" in globals_dict:
|
|
147
|
+
return globals_dict["Canvas"]()
|
|
148
|
+
if "fig" in globals_dict:
|
|
149
|
+
return globals_dict["fig"]
|
|
150
|
+
return None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _get_qt_top_parent(globals_dict):
|
|
154
|
+
if "QWidget" not in globals_dict and "QMainWindow" not in globals_dict and "QtWidgets" not in globals_dict:
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
qtwidgets = globals_dict.get("QtWidgets")
|
|
158
|
+
qmainwindow = globals_dict.get("QMainWindow", getattr(qtwidgets, "QMainWindow", None))
|
|
159
|
+
qwidget = globals_dict.get("QWidget", getattr(qtwidgets, "QWidget", qmainwindow))
|
|
160
|
+
all_qt_widgets = [widget for widget in globals_dict.values()
|
|
161
|
+
if isinstance(widget, qwidget) and widget is not None]
|
|
162
|
+
all_qt_mains = [widget for widget in all_qt_widgets if isinstance(widget, qmainwindow)]
|
|
163
|
+
if all_qt_mains:
|
|
164
|
+
return all_qt_mains[0]
|
|
165
|
+
if all_qt_widgets:
|
|
166
|
+
return all_qt_widgets[0]
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class FrameGrabber:
|
|
171
|
+
"""Helper to grab a series of screenshots from the current Canvas-like object."""
|
|
172
|
+
|
|
173
|
+
def __init__(self, canvas_obj, frame_grab_list: list[int]):
|
|
174
|
+
self._canvas = canvas_obj
|
|
175
|
+
self._done = False
|
|
176
|
+
self._current_frame = -1
|
|
177
|
+
self._collected_images = []
|
|
178
|
+
self._frames_to_grab = frame_grab_list[:] # copy so original list is preserved
|
|
179
|
+
|
|
180
|
+
def cleanup(self):
|
|
181
|
+
from PyQt5.QtWidgets import QApplication
|
|
182
|
+
for child_widget in QApplication.allWidgets():
|
|
183
|
+
if hasattr(child_widget, 'close'):
|
|
184
|
+
child_widget.close()
|
|
185
|
+
QApplication.processEvents()
|
|
186
|
+
|
|
187
|
+
def on_draw(self, _):
|
|
188
|
+
if self._done:
|
|
189
|
+
return # Grab only once
|
|
190
|
+
self._current_frame += 1
|
|
191
|
+
if self._current_frame in self._frames_to_grab:
|
|
192
|
+
self._frames_to_grab.remove(self._current_frame)
|
|
193
|
+
if isinstance(self._canvas, SceneCanvas):
|
|
194
|
+
im = self._canvas.render(alpha=True)
|
|
195
|
+
else:
|
|
196
|
+
im = _screenshot()
|
|
197
|
+
self._collected_images.append(im)
|
|
198
|
+
if not self._frames_to_grab or self._current_frame > self._frames_to_grab[0]:
|
|
199
|
+
self._done = True
|
|
200
|
+
|
|
201
|
+
def collect_frames(self):
|
|
202
|
+
"""Show current Canvas and render and collect all frames requested."""
|
|
203
|
+
if self._is_qt_widget():
|
|
204
|
+
self._grab_qt_screenshot()
|
|
205
|
+
else:
|
|
206
|
+
self._grab_vispy_screenshots()
|
|
207
|
+
|
|
208
|
+
def _is_qt_widget(self):
|
|
209
|
+
try:
|
|
210
|
+
from PyQt5.QtWidgets import QWidget
|
|
211
|
+
except ImportError:
|
|
212
|
+
return False
|
|
213
|
+
return isinstance(self._canvas, QWidget)
|
|
214
|
+
|
|
215
|
+
def _grab_qt_screenshot(self):
|
|
216
|
+
from PyQt5.QtWidgets import QApplication
|
|
217
|
+
from PyQt5.QtCore import QTimer
|
|
218
|
+
self._canvas.show()
|
|
219
|
+
# Qt is going to grab from the screen so we need the window on top
|
|
220
|
+
self._canvas.raise_()
|
|
221
|
+
# We need to give the GUI event loop and OS time to draw everything
|
|
222
|
+
time.sleep(1.5)
|
|
223
|
+
QApplication.processEvents()
|
|
224
|
+
QTimer.singleShot(1000, self._grab_widget_screenshot)
|
|
225
|
+
time.sleep(1.5)
|
|
226
|
+
QApplication.processEvents()
|
|
227
|
+
|
|
228
|
+
def _grab_widget_screenshot(self):
|
|
229
|
+
from PyQt5.QtWidgets import QApplication
|
|
230
|
+
screen = QApplication.screenAt(self._canvas.pos())
|
|
231
|
+
screenshot = screen.grabWindow(int(self._canvas.windowHandle().winId()))
|
|
232
|
+
arr = self._qpixmap_to_ndarray(screenshot)
|
|
233
|
+
self._collected_images.append(arr)
|
|
234
|
+
|
|
235
|
+
@staticmethod
|
|
236
|
+
def _qpixmap_to_ndarray(pixmap):
|
|
237
|
+
from PyQt5 import QtGui
|
|
238
|
+
import numpy as np
|
|
239
|
+
im = pixmap.toImage().convertToFormat(QtGui.QImage.Format.Format_RGB32)
|
|
240
|
+
size = pixmap.size()
|
|
241
|
+
width = size.width()
|
|
242
|
+
height = size.height()
|
|
243
|
+
im_bits = im.constBits()
|
|
244
|
+
im_bits.setsize(height * width * 4)
|
|
245
|
+
# Convert 0xffRRGGBB buffer -> (B, G, R, 0xff) -> (R, G, B)
|
|
246
|
+
return np.array(im_bits).reshape((height, width, 4))[:, :, 2::-1]
|
|
247
|
+
|
|
248
|
+
def _grab_vispy_screenshots(self):
|
|
249
|
+
os.environ['VISPY_IGNORE_OLD_VERSION'] = 'true'
|
|
250
|
+
self._canvas.events.draw.connect(self.on_draw, position='last')
|
|
251
|
+
with self._canvas as c:
|
|
252
|
+
self._collect_frames(c)
|
|
253
|
+
|
|
254
|
+
def _collect_frames(self, canvas, limit=10000):
|
|
255
|
+
n = 0
|
|
256
|
+
while not self._done and n < limit:
|
|
257
|
+
canvas.update()
|
|
258
|
+
canvas.app.process_events()
|
|
259
|
+
n += 1
|
|
260
|
+
if n >= limit or len(self._frames_to_grab) > 0:
|
|
261
|
+
raise RuntimeError("Could not collect any images")
|
|
262
|
+
|
|
263
|
+
def save_frame(self, filename, frame_index=0):
|
|
264
|
+
imsave(filename, self._collected_images[frame_index])
|
|
265
|
+
|
|
266
|
+
def save_animation(self, filename):
|
|
267
|
+
import imageio # multiple gif not properly supported yet
|
|
268
|
+
imageio.mimsave(filename, self._collected_images)
|
vispy/util/keys.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
"""Define constants for keys.
|
|
6
|
+
|
|
7
|
+
Each key constant is defined as a Key object, which allows comparison with
|
|
8
|
+
strings (e.g. 'A', 'Escape', 'Shift'). This enables handling of key events
|
|
9
|
+
without using the key constants explicitly (e.g. ``if ev.key == 'Left':``).
|
|
10
|
+
|
|
11
|
+
In addition, key objects that represent characters can be matched to
|
|
12
|
+
the integer ordinal (e.g. 32 for space, 65 for A). This behavior is mainly
|
|
13
|
+
intended as a compatibility measure.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Key(object):
|
|
19
|
+
"""Represent the identity of a certain key.
|
|
20
|
+
|
|
21
|
+
This represents one or more names that the key in question is known by.
|
|
22
|
+
|
|
23
|
+
A Key object can be compared to one of its string names (case
|
|
24
|
+
insensitive), to the integer ordinal of the key (only for keys that
|
|
25
|
+
represent characters), and to another Key instance.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, *names):
|
|
29
|
+
self._names = names
|
|
30
|
+
self._names_upper = tuple([v.upper() for v in names])
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def name(self):
|
|
34
|
+
"""The primary name of the key."""
|
|
35
|
+
return self._names[0]
|
|
36
|
+
|
|
37
|
+
def __hash__(self):
|
|
38
|
+
return self._names[0].__hash__()
|
|
39
|
+
|
|
40
|
+
def __repr__(self):
|
|
41
|
+
return "<Key %s>" % ', '.join([repr(v) for v in self._names])
|
|
42
|
+
|
|
43
|
+
def __eq__(self, other):
|
|
44
|
+
if isinstance(other, str):
|
|
45
|
+
return other.upper() in self._names_upper
|
|
46
|
+
elif isinstance(other, Key):
|
|
47
|
+
return self._names[0] == other
|
|
48
|
+
elif isinstance(other, int):
|
|
49
|
+
return other in [ord(v) for v in self._names_upper if len(v) == 1]
|
|
50
|
+
elif other is None:
|
|
51
|
+
return False
|
|
52
|
+
else:
|
|
53
|
+
raise ValueError('Key can only be compared to str, int and Key.')
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
SHIFT = Key('Shift')
|
|
57
|
+
CONTROL = Key('Control')
|
|
58
|
+
ALT = Key('Alt')
|
|
59
|
+
META = Key('Meta') # That Mac thingy
|
|
60
|
+
|
|
61
|
+
UP = Key('Up')
|
|
62
|
+
DOWN = Key('Down')
|
|
63
|
+
LEFT = Key('Left')
|
|
64
|
+
RIGHT = Key('Right')
|
|
65
|
+
PAGEUP = Key('PageUp')
|
|
66
|
+
PAGEDOWN = Key('PageDown')
|
|
67
|
+
|
|
68
|
+
INSERT = Key('Insert')
|
|
69
|
+
DELETE = Key('Delete')
|
|
70
|
+
HOME = Key('Home')
|
|
71
|
+
END = Key('End')
|
|
72
|
+
|
|
73
|
+
ESCAPE = Key('Escape')
|
|
74
|
+
BACKSPACE = Key('Backspace')
|
|
75
|
+
|
|
76
|
+
F1 = Key('F1')
|
|
77
|
+
F2 = Key('F2')
|
|
78
|
+
F3 = Key('F3')
|
|
79
|
+
F4 = Key('F4')
|
|
80
|
+
F5 = Key('F5')
|
|
81
|
+
F6 = Key('F6')
|
|
82
|
+
F7 = Key('F7')
|
|
83
|
+
F8 = Key('F8')
|
|
84
|
+
F9 = Key('F9')
|
|
85
|
+
F10 = Key('F10')
|
|
86
|
+
F11 = Key('F11')
|
|
87
|
+
F12 = Key('F12')
|
|
88
|
+
|
|
89
|
+
SPACE = Key('Space', ' ')
|
|
90
|
+
ENTER = Key('Enter', 'Return', '\n')
|
|
91
|
+
TAB = Key('Tab', '\t')
|