vispy 0.15.0__cp312-cp312-macosx_10_13_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of vispy might be problematic. Click here for more details.
- vispy/__init__.py +33 -0
- vispy/app/__init__.py +15 -0
- vispy/app/_default_app.py +76 -0
- vispy/app/_detect_eventloop.py +148 -0
- vispy/app/application.py +263 -0
- vispy/app/backends/__init__.py +52 -0
- vispy/app/backends/_egl.py +264 -0
- vispy/app/backends/_glfw.py +513 -0
- vispy/app/backends/_jupyter_rfb.py +278 -0
- vispy/app/backends/_offscreen_util.py +121 -0
- vispy/app/backends/_osmesa.py +235 -0
- vispy/app/backends/_pyglet.py +451 -0
- vispy/app/backends/_pyqt4.py +36 -0
- vispy/app/backends/_pyqt5.py +36 -0
- vispy/app/backends/_pyqt6.py +40 -0
- vispy/app/backends/_pyside.py +37 -0
- vispy/app/backends/_pyside2.py +52 -0
- vispy/app/backends/_pyside6.py +53 -0
- vispy/app/backends/_qt.py +1003 -0
- vispy/app/backends/_sdl2.py +444 -0
- vispy/app/backends/_template.py +244 -0
- vispy/app/backends/_test.py +8 -0
- vispy/app/backends/_tk.py +800 -0
- vispy/app/backends/_wx.py +476 -0
- vispy/app/backends/tests/__init__.py +0 -0
- vispy/app/backends/tests/test_offscreen_util.py +52 -0
- vispy/app/backends/tests/test_rfb.py +77 -0
- vispy/app/base.py +294 -0
- vispy/app/canvas.py +828 -0
- vispy/app/qt.py +92 -0
- vispy/app/tests/__init__.py +0 -0
- vispy/app/tests/qt-designer.ui +58 -0
- vispy/app/tests/test_app.py +442 -0
- vispy/app/tests/test_backends.py +164 -0
- vispy/app/tests/test_canvas.py +122 -0
- vispy/app/tests/test_context.py +92 -0
- vispy/app/tests/test_qt.py +47 -0
- vispy/app/tests/test_simultaneous.py +134 -0
- vispy/app/timer.py +174 -0
- vispy/color/__init__.py +17 -0
- vispy/color/_color_dict.py +193 -0
- vispy/color/color_array.py +447 -0
- vispy/color/color_space.py +181 -0
- vispy/color/colormap.py +1213 -0
- vispy/color/tests/__init__.py +0 -0
- vispy/color/tests/test_color.py +378 -0
- vispy/conftest.py +12 -0
- vispy/ext/__init__.py +0 -0
- vispy/ext/cocoapy.py +1522 -0
- vispy/ext/cubehelix.py +138 -0
- vispy/ext/egl.py +375 -0
- vispy/ext/fontconfig.py +118 -0
- vispy/ext/gdi32plus.py +206 -0
- vispy/ext/osmesa.py +105 -0
- vispy/geometry/__init__.py +23 -0
- vispy/geometry/_triangulation_debugger.py +171 -0
- vispy/geometry/calculations.py +162 -0
- vispy/geometry/curves.py +399 -0
- vispy/geometry/generation.py +643 -0
- vispy/geometry/isocurve.py +175 -0
- vispy/geometry/isosurface.py +465 -0
- vispy/geometry/meshdata.py +700 -0
- vispy/geometry/normals.py +78 -0
- vispy/geometry/parametric.py +56 -0
- vispy/geometry/polygon.py +137 -0
- vispy/geometry/rect.py +210 -0
- vispy/geometry/tests/__init__.py +0 -0
- vispy/geometry/tests/test_calculations.py +23 -0
- vispy/geometry/tests/test_generation.py +56 -0
- vispy/geometry/tests/test_meshdata.py +106 -0
- vispy/geometry/tests/test_triangulation.py +594 -0
- vispy/geometry/torusknot.py +142 -0
- vispy/geometry/triangulation.py +876 -0
- vispy/gloo/__init__.py +56 -0
- vispy/gloo/buffer.py +505 -0
- vispy/gloo/context.py +272 -0
- vispy/gloo/framebuffer.py +257 -0
- vispy/gloo/gl/__init__.py +234 -0
- vispy/gloo/gl/_constants.py +332 -0
- vispy/gloo/gl/_es2.py +986 -0
- vispy/gloo/gl/_gl2.py +1365 -0
- vispy/gloo/gl/_proxy.py +499 -0
- vispy/gloo/gl/_pyopengl2.py +362 -0
- vispy/gloo/gl/dummy.py +24 -0
- vispy/gloo/gl/es2.py +62 -0
- vispy/gloo/gl/gl2.py +98 -0
- vispy/gloo/gl/glplus.py +168 -0
- vispy/gloo/gl/pyopengl2.py +97 -0
- vispy/gloo/gl/tests/__init__.py +0 -0
- vispy/gloo/gl/tests/test_basics.py +282 -0
- vispy/gloo/gl/tests/test_functionality.py +568 -0
- vispy/gloo/gl/tests/test_names.py +246 -0
- vispy/gloo/gl/tests/test_use.py +71 -0
- vispy/gloo/glir.py +1824 -0
- vispy/gloo/globject.py +101 -0
- vispy/gloo/preprocessor.py +67 -0
- vispy/gloo/program.py +543 -0
- vispy/gloo/tests/__init__.py +0 -0
- vispy/gloo/tests/test_buffer.py +558 -0
- vispy/gloo/tests/test_context.py +119 -0
- vispy/gloo/tests/test_framebuffer.py +195 -0
- vispy/gloo/tests/test_glir.py +307 -0
- vispy/gloo/tests/test_globject.py +35 -0
- vispy/gloo/tests/test_program.py +302 -0
- vispy/gloo/tests/test_texture.py +732 -0
- vispy/gloo/tests/test_use_gloo.py +187 -0
- vispy/gloo/tests/test_util.py +60 -0
- vispy/gloo/tests/test_wrappers.py +261 -0
- vispy/gloo/texture.py +1046 -0
- vispy/gloo/util.py +129 -0
- vispy/gloo/wrappers.py +762 -0
- vispy/glsl/__init__.py +42 -0
- vispy/glsl/antialias/antialias.glsl +7 -0
- vispy/glsl/antialias/cap-butt.glsl +31 -0
- vispy/glsl/antialias/cap-round.glsl +29 -0
- vispy/glsl/antialias/cap-square.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
- vispy/glsl/antialias/cap.glsl +67 -0
- vispy/glsl/antialias/caps.glsl +67 -0
- vispy/glsl/antialias/filled.glsl +50 -0
- vispy/glsl/antialias/outline.glsl +40 -0
- vispy/glsl/antialias/stroke.glsl +43 -0
- vispy/glsl/arrowheads/angle.glsl +99 -0
- vispy/glsl/arrowheads/arrowheads.frag +60 -0
- vispy/glsl/arrowheads/arrowheads.glsl +12 -0
- vispy/glsl/arrowheads/arrowheads.vert +83 -0
- vispy/glsl/arrowheads/curved.glsl +48 -0
- vispy/glsl/arrowheads/inhibitor.glsl +26 -0
- vispy/glsl/arrowheads/stealth.glsl +46 -0
- vispy/glsl/arrowheads/triangle.glsl +97 -0
- vispy/glsl/arrowheads/util.glsl +13 -0
- vispy/glsl/arrows/angle-30.glsl +12 -0
- vispy/glsl/arrows/angle-60.glsl +12 -0
- vispy/glsl/arrows/angle-90.glsl +12 -0
- vispy/glsl/arrows/arrow.frag +39 -0
- vispy/glsl/arrows/arrow.vert +49 -0
- vispy/glsl/arrows/arrows.glsl +17 -0
- vispy/glsl/arrows/common.glsl +187 -0
- vispy/glsl/arrows/curved.glsl +63 -0
- vispy/glsl/arrows/stealth.glsl +50 -0
- vispy/glsl/arrows/triangle-30.glsl +12 -0
- vispy/glsl/arrows/triangle-60.glsl +12 -0
- vispy/glsl/arrows/triangle-90.glsl +12 -0
- vispy/glsl/arrows/util.glsl +98 -0
- vispy/glsl/build_spatial_filters.py +660 -0
- vispy/glsl/collections/agg-fast-path.frag +20 -0
- vispy/glsl/collections/agg-fast-path.vert +78 -0
- vispy/glsl/collections/agg-glyph.frag +60 -0
- vispy/glsl/collections/agg-glyph.vert +33 -0
- vispy/glsl/collections/agg-marker.frag +35 -0
- vispy/glsl/collections/agg-marker.vert +48 -0
- vispy/glsl/collections/agg-path.frag +55 -0
- vispy/glsl/collections/agg-path.vert +166 -0
- vispy/glsl/collections/agg-point.frag +21 -0
- vispy/glsl/collections/agg-point.vert +35 -0
- vispy/glsl/collections/agg-segment.frag +32 -0
- vispy/glsl/collections/agg-segment.vert +75 -0
- vispy/glsl/collections/marker.frag +38 -0
- vispy/glsl/collections/marker.vert +48 -0
- vispy/glsl/collections/raw-path.frag +15 -0
- vispy/glsl/collections/raw-path.vert +24 -0
- vispy/glsl/collections/raw-point.frag +14 -0
- vispy/glsl/collections/raw-point.vert +31 -0
- vispy/glsl/collections/raw-segment.frag +18 -0
- vispy/glsl/collections/raw-segment.vert +26 -0
- vispy/glsl/collections/raw-triangle.frag +13 -0
- vispy/glsl/collections/raw-triangle.vert +26 -0
- vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
- vispy/glsl/collections/sdf-glyph.frag +80 -0
- vispy/glsl/collections/sdf-glyph.vert +59 -0
- vispy/glsl/collections/tick-labels.vert +71 -0
- vispy/glsl/colormaps/autumn.glsl +20 -0
- vispy/glsl/colormaps/blues.glsl +20 -0
- vispy/glsl/colormaps/color-space.glsl +17 -0
- vispy/glsl/colormaps/colormaps.glsl +24 -0
- vispy/glsl/colormaps/cool.glsl +20 -0
- vispy/glsl/colormaps/fire.glsl +21 -0
- vispy/glsl/colormaps/gray.glsl +20 -0
- vispy/glsl/colormaps/greens.glsl +20 -0
- vispy/glsl/colormaps/hot.glsl +22 -0
- vispy/glsl/colormaps/ice.glsl +20 -0
- vispy/glsl/colormaps/icefire.glsl +23 -0
- vispy/glsl/colormaps/parse.py +40 -0
- vispy/glsl/colormaps/reds.glsl +20 -0
- vispy/glsl/colormaps/spring.glsl +20 -0
- vispy/glsl/colormaps/summer.glsl +20 -0
- vispy/glsl/colormaps/user.glsl +22 -0
- vispy/glsl/colormaps/util.glsl +41 -0
- vispy/glsl/colormaps/wheel.glsl +21 -0
- vispy/glsl/colormaps/winter.glsl +20 -0
- vispy/glsl/lines/agg.frag +320 -0
- vispy/glsl/lines/agg.vert +241 -0
- vispy/glsl/markers/arrow.glsl +12 -0
- vispy/glsl/markers/asterisk.glsl +16 -0
- vispy/glsl/markers/chevron.glsl +14 -0
- vispy/glsl/markers/clover.glsl +20 -0
- vispy/glsl/markers/club.glsl +31 -0
- vispy/glsl/markers/cross.glsl +17 -0
- vispy/glsl/markers/diamond.glsl +12 -0
- vispy/glsl/markers/disc.glsl +9 -0
- vispy/glsl/markers/ellipse.glsl +67 -0
- vispy/glsl/markers/hbar.glsl +9 -0
- vispy/glsl/markers/heart.glsl +15 -0
- vispy/glsl/markers/infinity.glsl +15 -0
- vispy/glsl/markers/marker-sdf.frag +74 -0
- vispy/glsl/markers/marker-sdf.vert +41 -0
- vispy/glsl/markers/marker.frag +36 -0
- vispy/glsl/markers/marker.vert +46 -0
- vispy/glsl/markers/markers.glsl +24 -0
- vispy/glsl/markers/pin.glsl +18 -0
- vispy/glsl/markers/ring.glsl +11 -0
- vispy/glsl/markers/spade.glsl +28 -0
- vispy/glsl/markers/square.glsl +10 -0
- vispy/glsl/markers/tag.glsl +11 -0
- vispy/glsl/markers/triangle.glsl +14 -0
- vispy/glsl/markers/vbar.glsl +9 -0
- vispy/glsl/math/circle-through-2-points.glsl +30 -0
- vispy/glsl/math/constants.glsl +48 -0
- vispy/glsl/math/double.glsl +114 -0
- vispy/glsl/math/functions.glsl +20 -0
- vispy/glsl/math/point-to-line-distance.glsl +31 -0
- vispy/glsl/math/point-to-line-projection.glsl +29 -0
- vispy/glsl/math/signed-line-distance.glsl +27 -0
- vispy/glsl/math/signed-segment-distance.glsl +30 -0
- vispy/glsl/misc/regular-grid.frag +244 -0
- vispy/glsl/misc/spatial-filters.frag +1407 -0
- vispy/glsl/misc/viewport-NDC.glsl +20 -0
- vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
- vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
- vispy/glsl/transforms/hammer.glsl +44 -0
- vispy/glsl/transforms/identity.glsl +6 -0
- vispy/glsl/transforms/identity_forward.glsl +23 -0
- vispy/glsl/transforms/identity_inverse.glsl +23 -0
- vispy/glsl/transforms/linear-scale.glsl +127 -0
- vispy/glsl/transforms/log-scale.glsl +126 -0
- vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
- vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
- vispy/glsl/transforms/panzoom.glsl +10 -0
- vispy/glsl/transforms/polar.glsl +41 -0
- vispy/glsl/transforms/position.glsl +44 -0
- vispy/glsl/transforms/power-scale.glsl +139 -0
- vispy/glsl/transforms/projection.glsl +7 -0
- vispy/glsl/transforms/pvm.glsl +13 -0
- vispy/glsl/transforms/rotate.glsl +45 -0
- vispy/glsl/transforms/trackball.glsl +15 -0
- vispy/glsl/transforms/translate.glsl +35 -0
- vispy/glsl/transforms/transverse_mercator.glsl +38 -0
- vispy/glsl/transforms/viewport-clipping.glsl +14 -0
- vispy/glsl/transforms/viewport-transform.glsl +16 -0
- vispy/glsl/transforms/viewport.glsl +50 -0
- vispy/glsl/transforms/x.glsl +24 -0
- vispy/glsl/transforms/y.glsl +19 -0
- vispy/glsl/transforms/z.glsl +14 -0
- vispy/io/__init__.py +20 -0
- vispy/io/_data/spatial-filters.npy +0 -0
- vispy/io/datasets.py +94 -0
- vispy/io/image.py +231 -0
- vispy/io/mesh.py +122 -0
- vispy/io/stl.py +167 -0
- vispy/io/tests/__init__.py +0 -0
- vispy/io/tests/test_image.py +47 -0
- vispy/io/tests/test_io.py +121 -0
- vispy/io/wavefront.py +350 -0
- vispy/plot/__init__.py +36 -0
- vispy/plot/fig.py +58 -0
- vispy/plot/plotwidget.py +522 -0
- vispy/plot/tests/__init__.py +0 -0
- vispy/plot/tests/test_plot.py +46 -0
- vispy/scene/__init__.py +43 -0
- vispy/scene/cameras/__init__.py +27 -0
- vispy/scene/cameras/_base.py +38 -0
- vispy/scene/cameras/arcball.py +105 -0
- vispy/scene/cameras/base_camera.py +551 -0
- vispy/scene/cameras/fly.py +474 -0
- vispy/scene/cameras/magnify.py +163 -0
- vispy/scene/cameras/panzoom.py +311 -0
- vispy/scene/cameras/perspective.py +338 -0
- vispy/scene/cameras/tests/__init__.py +0 -0
- vispy/scene/cameras/tests/test_cameras.py +27 -0
- vispy/scene/cameras/tests/test_link.py +53 -0
- vispy/scene/cameras/tests/test_perspective.py +122 -0
- vispy/scene/cameras/turntable.py +183 -0
- vispy/scene/canvas.py +639 -0
- vispy/scene/events.py +85 -0
- vispy/scene/node.py +644 -0
- vispy/scene/subscene.py +20 -0
- vispy/scene/tests/__init__.py +0 -0
- vispy/scene/tests/test_canvas.py +119 -0
- vispy/scene/tests/test_node.py +142 -0
- vispy/scene/tests/test_visuals.py +141 -0
- vispy/scene/visuals.py +276 -0
- vispy/scene/widgets/__init__.py +18 -0
- vispy/scene/widgets/anchor.py +25 -0
- vispy/scene/widgets/axis.py +88 -0
- vispy/scene/widgets/colorbar.py +176 -0
- vispy/scene/widgets/console.py +351 -0
- vispy/scene/widgets/grid.py +509 -0
- vispy/scene/widgets/label.py +50 -0
- vispy/scene/widgets/tests/__init__.py +0 -0
- vispy/scene/widgets/tests/test_colorbar.py +47 -0
- vispy/scene/widgets/viewbox.py +199 -0
- vispy/scene/widgets/widget.py +478 -0
- vispy/testing/__init__.py +51 -0
- vispy/testing/_runners.py +448 -0
- vispy/testing/_testing.py +416 -0
- vispy/testing/image_tester.py +494 -0
- vispy/testing/rendered_array_tester.py +85 -0
- vispy/testing/tests/__init__.py +0 -0
- vispy/testing/tests/test_testing.py +20 -0
- vispy/util/__init__.py +32 -0
- vispy/util/bunch.py +15 -0
- vispy/util/check_environment.py +57 -0
- vispy/util/config.py +490 -0
- vispy/util/dpi/__init__.py +19 -0
- vispy/util/dpi/_linux.py +69 -0
- vispy/util/dpi/_quartz.py +26 -0
- vispy/util/dpi/_win32.py +34 -0
- vispy/util/dpi/tests/__init__.py +0 -0
- vispy/util/dpi/tests/test_dpi.py +16 -0
- vispy/util/eq.py +41 -0
- vispy/util/event.py +774 -0
- vispy/util/fetching.py +276 -0
- vispy/util/filter.py +44 -0
- vispy/util/fonts/__init__.py +14 -0
- vispy/util/fonts/_freetype.py +73 -0
- vispy/util/fonts/_quartz.py +192 -0
- vispy/util/fonts/_triage.py +36 -0
- vispy/util/fonts/_vispy_fonts.py +20 -0
- vispy/util/fonts/_win32.py +105 -0
- vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
- vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
- vispy/util/fonts/tests/__init__.py +0 -0
- vispy/util/fonts/tests/test_font.py +45 -0
- vispy/util/fourier.py +69 -0
- vispy/util/frozen.py +25 -0
- vispy/util/gallery_scraper.py +268 -0
- vispy/util/keys.py +91 -0
- vispy/util/logs.py +358 -0
- vispy/util/osmesa_gl.py +17 -0
- vispy/util/profiler.py +135 -0
- vispy/util/ptime.py +16 -0
- vispy/util/quaternion.py +229 -0
- vispy/util/svg/__init__.py +18 -0
- vispy/util/svg/base.py +20 -0
- vispy/util/svg/color.py +219 -0
- vispy/util/svg/element.py +51 -0
- vispy/util/svg/geometry.py +478 -0
- vispy/util/svg/group.py +66 -0
- vispy/util/svg/length.py +81 -0
- vispy/util/svg/number.py +25 -0
- vispy/util/svg/path.py +332 -0
- vispy/util/svg/shapes.py +57 -0
- vispy/util/svg/style.py +59 -0
- vispy/util/svg/svg.py +40 -0
- vispy/util/svg/transform.py +223 -0
- vispy/util/svg/transformable.py +28 -0
- vispy/util/svg/viewport.py +73 -0
- vispy/util/tests/__init__.py +0 -0
- vispy/util/tests/test_config.py +58 -0
- vispy/util/tests/test_docstring_parameters.py +123 -0
- vispy/util/tests/test_emitter_group.py +262 -0
- vispy/util/tests/test_event_emitter.py +743 -0
- vispy/util/tests/test_fourier.py +35 -0
- vispy/util/tests/test_gallery_scraper.py +112 -0
- vispy/util/tests/test_import.py +127 -0
- vispy/util/tests/test_key.py +22 -0
- vispy/util/tests/test_logging.py +45 -0
- vispy/util/tests/test_run.py +14 -0
- vispy/util/tests/test_transforms.py +42 -0
- vispy/util/tests/test_vispy.py +48 -0
- vispy/util/transforms.py +201 -0
- vispy/util/wrappers.py +155 -0
- vispy/version.py +21 -0
- vispy/visuals/__init__.py +50 -0
- vispy/visuals/_scalable_textures.py +487 -0
- vispy/visuals/axis.py +678 -0
- vispy/visuals/border.py +208 -0
- vispy/visuals/box.py +79 -0
- vispy/visuals/collections/__init__.py +30 -0
- vispy/visuals/collections/agg_fast_path_collection.py +219 -0
- vispy/visuals/collections/agg_path_collection.py +197 -0
- vispy/visuals/collections/agg_point_collection.py +52 -0
- vispy/visuals/collections/agg_segment_collection.py +142 -0
- vispy/visuals/collections/array_list.py +401 -0
- vispy/visuals/collections/base_collection.py +482 -0
- vispy/visuals/collections/collection.py +253 -0
- vispy/visuals/collections/path_collection.py +23 -0
- vispy/visuals/collections/point_collection.py +19 -0
- vispy/visuals/collections/polygon_collection.py +25 -0
- vispy/visuals/collections/raw_path_collection.py +119 -0
- vispy/visuals/collections/raw_point_collection.py +113 -0
- vispy/visuals/collections/raw_polygon_collection.py +77 -0
- vispy/visuals/collections/raw_segment_collection.py +112 -0
- vispy/visuals/collections/raw_triangle_collection.py +78 -0
- vispy/visuals/collections/segment_collection.py +19 -0
- vispy/visuals/collections/triangle_collection.py +16 -0
- vispy/visuals/collections/util.py +168 -0
- vispy/visuals/colorbar.py +699 -0
- vispy/visuals/cube.py +41 -0
- vispy/visuals/ellipse.py +162 -0
- vispy/visuals/filters/__init__.py +10 -0
- vispy/visuals/filters/base_filter.py +242 -0
- vispy/visuals/filters/clipper.py +60 -0
- vispy/visuals/filters/clipping_planes.py +122 -0
- vispy/visuals/filters/color.py +181 -0
- vispy/visuals/filters/markers.py +28 -0
- vispy/visuals/filters/mesh.py +801 -0
- vispy/visuals/filters/picking.py +60 -0
- vispy/visuals/filters/tests/__init__.py +3 -0
- vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
- vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
- vispy/visuals/glsl/__init__.py +1 -0
- vispy/visuals/glsl/antialiasing.py +133 -0
- vispy/visuals/glsl/color.py +63 -0
- vispy/visuals/graphs/__init__.py +1 -0
- vispy/visuals/graphs/graph.py +240 -0
- vispy/visuals/graphs/layouts/__init__.py +55 -0
- vispy/visuals/graphs/layouts/circular.py +49 -0
- vispy/visuals/graphs/layouts/force_directed.py +211 -0
- vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
- vispy/visuals/graphs/layouts/random.py +52 -0
- vispy/visuals/graphs/tests/__init__.py +1 -0
- vispy/visuals/graphs/tests/test_layouts.py +139 -0
- vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
- vispy/visuals/graphs/util.py +120 -0
- vispy/visuals/gridlines.py +161 -0
- vispy/visuals/gridmesh.py +98 -0
- vispy/visuals/histogram.py +58 -0
- vispy/visuals/image.py +701 -0
- vispy/visuals/image_complex.py +130 -0
- vispy/visuals/infinite_line.py +199 -0
- vispy/visuals/instanced_mesh.py +152 -0
- vispy/visuals/isocurve.py +213 -0
- vispy/visuals/isoline.py +241 -0
- vispy/visuals/isosurface.py +113 -0
- vispy/visuals/line/__init__.py +6 -0
- vispy/visuals/line/arrow.py +289 -0
- vispy/visuals/line/dash_atlas.py +90 -0
- vispy/visuals/line/line.py +545 -0
- vispy/visuals/line_plot.py +135 -0
- vispy/visuals/linear_region.py +199 -0
- vispy/visuals/markers.py +819 -0
- vispy/visuals/mesh.py +373 -0
- vispy/visuals/mesh_normals.py +159 -0
- vispy/visuals/plane.py +54 -0
- vispy/visuals/polygon.py +145 -0
- vispy/visuals/rectangle.py +196 -0
- vispy/visuals/regular_polygon.py +56 -0
- vispy/visuals/scrolling_lines.py +197 -0
- vispy/visuals/shaders/__init__.py +17 -0
- vispy/visuals/shaders/compiler.py +206 -0
- vispy/visuals/shaders/expression.py +99 -0
- vispy/visuals/shaders/function.py +788 -0
- vispy/visuals/shaders/multiprogram.py +145 -0
- vispy/visuals/shaders/parsing.py +140 -0
- vispy/visuals/shaders/program.py +161 -0
- vispy/visuals/shaders/shader_object.py +162 -0
- vispy/visuals/shaders/tests/__init__.py +0 -0
- vispy/visuals/shaders/tests/test_function.py +486 -0
- vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
- vispy/visuals/shaders/tests/test_parsing.py +57 -0
- vispy/visuals/shaders/variable.py +272 -0
- vispy/visuals/spectrogram.py +169 -0
- vispy/visuals/sphere.py +80 -0
- vispy/visuals/surface_plot.py +192 -0
- vispy/visuals/tests/__init__.py +0 -0
- vispy/visuals/tests/test_arrows.py +109 -0
- vispy/visuals/tests/test_axis.py +120 -0
- vispy/visuals/tests/test_collections.py +15 -0
- vispy/visuals/tests/test_colorbar.py +179 -0
- vispy/visuals/tests/test_colormap.py +97 -0
- vispy/visuals/tests/test_ellipse.py +122 -0
- vispy/visuals/tests/test_gridlines.py +30 -0
- vispy/visuals/tests/test_histogram.py +24 -0
- vispy/visuals/tests/test_image.py +392 -0
- vispy/visuals/tests/test_image_complex.py +36 -0
- vispy/visuals/tests/test_infinite_line.py +53 -0
- vispy/visuals/tests/test_instanced_mesh.py +50 -0
- vispy/visuals/tests/test_isosurface.py +22 -0
- vispy/visuals/tests/test_linear_region.py +152 -0
- vispy/visuals/tests/test_markers.py +54 -0
- vispy/visuals/tests/test_mesh.py +261 -0
- vispy/visuals/tests/test_mesh_normals.py +218 -0
- vispy/visuals/tests/test_polygon.py +112 -0
- vispy/visuals/tests/test_rectangle.py +163 -0
- vispy/visuals/tests/test_regular_polygon.py +111 -0
- vispy/visuals/tests/test_scalable_textures.py +196 -0
- vispy/visuals/tests/test_sdf.py +73 -0
- vispy/visuals/tests/test_spectrogram.py +42 -0
- vispy/visuals/tests/test_surface_plot.py +57 -0
- vispy/visuals/tests/test_text.py +95 -0
- vispy/visuals/tests/test_volume.py +542 -0
- vispy/visuals/tests/test_windbarb.py +33 -0
- vispy/visuals/text/__init__.py +7 -0
- vispy/visuals/text/_sdf_cpu.cpython-312-darwin.so +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +112 -0
- vispy/visuals/text/_sdf_gpu.py +316 -0
- vispy/visuals/text/text.py +675 -0
- vispy/visuals/transforms/__init__.py +34 -0
- vispy/visuals/transforms/_util.py +191 -0
- vispy/visuals/transforms/base_transform.py +233 -0
- vispy/visuals/transforms/chain.py +300 -0
- vispy/visuals/transforms/interactive.py +98 -0
- vispy/visuals/transforms/linear.py +564 -0
- vispy/visuals/transforms/nonlinear.py +398 -0
- vispy/visuals/transforms/tests/__init__.py +0 -0
- vispy/visuals/transforms/tests/test_transforms.py +243 -0
- vispy/visuals/transforms/transform_system.py +339 -0
- vispy/visuals/tube.py +173 -0
- vispy/visuals/visual.py +923 -0
- vispy/visuals/volume.py +1366 -0
- vispy/visuals/windbarb.py +291 -0
- vispy/visuals/xyz_axis.py +34 -0
- vispy-0.15.0.dist-info/METADATA +243 -0
- vispy-0.15.0.dist-info/RECORD +521 -0
- vispy-0.15.0.dist-info/WHEEL +6 -0
- vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
- vispy-0.15.0.dist-info/top_level.txt +1 -0
vispy/visuals/axis.py
ADDED
|
@@ -0,0 +1,678 @@
|
|
|
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 math
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from .visual import CompoundVisual, updating_property
|
|
12
|
+
from .line import LineVisual
|
|
13
|
+
from .text import TextVisual
|
|
14
|
+
|
|
15
|
+
# XXX TODO list (see code, plus):
|
|
16
|
+
# 1. Automated tick direction?
|
|
17
|
+
# 2. Expand to 3D (only 2D supported currently)
|
|
18
|
+
# 3. Input validation
|
|
19
|
+
# 4. Property support
|
|
20
|
+
# 5. Reactivity to resizing (current tick lengths grow/shrink w/zoom)
|
|
21
|
+
# 6. Improve tick label naming (str(x) is not good) and tick selection
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AxisVisual(CompoundVisual):
|
|
25
|
+
"""Axis visual
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
pos : array
|
|
30
|
+
Co-ordinates of start and end of the axis.
|
|
31
|
+
domain : tuple
|
|
32
|
+
The data values at the beginning and end of the axis, used for tick
|
|
33
|
+
labels. i.e. (5, 10) means the axis starts at 5 and ends at 10. Default
|
|
34
|
+
is (0, 1).
|
|
35
|
+
tick_direction : array
|
|
36
|
+
The tick direction to use (in document coordinates).
|
|
37
|
+
scale_type : str
|
|
38
|
+
The type of scale. For now only 'linear' is supported.
|
|
39
|
+
axis_color : tuple
|
|
40
|
+
RGBA values for the axis colour. Default is black.
|
|
41
|
+
tick_color : tuple
|
|
42
|
+
RGBA values for the tick colours. The colour for the major and minor
|
|
43
|
+
ticks is currently fixed to be the same. Default is a dark grey.
|
|
44
|
+
text_color : Color
|
|
45
|
+
The color to use for drawing tick and axis labels
|
|
46
|
+
minor_tick_length : float
|
|
47
|
+
The length of minor ticks, in pixels
|
|
48
|
+
major_tick_length : float
|
|
49
|
+
The length of major ticks, in pixels
|
|
50
|
+
tick_width : float
|
|
51
|
+
Line width for the ticks
|
|
52
|
+
tick_label_margin : float
|
|
53
|
+
Margin between ticks and tick labels
|
|
54
|
+
tick_font_size : float
|
|
55
|
+
The font size to use for rendering tick labels.
|
|
56
|
+
axis_width : float
|
|
57
|
+
Line width for the axis
|
|
58
|
+
axis_label : str
|
|
59
|
+
Text to use for the axis label
|
|
60
|
+
axis_label_margin : float
|
|
61
|
+
Margin between ticks and axis labels
|
|
62
|
+
axis_font_size : float
|
|
63
|
+
The font size to use for rendering axis labels.
|
|
64
|
+
font_size : float
|
|
65
|
+
Font size for both the tick and axis labels. If this is set,
|
|
66
|
+
tick_font_size and axis_font_size are ignored.
|
|
67
|
+
anchors : iterable
|
|
68
|
+
A 2-element iterable (tuple, list, etc.) giving the horizontal and
|
|
69
|
+
vertical alignment of the tick labels. The first element should be one
|
|
70
|
+
of 'left', 'center', or 'right', and the second element should be one
|
|
71
|
+
of 'bottom', 'middle', or 'top'. If this is not specified, it is
|
|
72
|
+
determined automatically.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def __init__(self, pos=None, domain=(0., 1.),
|
|
76
|
+
tick_direction=(-1., 0.),
|
|
77
|
+
scale_type="linear",
|
|
78
|
+
axis_color=(1, 1, 1),
|
|
79
|
+
tick_color=(0.7, 0.7, 0.7),
|
|
80
|
+
text_color='w',
|
|
81
|
+
minor_tick_length=5,
|
|
82
|
+
major_tick_length=10,
|
|
83
|
+
tick_width=2,
|
|
84
|
+
tick_label_margin=12,
|
|
85
|
+
tick_font_size=8,
|
|
86
|
+
axis_width=3,
|
|
87
|
+
axis_label=None,
|
|
88
|
+
axis_label_margin=35,
|
|
89
|
+
axis_font_size=10,
|
|
90
|
+
font_size=None,
|
|
91
|
+
anchors=None):
|
|
92
|
+
|
|
93
|
+
if scale_type != 'linear':
|
|
94
|
+
raise NotImplementedError('only linear scaling is currently '
|
|
95
|
+
'supported')
|
|
96
|
+
|
|
97
|
+
if font_size is not None:
|
|
98
|
+
tick_font_size = font_size
|
|
99
|
+
axis_font_size = font_size
|
|
100
|
+
|
|
101
|
+
self._pos = None
|
|
102
|
+
self._domain = None
|
|
103
|
+
|
|
104
|
+
# If True, then axis stops at the first / last major tick.
|
|
105
|
+
# If False, then axis extends to edge of *pos*
|
|
106
|
+
# (private until we come up with a better name for this)
|
|
107
|
+
self._stop_at_major = (False, False)
|
|
108
|
+
|
|
109
|
+
self.ticker = Ticker(self, anchors=anchors)
|
|
110
|
+
self.tick_direction = np.array(tick_direction, float)
|
|
111
|
+
self.scale_type = scale_type
|
|
112
|
+
|
|
113
|
+
self._minor_tick_length = minor_tick_length # px
|
|
114
|
+
self._major_tick_length = major_tick_length # px
|
|
115
|
+
self._tick_label_margin = tick_label_margin # px
|
|
116
|
+
self._axis_label_margin = axis_label_margin # px
|
|
117
|
+
|
|
118
|
+
self._axis_label = axis_label
|
|
119
|
+
|
|
120
|
+
self._need_update = True
|
|
121
|
+
|
|
122
|
+
self._line = LineVisual(method='gl', width=axis_width, antialias=True,
|
|
123
|
+
color=axis_color)
|
|
124
|
+
self._ticks = LineVisual(method='gl', width=tick_width,
|
|
125
|
+
connect='segments', antialias=True,
|
|
126
|
+
color=tick_color)
|
|
127
|
+
|
|
128
|
+
self._text = TextVisual(font_size=tick_font_size, color=text_color)
|
|
129
|
+
self._axis_label_vis = TextVisual(font_size=axis_font_size,
|
|
130
|
+
color=text_color)
|
|
131
|
+
CompoundVisual.__init__(self, [self._line, self._text, self._ticks,
|
|
132
|
+
self._axis_label_vis])
|
|
133
|
+
if pos is not None:
|
|
134
|
+
self.pos = pos
|
|
135
|
+
self.domain = domain
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def text_color(self):
|
|
139
|
+
return self._text.color
|
|
140
|
+
|
|
141
|
+
@text_color.setter
|
|
142
|
+
def text_color(self, value):
|
|
143
|
+
self._text.color = value
|
|
144
|
+
self._axis_label_vis.color = value
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def axis_color(self):
|
|
148
|
+
return self._line.color
|
|
149
|
+
|
|
150
|
+
@axis_color.setter
|
|
151
|
+
def axis_color(self, value):
|
|
152
|
+
self._line.set_data(color=value)
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def axis_width(self):
|
|
156
|
+
return self._line.width
|
|
157
|
+
|
|
158
|
+
@axis_width.setter
|
|
159
|
+
def axis_width(self, value):
|
|
160
|
+
self._line.set_data(width=value)
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def tick_color(self):
|
|
164
|
+
return self._ticks.color
|
|
165
|
+
|
|
166
|
+
@tick_color.setter
|
|
167
|
+
def tick_color(self, value):
|
|
168
|
+
self._ticks.set_data(color=value)
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def tick_width(self):
|
|
172
|
+
return self._ticks.width
|
|
173
|
+
|
|
174
|
+
@tick_width.setter
|
|
175
|
+
def tick_width(self, value):
|
|
176
|
+
self._ticks.set_data(width=value)
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def tick_font_size(self):
|
|
180
|
+
return self._text.font_size
|
|
181
|
+
|
|
182
|
+
@tick_font_size.setter
|
|
183
|
+
def tick_font_size(self, value):
|
|
184
|
+
self._text.font_size = value
|
|
185
|
+
|
|
186
|
+
@updating_property
|
|
187
|
+
def tick_direction(self):
|
|
188
|
+
"""The tick direction to use (in document coordinates)."""
|
|
189
|
+
|
|
190
|
+
@tick_direction.setter
|
|
191
|
+
def tick_direction(self, tick_direction):
|
|
192
|
+
self._tick_direction = np.array(tick_direction, float)
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def axis_font_size(self):
|
|
196
|
+
return self._axis_label_vis.font_size
|
|
197
|
+
|
|
198
|
+
@axis_font_size.setter
|
|
199
|
+
def axis_font_size(self, value):
|
|
200
|
+
self._axis_label_vis.font_size = value
|
|
201
|
+
|
|
202
|
+
@updating_property
|
|
203
|
+
def domain(self):
|
|
204
|
+
"""The data values at the beginning and end of the axis, used for tick labels."""
|
|
205
|
+
|
|
206
|
+
@updating_property
|
|
207
|
+
def axis_label(self):
|
|
208
|
+
"""Text to use for the axis label."""
|
|
209
|
+
|
|
210
|
+
@updating_property
|
|
211
|
+
def pos(self):
|
|
212
|
+
"""Co-ordinates of start and end of the axis."""
|
|
213
|
+
|
|
214
|
+
@pos.setter
|
|
215
|
+
def pos(self, pos):
|
|
216
|
+
self._pos = np.array(pos, float)
|
|
217
|
+
|
|
218
|
+
@updating_property
|
|
219
|
+
def minor_tick_length(self):
|
|
220
|
+
"""The length of minor ticks, in pixels"""
|
|
221
|
+
|
|
222
|
+
@updating_property
|
|
223
|
+
def major_tick_length(self):
|
|
224
|
+
"""The length of major ticks, in pixels"""
|
|
225
|
+
|
|
226
|
+
@updating_property
|
|
227
|
+
def tick_label_margin(self):
|
|
228
|
+
"""Margin between ticks and tick labels"""
|
|
229
|
+
|
|
230
|
+
@updating_property
|
|
231
|
+
def axis_label_margin(self):
|
|
232
|
+
"""Margin between ticks and axis labels"""
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def _vec(self):
|
|
236
|
+
"""Vector in the direction of the axis line"""
|
|
237
|
+
return self.pos[1] - self.pos[0]
|
|
238
|
+
|
|
239
|
+
def _update_subvisuals(self):
|
|
240
|
+
tick_pos, labels, tick_label_pos, anchors, axis_label_pos = \
|
|
241
|
+
self.ticker.get_update()
|
|
242
|
+
|
|
243
|
+
self._line.set_data(pos=self.pos, color=self.axis_color)
|
|
244
|
+
self._ticks.set_data(pos=tick_pos, color=self.tick_color)
|
|
245
|
+
self._text.text = list(labels)
|
|
246
|
+
self._text.pos = tick_label_pos
|
|
247
|
+
self._text.anchors = anchors
|
|
248
|
+
if self.axis_label is not None:
|
|
249
|
+
self._axis_label_vis.text = self.axis_label
|
|
250
|
+
self._axis_label_vis.pos = axis_label_pos
|
|
251
|
+
self._need_update = False
|
|
252
|
+
|
|
253
|
+
def _prepare_draw(self, view):
|
|
254
|
+
if self._pos is None:
|
|
255
|
+
return False
|
|
256
|
+
if self.axis_label is not None:
|
|
257
|
+
self._axis_label_vis.rotation = self._rotation_angle
|
|
258
|
+
if self._need_update:
|
|
259
|
+
self._update_subvisuals()
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def _rotation_angle(self):
|
|
263
|
+
"""Determine the rotation angle of the axis as projected onto the canvas."""
|
|
264
|
+
# TODO: make sure we only call get_transform if the transform for
|
|
265
|
+
# the line is updated
|
|
266
|
+
tr = self._line.get_transform(map_from='visual', map_to='canvas')
|
|
267
|
+
trpos = tr.map(self.pos)
|
|
268
|
+
# Normalize homogeneous coordinates
|
|
269
|
+
# trpos /= trpos[:, 3:]
|
|
270
|
+
x1, y1, x2, y2 = trpos[:, :2].ravel()
|
|
271
|
+
if x1 > x2:
|
|
272
|
+
x1, y1, x2, y2 = x2, y2, x1, y1
|
|
273
|
+
return math.degrees(math.atan2(y2-y1, x2-x1))
|
|
274
|
+
|
|
275
|
+
def _compute_bounds(self, axis, view):
|
|
276
|
+
if axis == 2:
|
|
277
|
+
return (0., 0.)
|
|
278
|
+
# now axis in (0, 1)
|
|
279
|
+
return self.pos[:, axis].min(), self.pos[:, axis].max()
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class Ticker(object):
|
|
283
|
+
"""Class to determine tick marks
|
|
284
|
+
|
|
285
|
+
Parameters
|
|
286
|
+
----------
|
|
287
|
+
axis : instance of AxisVisual
|
|
288
|
+
The AxisVisual to generate ticks for.
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
def __init__(self, axis, anchors=None):
|
|
292
|
+
self.axis = axis
|
|
293
|
+
self._anchors = anchors
|
|
294
|
+
|
|
295
|
+
def get_update(self):
|
|
296
|
+
major_tick_fractions, minor_tick_fractions, tick_labels = \
|
|
297
|
+
self._get_tick_frac_labels()
|
|
298
|
+
tick_pos, tick_label_pos, axis_label_pos, anchors = \
|
|
299
|
+
self._get_tick_positions(major_tick_fractions,
|
|
300
|
+
minor_tick_fractions)
|
|
301
|
+
return tick_pos, tick_labels, tick_label_pos, anchors, axis_label_pos
|
|
302
|
+
|
|
303
|
+
def _get_tick_positions(self, major_tick_fractions, minor_tick_fractions):
|
|
304
|
+
# tick direction is defined in visual coords, but use document
|
|
305
|
+
# coords to determine the tick length
|
|
306
|
+
trs = self.axis.transforms
|
|
307
|
+
visual_to_document = trs.get_transform('visual', 'document')
|
|
308
|
+
direction = np.array(self.axis.tick_direction)
|
|
309
|
+
direction /= np.linalg.norm(direction)
|
|
310
|
+
|
|
311
|
+
if self._anchors is None:
|
|
312
|
+
# use the document (pixel) coord system to set text anchors
|
|
313
|
+
anchors = []
|
|
314
|
+
if direction[0] < 0:
|
|
315
|
+
anchors.append('right')
|
|
316
|
+
elif direction[0] > 0:
|
|
317
|
+
anchors.append('left')
|
|
318
|
+
else:
|
|
319
|
+
anchors.append('center')
|
|
320
|
+
if direction[1] < 0:
|
|
321
|
+
anchors.append('bottom')
|
|
322
|
+
elif direction[1] > 0:
|
|
323
|
+
anchors.append('top')
|
|
324
|
+
else:
|
|
325
|
+
anchors.append('middle')
|
|
326
|
+
else:
|
|
327
|
+
anchors = self._anchors
|
|
328
|
+
|
|
329
|
+
# now figure out the tick positions in visual (data) coords
|
|
330
|
+
doc_unit = visual_to_document.map([[0, 0], direction[:2]])
|
|
331
|
+
doc_unit = doc_unit[1] - doc_unit[0]
|
|
332
|
+
doc_len = np.linalg.norm(doc_unit)
|
|
333
|
+
|
|
334
|
+
vectors = np.array([[0., 0.],
|
|
335
|
+
direction * self.axis.minor_tick_length / doc_len,
|
|
336
|
+
direction * self.axis.major_tick_length / doc_len,
|
|
337
|
+
direction * (self.axis.major_tick_length +
|
|
338
|
+
self.axis.tick_label_margin) / doc_len
|
|
339
|
+
],
|
|
340
|
+
dtype=float)
|
|
341
|
+
minor_vector = vectors[1] - vectors[0]
|
|
342
|
+
major_vector = vectors[2] - vectors[0]
|
|
343
|
+
label_vector = vectors[3] - vectors[0]
|
|
344
|
+
|
|
345
|
+
axislabel_vector = direction * (self.axis.major_tick_length +
|
|
346
|
+
self.axis.axis_label_margin) / doc_len
|
|
347
|
+
|
|
348
|
+
major_origins, major_endpoints = self._tile_ticks(
|
|
349
|
+
major_tick_fractions, major_vector)
|
|
350
|
+
|
|
351
|
+
minor_origins, minor_endpoints = self._tile_ticks(
|
|
352
|
+
minor_tick_fractions, minor_vector)
|
|
353
|
+
|
|
354
|
+
tick_label_pos = major_origins + label_vector
|
|
355
|
+
|
|
356
|
+
axis_label_pos = 0.5 * (self.axis.pos[0] +
|
|
357
|
+
self.axis.pos[1]) + axislabel_vector
|
|
358
|
+
|
|
359
|
+
num_major = len(major_tick_fractions)
|
|
360
|
+
num_minor = len(minor_tick_fractions)
|
|
361
|
+
|
|
362
|
+
c = np.empty([(num_major + num_minor) * 2, 2])
|
|
363
|
+
|
|
364
|
+
c[0:(num_major-1)*2+1:2] = major_origins
|
|
365
|
+
c[1:(num_major-1)*2+2:2] = major_endpoints
|
|
366
|
+
c[(num_major-1)*2+2::2] = minor_origins
|
|
367
|
+
c[(num_major-1)*2+3::2] = minor_endpoints
|
|
368
|
+
|
|
369
|
+
return c, tick_label_pos, axis_label_pos, anchors
|
|
370
|
+
|
|
371
|
+
def _tile_ticks(self, frac, tickvec):
|
|
372
|
+
"""Tiles tick marks along the axis."""
|
|
373
|
+
origins = np.tile(self.axis._vec, (len(frac), 1))
|
|
374
|
+
origins = self.axis.pos[0].T + (origins.T*frac).T
|
|
375
|
+
endpoints = tickvec + origins
|
|
376
|
+
return origins, endpoints
|
|
377
|
+
|
|
378
|
+
def _get_tick_frac_labels(self):
|
|
379
|
+
"""Get the major ticks, minor ticks, and major labels"""
|
|
380
|
+
minor_num = 4 # number of minor ticks per major division
|
|
381
|
+
if (self.axis.scale_type == 'linear'):
|
|
382
|
+
domain = self.axis.domain
|
|
383
|
+
if domain[1] < domain[0]:
|
|
384
|
+
flip = True
|
|
385
|
+
domain = domain[::-1]
|
|
386
|
+
else:
|
|
387
|
+
flip = False
|
|
388
|
+
offset = domain[0]
|
|
389
|
+
scale = domain[1] - domain[0]
|
|
390
|
+
|
|
391
|
+
transforms = self.axis.transforms
|
|
392
|
+
length = self.axis.pos[1] - self.axis.pos[0] # in logical coords
|
|
393
|
+
n_inches = np.sqrt(np.sum(length ** 2)) / transforms.dpi
|
|
394
|
+
|
|
395
|
+
major = _get_ticks_talbot(domain[0], domain[1], n_inches, 2)
|
|
396
|
+
|
|
397
|
+
labels = ['%g' % x for x in major]
|
|
398
|
+
majstep = major[1] - major[0]
|
|
399
|
+
minor = []
|
|
400
|
+
minstep = majstep / (minor_num + 1)
|
|
401
|
+
minstart = 0 if self.axis._stop_at_major[0] else -1
|
|
402
|
+
minstop = -1 if self.axis._stop_at_major[1] else 0
|
|
403
|
+
for i in range(minstart, len(major) + minstop):
|
|
404
|
+
maj = major[0] + i * majstep
|
|
405
|
+
minor.extend(np.linspace(maj + minstep,
|
|
406
|
+
maj + majstep - minstep,
|
|
407
|
+
minor_num))
|
|
408
|
+
major_frac = major - offset
|
|
409
|
+
minor_frac = np.array(minor) - offset
|
|
410
|
+
if scale != 0: # maybe something better to do here?
|
|
411
|
+
major_frac /= scale
|
|
412
|
+
minor_frac /= scale
|
|
413
|
+
use_mask = (major_frac > -0.0001) & (major_frac < 1.0001)
|
|
414
|
+
major_frac = major_frac[use_mask]
|
|
415
|
+
labels = [l for li, l in enumerate(labels) if use_mask[li]]
|
|
416
|
+
minor_frac = minor_frac[(minor_frac > -0.0001) &
|
|
417
|
+
(minor_frac < 1.0001)]
|
|
418
|
+
# Flip ticks coordinates if necessary :
|
|
419
|
+
if flip:
|
|
420
|
+
major_frac = 1 - major_frac
|
|
421
|
+
minor_frac = 1 - minor_frac
|
|
422
|
+
elif self.axis.scale_type == 'logarithmic':
|
|
423
|
+
return NotImplementedError
|
|
424
|
+
elif self.axis.scale_type == 'power':
|
|
425
|
+
return NotImplementedError
|
|
426
|
+
return major_frac, minor_frac, labels
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
# #############################################################################
|
|
430
|
+
# Translated from matplotlib
|
|
431
|
+
|
|
432
|
+
class MaxNLocator(object):
|
|
433
|
+
"""Select no more than N intervals at nice locations."""
|
|
434
|
+
|
|
435
|
+
def __init__(self, nbins=10, steps=None, trim=True, integer=False,
|
|
436
|
+
symmetric=False, prune=None):
|
|
437
|
+
"""
|
|
438
|
+
Keyword args:
|
|
439
|
+
*nbins*
|
|
440
|
+
Maximum number of intervals; one less than max number of ticks.
|
|
441
|
+
*steps*
|
|
442
|
+
Sequence of nice numbers starting with 1 and ending with 10;
|
|
443
|
+
e.g., [1, 2, 4, 5, 10]
|
|
444
|
+
*integer*
|
|
445
|
+
If True, ticks will take only integer values.
|
|
446
|
+
*symmetric*
|
|
447
|
+
If True, autoscaling will result in a range symmetric
|
|
448
|
+
about zero.
|
|
449
|
+
*prune*
|
|
450
|
+
['lower' | 'upper' | 'both' | None]
|
|
451
|
+
Remove edge ticks -- useful for stacked or ganged plots
|
|
452
|
+
where the upper tick of one axes overlaps with the lower
|
|
453
|
+
tick of the axes above it.
|
|
454
|
+
If prune=='lower', the smallest tick will
|
|
455
|
+
be removed. If prune=='upper', the largest tick will be
|
|
456
|
+
removed. If prune=='both', the largest and smallest ticks
|
|
457
|
+
will be removed. If prune==None, no ticks will be removed.
|
|
458
|
+
"""
|
|
459
|
+
self._nbins = int(nbins)
|
|
460
|
+
self._trim = trim
|
|
461
|
+
self._integer = integer
|
|
462
|
+
self._symmetric = symmetric
|
|
463
|
+
if prune is not None and prune not in ['upper', 'lower', 'both']:
|
|
464
|
+
raise ValueError(
|
|
465
|
+
"prune must be 'upper', 'lower', 'both', or None")
|
|
466
|
+
self._prune = prune
|
|
467
|
+
if steps is None:
|
|
468
|
+
steps = [1, 2, 2.5, 3, 4, 5, 6, 8, 10]
|
|
469
|
+
else:
|
|
470
|
+
if int(steps[-1]) != 10:
|
|
471
|
+
steps = list(steps)
|
|
472
|
+
steps.append(10)
|
|
473
|
+
self._steps = steps
|
|
474
|
+
self._integer = integer
|
|
475
|
+
if self._integer:
|
|
476
|
+
self._steps = [n for n in self._steps
|
|
477
|
+
if divmod(n, 1)[1] < 0.001]
|
|
478
|
+
|
|
479
|
+
def bin_boundaries(self, vmin, vmax):
|
|
480
|
+
nbins = self._nbins
|
|
481
|
+
scale, offset = scale_range(vmin, vmax, nbins)
|
|
482
|
+
if self._integer:
|
|
483
|
+
scale = max(1, scale)
|
|
484
|
+
vmin = vmin - offset
|
|
485
|
+
vmax = vmax - offset
|
|
486
|
+
raw_step = (vmax - vmin) / nbins
|
|
487
|
+
scaled_raw_step = raw_step / scale
|
|
488
|
+
best_vmax = vmax
|
|
489
|
+
best_vmin = vmin
|
|
490
|
+
|
|
491
|
+
for step in self._steps:
|
|
492
|
+
if step < scaled_raw_step:
|
|
493
|
+
continue
|
|
494
|
+
step *= scale
|
|
495
|
+
best_vmin = step * divmod(vmin, step)[0]
|
|
496
|
+
best_vmax = best_vmin + step * nbins
|
|
497
|
+
if (best_vmax >= vmax):
|
|
498
|
+
break
|
|
499
|
+
if self._trim:
|
|
500
|
+
extra_bins = int(divmod((best_vmax - vmax), step)[0])
|
|
501
|
+
nbins -= extra_bins
|
|
502
|
+
return (np.arange(nbins + 1) * step + best_vmin + offset)
|
|
503
|
+
|
|
504
|
+
def __call__(self):
|
|
505
|
+
vmin, vmax = self.axis.get_view_interval()
|
|
506
|
+
return self.tick_values(vmin, vmax)
|
|
507
|
+
|
|
508
|
+
def tick_values(self, vmin, vmax):
|
|
509
|
+
locs = self.bin_boundaries(vmin, vmax)
|
|
510
|
+
prune = self._prune
|
|
511
|
+
if prune == 'lower':
|
|
512
|
+
locs = locs[1:]
|
|
513
|
+
elif prune == 'upper':
|
|
514
|
+
locs = locs[:-1]
|
|
515
|
+
elif prune == 'both':
|
|
516
|
+
locs = locs[1:-1]
|
|
517
|
+
return locs
|
|
518
|
+
|
|
519
|
+
def view_limits(self, dmin, dmax):
|
|
520
|
+
if self._symmetric:
|
|
521
|
+
maxabs = max(abs(dmin), abs(dmax))
|
|
522
|
+
dmin = -maxabs
|
|
523
|
+
dmax = maxabs
|
|
524
|
+
return np.take(self.bin_boundaries(dmin, dmax), [0, -1])
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
def scale_range(vmin, vmax, n=1, threshold=100):
|
|
528
|
+
dv = abs(vmax - vmin)
|
|
529
|
+
if dv == 0: # maxabsv == 0 is a special case of this.
|
|
530
|
+
return 1.0, 0.0
|
|
531
|
+
# Note: this should never occur because
|
|
532
|
+
# vmin, vmax should have been checked by nonsingular(),
|
|
533
|
+
# and spread apart if necessary.
|
|
534
|
+
meanv = 0.5 * (vmax + vmin)
|
|
535
|
+
if abs(meanv) / dv < threshold:
|
|
536
|
+
offset = 0
|
|
537
|
+
elif meanv > 0:
|
|
538
|
+
ex = divmod(np.log10(meanv), 1)[0]
|
|
539
|
+
offset = 10 ** ex
|
|
540
|
+
else:
|
|
541
|
+
ex = divmod(np.log10(-meanv), 1)[0]
|
|
542
|
+
offset = -10 ** ex
|
|
543
|
+
ex = divmod(np.log10(dv / n), 1)[0]
|
|
544
|
+
scale = 10 ** ex
|
|
545
|
+
return scale, offset
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
# #############################################################################
|
|
549
|
+
# Tranlated from http://www.justintalbot.com/research/axis-labeling/
|
|
550
|
+
|
|
551
|
+
# See "An Extension of Wilkinson's Algorithm for Positioning Tick Labels
|
|
552
|
+
# on Axes" # by Justin Talbot, Sharon Lin, and Pat Hanrahan, InfoVis 2010.
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def _coverage(dmin, dmax, lmin, lmax):
|
|
556
|
+
return 1 - 0.5 * ((dmax - lmax) ** 2 +
|
|
557
|
+
(dmin - lmin) ** 2) / (0.1 * (dmax - dmin)) ** 2
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
def _coverage_max(dmin, dmax, span):
|
|
561
|
+
range_ = dmax - dmin
|
|
562
|
+
if span <= range_:
|
|
563
|
+
return 1.
|
|
564
|
+
else:
|
|
565
|
+
half = (span - range_) / 2.0
|
|
566
|
+
return 1 - half ** 2 / (0.1 * range_) ** 2
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def _density(k, m, dmin, dmax, lmin, lmax):
|
|
570
|
+
r = (k-1.0) / (lmax-lmin)
|
|
571
|
+
rt = (m-1.0) / (max(lmax, dmax) - min(lmin, dmin))
|
|
572
|
+
return 2 - max(r / rt, rt / r)
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def _density_max(k, m):
|
|
576
|
+
return 2 - (k-1.0) / (m-1.0) if k >= m else 1.
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def _simplicity(q, Q, j, lmin, lmax, lstep):
|
|
580
|
+
eps = 1e-10
|
|
581
|
+
n = len(Q)
|
|
582
|
+
i = Q.index(q) + 1
|
|
583
|
+
if ((lmin % lstep) < eps or
|
|
584
|
+
(lstep - lmin % lstep) < eps) and lmin <= 0 and lmax >= 0:
|
|
585
|
+
v = 1
|
|
586
|
+
else:
|
|
587
|
+
v = 0
|
|
588
|
+
return (n - i) / (n - 1.0) + v - j
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def _simplicity_max(q, Q, j):
|
|
592
|
+
n = len(Q)
|
|
593
|
+
i = Q.index(q) + 1
|
|
594
|
+
return (n - i)/(n - 1.0) + 1. - j
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
def _get_ticks_talbot(dmin, dmax, n_inches, density=1.):
|
|
598
|
+
# density * size gives target number of intervals,
|
|
599
|
+
# density * size + 1 gives target number of tick marks,
|
|
600
|
+
# the density function converts this back to a density in data units
|
|
601
|
+
# (not inches)
|
|
602
|
+
n_inches = max(n_inches, 2.0) # Set minimum otherwise code can crash :(
|
|
603
|
+
|
|
604
|
+
if dmin == dmax:
|
|
605
|
+
return np.array([dmin, dmax])
|
|
606
|
+
|
|
607
|
+
m = density * n_inches + 1.0
|
|
608
|
+
only_inside = False # we cull values outside ourselves
|
|
609
|
+
Q = [1, 5, 2, 2.5, 4, 3]
|
|
610
|
+
w = [0.25, 0.2, 0.5, 0.05]
|
|
611
|
+
best_score = -2.0
|
|
612
|
+
best = None
|
|
613
|
+
|
|
614
|
+
j = 1.0
|
|
615
|
+
n_max = 1000
|
|
616
|
+
while j < n_max:
|
|
617
|
+
for q in Q:
|
|
618
|
+
sm = _simplicity_max(q, Q, j)
|
|
619
|
+
|
|
620
|
+
if w[0] * sm + w[1] + w[2] + w[3] < best_score:
|
|
621
|
+
j = n_max
|
|
622
|
+
break
|
|
623
|
+
|
|
624
|
+
k = 2.0
|
|
625
|
+
while k < n_max:
|
|
626
|
+
dm = _density_max(k, n_inches)
|
|
627
|
+
|
|
628
|
+
if w[0] * sm + w[1] + w[2] * dm + w[3] < best_score:
|
|
629
|
+
break
|
|
630
|
+
|
|
631
|
+
delta = (dmax-dmin)/(k+1.0)/j/q
|
|
632
|
+
z = np.ceil(np.log10(delta))
|
|
633
|
+
|
|
634
|
+
while z < float('infinity'):
|
|
635
|
+
step = j * q * 10 ** z
|
|
636
|
+
cm = _coverage_max(dmin, dmax, step*(k-1.0))
|
|
637
|
+
|
|
638
|
+
if (w[0] * sm +
|
|
639
|
+
w[1] * cm +
|
|
640
|
+
w[2] * dm +
|
|
641
|
+
w[3] < best_score):
|
|
642
|
+
break
|
|
643
|
+
|
|
644
|
+
min_start = np.floor(dmax/step)*j - (k-1.0)*j
|
|
645
|
+
max_start = np.ceil(dmin/step)*j
|
|
646
|
+
|
|
647
|
+
if min_start > max_start:
|
|
648
|
+
z = z+1
|
|
649
|
+
break
|
|
650
|
+
|
|
651
|
+
for start in range(int(min_start), int(max_start)+1):
|
|
652
|
+
lmin = start * (step/j)
|
|
653
|
+
lmax = lmin + step*(k-1.0)
|
|
654
|
+
lstep = step
|
|
655
|
+
|
|
656
|
+
s = _simplicity(q, Q, j, lmin, lmax, lstep)
|
|
657
|
+
c = _coverage(dmin, dmax, lmin, lmax)
|
|
658
|
+
d = _density(k, m, dmin, dmax, lmin, lmax)
|
|
659
|
+
leg = 1. # _legibility(lmin, lmax, lstep)
|
|
660
|
+
|
|
661
|
+
score = w[0] * s + w[1] * c + w[2] * d + w[3] * leg
|
|
662
|
+
|
|
663
|
+
if (score > best_score and
|
|
664
|
+
(not only_inside or (lmin >= dmin and
|
|
665
|
+
lmax <= dmax))):
|
|
666
|
+
best_score = score
|
|
667
|
+
best = (lmin, lmax, lstep, q, k)
|
|
668
|
+
z += 1
|
|
669
|
+
k += 1
|
|
670
|
+
if k == n_max:
|
|
671
|
+
raise RuntimeError('could not converge on ticks')
|
|
672
|
+
j += 1
|
|
673
|
+
if j == n_max:
|
|
674
|
+
raise RuntimeError('could not converge on ticks')
|
|
675
|
+
|
|
676
|
+
if best is None:
|
|
677
|
+
raise RuntimeError('could not converge on ticks')
|
|
678
|
+
return np.arange(best[4]) * best[2] + best[0]
|