vispy 0.15.0__cp313-cp313-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.

Files changed (521) hide show
  1. vispy/__init__.py +33 -0
  2. vispy/app/__init__.py +15 -0
  3. vispy/app/_default_app.py +76 -0
  4. vispy/app/_detect_eventloop.py +148 -0
  5. vispy/app/application.py +263 -0
  6. vispy/app/backends/__init__.py +52 -0
  7. vispy/app/backends/_egl.py +264 -0
  8. vispy/app/backends/_glfw.py +513 -0
  9. vispy/app/backends/_jupyter_rfb.py +278 -0
  10. vispy/app/backends/_offscreen_util.py +121 -0
  11. vispy/app/backends/_osmesa.py +235 -0
  12. vispy/app/backends/_pyglet.py +451 -0
  13. vispy/app/backends/_pyqt4.py +36 -0
  14. vispy/app/backends/_pyqt5.py +36 -0
  15. vispy/app/backends/_pyqt6.py +40 -0
  16. vispy/app/backends/_pyside.py +37 -0
  17. vispy/app/backends/_pyside2.py +52 -0
  18. vispy/app/backends/_pyside6.py +53 -0
  19. vispy/app/backends/_qt.py +1003 -0
  20. vispy/app/backends/_sdl2.py +444 -0
  21. vispy/app/backends/_template.py +244 -0
  22. vispy/app/backends/_test.py +8 -0
  23. vispy/app/backends/_tk.py +800 -0
  24. vispy/app/backends/_wx.py +476 -0
  25. vispy/app/backends/tests/__init__.py +0 -0
  26. vispy/app/backends/tests/test_offscreen_util.py +52 -0
  27. vispy/app/backends/tests/test_rfb.py +77 -0
  28. vispy/app/base.py +294 -0
  29. vispy/app/canvas.py +828 -0
  30. vispy/app/qt.py +92 -0
  31. vispy/app/tests/__init__.py +0 -0
  32. vispy/app/tests/qt-designer.ui +58 -0
  33. vispy/app/tests/test_app.py +442 -0
  34. vispy/app/tests/test_backends.py +164 -0
  35. vispy/app/tests/test_canvas.py +122 -0
  36. vispy/app/tests/test_context.py +92 -0
  37. vispy/app/tests/test_qt.py +47 -0
  38. vispy/app/tests/test_simultaneous.py +134 -0
  39. vispy/app/timer.py +174 -0
  40. vispy/color/__init__.py +17 -0
  41. vispy/color/_color_dict.py +193 -0
  42. vispy/color/color_array.py +447 -0
  43. vispy/color/color_space.py +181 -0
  44. vispy/color/colormap.py +1213 -0
  45. vispy/color/tests/__init__.py +0 -0
  46. vispy/color/tests/test_color.py +378 -0
  47. vispy/conftest.py +12 -0
  48. vispy/ext/__init__.py +0 -0
  49. vispy/ext/cocoapy.py +1522 -0
  50. vispy/ext/cubehelix.py +138 -0
  51. vispy/ext/egl.py +375 -0
  52. vispy/ext/fontconfig.py +118 -0
  53. vispy/ext/gdi32plus.py +206 -0
  54. vispy/ext/osmesa.py +105 -0
  55. vispy/geometry/__init__.py +23 -0
  56. vispy/geometry/_triangulation_debugger.py +171 -0
  57. vispy/geometry/calculations.py +162 -0
  58. vispy/geometry/curves.py +399 -0
  59. vispy/geometry/generation.py +643 -0
  60. vispy/geometry/isocurve.py +175 -0
  61. vispy/geometry/isosurface.py +465 -0
  62. vispy/geometry/meshdata.py +700 -0
  63. vispy/geometry/normals.py +78 -0
  64. vispy/geometry/parametric.py +56 -0
  65. vispy/geometry/polygon.py +137 -0
  66. vispy/geometry/rect.py +210 -0
  67. vispy/geometry/tests/__init__.py +0 -0
  68. vispy/geometry/tests/test_calculations.py +23 -0
  69. vispy/geometry/tests/test_generation.py +56 -0
  70. vispy/geometry/tests/test_meshdata.py +106 -0
  71. vispy/geometry/tests/test_triangulation.py +594 -0
  72. vispy/geometry/torusknot.py +142 -0
  73. vispy/geometry/triangulation.py +876 -0
  74. vispy/gloo/__init__.py +56 -0
  75. vispy/gloo/buffer.py +505 -0
  76. vispy/gloo/context.py +272 -0
  77. vispy/gloo/framebuffer.py +257 -0
  78. vispy/gloo/gl/__init__.py +234 -0
  79. vispy/gloo/gl/_constants.py +332 -0
  80. vispy/gloo/gl/_es2.py +986 -0
  81. vispy/gloo/gl/_gl2.py +1365 -0
  82. vispy/gloo/gl/_proxy.py +499 -0
  83. vispy/gloo/gl/_pyopengl2.py +362 -0
  84. vispy/gloo/gl/dummy.py +24 -0
  85. vispy/gloo/gl/es2.py +62 -0
  86. vispy/gloo/gl/gl2.py +98 -0
  87. vispy/gloo/gl/glplus.py +168 -0
  88. vispy/gloo/gl/pyopengl2.py +97 -0
  89. vispy/gloo/gl/tests/__init__.py +0 -0
  90. vispy/gloo/gl/tests/test_basics.py +282 -0
  91. vispy/gloo/gl/tests/test_functionality.py +568 -0
  92. vispy/gloo/gl/tests/test_names.py +246 -0
  93. vispy/gloo/gl/tests/test_use.py +71 -0
  94. vispy/gloo/glir.py +1824 -0
  95. vispy/gloo/globject.py +101 -0
  96. vispy/gloo/preprocessor.py +67 -0
  97. vispy/gloo/program.py +543 -0
  98. vispy/gloo/tests/__init__.py +0 -0
  99. vispy/gloo/tests/test_buffer.py +558 -0
  100. vispy/gloo/tests/test_context.py +119 -0
  101. vispy/gloo/tests/test_framebuffer.py +195 -0
  102. vispy/gloo/tests/test_glir.py +307 -0
  103. vispy/gloo/tests/test_globject.py +35 -0
  104. vispy/gloo/tests/test_program.py +302 -0
  105. vispy/gloo/tests/test_texture.py +732 -0
  106. vispy/gloo/tests/test_use_gloo.py +187 -0
  107. vispy/gloo/tests/test_util.py +60 -0
  108. vispy/gloo/tests/test_wrappers.py +261 -0
  109. vispy/gloo/texture.py +1046 -0
  110. vispy/gloo/util.py +129 -0
  111. vispy/gloo/wrappers.py +762 -0
  112. vispy/glsl/__init__.py +42 -0
  113. vispy/glsl/antialias/antialias.glsl +7 -0
  114. vispy/glsl/antialias/cap-butt.glsl +31 -0
  115. vispy/glsl/antialias/cap-round.glsl +29 -0
  116. vispy/glsl/antialias/cap-square.glsl +30 -0
  117. vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
  118. vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
  119. vispy/glsl/antialias/cap.glsl +67 -0
  120. vispy/glsl/antialias/caps.glsl +67 -0
  121. vispy/glsl/antialias/filled.glsl +50 -0
  122. vispy/glsl/antialias/outline.glsl +40 -0
  123. vispy/glsl/antialias/stroke.glsl +43 -0
  124. vispy/glsl/arrowheads/angle.glsl +99 -0
  125. vispy/glsl/arrowheads/arrowheads.frag +60 -0
  126. vispy/glsl/arrowheads/arrowheads.glsl +12 -0
  127. vispy/glsl/arrowheads/arrowheads.vert +83 -0
  128. vispy/glsl/arrowheads/curved.glsl +48 -0
  129. vispy/glsl/arrowheads/inhibitor.glsl +26 -0
  130. vispy/glsl/arrowheads/stealth.glsl +46 -0
  131. vispy/glsl/arrowheads/triangle.glsl +97 -0
  132. vispy/glsl/arrowheads/util.glsl +13 -0
  133. vispy/glsl/arrows/angle-30.glsl +12 -0
  134. vispy/glsl/arrows/angle-60.glsl +12 -0
  135. vispy/glsl/arrows/angle-90.glsl +12 -0
  136. vispy/glsl/arrows/arrow.frag +39 -0
  137. vispy/glsl/arrows/arrow.vert +49 -0
  138. vispy/glsl/arrows/arrows.glsl +17 -0
  139. vispy/glsl/arrows/common.glsl +187 -0
  140. vispy/glsl/arrows/curved.glsl +63 -0
  141. vispy/glsl/arrows/stealth.glsl +50 -0
  142. vispy/glsl/arrows/triangle-30.glsl +12 -0
  143. vispy/glsl/arrows/triangle-60.glsl +12 -0
  144. vispy/glsl/arrows/triangle-90.glsl +12 -0
  145. vispy/glsl/arrows/util.glsl +98 -0
  146. vispy/glsl/build_spatial_filters.py +660 -0
  147. vispy/glsl/collections/agg-fast-path.frag +20 -0
  148. vispy/glsl/collections/agg-fast-path.vert +78 -0
  149. vispy/glsl/collections/agg-glyph.frag +60 -0
  150. vispy/glsl/collections/agg-glyph.vert +33 -0
  151. vispy/glsl/collections/agg-marker.frag +35 -0
  152. vispy/glsl/collections/agg-marker.vert +48 -0
  153. vispy/glsl/collections/agg-path.frag +55 -0
  154. vispy/glsl/collections/agg-path.vert +166 -0
  155. vispy/glsl/collections/agg-point.frag +21 -0
  156. vispy/glsl/collections/agg-point.vert +35 -0
  157. vispy/glsl/collections/agg-segment.frag +32 -0
  158. vispy/glsl/collections/agg-segment.vert +75 -0
  159. vispy/glsl/collections/marker.frag +38 -0
  160. vispy/glsl/collections/marker.vert +48 -0
  161. vispy/glsl/collections/raw-path.frag +15 -0
  162. vispy/glsl/collections/raw-path.vert +24 -0
  163. vispy/glsl/collections/raw-point.frag +14 -0
  164. vispy/glsl/collections/raw-point.vert +31 -0
  165. vispy/glsl/collections/raw-segment.frag +18 -0
  166. vispy/glsl/collections/raw-segment.vert +26 -0
  167. vispy/glsl/collections/raw-triangle.frag +13 -0
  168. vispy/glsl/collections/raw-triangle.vert +26 -0
  169. vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
  170. vispy/glsl/collections/sdf-glyph.frag +80 -0
  171. vispy/glsl/collections/sdf-glyph.vert +59 -0
  172. vispy/glsl/collections/tick-labels.vert +71 -0
  173. vispy/glsl/colormaps/autumn.glsl +20 -0
  174. vispy/glsl/colormaps/blues.glsl +20 -0
  175. vispy/glsl/colormaps/color-space.glsl +17 -0
  176. vispy/glsl/colormaps/colormaps.glsl +24 -0
  177. vispy/glsl/colormaps/cool.glsl +20 -0
  178. vispy/glsl/colormaps/fire.glsl +21 -0
  179. vispy/glsl/colormaps/gray.glsl +20 -0
  180. vispy/glsl/colormaps/greens.glsl +20 -0
  181. vispy/glsl/colormaps/hot.glsl +22 -0
  182. vispy/glsl/colormaps/ice.glsl +20 -0
  183. vispy/glsl/colormaps/icefire.glsl +23 -0
  184. vispy/glsl/colormaps/parse.py +40 -0
  185. vispy/glsl/colormaps/reds.glsl +20 -0
  186. vispy/glsl/colormaps/spring.glsl +20 -0
  187. vispy/glsl/colormaps/summer.glsl +20 -0
  188. vispy/glsl/colormaps/user.glsl +22 -0
  189. vispy/glsl/colormaps/util.glsl +41 -0
  190. vispy/glsl/colormaps/wheel.glsl +21 -0
  191. vispy/glsl/colormaps/winter.glsl +20 -0
  192. vispy/glsl/lines/agg.frag +320 -0
  193. vispy/glsl/lines/agg.vert +241 -0
  194. vispy/glsl/markers/arrow.glsl +12 -0
  195. vispy/glsl/markers/asterisk.glsl +16 -0
  196. vispy/glsl/markers/chevron.glsl +14 -0
  197. vispy/glsl/markers/clover.glsl +20 -0
  198. vispy/glsl/markers/club.glsl +31 -0
  199. vispy/glsl/markers/cross.glsl +17 -0
  200. vispy/glsl/markers/diamond.glsl +12 -0
  201. vispy/glsl/markers/disc.glsl +9 -0
  202. vispy/glsl/markers/ellipse.glsl +67 -0
  203. vispy/glsl/markers/hbar.glsl +9 -0
  204. vispy/glsl/markers/heart.glsl +15 -0
  205. vispy/glsl/markers/infinity.glsl +15 -0
  206. vispy/glsl/markers/marker-sdf.frag +74 -0
  207. vispy/glsl/markers/marker-sdf.vert +41 -0
  208. vispy/glsl/markers/marker.frag +36 -0
  209. vispy/glsl/markers/marker.vert +46 -0
  210. vispy/glsl/markers/markers.glsl +24 -0
  211. vispy/glsl/markers/pin.glsl +18 -0
  212. vispy/glsl/markers/ring.glsl +11 -0
  213. vispy/glsl/markers/spade.glsl +28 -0
  214. vispy/glsl/markers/square.glsl +10 -0
  215. vispy/glsl/markers/tag.glsl +11 -0
  216. vispy/glsl/markers/triangle.glsl +14 -0
  217. vispy/glsl/markers/vbar.glsl +9 -0
  218. vispy/glsl/math/circle-through-2-points.glsl +30 -0
  219. vispy/glsl/math/constants.glsl +48 -0
  220. vispy/glsl/math/double.glsl +114 -0
  221. vispy/glsl/math/functions.glsl +20 -0
  222. vispy/glsl/math/point-to-line-distance.glsl +31 -0
  223. vispy/glsl/math/point-to-line-projection.glsl +29 -0
  224. vispy/glsl/math/signed-line-distance.glsl +27 -0
  225. vispy/glsl/math/signed-segment-distance.glsl +30 -0
  226. vispy/glsl/misc/regular-grid.frag +244 -0
  227. vispy/glsl/misc/spatial-filters.frag +1407 -0
  228. vispy/glsl/misc/viewport-NDC.glsl +20 -0
  229. vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
  230. vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
  231. vispy/glsl/transforms/hammer.glsl +44 -0
  232. vispy/glsl/transforms/identity.glsl +6 -0
  233. vispy/glsl/transforms/identity_forward.glsl +23 -0
  234. vispy/glsl/transforms/identity_inverse.glsl +23 -0
  235. vispy/glsl/transforms/linear-scale.glsl +127 -0
  236. vispy/glsl/transforms/log-scale.glsl +126 -0
  237. vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
  238. vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
  239. vispy/glsl/transforms/panzoom.glsl +10 -0
  240. vispy/glsl/transforms/polar.glsl +41 -0
  241. vispy/glsl/transforms/position.glsl +44 -0
  242. vispy/glsl/transforms/power-scale.glsl +139 -0
  243. vispy/glsl/transforms/projection.glsl +7 -0
  244. vispy/glsl/transforms/pvm.glsl +13 -0
  245. vispy/glsl/transforms/rotate.glsl +45 -0
  246. vispy/glsl/transforms/trackball.glsl +15 -0
  247. vispy/glsl/transforms/translate.glsl +35 -0
  248. vispy/glsl/transforms/transverse_mercator.glsl +38 -0
  249. vispy/glsl/transforms/viewport-clipping.glsl +14 -0
  250. vispy/glsl/transforms/viewport-transform.glsl +16 -0
  251. vispy/glsl/transforms/viewport.glsl +50 -0
  252. vispy/glsl/transforms/x.glsl +24 -0
  253. vispy/glsl/transforms/y.glsl +19 -0
  254. vispy/glsl/transforms/z.glsl +14 -0
  255. vispy/io/__init__.py +20 -0
  256. vispy/io/_data/spatial-filters.npy +0 -0
  257. vispy/io/datasets.py +94 -0
  258. vispy/io/image.py +231 -0
  259. vispy/io/mesh.py +122 -0
  260. vispy/io/stl.py +167 -0
  261. vispy/io/tests/__init__.py +0 -0
  262. vispy/io/tests/test_image.py +47 -0
  263. vispy/io/tests/test_io.py +121 -0
  264. vispy/io/wavefront.py +350 -0
  265. vispy/plot/__init__.py +36 -0
  266. vispy/plot/fig.py +58 -0
  267. vispy/plot/plotwidget.py +522 -0
  268. vispy/plot/tests/__init__.py +0 -0
  269. vispy/plot/tests/test_plot.py +46 -0
  270. vispy/scene/__init__.py +43 -0
  271. vispy/scene/cameras/__init__.py +27 -0
  272. vispy/scene/cameras/_base.py +38 -0
  273. vispy/scene/cameras/arcball.py +105 -0
  274. vispy/scene/cameras/base_camera.py +551 -0
  275. vispy/scene/cameras/fly.py +474 -0
  276. vispy/scene/cameras/magnify.py +163 -0
  277. vispy/scene/cameras/panzoom.py +311 -0
  278. vispy/scene/cameras/perspective.py +338 -0
  279. vispy/scene/cameras/tests/__init__.py +0 -0
  280. vispy/scene/cameras/tests/test_cameras.py +27 -0
  281. vispy/scene/cameras/tests/test_link.py +53 -0
  282. vispy/scene/cameras/tests/test_perspective.py +122 -0
  283. vispy/scene/cameras/turntable.py +183 -0
  284. vispy/scene/canvas.py +639 -0
  285. vispy/scene/events.py +85 -0
  286. vispy/scene/node.py +644 -0
  287. vispy/scene/subscene.py +20 -0
  288. vispy/scene/tests/__init__.py +0 -0
  289. vispy/scene/tests/test_canvas.py +119 -0
  290. vispy/scene/tests/test_node.py +142 -0
  291. vispy/scene/tests/test_visuals.py +141 -0
  292. vispy/scene/visuals.py +276 -0
  293. vispy/scene/widgets/__init__.py +18 -0
  294. vispy/scene/widgets/anchor.py +25 -0
  295. vispy/scene/widgets/axis.py +88 -0
  296. vispy/scene/widgets/colorbar.py +176 -0
  297. vispy/scene/widgets/console.py +351 -0
  298. vispy/scene/widgets/grid.py +509 -0
  299. vispy/scene/widgets/label.py +50 -0
  300. vispy/scene/widgets/tests/__init__.py +0 -0
  301. vispy/scene/widgets/tests/test_colorbar.py +47 -0
  302. vispy/scene/widgets/viewbox.py +199 -0
  303. vispy/scene/widgets/widget.py +478 -0
  304. vispy/testing/__init__.py +51 -0
  305. vispy/testing/_runners.py +448 -0
  306. vispy/testing/_testing.py +416 -0
  307. vispy/testing/image_tester.py +494 -0
  308. vispy/testing/rendered_array_tester.py +85 -0
  309. vispy/testing/tests/__init__.py +0 -0
  310. vispy/testing/tests/test_testing.py +20 -0
  311. vispy/util/__init__.py +32 -0
  312. vispy/util/bunch.py +15 -0
  313. vispy/util/check_environment.py +57 -0
  314. vispy/util/config.py +490 -0
  315. vispy/util/dpi/__init__.py +19 -0
  316. vispy/util/dpi/_linux.py +69 -0
  317. vispy/util/dpi/_quartz.py +26 -0
  318. vispy/util/dpi/_win32.py +34 -0
  319. vispy/util/dpi/tests/__init__.py +0 -0
  320. vispy/util/dpi/tests/test_dpi.py +16 -0
  321. vispy/util/eq.py +41 -0
  322. vispy/util/event.py +774 -0
  323. vispy/util/fetching.py +276 -0
  324. vispy/util/filter.py +44 -0
  325. vispy/util/fonts/__init__.py +14 -0
  326. vispy/util/fonts/_freetype.py +73 -0
  327. vispy/util/fonts/_quartz.py +192 -0
  328. vispy/util/fonts/_triage.py +36 -0
  329. vispy/util/fonts/_vispy_fonts.py +20 -0
  330. vispy/util/fonts/_win32.py +105 -0
  331. vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
  332. vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
  333. vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
  334. vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
  335. vispy/util/fonts/tests/__init__.py +0 -0
  336. vispy/util/fonts/tests/test_font.py +45 -0
  337. vispy/util/fourier.py +69 -0
  338. vispy/util/frozen.py +25 -0
  339. vispy/util/gallery_scraper.py +268 -0
  340. vispy/util/keys.py +91 -0
  341. vispy/util/logs.py +358 -0
  342. vispy/util/osmesa_gl.py +17 -0
  343. vispy/util/profiler.py +135 -0
  344. vispy/util/ptime.py +16 -0
  345. vispy/util/quaternion.py +229 -0
  346. vispy/util/svg/__init__.py +18 -0
  347. vispy/util/svg/base.py +20 -0
  348. vispy/util/svg/color.py +219 -0
  349. vispy/util/svg/element.py +51 -0
  350. vispy/util/svg/geometry.py +478 -0
  351. vispy/util/svg/group.py +66 -0
  352. vispy/util/svg/length.py +81 -0
  353. vispy/util/svg/number.py +25 -0
  354. vispy/util/svg/path.py +332 -0
  355. vispy/util/svg/shapes.py +57 -0
  356. vispy/util/svg/style.py +59 -0
  357. vispy/util/svg/svg.py +40 -0
  358. vispy/util/svg/transform.py +223 -0
  359. vispy/util/svg/transformable.py +28 -0
  360. vispy/util/svg/viewport.py +73 -0
  361. vispy/util/tests/__init__.py +0 -0
  362. vispy/util/tests/test_config.py +58 -0
  363. vispy/util/tests/test_docstring_parameters.py +123 -0
  364. vispy/util/tests/test_emitter_group.py +262 -0
  365. vispy/util/tests/test_event_emitter.py +743 -0
  366. vispy/util/tests/test_fourier.py +35 -0
  367. vispy/util/tests/test_gallery_scraper.py +112 -0
  368. vispy/util/tests/test_import.py +127 -0
  369. vispy/util/tests/test_key.py +22 -0
  370. vispy/util/tests/test_logging.py +45 -0
  371. vispy/util/tests/test_run.py +14 -0
  372. vispy/util/tests/test_transforms.py +42 -0
  373. vispy/util/tests/test_vispy.py +48 -0
  374. vispy/util/transforms.py +201 -0
  375. vispy/util/wrappers.py +155 -0
  376. vispy/version.py +21 -0
  377. vispy/visuals/__init__.py +50 -0
  378. vispy/visuals/_scalable_textures.py +487 -0
  379. vispy/visuals/axis.py +678 -0
  380. vispy/visuals/border.py +208 -0
  381. vispy/visuals/box.py +79 -0
  382. vispy/visuals/collections/__init__.py +30 -0
  383. vispy/visuals/collections/agg_fast_path_collection.py +219 -0
  384. vispy/visuals/collections/agg_path_collection.py +197 -0
  385. vispy/visuals/collections/agg_point_collection.py +52 -0
  386. vispy/visuals/collections/agg_segment_collection.py +142 -0
  387. vispy/visuals/collections/array_list.py +401 -0
  388. vispy/visuals/collections/base_collection.py +482 -0
  389. vispy/visuals/collections/collection.py +253 -0
  390. vispy/visuals/collections/path_collection.py +23 -0
  391. vispy/visuals/collections/point_collection.py +19 -0
  392. vispy/visuals/collections/polygon_collection.py +25 -0
  393. vispy/visuals/collections/raw_path_collection.py +119 -0
  394. vispy/visuals/collections/raw_point_collection.py +113 -0
  395. vispy/visuals/collections/raw_polygon_collection.py +77 -0
  396. vispy/visuals/collections/raw_segment_collection.py +112 -0
  397. vispy/visuals/collections/raw_triangle_collection.py +78 -0
  398. vispy/visuals/collections/segment_collection.py +19 -0
  399. vispy/visuals/collections/triangle_collection.py +16 -0
  400. vispy/visuals/collections/util.py +168 -0
  401. vispy/visuals/colorbar.py +699 -0
  402. vispy/visuals/cube.py +41 -0
  403. vispy/visuals/ellipse.py +162 -0
  404. vispy/visuals/filters/__init__.py +10 -0
  405. vispy/visuals/filters/base_filter.py +242 -0
  406. vispy/visuals/filters/clipper.py +60 -0
  407. vispy/visuals/filters/clipping_planes.py +122 -0
  408. vispy/visuals/filters/color.py +181 -0
  409. vispy/visuals/filters/markers.py +28 -0
  410. vispy/visuals/filters/mesh.py +801 -0
  411. vispy/visuals/filters/picking.py +60 -0
  412. vispy/visuals/filters/tests/__init__.py +3 -0
  413. vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
  414. vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
  415. vispy/visuals/glsl/__init__.py +1 -0
  416. vispy/visuals/glsl/antialiasing.py +133 -0
  417. vispy/visuals/glsl/color.py +63 -0
  418. vispy/visuals/graphs/__init__.py +1 -0
  419. vispy/visuals/graphs/graph.py +240 -0
  420. vispy/visuals/graphs/layouts/__init__.py +55 -0
  421. vispy/visuals/graphs/layouts/circular.py +49 -0
  422. vispy/visuals/graphs/layouts/force_directed.py +211 -0
  423. vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
  424. vispy/visuals/graphs/layouts/random.py +52 -0
  425. vispy/visuals/graphs/tests/__init__.py +1 -0
  426. vispy/visuals/graphs/tests/test_layouts.py +139 -0
  427. vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
  428. vispy/visuals/graphs/util.py +120 -0
  429. vispy/visuals/gridlines.py +161 -0
  430. vispy/visuals/gridmesh.py +98 -0
  431. vispy/visuals/histogram.py +58 -0
  432. vispy/visuals/image.py +701 -0
  433. vispy/visuals/image_complex.py +130 -0
  434. vispy/visuals/infinite_line.py +199 -0
  435. vispy/visuals/instanced_mesh.py +152 -0
  436. vispy/visuals/isocurve.py +213 -0
  437. vispy/visuals/isoline.py +241 -0
  438. vispy/visuals/isosurface.py +113 -0
  439. vispy/visuals/line/__init__.py +6 -0
  440. vispy/visuals/line/arrow.py +289 -0
  441. vispy/visuals/line/dash_atlas.py +90 -0
  442. vispy/visuals/line/line.py +545 -0
  443. vispy/visuals/line_plot.py +135 -0
  444. vispy/visuals/linear_region.py +199 -0
  445. vispy/visuals/markers.py +819 -0
  446. vispy/visuals/mesh.py +373 -0
  447. vispy/visuals/mesh_normals.py +159 -0
  448. vispy/visuals/plane.py +54 -0
  449. vispy/visuals/polygon.py +145 -0
  450. vispy/visuals/rectangle.py +196 -0
  451. vispy/visuals/regular_polygon.py +56 -0
  452. vispy/visuals/scrolling_lines.py +197 -0
  453. vispy/visuals/shaders/__init__.py +17 -0
  454. vispy/visuals/shaders/compiler.py +206 -0
  455. vispy/visuals/shaders/expression.py +99 -0
  456. vispy/visuals/shaders/function.py +788 -0
  457. vispy/visuals/shaders/multiprogram.py +145 -0
  458. vispy/visuals/shaders/parsing.py +140 -0
  459. vispy/visuals/shaders/program.py +161 -0
  460. vispy/visuals/shaders/shader_object.py +162 -0
  461. vispy/visuals/shaders/tests/__init__.py +0 -0
  462. vispy/visuals/shaders/tests/test_function.py +486 -0
  463. vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
  464. vispy/visuals/shaders/tests/test_parsing.py +57 -0
  465. vispy/visuals/shaders/variable.py +272 -0
  466. vispy/visuals/spectrogram.py +169 -0
  467. vispy/visuals/sphere.py +80 -0
  468. vispy/visuals/surface_plot.py +192 -0
  469. vispy/visuals/tests/__init__.py +0 -0
  470. vispy/visuals/tests/test_arrows.py +109 -0
  471. vispy/visuals/tests/test_axis.py +120 -0
  472. vispy/visuals/tests/test_collections.py +15 -0
  473. vispy/visuals/tests/test_colorbar.py +179 -0
  474. vispy/visuals/tests/test_colormap.py +97 -0
  475. vispy/visuals/tests/test_ellipse.py +122 -0
  476. vispy/visuals/tests/test_gridlines.py +30 -0
  477. vispy/visuals/tests/test_histogram.py +24 -0
  478. vispy/visuals/tests/test_image.py +392 -0
  479. vispy/visuals/tests/test_image_complex.py +36 -0
  480. vispy/visuals/tests/test_infinite_line.py +53 -0
  481. vispy/visuals/tests/test_instanced_mesh.py +50 -0
  482. vispy/visuals/tests/test_isosurface.py +22 -0
  483. vispy/visuals/tests/test_linear_region.py +152 -0
  484. vispy/visuals/tests/test_markers.py +54 -0
  485. vispy/visuals/tests/test_mesh.py +261 -0
  486. vispy/visuals/tests/test_mesh_normals.py +218 -0
  487. vispy/visuals/tests/test_polygon.py +112 -0
  488. vispy/visuals/tests/test_rectangle.py +163 -0
  489. vispy/visuals/tests/test_regular_polygon.py +111 -0
  490. vispy/visuals/tests/test_scalable_textures.py +196 -0
  491. vispy/visuals/tests/test_sdf.py +73 -0
  492. vispy/visuals/tests/test_spectrogram.py +42 -0
  493. vispy/visuals/tests/test_surface_plot.py +57 -0
  494. vispy/visuals/tests/test_text.py +95 -0
  495. vispy/visuals/tests/test_volume.py +542 -0
  496. vispy/visuals/tests/test_windbarb.py +33 -0
  497. vispy/visuals/text/__init__.py +7 -0
  498. vispy/visuals/text/_sdf_cpu.cpython-313-darwin.so +0 -0
  499. vispy/visuals/text/_sdf_cpu.pyx +112 -0
  500. vispy/visuals/text/_sdf_gpu.py +316 -0
  501. vispy/visuals/text/text.py +675 -0
  502. vispy/visuals/transforms/__init__.py +34 -0
  503. vispy/visuals/transforms/_util.py +191 -0
  504. vispy/visuals/transforms/base_transform.py +233 -0
  505. vispy/visuals/transforms/chain.py +300 -0
  506. vispy/visuals/transforms/interactive.py +98 -0
  507. vispy/visuals/transforms/linear.py +564 -0
  508. vispy/visuals/transforms/nonlinear.py +398 -0
  509. vispy/visuals/transforms/tests/__init__.py +0 -0
  510. vispy/visuals/transforms/tests/test_transforms.py +243 -0
  511. vispy/visuals/transforms/transform_system.py +339 -0
  512. vispy/visuals/tube.py +173 -0
  513. vispy/visuals/visual.py +923 -0
  514. vispy/visuals/volume.py +1366 -0
  515. vispy/visuals/windbarb.py +291 -0
  516. vispy/visuals/xyz_axis.py +34 -0
  517. vispy-0.15.0.dist-info/METADATA +243 -0
  518. vispy-0.15.0.dist-info/RECORD +521 -0
  519. vispy-0.15.0.dist-info/WHEEL +6 -0
  520. vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
  521. vispy-0.15.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)