vispy 0.14.0__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of vispy might be problematic. Click here for more details.
- vispy/__init__.py +33 -0
- vispy/app/__init__.py +15 -0
- vispy/app/_default_app.py +76 -0
- vispy/app/_detect_eventloop.py +148 -0
- vispy/app/application.py +263 -0
- vispy/app/backends/__init__.py +52 -0
- vispy/app/backends/_egl.py +264 -0
- vispy/app/backends/_glfw.py +513 -0
- vispy/app/backends/_jupyter_rfb.py +278 -0
- vispy/app/backends/_offscreen_util.py +121 -0
- vispy/app/backends/_osmesa.py +235 -0
- vispy/app/backends/_pyglet.py +451 -0
- vispy/app/backends/_pyqt4.py +36 -0
- vispy/app/backends/_pyqt5.py +36 -0
- vispy/app/backends/_pyqt6.py +40 -0
- vispy/app/backends/_pyside.py +37 -0
- vispy/app/backends/_pyside2.py +52 -0
- vispy/app/backends/_pyside6.py +53 -0
- vispy/app/backends/_qt.py +968 -0
- vispy/app/backends/_sdl2.py +444 -0
- vispy/app/backends/_template.py +244 -0
- vispy/app/backends/_test.py +8 -0
- vispy/app/backends/_tk.py +800 -0
- vispy/app/backends/_wx.py +476 -0
- vispy/app/backends/tests/__init__.py +0 -0
- vispy/app/backends/tests/test_offscreen_util.py +52 -0
- vispy/app/backends/tests/test_rfb.py +77 -0
- vispy/app/base.py +294 -0
- vispy/app/canvas.py +828 -0
- vispy/app/qt.py +92 -0
- vispy/app/tests/__init__.py +0 -0
- vispy/app/tests/qt-designer.ui +58 -0
- vispy/app/tests/test_app.py +442 -0
- vispy/app/tests/test_backends.py +164 -0
- vispy/app/tests/test_canvas.py +122 -0
- vispy/app/tests/test_context.py +92 -0
- vispy/app/tests/test_qt.py +47 -0
- vispy/app/tests/test_simultaneous.py +134 -0
- vispy/app/timer.py +174 -0
- vispy/color/__init__.py +17 -0
- vispy/color/_color_dict.py +193 -0
- vispy/color/color_array.py +447 -0
- vispy/color/color_space.py +181 -0
- vispy/color/colormap.py +1134 -0
- vispy/color/tests/__init__.py +0 -0
- vispy/color/tests/test_color.py +352 -0
- vispy/conftest.py +12 -0
- vispy/ext/__init__.py +0 -0
- vispy/ext/cocoapy.py +1542 -0
- vispy/ext/cubehelix.py +138 -0
- vispy/ext/egl.py +375 -0
- vispy/ext/fontconfig.py +118 -0
- vispy/ext/gdi32plus.py +206 -0
- vispy/ext/osmesa.py +105 -0
- vispy/geometry/__init__.py +23 -0
- vispy/geometry/_triangulation_debugger.py +171 -0
- vispy/geometry/calculations.py +134 -0
- vispy/geometry/curves.py +399 -0
- vispy/geometry/generation.py +643 -0
- vispy/geometry/isocurve.py +175 -0
- vispy/geometry/isosurface.py +465 -0
- vispy/geometry/meshdata.py +698 -0
- vispy/geometry/normals.py +78 -0
- vispy/geometry/parametric.py +56 -0
- vispy/geometry/polygon.py +137 -0
- vispy/geometry/rect.py +210 -0
- vispy/geometry/tests/__init__.py +0 -0
- vispy/geometry/tests/test_calculations.py +23 -0
- vispy/geometry/tests/test_generation.py +56 -0
- vispy/geometry/tests/test_meshdata.py +106 -0
- vispy/geometry/tests/test_triangulation.py +506 -0
- vispy/geometry/torusknot.py +142 -0
- vispy/geometry/triangulation.py +876 -0
- vispy/gloo/__init__.py +56 -0
- vispy/gloo/buffer.py +505 -0
- vispy/gloo/context.py +272 -0
- vispy/gloo/framebuffer.py +257 -0
- vispy/gloo/gl/__init__.py +234 -0
- vispy/gloo/gl/_constants.py +332 -0
- vispy/gloo/gl/_es2.py +986 -0
- vispy/gloo/gl/_gl2.py +1365 -0
- vispy/gloo/gl/_proxy.py +499 -0
- vispy/gloo/gl/_pyopengl2.py +362 -0
- vispy/gloo/gl/dummy.py +24 -0
- vispy/gloo/gl/es2.py +62 -0
- vispy/gloo/gl/gl2.py +98 -0
- vispy/gloo/gl/glplus.py +168 -0
- vispy/gloo/gl/pyopengl2.py +97 -0
- vispy/gloo/gl/tests/__init__.py +0 -0
- vispy/gloo/gl/tests/test_basics.py +282 -0
- vispy/gloo/gl/tests/test_functionality.py +566 -0
- vispy/gloo/gl/tests/test_names.py +246 -0
- vispy/gloo/gl/tests/test_use.py +71 -0
- vispy/gloo/glir.py +1816 -0
- vispy/gloo/globject.py +101 -0
- vispy/gloo/preprocessor.py +67 -0
- vispy/gloo/program.py +543 -0
- vispy/gloo/tests/__init__.py +0 -0
- vispy/gloo/tests/test_buffer.py +558 -0
- vispy/gloo/tests/test_context.py +119 -0
- vispy/gloo/tests/test_framebuffer.py +195 -0
- vispy/gloo/tests/test_glir.py +307 -0
- vispy/gloo/tests/test_globject.py +35 -0
- vispy/gloo/tests/test_program.py +302 -0
- vispy/gloo/tests/test_texture.py +732 -0
- vispy/gloo/tests/test_use_gloo.py +187 -0
- vispy/gloo/tests/test_util.py +60 -0
- vispy/gloo/tests/test_wrappers.py +261 -0
- vispy/gloo/texture.py +1045 -0
- vispy/gloo/util.py +129 -0
- vispy/gloo/wrappers.py +762 -0
- vispy/glsl/__init__.py +42 -0
- vispy/glsl/antialias/antialias.glsl +7 -0
- vispy/glsl/antialias/cap-butt.glsl +31 -0
- vispy/glsl/antialias/cap-round.glsl +29 -0
- vispy/glsl/antialias/cap-square.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
- vispy/glsl/antialias/cap.glsl +67 -0
- vispy/glsl/antialias/caps.glsl +67 -0
- vispy/glsl/antialias/filled.glsl +50 -0
- vispy/glsl/antialias/outline.glsl +40 -0
- vispy/glsl/antialias/stroke.glsl +43 -0
- vispy/glsl/arrowheads/angle.glsl +99 -0
- vispy/glsl/arrowheads/arrowheads.frag +60 -0
- vispy/glsl/arrowheads/arrowheads.glsl +12 -0
- vispy/glsl/arrowheads/arrowheads.vert +83 -0
- vispy/glsl/arrowheads/curved.glsl +48 -0
- vispy/glsl/arrowheads/inhibitor.glsl +26 -0
- vispy/glsl/arrowheads/stealth.glsl +46 -0
- vispy/glsl/arrowheads/triangle.glsl +97 -0
- vispy/glsl/arrowheads/util.glsl +13 -0
- vispy/glsl/arrows/angle-30.glsl +12 -0
- vispy/glsl/arrows/angle-60.glsl +12 -0
- vispy/glsl/arrows/angle-90.glsl +12 -0
- vispy/glsl/arrows/arrow.frag +39 -0
- vispy/glsl/arrows/arrow.vert +49 -0
- vispy/glsl/arrows/arrows.glsl +17 -0
- vispy/glsl/arrows/common.glsl +187 -0
- vispy/glsl/arrows/curved.glsl +63 -0
- vispy/glsl/arrows/stealth.glsl +50 -0
- vispy/glsl/arrows/triangle-30.glsl +12 -0
- vispy/glsl/arrows/triangle-60.glsl +12 -0
- vispy/glsl/arrows/triangle-90.glsl +12 -0
- vispy/glsl/arrows/util.glsl +98 -0
- vispy/glsl/build_spatial_filters.py +660 -0
- vispy/glsl/collections/agg-fast-path.frag +20 -0
- vispy/glsl/collections/agg-fast-path.vert +78 -0
- vispy/glsl/collections/agg-glyph.frag +60 -0
- vispy/glsl/collections/agg-glyph.vert +33 -0
- vispy/glsl/collections/agg-marker.frag +35 -0
- vispy/glsl/collections/agg-marker.vert +48 -0
- vispy/glsl/collections/agg-path.frag +55 -0
- vispy/glsl/collections/agg-path.vert +166 -0
- vispy/glsl/collections/agg-point.frag +21 -0
- vispy/glsl/collections/agg-point.vert +35 -0
- vispy/glsl/collections/agg-segment.frag +32 -0
- vispy/glsl/collections/agg-segment.vert +75 -0
- vispy/glsl/collections/marker.frag +38 -0
- vispy/glsl/collections/marker.vert +48 -0
- vispy/glsl/collections/raw-path.frag +15 -0
- vispy/glsl/collections/raw-path.vert +24 -0
- vispy/glsl/collections/raw-point.frag +14 -0
- vispy/glsl/collections/raw-point.vert +31 -0
- vispy/glsl/collections/raw-segment.frag +18 -0
- vispy/glsl/collections/raw-segment.vert +26 -0
- vispy/glsl/collections/raw-triangle.frag +13 -0
- vispy/glsl/collections/raw-triangle.vert +26 -0
- vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
- vispy/glsl/collections/sdf-glyph.frag +80 -0
- vispy/glsl/collections/sdf-glyph.vert +59 -0
- vispy/glsl/collections/tick-labels.vert +71 -0
- vispy/glsl/colormaps/autumn.glsl +20 -0
- vispy/glsl/colormaps/blues.glsl +20 -0
- vispy/glsl/colormaps/color-space.glsl +17 -0
- vispy/glsl/colormaps/colormaps.glsl +24 -0
- vispy/glsl/colormaps/cool.glsl +20 -0
- vispy/glsl/colormaps/fire.glsl +21 -0
- vispy/glsl/colormaps/gray.glsl +20 -0
- vispy/glsl/colormaps/greens.glsl +20 -0
- vispy/glsl/colormaps/hot.glsl +22 -0
- vispy/glsl/colormaps/ice.glsl +20 -0
- vispy/glsl/colormaps/icefire.glsl +23 -0
- vispy/glsl/colormaps/parse.py +40 -0
- vispy/glsl/colormaps/reds.glsl +20 -0
- vispy/glsl/colormaps/spring.glsl +20 -0
- vispy/glsl/colormaps/summer.glsl +20 -0
- vispy/glsl/colormaps/user.glsl +22 -0
- vispy/glsl/colormaps/util.glsl +41 -0
- vispy/glsl/colormaps/wheel.glsl +21 -0
- vispy/glsl/colormaps/winter.glsl +20 -0
- vispy/glsl/lines/agg.frag +320 -0
- vispy/glsl/lines/agg.vert +241 -0
- vispy/glsl/markers/arrow.glsl +12 -0
- vispy/glsl/markers/asterisk.glsl +16 -0
- vispy/glsl/markers/chevron.glsl +14 -0
- vispy/glsl/markers/clover.glsl +20 -0
- vispy/glsl/markers/club.glsl +31 -0
- vispy/glsl/markers/cross.glsl +17 -0
- vispy/glsl/markers/diamond.glsl +12 -0
- vispy/glsl/markers/disc.glsl +9 -0
- vispy/glsl/markers/ellipse.glsl +67 -0
- vispy/glsl/markers/hbar.glsl +9 -0
- vispy/glsl/markers/heart.glsl +15 -0
- vispy/glsl/markers/infinity.glsl +15 -0
- vispy/glsl/markers/marker-sdf.frag +74 -0
- vispy/glsl/markers/marker-sdf.vert +41 -0
- vispy/glsl/markers/marker.frag +36 -0
- vispy/glsl/markers/marker.vert +46 -0
- vispy/glsl/markers/markers.glsl +24 -0
- vispy/glsl/markers/pin.glsl +18 -0
- vispy/glsl/markers/ring.glsl +11 -0
- vispy/glsl/markers/spade.glsl +28 -0
- vispy/glsl/markers/square.glsl +10 -0
- vispy/glsl/markers/tag.glsl +11 -0
- vispy/glsl/markers/triangle.glsl +14 -0
- vispy/glsl/markers/vbar.glsl +9 -0
- vispy/glsl/math/circle-through-2-points.glsl +30 -0
- vispy/glsl/math/constants.glsl +48 -0
- vispy/glsl/math/double.glsl +114 -0
- vispy/glsl/math/functions.glsl +20 -0
- vispy/glsl/math/point-to-line-distance.glsl +31 -0
- vispy/glsl/math/point-to-line-projection.glsl +29 -0
- vispy/glsl/math/signed-line-distance.glsl +27 -0
- vispy/glsl/math/signed-segment-distance.glsl +30 -0
- vispy/glsl/misc/regular-grid.frag +244 -0
- vispy/glsl/misc/spatial-filters.frag +1407 -0
- vispy/glsl/misc/viewport-NDC.glsl +20 -0
- vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
- vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
- vispy/glsl/transforms/hammer.glsl +44 -0
- vispy/glsl/transforms/identity.glsl +6 -0
- vispy/glsl/transforms/identity_forward.glsl +23 -0
- vispy/glsl/transforms/identity_inverse.glsl +23 -0
- vispy/glsl/transforms/linear-scale.glsl +127 -0
- vispy/glsl/transforms/log-scale.glsl +126 -0
- vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
- vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
- vispy/glsl/transforms/panzoom.glsl +10 -0
- vispy/glsl/transforms/polar.glsl +41 -0
- vispy/glsl/transforms/position.glsl +44 -0
- vispy/glsl/transforms/power-scale.glsl +139 -0
- vispy/glsl/transforms/projection.glsl +7 -0
- vispy/glsl/transforms/pvm.glsl +13 -0
- vispy/glsl/transforms/rotate.glsl +45 -0
- vispy/glsl/transforms/trackball.glsl +15 -0
- vispy/glsl/transforms/translate.glsl +35 -0
- vispy/glsl/transforms/transverse_mercator.glsl +38 -0
- vispy/glsl/transforms/viewport-clipping.glsl +14 -0
- vispy/glsl/transforms/viewport-transform.glsl +16 -0
- vispy/glsl/transforms/viewport.glsl +50 -0
- vispy/glsl/transforms/x.glsl +24 -0
- vispy/glsl/transforms/y.glsl +19 -0
- vispy/glsl/transforms/z.glsl +14 -0
- vispy/io/__init__.py +20 -0
- vispy/io/_data/spatial-filters.npy +0 -0
- vispy/io/datasets.py +94 -0
- vispy/io/image.py +231 -0
- vispy/io/mesh.py +122 -0
- vispy/io/stl.py +167 -0
- vispy/io/tests/__init__.py +0 -0
- vispy/io/tests/test_image.py +47 -0
- vispy/io/tests/test_io.py +121 -0
- vispy/io/wavefront.py +350 -0
- vispy/plot/__init__.py +36 -0
- vispy/plot/fig.py +58 -0
- vispy/plot/plotwidget.py +522 -0
- vispy/plot/tests/__init__.py +0 -0
- vispy/plot/tests/test_plot.py +46 -0
- vispy/scene/__init__.py +43 -0
- vispy/scene/cameras/__init__.py +27 -0
- vispy/scene/cameras/_base.py +38 -0
- vispy/scene/cameras/arcball.py +106 -0
- vispy/scene/cameras/base_camera.py +538 -0
- vispy/scene/cameras/fly.py +474 -0
- vispy/scene/cameras/magnify.py +163 -0
- vispy/scene/cameras/panzoom.py +308 -0
- vispy/scene/cameras/perspective.py +333 -0
- vispy/scene/cameras/tests/__init__.py +0 -0
- vispy/scene/cameras/tests/test_cameras.py +27 -0
- vispy/scene/cameras/tests/test_link.py +53 -0
- vispy/scene/cameras/tests/test_perspective.py +122 -0
- vispy/scene/cameras/turntable.py +173 -0
- vispy/scene/canvas.py +639 -0
- vispy/scene/events.py +85 -0
- vispy/scene/node.py +644 -0
- vispy/scene/subscene.py +20 -0
- vispy/scene/tests/__init__.py +0 -0
- vispy/scene/tests/test_canvas.py +119 -0
- vispy/scene/tests/test_node.py +142 -0
- vispy/scene/tests/test_visuals.py +141 -0
- vispy/scene/visuals.py +276 -0
- vispy/scene/widgets/__init__.py +18 -0
- vispy/scene/widgets/anchor.py +25 -0
- vispy/scene/widgets/axis.py +88 -0
- vispy/scene/widgets/colorbar.py +176 -0
- vispy/scene/widgets/console.py +351 -0
- vispy/scene/widgets/grid.py +509 -0
- vispy/scene/widgets/label.py +50 -0
- vispy/scene/widgets/tests/__init__.py +0 -0
- vispy/scene/widgets/tests/test_colorbar.py +47 -0
- vispy/scene/widgets/viewbox.py +199 -0
- vispy/scene/widgets/widget.py +478 -0
- vispy/testing/__init__.py +51 -0
- vispy/testing/_runners.py +446 -0
- vispy/testing/_testing.py +416 -0
- vispy/testing/image_tester.py +473 -0
- vispy/testing/rendered_array_tester.py +85 -0
- vispy/testing/tests/__init__.py +0 -0
- vispy/testing/tests/test_testing.py +20 -0
- vispy/util/__init__.py +17 -0
- vispy/util/bunch.py +15 -0
- vispy/util/check_environment.py +57 -0
- vispy/util/config.py +490 -0
- vispy/util/dpi/__init__.py +19 -0
- vispy/util/dpi/_linux.py +69 -0
- vispy/util/dpi/_quartz.py +26 -0
- vispy/util/dpi/_win32.py +34 -0
- vispy/util/dpi/tests/__init__.py +0 -0
- vispy/util/dpi/tests/test_dpi.py +16 -0
- vispy/util/eq.py +41 -0
- vispy/util/event.py +774 -0
- vispy/util/fetching.py +276 -0
- vispy/util/filter.py +44 -0
- vispy/util/fonts/__init__.py +14 -0
- vispy/util/fonts/_freetype.py +73 -0
- vispy/util/fonts/_quartz.py +192 -0
- vispy/util/fonts/_triage.py +36 -0
- vispy/util/fonts/_vispy_fonts.py +20 -0
- vispy/util/fonts/_win32.py +105 -0
- vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
- vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
- vispy/util/fonts/tests/__init__.py +0 -0
- vispy/util/fonts/tests/test_font.py +45 -0
- vispy/util/fourier.py +69 -0
- vispy/util/frozen.py +25 -0
- vispy/util/gallery_scraper.py +268 -0
- vispy/util/keys.py +91 -0
- vispy/util/logs.py +358 -0
- vispy/util/osmesa_gl.py +17 -0
- vispy/util/profiler.py +135 -0
- vispy/util/ptime.py +16 -0
- vispy/util/quaternion.py +229 -0
- vispy/util/svg/__init__.py +18 -0
- vispy/util/svg/base.py +20 -0
- vispy/util/svg/color.py +219 -0
- vispy/util/svg/element.py +51 -0
- vispy/util/svg/geometry.py +478 -0
- vispy/util/svg/group.py +66 -0
- vispy/util/svg/length.py +81 -0
- vispy/util/svg/number.py +25 -0
- vispy/util/svg/path.py +332 -0
- vispy/util/svg/shapes.py +57 -0
- vispy/util/svg/style.py +59 -0
- vispy/util/svg/svg.py +40 -0
- vispy/util/svg/transform.py +223 -0
- vispy/util/svg/transformable.py +28 -0
- vispy/util/svg/viewport.py +73 -0
- vispy/util/tests/__init__.py +0 -0
- vispy/util/tests/test_config.py +58 -0
- vispy/util/tests/test_docstring_parameters.py +123 -0
- vispy/util/tests/test_emitter_group.py +262 -0
- vispy/util/tests/test_event_emitter.py +743 -0
- vispy/util/tests/test_fourier.py +35 -0
- vispy/util/tests/test_gallery_scraper.py +112 -0
- vispy/util/tests/test_import.py +127 -0
- vispy/util/tests/test_key.py +22 -0
- vispy/util/tests/test_logging.py +45 -0
- vispy/util/tests/test_run.py +14 -0
- vispy/util/tests/test_transforms.py +42 -0
- vispy/util/tests/test_vispy.py +48 -0
- vispy/util/transforms.py +201 -0
- vispy/util/wrappers.py +155 -0
- vispy/version.py +4 -0
- vispy/visuals/__init__.py +50 -0
- vispy/visuals/_scalable_textures.py +485 -0
- vispy/visuals/axis.py +678 -0
- vispy/visuals/border.py +208 -0
- vispy/visuals/box.py +79 -0
- vispy/visuals/collections/__init__.py +30 -0
- vispy/visuals/collections/agg_fast_path_collection.py +219 -0
- vispy/visuals/collections/agg_path_collection.py +197 -0
- vispy/visuals/collections/agg_point_collection.py +52 -0
- vispy/visuals/collections/agg_segment_collection.py +142 -0
- vispy/visuals/collections/array_list.py +401 -0
- vispy/visuals/collections/base_collection.py +482 -0
- vispy/visuals/collections/collection.py +253 -0
- vispy/visuals/collections/path_collection.py +23 -0
- vispy/visuals/collections/point_collection.py +19 -0
- vispy/visuals/collections/polygon_collection.py +25 -0
- vispy/visuals/collections/raw_path_collection.py +119 -0
- vispy/visuals/collections/raw_point_collection.py +113 -0
- vispy/visuals/collections/raw_polygon_collection.py +77 -0
- vispy/visuals/collections/raw_segment_collection.py +112 -0
- vispy/visuals/collections/raw_triangle_collection.py +78 -0
- vispy/visuals/collections/segment_collection.py +19 -0
- vispy/visuals/collections/triangle_collection.py +16 -0
- vispy/visuals/collections/util.py +168 -0
- vispy/visuals/colorbar.py +699 -0
- vispy/visuals/cube.py +41 -0
- vispy/visuals/ellipse.py +163 -0
- vispy/visuals/filters/__init__.py +10 -0
- vispy/visuals/filters/base_filter.py +242 -0
- vispy/visuals/filters/clipper.py +60 -0
- vispy/visuals/filters/clipping_planes.py +122 -0
- vispy/visuals/filters/color.py +181 -0
- vispy/visuals/filters/markers.py +28 -0
- vispy/visuals/filters/mesh.py +796 -0
- vispy/visuals/filters/picking.py +60 -0
- vispy/visuals/filters/tests/__init__.py +3 -0
- vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
- vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
- vispy/visuals/glsl/__init__.py +1 -0
- vispy/visuals/glsl/antialiasing.py +133 -0
- vispy/visuals/glsl/color.py +63 -0
- vispy/visuals/graphs/__init__.py +1 -0
- vispy/visuals/graphs/graph.py +240 -0
- vispy/visuals/graphs/layouts/__init__.py +55 -0
- vispy/visuals/graphs/layouts/circular.py +49 -0
- vispy/visuals/graphs/layouts/force_directed.py +211 -0
- vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
- vispy/visuals/graphs/layouts/random.py +52 -0
- vispy/visuals/graphs/tests/__init__.py +1 -0
- vispy/visuals/graphs/tests/test_layouts.py +139 -0
- vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
- vispy/visuals/graphs/util.py +120 -0
- vispy/visuals/gridlines.py +105 -0
- vispy/visuals/gridmesh.py +98 -0
- vispy/visuals/histogram.py +58 -0
- vispy/visuals/image.py +688 -0
- vispy/visuals/image_complex.py +130 -0
- vispy/visuals/infinite_line.py +199 -0
- vispy/visuals/instanced_mesh.py +152 -0
- vispy/visuals/isocurve.py +213 -0
- vispy/visuals/isoline.py +241 -0
- vispy/visuals/isosurface.py +113 -0
- vispy/visuals/line/__init__.py +6 -0
- vispy/visuals/line/arrow.py +289 -0
- vispy/visuals/line/dash_atlas.py +90 -0
- vispy/visuals/line/line.py +545 -0
- vispy/visuals/line_plot.py +135 -0
- vispy/visuals/linear_region.py +199 -0
- vispy/visuals/markers.py +810 -0
- vispy/visuals/mesh.py +373 -0
- vispy/visuals/mesh_normals.py +159 -0
- vispy/visuals/plane.py +54 -0
- vispy/visuals/polygon.py +145 -0
- vispy/visuals/rectangle.py +196 -0
- vispy/visuals/regular_polygon.py +56 -0
- vispy/visuals/scrolling_lines.py +197 -0
- vispy/visuals/shaders/__init__.py +17 -0
- vispy/visuals/shaders/compiler.py +206 -0
- vispy/visuals/shaders/expression.py +99 -0
- vispy/visuals/shaders/function.py +788 -0
- vispy/visuals/shaders/multiprogram.py +145 -0
- vispy/visuals/shaders/parsing.py +140 -0
- vispy/visuals/shaders/program.py +161 -0
- vispy/visuals/shaders/shader_object.py +162 -0
- vispy/visuals/shaders/tests/__init__.py +0 -0
- vispy/visuals/shaders/tests/test_function.py +486 -0
- vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
- vispy/visuals/shaders/tests/test_parsing.py +57 -0
- vispy/visuals/shaders/variable.py +272 -0
- vispy/visuals/spectrogram.py +169 -0
- vispy/visuals/sphere.py +80 -0
- vispy/visuals/surface_plot.py +192 -0
- vispy/visuals/tests/__init__.py +0 -0
- vispy/visuals/tests/test_arrows.py +109 -0
- vispy/visuals/tests/test_axis.py +120 -0
- vispy/visuals/tests/test_collections.py +15 -0
- vispy/visuals/tests/test_colorbar.py +179 -0
- vispy/visuals/tests/test_colormap.py +97 -0
- vispy/visuals/tests/test_ellipse.py +122 -0
- vispy/visuals/tests/test_histogram.py +24 -0
- vispy/visuals/tests/test_image.py +390 -0
- vispy/visuals/tests/test_image_complex.py +36 -0
- vispy/visuals/tests/test_infinite_line.py +53 -0
- vispy/visuals/tests/test_instanced_mesh.py +50 -0
- vispy/visuals/tests/test_isosurface.py +22 -0
- vispy/visuals/tests/test_linear_region.py +152 -0
- vispy/visuals/tests/test_markers.py +54 -0
- vispy/visuals/tests/test_mesh.py +261 -0
- vispy/visuals/tests/test_mesh_normals.py +218 -0
- vispy/visuals/tests/test_polygon.py +112 -0
- vispy/visuals/tests/test_rectangle.py +163 -0
- vispy/visuals/tests/test_regular_polygon.py +111 -0
- vispy/visuals/tests/test_scalable_textures.py +180 -0
- vispy/visuals/tests/test_sdf.py +73 -0
- vispy/visuals/tests/test_spectrogram.py +42 -0
- vispy/visuals/tests/test_text.py +95 -0
- vispy/visuals/tests/test_volume.py +542 -0
- vispy/visuals/tests/test_windbarb.py +33 -0
- vispy/visuals/text/__init__.py +7 -0
- vispy/visuals/text/_sdf_cpu.cpython-312-aarch64-linux-gnu.so +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +110 -0
- vispy/visuals/text/_sdf_gpu.py +316 -0
- vispy/visuals/text/text.py +675 -0
- vispy/visuals/transforms/__init__.py +34 -0
- vispy/visuals/transforms/_util.py +191 -0
- vispy/visuals/transforms/base_transform.py +233 -0
- vispy/visuals/transforms/chain.py +300 -0
- vispy/visuals/transforms/interactive.py +98 -0
- vispy/visuals/transforms/linear.py +564 -0
- vispy/visuals/transforms/nonlinear.py +398 -0
- vispy/visuals/transforms/tests/__init__.py +0 -0
- vispy/visuals/transforms/tests/test_transforms.py +243 -0
- vispy/visuals/transforms/transform_system.py +339 -0
- vispy/visuals/tube.py +173 -0
- vispy/visuals/visual.py +923 -0
- vispy/visuals/volume.py +1335 -0
- vispy/visuals/windbarb.py +291 -0
- vispy/visuals/xyz_axis.py +34 -0
- vispy-0.14.0.dist-info/LICENSE.txt +36 -0
- vispy-0.14.0.dist-info/METADATA +218 -0
- vispy-0.14.0.dist-info/RECORD +519 -0
- vispy-0.14.0.dist-info/WHEEL +6 -0
- vispy-0.14.0.dist-info/top_level.txt +1 -0
vispy/util/fetching.py
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
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
|
+
"""Data downloading and reading functions"""
|
|
6
|
+
|
|
7
|
+
from math import log
|
|
8
|
+
import os
|
|
9
|
+
from os import path as op
|
|
10
|
+
import sys
|
|
11
|
+
import shutil
|
|
12
|
+
import time
|
|
13
|
+
|
|
14
|
+
import urllib.request
|
|
15
|
+
|
|
16
|
+
from ..util.config import config
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
###############################################################################
|
|
20
|
+
# Vispy data directory
|
|
21
|
+
|
|
22
|
+
def load_data_file(fname, directory=None, force_download=False):
|
|
23
|
+
"""Get a standard vispy demo data file
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
fname : str
|
|
28
|
+
The filename on the remote ``demo-data`` repository to download,
|
|
29
|
+
e.g. ``'molecular_viewer/micelle.npy'``. These correspond to paths
|
|
30
|
+
on ``https://github.com/vispy/demo-data/``.
|
|
31
|
+
directory : str | None
|
|
32
|
+
Directory to use to save the file. By default, the vispy
|
|
33
|
+
configuration directory is used.
|
|
34
|
+
force_download : bool | str
|
|
35
|
+
If True, the file will be downloaded even if a local copy exists
|
|
36
|
+
(and this copy will be overwritten). Can also be a YYYY-MM-DD date
|
|
37
|
+
to ensure a file is up-to-date (modified date of a file on disk,
|
|
38
|
+
if present, is checked).
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
fname : str
|
|
43
|
+
The path to the file on the local system.
|
|
44
|
+
"""
|
|
45
|
+
_url_root = 'https://raw.githubusercontent.com/vispy/demo-data/main/'
|
|
46
|
+
url = _url_root + fname
|
|
47
|
+
if directory is None:
|
|
48
|
+
directory = config['data_path']
|
|
49
|
+
if directory is None:
|
|
50
|
+
raise ValueError('config["data_path"] is not defined, '
|
|
51
|
+
'so directory must be supplied')
|
|
52
|
+
|
|
53
|
+
fname = op.join(directory, op.normcase(fname)) # convert to native
|
|
54
|
+
if op.isfile(fname):
|
|
55
|
+
if not force_download: # we're done
|
|
56
|
+
return fname
|
|
57
|
+
if isinstance(force_download, str):
|
|
58
|
+
ntime = time.strptime(force_download, '%Y-%m-%d')
|
|
59
|
+
ftime = time.gmtime(op.getctime(fname))
|
|
60
|
+
if ftime >= ntime:
|
|
61
|
+
return fname
|
|
62
|
+
else:
|
|
63
|
+
print('File older than %s, updating...' % force_download)
|
|
64
|
+
if not op.isdir(op.dirname(fname)):
|
|
65
|
+
os.makedirs(op.abspath(op.dirname(fname)))
|
|
66
|
+
# let's go get the file
|
|
67
|
+
_fetch_file(url, fname)
|
|
68
|
+
return fname
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
###############################################################################
|
|
72
|
+
# File downloading (most adapted from mne-python)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ProgressBar(object):
|
|
76
|
+
"""Class for generating a command-line progressbar
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
max_value : int
|
|
81
|
+
Maximum value of process (e.g. number of samples to process, bytes to
|
|
82
|
+
download, etc.).
|
|
83
|
+
initial_value : int
|
|
84
|
+
Initial value of process, useful when resuming process from a specific
|
|
85
|
+
value, defaults to 0.
|
|
86
|
+
mesg : str
|
|
87
|
+
Message to include at end of progress bar.
|
|
88
|
+
max_chars : int
|
|
89
|
+
Number of characters to use for progress bar (be sure to save some room
|
|
90
|
+
for the message and % complete as well).
|
|
91
|
+
progress_character : char
|
|
92
|
+
Character in the progress bar that indicates the portion completed.
|
|
93
|
+
spinner : bool
|
|
94
|
+
Show a spinner. Useful for long-running processes that may not
|
|
95
|
+
increment the progress bar very often. This provides the user with
|
|
96
|
+
feedback that the progress has not stalled.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
spinner_symbols = ['|', '/', '-', '\\']
|
|
100
|
+
template = '\r[{0}{1}] {2:.05f} {3} {4} '
|
|
101
|
+
|
|
102
|
+
def __init__(self, max_value, initial_value=0, mesg='', max_chars=40,
|
|
103
|
+
progress_character='.', spinner=False):
|
|
104
|
+
self.cur_value = initial_value
|
|
105
|
+
self.max_value = float(max_value)
|
|
106
|
+
self.mesg = mesg
|
|
107
|
+
self.max_chars = max_chars
|
|
108
|
+
self.progress_character = progress_character
|
|
109
|
+
self.spinner = spinner
|
|
110
|
+
self.spinner_index = 0
|
|
111
|
+
self.n_spinner = len(self.spinner_symbols)
|
|
112
|
+
|
|
113
|
+
def update(self, cur_value, mesg=None):
|
|
114
|
+
"""Update progressbar with current value of process
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
cur_value : number
|
|
119
|
+
Current value of process. Should be <= max_value (but this is not
|
|
120
|
+
enforced). The percent of the progressbar will be computed as
|
|
121
|
+
(cur_value / max_value) * 100
|
|
122
|
+
mesg : str
|
|
123
|
+
Message to display to the right of the progressbar. If None, the
|
|
124
|
+
last message provided will be used. To clear the current message,
|
|
125
|
+
pass a null string, ''.
|
|
126
|
+
"""
|
|
127
|
+
# Ensure floating-point division so we can get fractions of a percent
|
|
128
|
+
# for the progressbar.
|
|
129
|
+
self.cur_value = cur_value
|
|
130
|
+
progress = float(self.cur_value) / self.max_value
|
|
131
|
+
num_chars = int(progress * self.max_chars)
|
|
132
|
+
num_left = self.max_chars - num_chars
|
|
133
|
+
|
|
134
|
+
# Update the message
|
|
135
|
+
if mesg is not None:
|
|
136
|
+
self.mesg = mesg
|
|
137
|
+
|
|
138
|
+
# The \r tells the cursor to return to the beginning of the line rather
|
|
139
|
+
# than starting a new line. This allows us to have a progressbar-style
|
|
140
|
+
# display in the console window.
|
|
141
|
+
bar = self.template.format(self.progress_character * num_chars,
|
|
142
|
+
' ' * num_left,
|
|
143
|
+
progress * 100,
|
|
144
|
+
self.spinner_symbols[self.spinner_index],
|
|
145
|
+
self.mesg)
|
|
146
|
+
sys.stdout.write(bar)
|
|
147
|
+
# Increament the spinner
|
|
148
|
+
if self.spinner:
|
|
149
|
+
self.spinner_index = (self.spinner_index + 1) % self.n_spinner
|
|
150
|
+
|
|
151
|
+
# Force a flush because sometimes when using bash scripts and pipes,
|
|
152
|
+
# the output is not printed until after the program exits.
|
|
153
|
+
sys.stdout.flush()
|
|
154
|
+
|
|
155
|
+
def update_with_increment_value(self, increment_value, mesg=None):
|
|
156
|
+
"""Update progressbar with the value of the increment instead of the
|
|
157
|
+
current value of process as in update()
|
|
158
|
+
|
|
159
|
+
Parameters
|
|
160
|
+
----------
|
|
161
|
+
increment_value : int
|
|
162
|
+
Value of the increment of process. The percent of the progressbar
|
|
163
|
+
will be computed as
|
|
164
|
+
(self.cur_value + increment_value / max_value) * 100
|
|
165
|
+
mesg : str
|
|
166
|
+
Message to display to the right of the progressbar. If None, the
|
|
167
|
+
last message provided will be used. To clear the current message,
|
|
168
|
+
pass a null string, ''.
|
|
169
|
+
"""
|
|
170
|
+
self.cur_value += increment_value
|
|
171
|
+
self.update(self.cur_value, mesg)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _chunk_read(response, local_file, chunk_size=65536, initial_size=0):
|
|
175
|
+
"""Download a file chunk by chunk and show advancement
|
|
176
|
+
|
|
177
|
+
Can also be used when resuming downloads over http.
|
|
178
|
+
|
|
179
|
+
Parameters
|
|
180
|
+
----------
|
|
181
|
+
response: urllib.response.addinfourl
|
|
182
|
+
Response to the download request in order to get file size.
|
|
183
|
+
local_file: file
|
|
184
|
+
Hard disk file where data should be written.
|
|
185
|
+
chunk_size: integer, optional
|
|
186
|
+
Size of downloaded chunks. Default: 8192
|
|
187
|
+
initial_size: int, optional
|
|
188
|
+
If resuming, indicate the initial size of the file.
|
|
189
|
+
"""
|
|
190
|
+
# Adapted from NISL:
|
|
191
|
+
# https://github.com/nisl/tutorial/blob/master/nisl/datasets.py
|
|
192
|
+
|
|
193
|
+
bytes_so_far = initial_size
|
|
194
|
+
# Returns only amount left to download when resuming, not the size of the
|
|
195
|
+
# entire file
|
|
196
|
+
total_size = int(response.headers['Content-Length'].strip())
|
|
197
|
+
total_size += initial_size
|
|
198
|
+
|
|
199
|
+
progress = ProgressBar(total_size, initial_value=bytes_so_far,
|
|
200
|
+
max_chars=40, spinner=True, mesg='downloading')
|
|
201
|
+
while True:
|
|
202
|
+
chunk = response.read(chunk_size)
|
|
203
|
+
bytes_so_far += len(chunk)
|
|
204
|
+
if not chunk:
|
|
205
|
+
sys.stderr.write('\n')
|
|
206
|
+
break
|
|
207
|
+
_chunk_write(chunk, local_file, progress)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _chunk_write(chunk, local_file, progress):
|
|
211
|
+
"""Write a chunk to file and update the progress bar"""
|
|
212
|
+
local_file.write(chunk)
|
|
213
|
+
progress.update_with_increment_value(len(chunk))
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _fetch_file(url, file_name, print_destination=True):
|
|
217
|
+
"""Load requested file, downloading it if needed or requested
|
|
218
|
+
|
|
219
|
+
Parameters
|
|
220
|
+
----------
|
|
221
|
+
url: string
|
|
222
|
+
The url of file to be downloaded.
|
|
223
|
+
file_name: string
|
|
224
|
+
Name, along with the path, of where downloaded file will be saved.
|
|
225
|
+
print_destination: bool, optional
|
|
226
|
+
If true, destination of where file was saved will be printed after
|
|
227
|
+
download finishes.
|
|
228
|
+
"""
|
|
229
|
+
# Adapted from NISL:
|
|
230
|
+
# https://github.com/nisl/tutorial/blob/master/nisl/datasets.py
|
|
231
|
+
|
|
232
|
+
temp_file_name = file_name + ".part"
|
|
233
|
+
local_file = None
|
|
234
|
+
initial_size = 0
|
|
235
|
+
# Checking file size and displaying it alongside the download url
|
|
236
|
+
n_try = 3
|
|
237
|
+
for ii in range(n_try):
|
|
238
|
+
try:
|
|
239
|
+
data = urllib.request.urlopen(url, timeout=15.)
|
|
240
|
+
except Exception as e:
|
|
241
|
+
if ii == n_try - 1:
|
|
242
|
+
raise RuntimeError('Error while fetching file %s.\n'
|
|
243
|
+
'Dataset fetching aborted (%s)' % (url, e))
|
|
244
|
+
try:
|
|
245
|
+
file_size = int(data.headers['Content-Length'].strip())
|
|
246
|
+
print('Downloading data from %s (%s)' % (url, sizeof_fmt(file_size)))
|
|
247
|
+
local_file = open(temp_file_name, "wb")
|
|
248
|
+
_chunk_read(data, local_file, initial_size=initial_size)
|
|
249
|
+
# temp file must be closed prior to the move
|
|
250
|
+
if not local_file.closed:
|
|
251
|
+
local_file.close()
|
|
252
|
+
shutil.move(temp_file_name, file_name)
|
|
253
|
+
if print_destination is True:
|
|
254
|
+
sys.stdout.write('File saved as %s.\n' % file_name)
|
|
255
|
+
except Exception as e:
|
|
256
|
+
raise RuntimeError('Error while fetching file %s.\n'
|
|
257
|
+
'Dataset fetching aborted (%s)' % (url, e))
|
|
258
|
+
finally:
|
|
259
|
+
if local_file is not None:
|
|
260
|
+
if not local_file.closed:
|
|
261
|
+
local_file.close()
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def sizeof_fmt(num):
|
|
265
|
+
"""Turn number of bytes into human-readable str"""
|
|
266
|
+
units = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB']
|
|
267
|
+
decimals = [0, 0, 1, 2, 2, 2]
|
|
268
|
+
"""Human friendly file size"""
|
|
269
|
+
if num > 1:
|
|
270
|
+
exponent = min(int(log(num, 1024)), len(units) - 1)
|
|
271
|
+
quotient = float(num) / 1024 ** exponent
|
|
272
|
+
unit = units[exponent]
|
|
273
|
+
num_decimals = decimals[exponent]
|
|
274
|
+
format_string = '{0:.%sf} {1}' % (num_decimals)
|
|
275
|
+
return format_string.format(quotient, unit)
|
|
276
|
+
return '0 bytes' if num == 0 else '1 byte'
|
vispy/util/filter.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
3
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def gaussian_filter(data, sigma):
|
|
9
|
+
"""
|
|
10
|
+
Drop-in replacement for scipy.ndimage.gaussian_filter.
|
|
11
|
+
|
|
12
|
+
(note: results are only approximately equal to the output of
|
|
13
|
+
gaussian_filter)
|
|
14
|
+
"""
|
|
15
|
+
if np.isscalar(sigma):
|
|
16
|
+
sigma = (sigma,) * data.ndim
|
|
17
|
+
|
|
18
|
+
baseline = data.mean()
|
|
19
|
+
filtered = data - baseline
|
|
20
|
+
for ax in range(data.ndim):
|
|
21
|
+
s = float(sigma[ax])
|
|
22
|
+
if s == 0:
|
|
23
|
+
continue
|
|
24
|
+
|
|
25
|
+
# generate 1D gaussian kernel
|
|
26
|
+
ksize = int(s * 6)
|
|
27
|
+
x = np.arange(-ksize, ksize)
|
|
28
|
+
kernel = np.exp(-x**2 / (2*s**2))
|
|
29
|
+
kshape = [1, ] * data.ndim
|
|
30
|
+
kshape[ax] = len(kernel)
|
|
31
|
+
kernel = kernel.reshape(kshape)
|
|
32
|
+
|
|
33
|
+
# convolve as product of FFTs
|
|
34
|
+
shape = data.shape[ax] + ksize
|
|
35
|
+
scale = 1.0 / (abs(s) * (2*np.pi)**0.5)
|
|
36
|
+
filtered = scale * np.fft.irfft(np.fft.rfft(filtered, shape, axis=ax) *
|
|
37
|
+
np.fft.rfft(kernel, shape, axis=ax),
|
|
38
|
+
axis=ax)
|
|
39
|
+
|
|
40
|
+
# clip off extra data
|
|
41
|
+
sl = [slice(None)] * data.ndim
|
|
42
|
+
sl[ax] = slice(filtered.shape[ax]-data.shape[ax], None, None)
|
|
43
|
+
filtered = filtered[tuple(sl)]
|
|
44
|
+
return filtered + baseline
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
The fonts module implements some helpful functions for dealing with system
|
|
8
|
+
fonts.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__all__ = ['list_fonts']
|
|
12
|
+
|
|
13
|
+
from ._triage import _load_glyph, list_fonts # noqa, analysis:ignore
|
|
14
|
+
from ._vispy_fonts import _vispy_fonts # noqa, analysis:ignore
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
# Use freetype to get glyph bitmaps
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Convert face to filename
|
|
14
|
+
from ._vispy_fonts import _vispy_fonts, _get_vispy_font_filename
|
|
15
|
+
if sys.platform.startswith('linux'):
|
|
16
|
+
from ...ext.fontconfig import find_font
|
|
17
|
+
elif sys.platform.startswith('win'):
|
|
18
|
+
from ._win32 import find_font # noqa, analysis:ignore
|
|
19
|
+
else:
|
|
20
|
+
raise NotImplementedError
|
|
21
|
+
|
|
22
|
+
_font_dict = {}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Nest freetype imports in case someone doesn't have freetype on their system
|
|
26
|
+
# and isn't using fonts (Windows)
|
|
27
|
+
|
|
28
|
+
def _load_font(face, bold, italic):
|
|
29
|
+
from freetype import Face, FT_FACE_FLAG_SCALABLE
|
|
30
|
+
key = '%s-%s-%s' % (face, bold, italic)
|
|
31
|
+
if key in _font_dict:
|
|
32
|
+
return _font_dict[key]
|
|
33
|
+
if face in _vispy_fonts:
|
|
34
|
+
fname = _get_vispy_font_filename(face, bold, italic)
|
|
35
|
+
else:
|
|
36
|
+
fname = find_font(face, bold, italic)
|
|
37
|
+
font = Face(fname)
|
|
38
|
+
if (FT_FACE_FLAG_SCALABLE & font.face_flags) == 0:
|
|
39
|
+
raise RuntimeError('Font %s is not scalable, so cannot be loaded'
|
|
40
|
+
% face)
|
|
41
|
+
_font_dict[key] = font
|
|
42
|
+
return font
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _load_glyph(f, char, glyphs_dict):
|
|
46
|
+
"""Load glyph from font into dict"""
|
|
47
|
+
from freetype import (FT_LOAD_RENDER, FT_LOAD_NO_HINTING,
|
|
48
|
+
FT_LOAD_NO_AUTOHINT)
|
|
49
|
+
flags = FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT
|
|
50
|
+
face = _load_font(f['face'], f['bold'], f['italic'])
|
|
51
|
+
face.set_char_size(f['size'] * 64)
|
|
52
|
+
# get the character of interest
|
|
53
|
+
face.load_char(char, flags)
|
|
54
|
+
bitmap = face.glyph.bitmap
|
|
55
|
+
width = face.glyph.bitmap.width
|
|
56
|
+
height = face.glyph.bitmap.rows
|
|
57
|
+
bitmap = np.array(bitmap.buffer)
|
|
58
|
+
w0 = bitmap.size // height if bitmap.size > 0 else 0
|
|
59
|
+
bitmap.shape = (height, w0)
|
|
60
|
+
bitmap = bitmap[:, :width].astype(np.ubyte)
|
|
61
|
+
|
|
62
|
+
left = face.glyph.bitmap_left
|
|
63
|
+
top = face.glyph.bitmap_top
|
|
64
|
+
advance = face.glyph.advance.x / 64.
|
|
65
|
+
glyph = dict(char=char, offset=(left, top), bitmap=bitmap,
|
|
66
|
+
advance=advance, kerning={})
|
|
67
|
+
glyphs_dict[char] = glyph
|
|
68
|
+
# Generate kerning
|
|
69
|
+
for other_char, other_glyph in glyphs_dict.items():
|
|
70
|
+
kerning = face.get_kerning(other_char, char)
|
|
71
|
+
glyph['kerning'][other_char] = kerning.x / 64.
|
|
72
|
+
kerning = face.get_kerning(char, other_char)
|
|
73
|
+
other_glyph['kerning'][char] = kerning.x / 64.
|
|
@@ -0,0 +1,192 @@
|
|
|
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
|
+
# Use OSX cocoa/quartz to get glyph bitmaps
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from ctypes import byref, c_int32, c_byte
|
|
11
|
+
|
|
12
|
+
from ...ext.cocoapy import cf, ct, quartz, CFRange, CFSTR, CGGlyph, UniChar, \
|
|
13
|
+
kCTFontFamilyNameAttribute, kCTFontBoldTrait, kCTFontItalicTrait, \
|
|
14
|
+
kCTFontSymbolicTrait, kCTFontTraitsAttribute, kCTFontAttributeName, \
|
|
15
|
+
kCGImageAlphaPremultipliedLast, kCFNumberSInt32Type, ObjCClass
|
|
16
|
+
from ._vispy_fonts import _vispy_fonts, _get_vispy_font_filename
|
|
17
|
+
|
|
18
|
+
_font_dict = {}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _load_vispy_font(face, bold, italic):
|
|
22
|
+
# http://stackoverflow.com/questions/2703085/
|
|
23
|
+
# how-can-you-load-a-font-ttf-from-a-file-using-core-text
|
|
24
|
+
fname = _get_vispy_font_filename(face, bold, italic)
|
|
25
|
+
url = cf.CFURLCreateWithFileSystemPath(None, CFSTR(fname), 0, False)
|
|
26
|
+
# data_provider = quartz.CGDataProviderCreateWithURL(url)
|
|
27
|
+
# cg_font = quartz.CGFontCreateWithDataProvider(data_provider)
|
|
28
|
+
# font = ct.CTFontCreateWithGraphicsFont(cg_font, 12., None, None)
|
|
29
|
+
array = ct.CTFontManagerCreateFontDescriptorsFromURL(url)
|
|
30
|
+
desc = cf.CFArrayGetValueAtIndex(array, 0)
|
|
31
|
+
font = ct.CTFontCreateWithFontDescriptor(desc, 12., None)
|
|
32
|
+
cf.CFRelease(array)
|
|
33
|
+
cf.CFRelease(url)
|
|
34
|
+
if not font:
|
|
35
|
+
raise RuntimeError("Couldn't load font: %s" % face)
|
|
36
|
+
key = '%s-%s-%s' % (face, bold, italic)
|
|
37
|
+
_font_dict[key] = font
|
|
38
|
+
return font
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _load_font(face, bold, italic):
|
|
42
|
+
key = '%s-%s-%s' % (face, bold, italic)
|
|
43
|
+
if key in _font_dict:
|
|
44
|
+
return _font_dict[key]
|
|
45
|
+
if face in _vispy_fonts:
|
|
46
|
+
return _load_vispy_font(face, bold, italic)
|
|
47
|
+
traits = 0
|
|
48
|
+
traits |= kCTFontBoldTrait if bold else 0
|
|
49
|
+
traits |= kCTFontItalicTrait if italic else 0
|
|
50
|
+
|
|
51
|
+
# Create an attribute dictionary.
|
|
52
|
+
args = [None, 0, cf.kCFTypeDictionaryKeyCallBacks,
|
|
53
|
+
cf.kCFTypeDictionaryValueCallBacks]
|
|
54
|
+
attributes = cf.CFDictionaryCreateMutable(*args)
|
|
55
|
+
# Add family name to attributes.
|
|
56
|
+
cfname = CFSTR(face)
|
|
57
|
+
cf.CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, cfname)
|
|
58
|
+
cf.CFRelease(cfname)
|
|
59
|
+
# Construct a CFNumber to represent the traits.
|
|
60
|
+
itraits = c_int32(traits)
|
|
61
|
+
sym_traits = cf.CFNumberCreate(None, kCFNumberSInt32Type, byref(itraits))
|
|
62
|
+
if sym_traits:
|
|
63
|
+
# Construct a dictionary to hold the traits values.
|
|
64
|
+
args = [None, 0, cf.kCFTypeDictionaryKeyCallBacks,
|
|
65
|
+
cf.kCFTypeDictionaryValueCallBacks]
|
|
66
|
+
traits_dict = cf.CFDictionaryCreateMutable(*args)
|
|
67
|
+
if traits_dict:
|
|
68
|
+
# Add CFNumber traits to traits dictionary.
|
|
69
|
+
cf.CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait,
|
|
70
|
+
sym_traits)
|
|
71
|
+
# Add traits dictionary to attributes.
|
|
72
|
+
cf.CFDictionaryAddValue(attributes, kCTFontTraitsAttribute,
|
|
73
|
+
traits_dict)
|
|
74
|
+
cf.CFRelease(traits_dict)
|
|
75
|
+
cf.CFRelease(sym_traits)
|
|
76
|
+
# Create font descriptor with attributes.
|
|
77
|
+
desc = ct.CTFontDescriptorCreateWithAttributes(attributes)
|
|
78
|
+
cf.CFRelease(attributes)
|
|
79
|
+
font = ct.CTFontCreateWithFontDescriptor(desc, 12., None)
|
|
80
|
+
if not font:
|
|
81
|
+
raise RuntimeError("Couldn't load font: %s" % face)
|
|
82
|
+
_font_dict[key] = font
|
|
83
|
+
return font
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _load_glyph(f, char, glyphs_dict):
|
|
87
|
+
font = _load_font(f['face'], f['bold'], f['italic'])
|
|
88
|
+
# resize loaded font
|
|
89
|
+
args = [None, 0, cf.kCFTypeDictionaryKeyCallBacks,
|
|
90
|
+
cf.kCFTypeDictionaryValueCallBacks]
|
|
91
|
+
attributes = cf.CFDictionaryCreateMutable(*args)
|
|
92
|
+
desc = ct.CTFontDescriptorCreateWithAttributes(attributes)
|
|
93
|
+
cf.CFRelease(attributes)
|
|
94
|
+
font = ct.CTFontCreateCopyWithAttributes(font, f['size'], None, desc)
|
|
95
|
+
cf.CFRelease(desc)
|
|
96
|
+
if not font:
|
|
97
|
+
raise RuntimeError("Couldn't load font")
|
|
98
|
+
# Create an attributed string using text and font.
|
|
99
|
+
args = [None, 1, cf.kCFTypeDictionaryKeyCallBacks,
|
|
100
|
+
cf.kCFTypeDictionaryValueCallBacks]
|
|
101
|
+
attributes = cf.CFDictionaryCreateMutable(*args)
|
|
102
|
+
cf.CFDictionaryAddValue(attributes, kCTFontAttributeName, font)
|
|
103
|
+
string = cf.CFAttributedStringCreate(None, CFSTR(char), attributes)
|
|
104
|
+
# Create a CTLine object to render the string.
|
|
105
|
+
line = ct.CTLineCreateWithAttributedString(string)
|
|
106
|
+
cf.CFRelease(string)
|
|
107
|
+
cf.CFRelease(attributes)
|
|
108
|
+
# Get a bounding rectangle for glyphs in string.
|
|
109
|
+
chars = (UniChar * 1)(*map(ord, char))
|
|
110
|
+
glyphs = (CGGlyph * 1)()
|
|
111
|
+
ct.CTFontGetGlyphsForCharacters(font, chars, glyphs, 1)
|
|
112
|
+
rect = ct.CTFontGetBoundingRectsForGlyphs(font, 0, glyphs, None, 1)
|
|
113
|
+
# Get advance for all glyphs in string.
|
|
114
|
+
advance = ct.CTFontGetAdvancesForGlyphs(font, 1, glyphs, None, 1)
|
|
115
|
+
width = max(int(np.ceil(rect.size.width) + 1), 1)
|
|
116
|
+
height = max(int(np.ceil(rect.size.height) + 1), 1)
|
|
117
|
+
|
|
118
|
+
left = rect.origin.x
|
|
119
|
+
baseline = -rect.origin.y
|
|
120
|
+
top = height - baseline
|
|
121
|
+
|
|
122
|
+
bits_per_component = 8
|
|
123
|
+
bytes_per_row = 4*width
|
|
124
|
+
color_space = quartz.CGColorSpaceCreateDeviceRGB()
|
|
125
|
+
args = [None, width, height, bits_per_component, bytes_per_row,
|
|
126
|
+
color_space, kCGImageAlphaPremultipliedLast]
|
|
127
|
+
bitmap = quartz.CGBitmapContextCreate(*args)
|
|
128
|
+
# Draw text to bitmap context.
|
|
129
|
+
quartz.CGContextSetShouldAntialias(bitmap, True)
|
|
130
|
+
quartz.CGContextSetTextPosition(bitmap, -left, baseline)
|
|
131
|
+
ct.CTLineDraw(line, bitmap)
|
|
132
|
+
cf.CFRelease(line)
|
|
133
|
+
# Create an image to get the data out.
|
|
134
|
+
image_ref = quartz.CGBitmapContextCreateImage(bitmap)
|
|
135
|
+
assert quartz.CGImageGetBytesPerRow(image_ref) == bytes_per_row
|
|
136
|
+
data_provider = quartz.CGImageGetDataProvider(image_ref)
|
|
137
|
+
image_data = quartz.CGDataProviderCopyData(data_provider)
|
|
138
|
+
buffer_size = cf.CFDataGetLength(image_data)
|
|
139
|
+
assert buffer_size == width * height * 4
|
|
140
|
+
buffer = (c_byte * buffer_size)()
|
|
141
|
+
byte_range = CFRange(0, buffer_size)
|
|
142
|
+
cf.CFDataGetBytes(image_data, byte_range, buffer)
|
|
143
|
+
quartz.CGImageRelease(image_ref)
|
|
144
|
+
quartz.CGDataProviderRelease(image_data)
|
|
145
|
+
cf.CFRelease(bitmap)
|
|
146
|
+
cf.CFRelease(color_space)
|
|
147
|
+
|
|
148
|
+
# reshape bitmap (don't know why it's only alpha on OSX...)
|
|
149
|
+
bitmap = np.array(buffer, np.ubyte)
|
|
150
|
+
bitmap.shape = (height, width, 4)
|
|
151
|
+
bitmap = bitmap[:, :, 3].copy()
|
|
152
|
+
glyph = dict(char=char, offset=(left, top), bitmap=bitmap,
|
|
153
|
+
advance=advance, kerning={})
|
|
154
|
+
glyphs_dict[char] = glyph
|
|
155
|
+
# Generate kerning
|
|
156
|
+
for other_char, other_glyph in glyphs_dict.items():
|
|
157
|
+
glyph['kerning'][other_char] = (_get_k_p_a(font, other_char, char) -
|
|
158
|
+
other_glyph['advance'])
|
|
159
|
+
other_glyph['kerning'][char] = (_get_k_p_a(font, char, other_char) -
|
|
160
|
+
glyph['advance'])
|
|
161
|
+
cf.CFRelease(font)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _get_k_p_a(font, left, right):
|
|
165
|
+
"""This actually calculates the kerning + advance"""
|
|
166
|
+
# http://lists.apple.com/archives/coretext-dev/2010/Dec/msg00020.html
|
|
167
|
+
# 1) set up a CTTypesetter
|
|
168
|
+
chars = left + right
|
|
169
|
+
args = [None, 1, cf.kCFTypeDictionaryKeyCallBacks,
|
|
170
|
+
cf.kCFTypeDictionaryValueCallBacks]
|
|
171
|
+
attributes = cf.CFDictionaryCreateMutable(*args)
|
|
172
|
+
cf.CFDictionaryAddValue(attributes, kCTFontAttributeName, font)
|
|
173
|
+
string = cf.CFAttributedStringCreate(None, CFSTR(chars), attributes)
|
|
174
|
+
typesetter = ct.CTTypesetterCreateWithAttributedString(string)
|
|
175
|
+
cf.CFRelease(string)
|
|
176
|
+
cf.CFRelease(attributes)
|
|
177
|
+
# 2) extract a CTLine from it
|
|
178
|
+
range = CFRange(0, 1)
|
|
179
|
+
line = ct.CTTypesetterCreateLine(typesetter, range)
|
|
180
|
+
# 3) use CTLineGetOffsetForStringIndex to get the character positions
|
|
181
|
+
offset = ct.CTLineGetOffsetForStringIndex(line, 1, None)
|
|
182
|
+
cf.CFRelease(line)
|
|
183
|
+
cf.CFRelease(typesetter)
|
|
184
|
+
return offset
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _list_fonts():
|
|
188
|
+
manager = ObjCClass('NSFontManager').sharedFontManager()
|
|
189
|
+
avail = manager.availableFontFamilies()
|
|
190
|
+
fonts = [avail.objectAtIndex_(ii).UTF8String().decode('utf-8')
|
|
191
|
+
for ii in range(avail.count())]
|
|
192
|
+
return fonts
|
|
@@ -0,0 +1,36 @@
|
|
|
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 sys
|
|
8
|
+
|
|
9
|
+
from ._vispy_fonts import _vispy_fonts
|
|
10
|
+
if sys.platform.startswith('linux'):
|
|
11
|
+
from ._freetype import _load_glyph
|
|
12
|
+
from ...ext.fontconfig import _list_fonts
|
|
13
|
+
elif sys.platform == 'darwin':
|
|
14
|
+
from ._quartz import _load_glyph, _list_fonts
|
|
15
|
+
elif sys.platform.startswith('win'):
|
|
16
|
+
from ._freetype import _load_glyph # noqa, analysis:ignore
|
|
17
|
+
from ._win32 import _list_fonts # noqa, analysis:ignore
|
|
18
|
+
else:
|
|
19
|
+
raise NotImplementedError('unknown system %s' % sys.platform)
|
|
20
|
+
|
|
21
|
+
_fonts = {}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def list_fonts():
|
|
25
|
+
"""List system fonts
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
fonts : list of str
|
|
30
|
+
List of system fonts.
|
|
31
|
+
"""
|
|
32
|
+
vals = _list_fonts()
|
|
33
|
+
for font in _vispy_fonts:
|
|
34
|
+
vals += [font] if font not in vals else []
|
|
35
|
+
vals = sorted(vals, key=lambda s: s.lower())
|
|
36
|
+
return vals
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# -----------------------------------------------------------------------------
|
|
3
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
4
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
import os.path as op
|
|
8
|
+
|
|
9
|
+
# List the vispy fonts made available online
|
|
10
|
+
_vispy_fonts = ('OpenSans',)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _get_vispy_font_filename(face, bold, italic):
|
|
14
|
+
"""Fetch a remote vispy font"""
|
|
15
|
+
name = face + '-'
|
|
16
|
+
name += 'Regular' if not bold and not italic else ''
|
|
17
|
+
name += 'Bold' if bold else ''
|
|
18
|
+
name += 'Italic' if italic else ''
|
|
19
|
+
name += '.ttf'
|
|
20
|
+
return op.join(op.dirname(__file__), 'data', name)
|