vispy 0.15.0__cp313-cp313-win_amd64.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.cp313-win_amd64.pyd +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 +5 -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,211 @@
|
|
|
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
|
+
Force-Directed Graph Layout
|
|
6
|
+
===========================
|
|
7
|
+
|
|
8
|
+
This module contains implementations for a force-directed layout, where the
|
|
9
|
+
graph is modelled like a collection of springs or as a collection of
|
|
10
|
+
particles attracting and repelling each other. The whole graph tries to
|
|
11
|
+
reach a state which requires the minimum energy.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
from scipy.sparse import issparse
|
|
18
|
+
except ImportError:
|
|
19
|
+
def issparse(*args, **kwargs):
|
|
20
|
+
return False
|
|
21
|
+
|
|
22
|
+
from ..util import _straight_line_vertices, _rescale_layout
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class fruchterman_reingold(object):
|
|
26
|
+
r"""Fruchterman-Reingold implementation adapted from NetworkX.
|
|
27
|
+
|
|
28
|
+
In the Fruchterman-Reingold algorithm, the whole graph is modelled as a
|
|
29
|
+
collection of particles, it runs a simplified particle simulation to
|
|
30
|
+
find a nice layout for the graph.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
optimal : number
|
|
35
|
+
Optimal distance between nodes. Defaults to :math:`1/\\sqrt{N}` where
|
|
36
|
+
N is the number of nodes.
|
|
37
|
+
iterations : int
|
|
38
|
+
Number of iterations to perform for layout calculation.
|
|
39
|
+
pos : array
|
|
40
|
+
Initial positions of the nodes
|
|
41
|
+
|
|
42
|
+
Notes
|
|
43
|
+
-----
|
|
44
|
+
The algorithm is explained in more detail in the original paper [1]_.
|
|
45
|
+
|
|
46
|
+
.. [1] Fruchterman, Thomas MJ, and Edward M. Reingold. "Graph drawing by
|
|
47
|
+
force-directed placement." Softw., Pract. Exper. 21.11 (1991),
|
|
48
|
+
1129-1164.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, optimal=None, iterations=50, pos=None):
|
|
52
|
+
self.dim = 2
|
|
53
|
+
self.optimal = optimal
|
|
54
|
+
self.iterations = iterations
|
|
55
|
+
self.num_nodes = None
|
|
56
|
+
self.pos = pos
|
|
57
|
+
|
|
58
|
+
def __call__(self, adjacency_mat, directed=False):
|
|
59
|
+
"""
|
|
60
|
+
Starts the calculation of the graph layout.
|
|
61
|
+
|
|
62
|
+
This is a generator, and after each iteration it yields the new
|
|
63
|
+
positions for the nodes, together with the vertices for the edges
|
|
64
|
+
and the arrows.
|
|
65
|
+
|
|
66
|
+
There are two solvers here: one specially adapted for SciPy sparse
|
|
67
|
+
matrices, and the other for larger networks.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
adjacency_mat : array
|
|
72
|
+
The graph adjacency matrix.
|
|
73
|
+
directed : bool
|
|
74
|
+
Wether the graph is directed or not. If this is True,
|
|
75
|
+
it will draw arrows for directed edges.
|
|
76
|
+
|
|
77
|
+
Yields
|
|
78
|
+
------
|
|
79
|
+
layout : tuple
|
|
80
|
+
For each iteration of the layout calculation it yields a tuple
|
|
81
|
+
containing (node_vertices, line_vertices, arrow_vertices). These
|
|
82
|
+
vertices can be passed to the `MarkersVisual` and `ArrowVisual`.
|
|
83
|
+
"""
|
|
84
|
+
if adjacency_mat.shape[0] != adjacency_mat.shape[1]:
|
|
85
|
+
raise ValueError("Adjacency matrix should be square.")
|
|
86
|
+
|
|
87
|
+
self.num_nodes = adjacency_mat.shape[0]
|
|
88
|
+
|
|
89
|
+
if issparse(adjacency_mat):
|
|
90
|
+
# Use the sparse solver
|
|
91
|
+
solver = self._sparse_fruchterman_reingold
|
|
92
|
+
else:
|
|
93
|
+
solver = self._fruchterman_reingold
|
|
94
|
+
|
|
95
|
+
for result in solver(adjacency_mat, directed):
|
|
96
|
+
yield result
|
|
97
|
+
|
|
98
|
+
def _fruchterman_reingold(self, adjacency_mat, directed=False):
|
|
99
|
+
if self.optimal is None:
|
|
100
|
+
self.optimal = 1 / np.sqrt(self.num_nodes)
|
|
101
|
+
|
|
102
|
+
if self.pos is None:
|
|
103
|
+
# Random initial positions
|
|
104
|
+
pos = np.asarray(
|
|
105
|
+
np.random.random((self.num_nodes, self.dim)),
|
|
106
|
+
dtype=np.float32
|
|
107
|
+
)
|
|
108
|
+
else:
|
|
109
|
+
pos = self.pos.astype(np.float32)
|
|
110
|
+
|
|
111
|
+
# Yield initial positions
|
|
112
|
+
line_vertices, arrows = _straight_line_vertices(adjacency_mat, pos,
|
|
113
|
+
directed)
|
|
114
|
+
yield pos, line_vertices, arrows
|
|
115
|
+
|
|
116
|
+
# The initial "temperature" is about .1 of domain area (=1x1)
|
|
117
|
+
# this is the largest step allowed in the dynamics.
|
|
118
|
+
t = 0.1
|
|
119
|
+
|
|
120
|
+
# Simple cooling scheme.
|
|
121
|
+
# Linearly step down by dt on each iteration so last iteration is
|
|
122
|
+
# size dt.
|
|
123
|
+
dt = t / float(self.iterations+1)
|
|
124
|
+
# The inscrutable (but fast) version
|
|
125
|
+
# This is still O(V^2)
|
|
126
|
+
# Could use multilevel methods to speed this up significantly
|
|
127
|
+
for iteration in range(self.iterations):
|
|
128
|
+
delta_pos = _calculate_delta_pos(adjacency_mat, pos, t,
|
|
129
|
+
self.optimal)
|
|
130
|
+
pos += delta_pos
|
|
131
|
+
_rescale_layout(pos)
|
|
132
|
+
|
|
133
|
+
# cool temperature
|
|
134
|
+
t -= dt
|
|
135
|
+
|
|
136
|
+
# Calculate edge vertices and arrows
|
|
137
|
+
line_vertices, arrows = _straight_line_vertices(adjacency_mat,
|
|
138
|
+
pos, directed)
|
|
139
|
+
|
|
140
|
+
yield pos, line_vertices, arrows
|
|
141
|
+
|
|
142
|
+
def _sparse_fruchterman_reingold(self, adjacency_mat, directed=False):
|
|
143
|
+
# Optimal distance between nodes
|
|
144
|
+
if self.optimal is None:
|
|
145
|
+
self.optimal = 1 / np.sqrt(self.num_nodes)
|
|
146
|
+
|
|
147
|
+
# Change to list of list format
|
|
148
|
+
# Also construct the matrix in COO format for easy edge construction
|
|
149
|
+
adjacency_arr = adjacency_mat.toarray()
|
|
150
|
+
adjacency_coo = adjacency_mat.tocoo()
|
|
151
|
+
|
|
152
|
+
if self.pos is None:
|
|
153
|
+
# Random initial positions
|
|
154
|
+
pos = np.asarray(
|
|
155
|
+
np.random.random((self.num_nodes, self.dim)),
|
|
156
|
+
dtype=np.float32
|
|
157
|
+
)
|
|
158
|
+
else:
|
|
159
|
+
pos = self.pos.astype(np.float32)
|
|
160
|
+
|
|
161
|
+
# Yield initial positions
|
|
162
|
+
line_vertices, arrows = _straight_line_vertices(adjacency_coo, pos,
|
|
163
|
+
directed)
|
|
164
|
+
yield pos, line_vertices, arrows
|
|
165
|
+
|
|
166
|
+
# The initial "temperature" is about .1 of domain area (=1x1)
|
|
167
|
+
# This is the largest step allowed in the dynamics.
|
|
168
|
+
t = 0.1
|
|
169
|
+
# Simple cooling scheme.
|
|
170
|
+
# Linearly step down by dt on each iteration so last iteration is
|
|
171
|
+
# size dt.
|
|
172
|
+
dt = t / float(self.iterations+1)
|
|
173
|
+
for iteration in range(self.iterations):
|
|
174
|
+
delta_pos = _calculate_delta_pos(adjacency_arr, pos, t,
|
|
175
|
+
self.optimal)
|
|
176
|
+
pos += delta_pos
|
|
177
|
+
_rescale_layout(pos)
|
|
178
|
+
|
|
179
|
+
# Cool temperature
|
|
180
|
+
t -= dt
|
|
181
|
+
|
|
182
|
+
# Calculate line vertices
|
|
183
|
+
line_vertices, arrows = _straight_line_vertices(adjacency_coo,
|
|
184
|
+
pos, directed)
|
|
185
|
+
|
|
186
|
+
yield pos, line_vertices, arrows
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _calculate_delta_pos(adjacency_arr, pos, t, optimal):
|
|
190
|
+
"""Helper to calculate the delta position"""
|
|
191
|
+
# XXX eventually this should be refactored for the sparse case to only
|
|
192
|
+
# do the necessary pairwise distances
|
|
193
|
+
delta = pos[:, np.newaxis, :] - pos
|
|
194
|
+
|
|
195
|
+
# Distance between points
|
|
196
|
+
distance2 = (delta*delta).sum(axis=-1)
|
|
197
|
+
# Enforce minimum distance of 0.01
|
|
198
|
+
distance2 = np.where(distance2 < 0.0001, 0.0001, distance2)
|
|
199
|
+
distance = np.sqrt(distance2)
|
|
200
|
+
# Displacement "force"
|
|
201
|
+
displacement = np.zeros((len(delta), 2))
|
|
202
|
+
for ii in range(2):
|
|
203
|
+
displacement[:, ii] = (
|
|
204
|
+
delta[:, :, ii] *
|
|
205
|
+
((optimal * optimal) / (distance*distance) -
|
|
206
|
+
(adjacency_arr * distance) / optimal)).sum(axis=1)
|
|
207
|
+
|
|
208
|
+
length = np.sqrt((displacement**2).sum(axis=1))
|
|
209
|
+
length = np.where(length < 0.01, 0.1, length)
|
|
210
|
+
delta_pos = displacement * t / length[:, np.newaxis]
|
|
211
|
+
return delta_pos
|
|
@@ -0,0 +1,87 @@
|
|
|
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.#!/usr/bin/env python3
|
|
4
|
+
from ..util import _straight_line_vertices, issparse
|
|
5
|
+
import numpy as np
|
|
6
|
+
try:
|
|
7
|
+
import networkx as nx
|
|
8
|
+
except ModuleNotFoundError:
|
|
9
|
+
nx = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class NetworkxCoordinates:
|
|
13
|
+
def __init__(self, graph=None, layout=None, **kwargs):
|
|
14
|
+
"""
|
|
15
|
+
Converts :graph: into a layout. Can be used in conjunction with networkx layouts or using raw 2D-numpy arrays.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
graph : a networkx graph.
|
|
20
|
+
layout : str or dict or iterable-object of float32, optional
|
|
21
|
+
- When :layout: is s string, a lookup will be performed in the networkx avaiable layouts.
|
|
22
|
+
- When :layout: is a dict, it will be assumed that it takes the shape (key, value) = (node_id, 2D-coordinate).
|
|
23
|
+
- When :layout: is numpy array it is assumed it takes the shape (number_of_nodes, 2).
|
|
24
|
+
kwargs: dict, optional
|
|
25
|
+
when layout is :str: :kwargs: will act as a setting dictionary for the layout function of networkx
|
|
26
|
+
"""
|
|
27
|
+
if nx is None:
|
|
28
|
+
raise ValueError("networkx not found, please install networkx to use its layouts")
|
|
29
|
+
if isinstance(graph, type(None)):
|
|
30
|
+
raise ValueError("Requires networkx input")
|
|
31
|
+
self.graph = graph
|
|
32
|
+
self.positions = np.zeros((len(graph), 2), dtype=np.float32)
|
|
33
|
+
# default random positions
|
|
34
|
+
if isinstance(layout, type(None)):
|
|
35
|
+
self.positions = np.random.rand(*self.positions.shape)
|
|
36
|
+
|
|
37
|
+
# check for networkx
|
|
38
|
+
elif isinstance(layout, str):
|
|
39
|
+
if not layout.endswith("_layout"):
|
|
40
|
+
layout += "_layout" # append for nx
|
|
41
|
+
layout_function = getattr(nx, layout)
|
|
42
|
+
if layout_function:
|
|
43
|
+
self.positions = np.asarray(
|
|
44
|
+
[i for i in dict(layout_function(graph, **kwargs)).values()])
|
|
45
|
+
else:
|
|
46
|
+
raise ValueError("Check networkx for layouts")
|
|
47
|
+
# assume dict from networkx; values are 2-array
|
|
48
|
+
elif isinstance(layout, dict):
|
|
49
|
+
self.positions = np.asarray([i for i in layout.values()])
|
|
50
|
+
|
|
51
|
+
# assume given values
|
|
52
|
+
elif isinstance(layout, np.ndarray):
|
|
53
|
+
assert layout.ndim == 2
|
|
54
|
+
assert layout.shape[0] == len(graph)
|
|
55
|
+
self.positions = layout
|
|
56
|
+
else:
|
|
57
|
+
raise ValueError("Input not understood")
|
|
58
|
+
|
|
59
|
+
# normalize coordinates
|
|
60
|
+
self.positions = (self.positions - self.positions.min()) / \
|
|
61
|
+
(self.positions.max() - self.positions.min())
|
|
62
|
+
self.positions = self.positions.astype(np.float32)
|
|
63
|
+
|
|
64
|
+
def __call__(self, adjacency_mat, directed=False):
|
|
65
|
+
"""
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
adjacency_mat : sparse adjacency matrix.
|
|
69
|
+
directed : bool, default False
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
---------
|
|
73
|
+
(node_vertices, line_vertices, arrow_vertices) : tuple
|
|
74
|
+
Yields the node and line vertices in a tuple. This layout only yields a
|
|
75
|
+
single time, and has no builtin animation
|
|
76
|
+
"""
|
|
77
|
+
if issparse(adjacency_mat):
|
|
78
|
+
adjacency_mat = adjacency_mat.tocoo()
|
|
79
|
+
line_vertices, arrows = _straight_line_vertices(
|
|
80
|
+
adjacency_mat, self.positions, directed)
|
|
81
|
+
|
|
82
|
+
yield self.positions, line_vertices, arrows
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def adj(self):
|
|
86
|
+
"""Convenient storage and holder of the adjacency matrix for the :scene.visuals.Graph: function."""
|
|
87
|
+
return nx.adjacency_matrix(self.graph)
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
Random Graph Layout
|
|
6
|
+
====================
|
|
7
|
+
|
|
8
|
+
This layout positions the nodes at random
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
from ..util import _straight_line_vertices, issparse
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def random(adjacency_mat, directed=False, random_state=None):
|
|
17
|
+
"""
|
|
18
|
+
Place the graph nodes at random places.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
adjacency_mat : matrix or sparse
|
|
23
|
+
The graph adjacency matrix
|
|
24
|
+
directed : bool
|
|
25
|
+
Whether the graph is directed. If this is True, is will also
|
|
26
|
+
generate the vertices for arrows, which can be passed to an
|
|
27
|
+
ArrowVisual.
|
|
28
|
+
random_state : instance of RandomState | int | None
|
|
29
|
+
Random state to use. Can be None to use ``np.random``.
|
|
30
|
+
|
|
31
|
+
Yields
|
|
32
|
+
------
|
|
33
|
+
(node_vertices, line_vertices, arrow_vertices) : tuple
|
|
34
|
+
Yields the node and line vertices in a tuple. This layout only yields a
|
|
35
|
+
single time, and has no builtin animation
|
|
36
|
+
"""
|
|
37
|
+
if random_state is None:
|
|
38
|
+
random_state = np.random
|
|
39
|
+
elif not isinstance(random_state, np.random.RandomState):
|
|
40
|
+
random_state = np.random.RandomState(random_state)
|
|
41
|
+
|
|
42
|
+
if issparse(adjacency_mat):
|
|
43
|
+
adjacency_mat = adjacency_mat.tocoo()
|
|
44
|
+
|
|
45
|
+
# Randomly place nodes, visual coordinate system is between 0 and 1
|
|
46
|
+
num_nodes = adjacency_mat.shape[0]
|
|
47
|
+
node_coords = random_state.rand(num_nodes, 2)
|
|
48
|
+
|
|
49
|
+
line_vertices, arrows = _straight_line_vertices(adjacency_mat,
|
|
50
|
+
node_coords, directed)
|
|
51
|
+
|
|
52
|
+
yield node_coords, line_vertices, arrows
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__author__ = 'lucas'
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
3
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy.testing import assert_allclose, assert_equal
|
|
7
|
+
|
|
8
|
+
from vispy.visuals.graphs.layouts import get_layout
|
|
9
|
+
from vispy.testing import (run_tests_if_main, assert_raises)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
adjacency_mat = np.array([
|
|
13
|
+
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
14
|
+
[1, 0, 0, 0, 1, 0, 1, 1, 0, 0],
|
|
15
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
16
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
|
17
|
+
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
18
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
19
|
+
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
20
|
+
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
21
|
+
[0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
|
|
22
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
|
|
23
|
+
])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_get_layout():
|
|
27
|
+
from vispy.visuals.graphs.layouts.random import random
|
|
28
|
+
|
|
29
|
+
# Simple retrieval
|
|
30
|
+
assert_equal(random, get_layout('random'))
|
|
31
|
+
|
|
32
|
+
# Pass arguments
|
|
33
|
+
fruchterman_reingold = get_layout('force_directed', iterations=100)
|
|
34
|
+
assert_equal(fruchterman_reingold.iterations, 100)
|
|
35
|
+
|
|
36
|
+
# Check if layout exists
|
|
37
|
+
assert_raises(KeyError, get_layout, 'fdgdfgs_non_existent')
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_random_layout():
|
|
41
|
+
layout = get_layout('random')
|
|
42
|
+
|
|
43
|
+
expected_pos = np.array([
|
|
44
|
+
[0.22270932715095826, 0.7728936927702302],
|
|
45
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
46
|
+
[0.75002099889163, 0.5592076821676369],
|
|
47
|
+
[0.1786754307911973, 0.6442165368790972],
|
|
48
|
+
[0.5979199081208609, 0.615159318836822],
|
|
49
|
+
[0.46328431255222746, 0.3582897386994869],
|
|
50
|
+
[0.9595461883180398, 0.2350580044144016],
|
|
51
|
+
[0.094482942129406, 0.20584398882694932],
|
|
52
|
+
[0.5758593091748346, 0.8158957494444451],
|
|
53
|
+
[0.5908647616961652, 0.1584550825482285]
|
|
54
|
+
])
|
|
55
|
+
|
|
56
|
+
expected_vertices = np.array([
|
|
57
|
+
[0.22270932715095826, 0.7728936927702302],
|
|
58
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
59
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
60
|
+
[0.22270932715095826, 0.7728936927702302],
|
|
61
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
62
|
+
[0.5979199081208609, 0.615159318836822],
|
|
63
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
64
|
+
[0.9595461883180398, 0.2350580044144016],
|
|
65
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
66
|
+
[0.094482942129406, 0.20584398882694932],
|
|
67
|
+
[0.1786754307911973, 0.6442165368790972],
|
|
68
|
+
[0.5758593091748346, 0.8158957494444451],
|
|
69
|
+
[0.5979199081208609, 0.615159318836822],
|
|
70
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
71
|
+
[0.9595461883180398, 0.2350580044144016],
|
|
72
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
73
|
+
[0.094482942129406, 0.20584398882694932],
|
|
74
|
+
[0.6298054094517744, 0.21851589821484974],
|
|
75
|
+
[0.5758593091748346, 0.8158957494444451],
|
|
76
|
+
[0.1786754307911973, 0.6442165368790972],
|
|
77
|
+
[0.5758593091748346, 0.8158957494444451],
|
|
78
|
+
[0.5908647616961652, 0.1584550825482285],
|
|
79
|
+
[0.5908647616961652, 0.1584550825482285],
|
|
80
|
+
[0.5758593091748346, 0.8158957494444451]
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
pos, line_vertices, arrows = next(layout(adjacency_mat,
|
|
84
|
+
random_state=0xDEADBEEF))
|
|
85
|
+
|
|
86
|
+
assert_allclose(pos, expected_pos, atol=1e-7)
|
|
87
|
+
assert_allclose(line_vertices, expected_vertices, atol=1e-7)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_circular_layout():
|
|
91
|
+
layout = get_layout('circular')
|
|
92
|
+
|
|
93
|
+
expected_pos = np.array([
|
|
94
|
+
[1.0, 0.5],
|
|
95
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
96
|
+
[0.6545084714889526, 0.9755282402038574],
|
|
97
|
+
[0.3454914689064026, 0.9755282402038574],
|
|
98
|
+
[0.09549146890640259, 0.7938926219940186],
|
|
99
|
+
[0.0, 0.4999999701976776],
|
|
100
|
+
[0.09549152851104736, 0.20610731840133667],
|
|
101
|
+
[0.3454914689064026, 0.024471759796142578],
|
|
102
|
+
[0.6545085906982422, 0.024471759796142578],
|
|
103
|
+
[0.9045084714889526, 0.20610734820365906]
|
|
104
|
+
])
|
|
105
|
+
|
|
106
|
+
expected_vertices = np.array([
|
|
107
|
+
[1.0, 0.5],
|
|
108
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
109
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
110
|
+
[1.0, 0.5],
|
|
111
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
112
|
+
[0.09549146890640259, 0.7938926219940186],
|
|
113
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
114
|
+
[0.09549152851104736, 0.20610731840133667],
|
|
115
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
116
|
+
[0.3454914689064026, 0.024471759796142578],
|
|
117
|
+
[0.3454914689064026, 0.9755282402038574],
|
|
118
|
+
[0.6545085906982422, 0.024471759796142578],
|
|
119
|
+
[0.09549146890640259, 0.7938926219940186],
|
|
120
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
121
|
+
[0.09549152851104736, 0.20610731840133667],
|
|
122
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
123
|
+
[0.3454914689064026, 0.024471759796142578],
|
|
124
|
+
[0.9045084714889526, 0.7938926219940186],
|
|
125
|
+
[0.6545085906982422, 0.024471759796142578],
|
|
126
|
+
[0.3454914689064026, 0.9755282402038574],
|
|
127
|
+
[0.6545085906982422, 0.024471759796142578],
|
|
128
|
+
[0.9045084714889526, 0.20610734820365906],
|
|
129
|
+
[0.9045084714889526, 0.20610734820365906],
|
|
130
|
+
[0.6545085906982422, 0.024471759796142578]
|
|
131
|
+
])
|
|
132
|
+
|
|
133
|
+
pos, line_vertices, arrows = next(layout(adjacency_mat))
|
|
134
|
+
|
|
135
|
+
assert_allclose(pos, expected_pos, atol=1e-4)
|
|
136
|
+
assert_allclose(line_vertices, expected_vertices, atol=1e-4)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
run_tests_if_main()
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
from vispy import testing
|
|
5
|
+
from vispy.visuals.graphs.layouts import get_layout
|
|
6
|
+
from vispy.visuals.graphs.layouts.networkx_layout import NetworkxCoordinates
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
# conditional import
|
|
10
|
+
try:
|
|
11
|
+
import networkx as nx
|
|
12
|
+
except ModuleNotFoundError:
|
|
13
|
+
nx = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_networkx_layout_with_graph():
|
|
17
|
+
"""Testing the various inputs to the networkx layout."""
|
|
18
|
+
settings = dict(name="networkx_layout")
|
|
19
|
+
if nx is None:
|
|
20
|
+
return testing.SkipTest("'networkx' required")
|
|
21
|
+
|
|
22
|
+
# empty input
|
|
23
|
+
# testing.assert_raises(ValueError("Requires networkx input"), get_layout(**settings))
|
|
24
|
+
|
|
25
|
+
# define graph
|
|
26
|
+
graph = nx.complete_graph(5)
|
|
27
|
+
# define positions
|
|
28
|
+
layout = np.random.rand(5, 2)
|
|
29
|
+
settings['graph'] = graph
|
|
30
|
+
settings['layout'] = layout
|
|
31
|
+
|
|
32
|
+
# test numpy array input
|
|
33
|
+
testing.assert_true(isinstance(
|
|
34
|
+
get_layout(**settings), NetworkxCoordinates))
|
|
35
|
+
# testing string input
|
|
36
|
+
settings['layout'] = 'circular'
|
|
37
|
+
testing.assert_true(isinstance(
|
|
38
|
+
get_layout(**settings), NetworkxCoordinates))
|
|
39
|
+
# testing dict input
|
|
40
|
+
settings['layout'] = nx.circular_layout(graph)
|
|
41
|
+
testing.assert_true(isinstance(
|
|
42
|
+
get_layout(**settings), NetworkxCoordinates))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_networkx_layout_no_networkx():
|
|
46
|
+
settings = dict(name="networkx_layout")
|
|
47
|
+
testing.assert_raises(ValueError, get_layout, **settings)
|
|
@@ -0,0 +1,120 @@
|
|
|
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
|
+
Graph utilities
|
|
6
|
+
===============
|
|
7
|
+
|
|
8
|
+
A module containing several graph utility functions.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from scipy.sparse import issparse
|
|
15
|
+
from scipy import sparse
|
|
16
|
+
except ImportError:
|
|
17
|
+
def issparse(*args, **kwargs):
|
|
18
|
+
return False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_edges(adjacency_mat):
|
|
22
|
+
func = _sparse_get_edges if issparse(adjacency_mat) else _ndarray_get_edges
|
|
23
|
+
return func(adjacency_mat)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _sparse_get_edges(adjacency_mat):
|
|
27
|
+
return np.concatenate((adjacency_mat.row[:, np.newaxis],
|
|
28
|
+
adjacency_mat.col[:, np.newaxis]), axis=-1)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _ndarray_get_edges(adjacency_mat):
|
|
32
|
+
# Get indices of all non zero values
|
|
33
|
+
i, j = np.where(adjacency_mat)
|
|
34
|
+
|
|
35
|
+
return np.concatenate((i[:, np.newaxis], j[:, np.newaxis]), axis=-1)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _get_directed_edges(adjacency_mat):
|
|
39
|
+
func = _sparse_get_edges if issparse(adjacency_mat) else _ndarray_get_edges
|
|
40
|
+
|
|
41
|
+
if issparse(adjacency_mat):
|
|
42
|
+
triu = sparse.triu
|
|
43
|
+
tril = sparse.tril
|
|
44
|
+
else:
|
|
45
|
+
triu = np.triu
|
|
46
|
+
tril = np.tril
|
|
47
|
+
|
|
48
|
+
upper = triu(adjacency_mat)
|
|
49
|
+
lower = tril(adjacency_mat)
|
|
50
|
+
|
|
51
|
+
return np.concatenate((func(upper), func(lower)))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _straight_line_vertices(adjacency_mat, node_coords, directed=False):
|
|
55
|
+
"""
|
|
56
|
+
Generate the vertices for straight lines between nodes.
|
|
57
|
+
|
|
58
|
+
If it is a directed graph, it also generates the vertices which can be
|
|
59
|
+
passed to an :class:`ArrowVisual`.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
adjacency_mat : array
|
|
64
|
+
The adjacency matrix of the graph
|
|
65
|
+
node_coords : array
|
|
66
|
+
The current coordinates of all nodes in the graph
|
|
67
|
+
directed : bool
|
|
68
|
+
Wether the graph is directed. If this is true it will also generate
|
|
69
|
+
the vertices for arrows which can be passed to :class:`ArrowVisual`.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
vertices : tuple
|
|
74
|
+
Returns a tuple containing containing (`line_vertices`,
|
|
75
|
+
`arrow_vertices`)
|
|
76
|
+
"""
|
|
77
|
+
if not issparse(adjacency_mat):
|
|
78
|
+
adjacency_mat = np.asarray(adjacency_mat, float)
|
|
79
|
+
|
|
80
|
+
if (adjacency_mat.ndim != 2 or adjacency_mat.shape[0] !=
|
|
81
|
+
adjacency_mat.shape[1]):
|
|
82
|
+
raise ValueError("Adjacency matrix should be square.")
|
|
83
|
+
|
|
84
|
+
arrow_vertices = np.array([])
|
|
85
|
+
|
|
86
|
+
edges = _get_edges(adjacency_mat)
|
|
87
|
+
line_vertices = node_coords[edges.ravel()]
|
|
88
|
+
|
|
89
|
+
if directed:
|
|
90
|
+
arrows = np.array(list(_get_directed_edges(adjacency_mat)))
|
|
91
|
+
arrow_vertices = node_coords[arrows.ravel()]
|
|
92
|
+
arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)//2, 4))
|
|
93
|
+
|
|
94
|
+
return line_vertices, arrow_vertices
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _rescale_layout(pos, scale=1):
|
|
98
|
+
"""
|
|
99
|
+
Normalize the given coordinate list to the range [0, `scale`].
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
pos : array
|
|
104
|
+
Coordinate list
|
|
105
|
+
scale : number
|
|
106
|
+
The upperbound value for the coordinates range
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
pos : array
|
|
111
|
+
The rescaled (normalized) coordinates in the range [0, `scale`].
|
|
112
|
+
|
|
113
|
+
Notes
|
|
114
|
+
-----
|
|
115
|
+
Changes `pos` in place.
|
|
116
|
+
"""
|
|
117
|
+
pos -= pos.min(axis=0)
|
|
118
|
+
pos *= scale / pos.max()
|
|
119
|
+
|
|
120
|
+
return pos
|