ultraplot 0.99.3__py3-none-any.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.
Files changed (416) hide show
  1. ultraplot/__init__.py +115 -0
  2. ultraplot/__init__.py.rej +58 -0
  3. ultraplot/axes/__init__.py +42 -0
  4. ultraplot/axes/base.py +3240 -0
  5. ultraplot/axes/cartesian.py +1425 -0
  6. ultraplot/axes/geo.py +1675 -0
  7. ultraplot/axes/plot.py +4569 -0
  8. ultraplot/axes/polar.py +381 -0
  9. ultraplot/axes/shared.py +186 -0
  10. ultraplot/axes/three.py +34 -0
  11. ultraplot/cmaps/Algae.rgb +256 -0
  12. ultraplot/cmaps/Amp.rgb +256 -0
  13. ultraplot/cmaps/BR.rgb +256 -0
  14. ultraplot/cmaps/Balance.rgb +256 -0
  15. ultraplot/cmaps/Blues1_r.xml +17 -0
  16. ultraplot/cmaps/Blues2.xml +16 -0
  17. ultraplot/cmaps/Blues3.xml +25 -0
  18. ultraplot/cmaps/Blues4_r.xml +17 -0
  19. ultraplot/cmaps/Blues5.xml +16 -0
  20. ultraplot/cmaps/Blues6.xml +25 -0
  21. ultraplot/cmaps/Blues7.xml +16 -0
  22. ultraplot/cmaps/Blues8.xml +17 -0
  23. ultraplot/cmaps/Blues9.xml +1 -0
  24. ultraplot/cmaps/Boreal.json +53 -0
  25. ultraplot/cmaps/Browns1.xml +16 -0
  26. ultraplot/cmaps/Browns2.xml +26 -0
  27. ultraplot/cmaps/Browns3.xml +17 -0
  28. ultraplot/cmaps/Browns4.xml +17 -0
  29. ultraplot/cmaps/Browns5.xml +26 -0
  30. ultraplot/cmaps/Browns6.xml +17 -0
  31. ultraplot/cmaps/Browns7.xml +19 -0
  32. ultraplot/cmaps/Browns8.xml +11 -0
  33. ultraplot/cmaps/Browns9.xml +1 -0
  34. ultraplot/cmaps/ColdHot.rgb +229 -0
  35. ultraplot/cmaps/Crest.rgb +256 -0
  36. ultraplot/cmaps/Curl.rgb +512 -0
  37. ultraplot/cmaps/Deep.rgb +256 -0
  38. ultraplot/cmaps/Delta.rgb +512 -0
  39. ultraplot/cmaps/Dense.rgb +256 -0
  40. ultraplot/cmaps/Div.json +71 -0
  41. ultraplot/cmaps/DryWet.json +73 -0
  42. ultraplot/cmaps/Dusk.json +53 -0
  43. ultraplot/cmaps/Fire.json +53 -0
  44. ultraplot/cmaps/Flare.rgb +256 -0
  45. ultraplot/cmaps/Glacial.json +53 -0
  46. ultraplot/cmaps/Greens1_r.xml +26 -0
  47. ultraplot/cmaps/Greens2.xml +28 -0
  48. ultraplot/cmaps/Greens3_r.xml +28 -0
  49. ultraplot/cmaps/Greens4.xml +17 -0
  50. ultraplot/cmaps/Greens5.xml +16 -0
  51. ultraplot/cmaps/Greens6_r.xml +16 -0
  52. ultraplot/cmaps/Greens7.xml +16 -0
  53. ultraplot/cmaps/Greens8.xml +26 -0
  54. ultraplot/cmaps/Haline.rgb +256 -0
  55. ultraplot/cmaps/Ice.rgb +256 -0
  56. ultraplot/cmaps/IceFire.rgb +256 -0
  57. ultraplot/cmaps/Mako.rgb +256 -0
  58. ultraplot/cmaps/Marine.json +53 -0
  59. ultraplot/cmaps/Matter.rgb +256 -0
  60. ultraplot/cmaps/Mono.txt +256 -0
  61. ultraplot/cmaps/MonoCycle.txt +256 -0
  62. ultraplot/cmaps/NegPos.json +71 -0
  63. ultraplot/cmaps/Oranges1.xml +27 -0
  64. ultraplot/cmaps/Oranges2.xml +26 -0
  65. ultraplot/cmaps/Oranges3.xml +15 -0
  66. ultraplot/cmaps/Oranges4.xml +23 -0
  67. ultraplot/cmaps/Oxy.rgb +256 -0
  68. ultraplot/cmaps/Phase.rgb +256 -0
  69. ultraplot/cmaps/Purples1_r.xml +16 -0
  70. ultraplot/cmaps/Purples2.xml +17 -0
  71. ultraplot/cmaps/Purples3.xml +18 -0
  72. ultraplot/cmaps/Reds1.xml +26 -0
  73. ultraplot/cmaps/Reds2.xml +22 -0
  74. ultraplot/cmaps/Reds3.xml +23 -0
  75. ultraplot/cmaps/Reds4.xml +26 -0
  76. ultraplot/cmaps/Reds5.xml +17 -0
  77. ultraplot/cmaps/Rocket.rgb +256 -0
  78. ultraplot/cmaps/Solar.rgb +256 -0
  79. ultraplot/cmaps/Speed.rgb +256 -0
  80. ultraplot/cmaps/Stellar.json +53 -0
  81. ultraplot/cmaps/Sunrise.json +53 -0
  82. ultraplot/cmaps/Sunset.json +53 -0
  83. ultraplot/cmaps/Tempo.rgb +256 -0
  84. ultraplot/cmaps/Thermal.rgb +256 -0
  85. ultraplot/cmaps/Turbid.rgb +256 -0
  86. ultraplot/cmaps/Vivid.xml +11 -0
  87. ultraplot/cmaps/Vlag.rgb +256 -0
  88. ultraplot/cmaps/Yellows1.xml +17 -0
  89. ultraplot/cmaps/Yellows2.xml +17 -0
  90. ultraplot/cmaps/Yellows3.xml +17 -0
  91. ultraplot/cmaps/Yellows4.xml +17 -0
  92. ultraplot/cmaps/acton.txt +256 -0
  93. ultraplot/cmaps/bam.txt +256 -0
  94. ultraplot/cmaps/bamO.txt +256 -0
  95. ultraplot/cmaps/bamako.txt +256 -0
  96. ultraplot/cmaps/batlow.txt +256 -0
  97. ultraplot/cmaps/batlowK.txt +256 -0
  98. ultraplot/cmaps/batlowW.txt +256 -0
  99. ultraplot/cmaps/berlin.txt +256 -0
  100. ultraplot/cmaps/bilbao.txt +256 -0
  101. ultraplot/cmaps/broc.txt +256 -0
  102. ultraplot/cmaps/brocO.txt +256 -0
  103. ultraplot/cmaps/buda.txt +256 -0
  104. ultraplot/cmaps/bukavu.txt +256 -0
  105. ultraplot/cmaps/cork.txt +256 -0
  106. ultraplot/cmaps/corkO.txt +256 -0
  107. ultraplot/cmaps/davos.txt +256 -0
  108. ultraplot/cmaps/devon.txt +256 -0
  109. ultraplot/cmaps/fes.txt +256 -0
  110. ultraplot/cmaps/hawaii.txt +256 -0
  111. ultraplot/cmaps/imola.txt +256 -0
  112. ultraplot/cmaps/lajolla.txt +256 -0
  113. ultraplot/cmaps/lapaz.txt +256 -0
  114. ultraplot/cmaps/lisbon.txt +256 -0
  115. ultraplot/cmaps/nuuk.txt +256 -0
  116. ultraplot/cmaps/oleron.txt +256 -0
  117. ultraplot/cmaps/oslo.txt +256 -0
  118. ultraplot/cmaps/roma.txt +256 -0
  119. ultraplot/cmaps/romaO.txt +256 -0
  120. ultraplot/cmaps/tofino.txt +256 -0
  121. ultraplot/cmaps/tokyo.txt +256 -0
  122. ultraplot/cmaps/turku.txt +256 -0
  123. ultraplot/cmaps/vanimo.txt +256 -0
  124. ultraplot/cmaps/vik.txt +256 -0
  125. ultraplot/cmaps/vikO.txt +256 -0
  126. ultraplot/colors/opencolor.txt +132 -0
  127. ultraplot/colors/xkcd.txt +951 -0
  128. ultraplot/colors.py +3241 -0
  129. ultraplot/colors.py.rej +243 -0
  130. ultraplot/config.py +1809 -0
  131. ultraplot/constructor.py +1633 -0
  132. ultraplot/cycles/538.hex +2 -0
  133. ultraplot/cycles/FlatUI.hex +1 -0
  134. ultraplot/cycles/Qual1.rgb +7 -0
  135. ultraplot/cycles/Qual2.rgb +13 -0
  136. ultraplot/cycles/bmh.hex +2 -0
  137. ultraplot/cycles/classic.hex +2 -0
  138. ultraplot/cycles/colorblind.hex +2 -0
  139. ultraplot/cycles/colorblind10.hex +2 -0
  140. ultraplot/cycles/default.hex +2 -0
  141. ultraplot/cycles/ggplot.hex +1 -0
  142. ultraplot/cycles/seaborn.hex +2 -0
  143. ultraplot/cycles/tableau.hex +2 -0
  144. ultraplot/demos.py +1201 -0
  145. ultraplot/externals/__init__.py +5 -0
  146. ultraplot/externals/hsluv.py +330 -0
  147. ultraplot/figure.py +2102 -0
  148. ultraplot/fonts/FiraMath-Bold.ttf +0 -0
  149. ultraplot/fonts/FiraMath-ExtraLight.ttf +0 -0
  150. ultraplot/fonts/FiraMath-Heavy.ttf +0 -0
  151. ultraplot/fonts/FiraMath-Light.ttf +0 -0
  152. ultraplot/fonts/FiraMath-Medium.ttf +0 -0
  153. ultraplot/fonts/FiraMath-Regular.ttf +0 -0
  154. ultraplot/fonts/FiraMath-SemiBold.ttf +0 -0
  155. ultraplot/fonts/FiraMath-UltraLight.ttf +0 -0
  156. ultraplot/fonts/FiraSans-Black.ttf +0 -0
  157. ultraplot/fonts/FiraSans-BlackItalic.ttf +0 -0
  158. ultraplot/fonts/FiraSans-Bold.ttf +0 -0
  159. ultraplot/fonts/FiraSans-BoldItalic.ttf +0 -0
  160. ultraplot/fonts/FiraSans-ExtraBold.ttf +0 -0
  161. ultraplot/fonts/FiraSans-ExtraBoldItalic.ttf +0 -0
  162. ultraplot/fonts/FiraSans-ExtraLight.ttf +0 -0
  163. ultraplot/fonts/FiraSans-ExtraLightItalic.ttf +0 -0
  164. ultraplot/fonts/FiraSans-Italic.ttf +0 -0
  165. ultraplot/fonts/FiraSans-Light.ttf +0 -0
  166. ultraplot/fonts/FiraSans-LightItalic.ttf +0 -0
  167. ultraplot/fonts/FiraSans-Medium.ttf +0 -0
  168. ultraplot/fonts/FiraSans-MediumItalic.ttf +0 -0
  169. ultraplot/fonts/FiraSans-Regular.ttf +0 -0
  170. ultraplot/fonts/FiraSans-SemiBold.ttf +0 -0
  171. ultraplot/fonts/FiraSans-SemiBoldItalic.ttf +0 -0
  172. ultraplot/fonts/LICENSE_FIRAMATH.txt +92 -0
  173. ultraplot/fonts/LICENSE_FIRASANS.txt +97 -0
  174. ultraplot/fonts/LICENSE_NOTOSANS.txt +202 -0
  175. ultraplot/fonts/LICENSE_NOTOSERIF.txt +93 -0
  176. ultraplot/fonts/LICENSE_OPENSANS.txt +202 -0
  177. ultraplot/fonts/LICENSE_ROBOTO.txt +202 -0
  178. ultraplot/fonts/LICENSE_SOURCESANS.txt +93 -0
  179. ultraplot/fonts/LICENSE_SOURCESERIF.txt +93 -0
  180. ultraplot/fonts/LICENSE_TEXGYRE.txt +29 -0
  181. ultraplot/fonts/LICENSE_UBUNTU.txt +96 -0
  182. ultraplot/fonts/NotoSans-Bold.ttf +0 -0
  183. ultraplot/fonts/NotoSans-BoldItalic.ttf +0 -0
  184. ultraplot/fonts/NotoSans-Italic.ttf +0 -0
  185. ultraplot/fonts/NotoSans-Regular.ttf +0 -0
  186. ultraplot/fonts/NotoSerif-Bold.ttf +0 -0
  187. ultraplot/fonts/NotoSerif-BoldItalic.ttf +0 -0
  188. ultraplot/fonts/NotoSerif-Italic.ttf +0 -0
  189. ultraplot/fonts/NotoSerif-Regular.ttf +0 -0
  190. ultraplot/fonts/OpenSans-Bold.ttf +0 -0
  191. ultraplot/fonts/OpenSans-BoldItalic.ttf +0 -0
  192. ultraplot/fonts/OpenSans-Italic.ttf +0 -0
  193. ultraplot/fonts/OpenSans-Regular.ttf +0 -0
  194. ultraplot/fonts/OpenSans-Semibold.ttf +0 -0
  195. ultraplot/fonts/OpenSans-SemiboldItalic.ttf +0 -0
  196. ultraplot/fonts/Roboto-Black.ttf +0 -0
  197. ultraplot/fonts/Roboto-BlackItalic.ttf +0 -0
  198. ultraplot/fonts/Roboto-Bold.ttf +0 -0
  199. ultraplot/fonts/Roboto-BoldItalic.ttf +0 -0
  200. ultraplot/fonts/Roboto-Italic.ttf +0 -0
  201. ultraplot/fonts/Roboto-Light.ttf +0 -0
  202. ultraplot/fonts/Roboto-LightItalic.ttf +0 -0
  203. ultraplot/fonts/Roboto-Medium.ttf +0 -0
  204. ultraplot/fonts/Roboto-MediumItalic.ttf +0 -0
  205. ultraplot/fonts/Roboto-Regular.ttf +0 -0
  206. ultraplot/fonts/SourceSansPro-Black.ttf +0 -0
  207. ultraplot/fonts/SourceSansPro-BlackItalic.ttf +0 -0
  208. ultraplot/fonts/SourceSansPro-Bold.ttf +0 -0
  209. ultraplot/fonts/SourceSansPro-BoldItalic.ttf +0 -0
  210. ultraplot/fonts/SourceSansPro-ExtraLight.ttf +0 -0
  211. ultraplot/fonts/SourceSansPro-ExtraLightItalic.ttf +0 -0
  212. ultraplot/fonts/SourceSansPro-Italic.ttf +0 -0
  213. ultraplot/fonts/SourceSansPro-Light.ttf +0 -0
  214. ultraplot/fonts/SourceSansPro-LightItalic.ttf +0 -0
  215. ultraplot/fonts/SourceSansPro-Regular.ttf +0 -0
  216. ultraplot/fonts/SourceSansPro-SemiBold.ttf +0 -0
  217. ultraplot/fonts/SourceSansPro-SemiBoldItalic.ttf +0 -0
  218. ultraplot/fonts/SourceSerifPro-Black.ttf +0 -0
  219. ultraplot/fonts/SourceSerifPro-BlackItalic.ttf +0 -0
  220. ultraplot/fonts/SourceSerifPro-Bold.ttf +0 -0
  221. ultraplot/fonts/SourceSerifPro-BoldItalic.ttf +0 -0
  222. ultraplot/fonts/SourceSerifPro-ExtraLight.ttf +0 -0
  223. ultraplot/fonts/SourceSerifPro-ExtraLightItalic.ttf +0 -0
  224. ultraplot/fonts/SourceSerifPro-Italic.ttf +0 -0
  225. ultraplot/fonts/SourceSerifPro-Light.ttf +0 -0
  226. ultraplot/fonts/SourceSerifPro-LightItalic.ttf +0 -0
  227. ultraplot/fonts/SourceSerifPro-Regular.ttf +0 -0
  228. ultraplot/fonts/SourceSerifPro-SemiBold.ttf +0 -0
  229. ultraplot/fonts/SourceSerifPro-SemiBoldItalic.ttf +0 -0
  230. ultraplot/fonts/Ubuntu-Bold.ttf +0 -0
  231. ultraplot/fonts/Ubuntu-BoldItalic.ttf +0 -0
  232. ultraplot/fonts/Ubuntu-Italic.ttf +0 -0
  233. ultraplot/fonts/Ubuntu-Light.ttf +0 -0
  234. ultraplot/fonts/Ubuntu-LightItalic.ttf +0 -0
  235. ultraplot/fonts/Ubuntu-Medium.ttf +0 -0
  236. ultraplot/fonts/Ubuntu-MediumItalic.ttf +0 -0
  237. ultraplot/fonts/Ubuntu-Regular.ttf +0 -0
  238. ultraplot/fonts/texgyreadventor-bold.ttf +0 -0
  239. ultraplot/fonts/texgyreadventor-bolditalic.ttf +0 -0
  240. ultraplot/fonts/texgyreadventor-italic.ttf +0 -0
  241. ultraplot/fonts/texgyreadventor-regular.ttf +0 -0
  242. ultraplot/fonts/texgyrebonum-bold.ttf +0 -0
  243. ultraplot/fonts/texgyrebonum-bolditalic.ttf +0 -0
  244. ultraplot/fonts/texgyrebonum-italic.ttf +0 -0
  245. ultraplot/fonts/texgyrebonum-regular.ttf +0 -0
  246. ultraplot/fonts/texgyrechorus-mediumitalic.ttf +0 -0
  247. ultraplot/fonts/texgyrecursor-bold.ttf +0 -0
  248. ultraplot/fonts/texgyrecursor-bolditalic.ttf +0 -0
  249. ultraplot/fonts/texgyrecursor-italic.ttf +0 -0
  250. ultraplot/fonts/texgyrecursor-regular.ttf +0 -0
  251. ultraplot/fonts/texgyreheros-bold.ttf +0 -0
  252. ultraplot/fonts/texgyreheros-bolditalic.ttf +0 -0
  253. ultraplot/fonts/texgyreheros-italic.ttf +0 -0
  254. ultraplot/fonts/texgyreheros-regular.ttf +0 -0
  255. ultraplot/fonts/texgyrepagella-bold.ttf +0 -0
  256. ultraplot/fonts/texgyrepagella-bolditalic.ttf +0 -0
  257. ultraplot/fonts/texgyrepagella-italic.ttf +0 -0
  258. ultraplot/fonts/texgyrepagella-regular.ttf +0 -0
  259. ultraplot/fonts/texgyreschola-bold.ttf +0 -0
  260. ultraplot/fonts/texgyreschola-bolditalic.ttf +0 -0
  261. ultraplot/fonts/texgyreschola-italic.ttf +0 -0
  262. ultraplot/fonts/texgyreschola-regular.ttf +0 -0
  263. ultraplot/fonts/texgyretermes-bold.ttf +0 -0
  264. ultraplot/fonts/texgyretermes-bolditalic.ttf +0 -0
  265. ultraplot/fonts/texgyretermes-italic.ttf +0 -0
  266. ultraplot/fonts/texgyretermes-regular.ttf +0 -0
  267. ultraplot/gridspec.py +1698 -0
  268. ultraplot/internals/__init__.py +529 -0
  269. ultraplot/internals/benchmarks.py +26 -0
  270. ultraplot/internals/context.py +44 -0
  271. ultraplot/internals/docstring.py +139 -0
  272. ultraplot/internals/fonts.py +75 -0
  273. ultraplot/internals/guides.py +167 -0
  274. ultraplot/internals/inputs.py +862 -0
  275. ultraplot/internals/labels.py +85 -0
  276. ultraplot/internals/rcsetup.py +1933 -0
  277. ultraplot/internals/versions.py +61 -0
  278. ultraplot/internals/warnings.py +122 -0
  279. ultraplot/proj.py +325 -0
  280. ultraplot/scale.py +966 -0
  281. ultraplot/tests/__init__.py +28 -0
  282. ultraplot/tests/baseline/test_align_labels.png +0 -0
  283. ultraplot/tests/baseline/test_aligned_outer_guides.png +0 -0
  284. ultraplot/tests/baseline/test_aspect_ratios.png +0 -0
  285. ultraplot/tests/baseline/test_auto_diverging1.png +0 -0
  286. ultraplot/tests/baseline/test_auto_legend.png +0 -0
  287. ultraplot/tests/baseline/test_auto_reverse.png +0 -0
  288. ultraplot/tests/baseline/test_autodiverging3.png +0 -0
  289. ultraplot/tests/baseline/test_autodiverging4.png +0 -0
  290. ultraplot/tests/baseline/test_autodiverging5.png +0 -0
  291. ultraplot/tests/baseline/test_axes_colors.png +0 -0
  292. ultraplot/tests/baseline/test_bar_vectors.png +0 -0
  293. ultraplot/tests/baseline/test_bar_width.png +0 -0
  294. ultraplot/tests/baseline/test_both_ticklabels.png +0 -0
  295. ultraplot/tests/baseline/test_bounds_ticks.png +0 -0
  296. ultraplot/tests/baseline/test_boxplot_colors.png +0 -0
  297. ultraplot/tests/baseline/test_boxplot_vectors.png +0 -0
  298. ultraplot/tests/baseline/test_cartopy_contours.png +0 -0
  299. ultraplot/tests/baseline/test_cartopy_labels.png +0 -0
  300. ultraplot/tests/baseline/test_cartopy_manual.png +0 -0
  301. ultraplot/tests/baseline/test_centered_legends.png +0 -0
  302. ultraplot/tests/baseline/test_cmap_cycles.png +0 -0
  303. ultraplot/tests/baseline/test_colorbar.png +0 -0
  304. ultraplot/tests/baseline/test_colorbar_ticks.png +0 -0
  305. ultraplot/tests/baseline/test_colormap_mode.png +0 -0
  306. ultraplot/tests/baseline/test_column_iteration.png +0 -0
  307. ultraplot/tests/baseline/test_complex_ticks.png +0 -0
  308. ultraplot/tests/baseline/test_contour_labels.png +0 -0
  309. ultraplot/tests/baseline/test_contour_legend_with_label.png +0 -0
  310. ultraplot/tests/baseline/test_contour_legend_without_label.png +0 -0
  311. ultraplot/tests/baseline/test_contour_negative.png +0 -0
  312. ultraplot/tests/baseline/test_contour_single.png +0 -0
  313. ultraplot/tests/baseline/test_cutoff_ticks.png +0 -0
  314. ultraplot/tests/baseline/test_data_keyword.png +0 -0
  315. ultraplot/tests/baseline/test_discrete_ticks.png +0 -0
  316. ultraplot/tests/baseline/test_discrete_vs_fixed.png +0 -0
  317. ultraplot/tests/baseline/test_drawing_in_projection_with_globe.png +0 -0
  318. ultraplot/tests/baseline/test_drawing_in_projection_without_globe.png +0 -0
  319. ultraplot/tests/baseline/test_edge_fix.png +0 -0
  320. ultraplot/tests/baseline/test_flow_functions.png +0 -0
  321. ultraplot/tests/baseline/test_font_adjustments.png +0 -0
  322. ultraplot/tests/baseline/test_geographic_multiple_projections.png +0 -0
  323. ultraplot/tests/baseline/test_geographic_single_projection.png +0 -0
  324. ultraplot/tests/baseline/test_gray_adjustment.png +0 -0
  325. ultraplot/tests/baseline/test_histogram_legend.png +0 -0
  326. ultraplot/tests/baseline/test_histogram_types.png +0 -0
  327. ultraplot/tests/baseline/test_ignore_message.png +0 -0
  328. ultraplot/tests/baseline/test_inbounds_data.png +0 -0
  329. ultraplot/tests/baseline/test_init_format.png +0 -0
  330. ultraplot/tests/baseline/test_inner_title_zorder.png +0 -0
  331. ultraplot/tests/baseline/test_inset_basic.png +0 -0
  332. ultraplot/tests/baseline/test_inset_colorbars.png +0 -0
  333. ultraplot/tests/baseline/test_inset_colors_1.png +0 -0
  334. ultraplot/tests/baseline/test_inset_colors_2.png +0 -0
  335. ultraplot/tests/baseline/test_inset_zoom_update.png +0 -0
  336. ultraplot/tests/baseline/test_invalid_dist.png +0 -0
  337. ultraplot/tests/baseline/test_invalid_plot.png +0 -0
  338. ultraplot/tests/baseline/test_keep_guide_labels.png +0 -0
  339. ultraplot/tests/baseline/test_label_settings.png +0 -0
  340. ultraplot/tests/baseline/test_level_restriction.png +0 -0
  341. ultraplot/tests/baseline/test_levels_with_vmin_vmax.png +0 -0
  342. ultraplot/tests/baseline/test_locale_formatting.png +0 -0
  343. ultraplot/tests/baseline/test_locale_formatting_en_US.UTF-8.png +0 -0
  344. ultraplot/tests/baseline/test_manual_labels.png +0 -0
  345. ultraplot/tests/baseline/test_multi_formatting.png +0 -0
  346. ultraplot/tests/baseline/test_multiple_calls.png +0 -0
  347. ultraplot/tests/baseline/test_on_the_fly_mappable.png +0 -0
  348. ultraplot/tests/baseline/test_outer_align.png +0 -0
  349. ultraplot/tests/baseline/test_panel_dist.png +0 -0
  350. ultraplot/tests/baseline/test_panels_suplabels_three_hor_panels.png +0 -0
  351. ultraplot/tests/baseline/test_panels_with_sharing.png +0 -0
  352. ultraplot/tests/baseline/test_panels_without_sharing_1.png +0 -0
  353. ultraplot/tests/baseline/test_panels_without_sharing_2.png +0 -0
  354. ultraplot/tests/baseline/test_parametric_colors.png +0 -0
  355. ultraplot/tests/baseline/test_parametric_labels.png +0 -0
  356. ultraplot/tests/baseline/test_patch_format.png +0 -0
  357. ultraplot/tests/baseline/test_pie_charts.png +0 -0
  358. ultraplot/tests/baseline/test_pint_quantities.png +0 -0
  359. ultraplot/tests/baseline/test_polar_projections.png +0 -0
  360. ultraplot/tests/baseline/test_projection_dicts.png +0 -0
  361. ultraplot/tests/baseline/test_qualitative_colormaps_1.png +0 -0
  362. ultraplot/tests/baseline/test_qualitative_colormaps_2.png +0 -0
  363. ultraplot/tests/baseline/test_reversed_levels.png +0 -0
  364. ultraplot/tests/baseline/test_scatter_alpha.png +0 -0
  365. ultraplot/tests/baseline/test_scatter_args.png +0 -0
  366. ultraplot/tests/baseline/test_scatter_cycle.png +0 -0
  367. ultraplot/tests/baseline/test_scatter_inbounds.png +0 -0
  368. ultraplot/tests/baseline/test_scatter_sizes.png +0 -0
  369. ultraplot/tests/baseline/test_seaborn_heatmap.png +0 -0
  370. ultraplot/tests/baseline/test_seaborn_hist.png +0 -0
  371. ultraplot/tests/baseline/test_seaborn_relational.png +0 -0
  372. ultraplot/tests/baseline/test_seaborn_swarmplot.png +0 -0
  373. ultraplot/tests/baseline/test_segmented_norm.png +0 -0
  374. ultraplot/tests/baseline/test_segmented_norm_ticks.png +0 -0
  375. ultraplot/tests/baseline/test_share_all_basic.png +0 -0
  376. ultraplot/tests/baseline/test_singleton_legend.png +0 -0
  377. ultraplot/tests/baseline/test_span_labels.png +0 -0
  378. ultraplot/tests/baseline/test_spine_offset.png +0 -0
  379. ultraplot/tests/baseline/test_spine_side.png +0 -0
  380. ultraplot/tests/baseline/test_standardized_input.png +0 -0
  381. ultraplot/tests/baseline/test_statistical_boxplot.png +0 -0
  382. ultraplot/tests/baseline/test_three_axes.png +0 -0
  383. ultraplot/tests/baseline/test_tick_direction.png +0 -0
  384. ultraplot/tests/baseline/test_tick_labels.png +0 -0
  385. ultraplot/tests/baseline/test_tick_length.png +0 -0
  386. ultraplot/tests/baseline/test_tick_width.png +0 -0
  387. ultraplot/tests/baseline/test_title_deflection.png +0 -0
  388. ultraplot/tests/baseline/test_triangular_functions.png +0 -0
  389. ultraplot/tests/baseline/test_tuple_handles.png +0 -0
  390. ultraplot/tests/baseline/test_twin_axes_1.png +0 -0
  391. ultraplot/tests/baseline/test_twin_axes_2.png +0 -0
  392. ultraplot/tests/baseline/test_twin_axes_3.png +0 -0
  393. ultraplot/tests/baseline/test_uneven_levels.png +0 -0
  394. ultraplot/tests/test_1dplots.py +373 -0
  395. ultraplot/tests/test_2dplots.py +354 -0
  396. ultraplot/tests/test_axes.py +179 -0
  397. ultraplot/tests/test_colorbar.py +253 -0
  398. ultraplot/tests/test_docs.py +78 -0
  399. ultraplot/tests/test_format.py +340 -0
  400. ultraplot/tests/test_geographic.py +116 -0
  401. ultraplot/tests/test_imshow.py +110 -0
  402. ultraplot/tests/test_inset.py +28 -0
  403. ultraplot/tests/test_integration.py +149 -0
  404. ultraplot/tests/test_legend.py +181 -0
  405. ultraplot/tests/test_projections.py +138 -0
  406. ultraplot/tests/test_statistical_plotting.py +77 -0
  407. ultraplot/tests/test_subplots.py +174 -0
  408. ultraplot/ticker.py +879 -0
  409. ultraplot/ui.py +233 -0
  410. ultraplot/utils.py +912 -0
  411. ultraplot-0.99.3.dist-info/LICENSE.txt +427 -0
  412. ultraplot-0.99.3.dist-info/METADATA +88 -0
  413. ultraplot-0.99.3.dist-info/RECORD +416 -0
  414. ultraplot-0.99.3.dist-info/WHEEL +5 -0
  415. ultraplot-0.99.3.dist-info/entry_points.txt +2 -0
  416. ultraplot-0.99.3.dist-info/top_level.txt +1 -0
ultraplot/demos.py ADDED
@@ -0,0 +1,1201 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Functions for displaying colors and fonts.
4
+ """
5
+ import os
6
+ import re
7
+
8
+ import cycler
9
+ import matplotlib.colors as mcolors
10
+ import matplotlib.font_manager as mfonts
11
+ import numpy as np
12
+
13
+ from . import colors as pcolors
14
+ from . import constructor, ui
15
+ from .config import _get_data_folders, rc
16
+ from .internals import ic # noqa: F401
17
+ from .internals import _not_none, _version_mpl, docstring, warnings
18
+ from .utils import to_rgb, to_xyz
19
+
20
+ __all__ = [
21
+ "show_cmaps",
22
+ "show_channels",
23
+ "show_colors",
24
+ "show_colorspaces",
25
+ "show_cycles",
26
+ "show_fonts",
27
+ ]
28
+
29
+
30
+ # Tables and constants
31
+ FAMILY_TEXGYRE = (
32
+ "TeX Gyre Heros", # sans-serif
33
+ "TeX Gyre Schola", # serif
34
+ "TeX Gyre Bonum",
35
+ "TeX Gyre Termes",
36
+ "TeX Gyre Pagella",
37
+ "TeX Gyre Chorus", # cursive
38
+ "TeX Gyre Adventor", # fantasy
39
+ "TeX Gyre Cursor", # monospace
40
+ )
41
+ COLOR_TABLE = {
42
+ # NOTE: Just want the names but point to the dictionaries because
43
+ # they don't get filled until after __init__ imports this module.
44
+ "base": mcolors.BASE_COLORS,
45
+ "css4": mcolors.CSS4_COLORS,
46
+ "opencolor": pcolors.COLORS_OPEN,
47
+ "xkcd": pcolors.COLORS_XKCD,
48
+ }
49
+ CYCLE_TABLE = {
50
+ "Matplotlib defaults": (
51
+ "default",
52
+ "classic",
53
+ ),
54
+ "Matplotlib stylesheets": (
55
+ # NOTE: Do not include 'solarized' because colors are terrible for
56
+ # colorblind folks.
57
+ "colorblind",
58
+ "colorblind10",
59
+ "tableau",
60
+ "ggplot",
61
+ "538",
62
+ "seaborn",
63
+ "bmh",
64
+ ),
65
+ "ColorBrewer2.0 qualitative": (
66
+ "Accent",
67
+ "Dark2",
68
+ "Paired",
69
+ "Pastel1",
70
+ "Pastel2",
71
+ "Set1",
72
+ "Set2",
73
+ "Set3",
74
+ "tab10",
75
+ "tab20",
76
+ "tab20b",
77
+ "tab20c",
78
+ ),
79
+ "Other qualitative": (
80
+ "FlatUI",
81
+ "Qual1",
82
+ "Qual2",
83
+ ),
84
+ }
85
+ CMAP_TABLE = {
86
+ # NOTE: No longer rename colorbrewer greys map, just redirect 'grays'
87
+ # to 'greys' in colormap database.
88
+ "Grayscale": ( # assorted origin, but they belong together
89
+ "Greys",
90
+ "Mono",
91
+ "MonoCycle",
92
+ ),
93
+ "Matplotlib sequential": (
94
+ "viridis",
95
+ "plasma",
96
+ "inferno",
97
+ "magma",
98
+ "cividis",
99
+ ),
100
+ "Matplotlib cyclic": ("twilight",),
101
+ "Seaborn sequential": (
102
+ "Rocket",
103
+ "Flare",
104
+ "Mako",
105
+ "Crest",
106
+ ),
107
+ "Seaborn diverging": (
108
+ "IceFire",
109
+ "Vlag",
110
+ ),
111
+ "ultraplot sequential": (
112
+ "Fire",
113
+ "Stellar",
114
+ "Glacial",
115
+ "Dusk",
116
+ "Marine",
117
+ "Boreal",
118
+ "Sunrise",
119
+ "Sunset",
120
+ ),
121
+ "ultraplot diverging": (
122
+ "Div",
123
+ "NegPos",
124
+ "DryWet",
125
+ ),
126
+ "Other sequential": ("cubehelix", "turbo"),
127
+ "Other diverging": (
128
+ "BR",
129
+ "ColdHot",
130
+ "CoolWarm",
131
+ ),
132
+ "cmOcean sequential": (
133
+ "Oxy",
134
+ "Thermal",
135
+ "Dense",
136
+ "Ice",
137
+ "Haline",
138
+ "Deep",
139
+ "Algae",
140
+ "Tempo",
141
+ "Speed",
142
+ "Turbid",
143
+ "Solar",
144
+ "Matter",
145
+ "Amp",
146
+ ),
147
+ "cmOcean diverging": (
148
+ "Balance",
149
+ "Delta",
150
+ "Curl",
151
+ ),
152
+ "cmOcean cyclic": ("Phase",),
153
+ "Scientific colour maps sequential": (
154
+ "batlow",
155
+ "batlowK",
156
+ "batlowW",
157
+ "devon",
158
+ "davos",
159
+ "oslo",
160
+ "lapaz",
161
+ "acton",
162
+ "lajolla",
163
+ "bilbao",
164
+ "tokyo",
165
+ "turku",
166
+ "bamako",
167
+ "nuuk",
168
+ "hawaii",
169
+ "buda",
170
+ "imola",
171
+ "oleron",
172
+ "bukavu",
173
+ "fes",
174
+ ),
175
+ "Scientific colour maps diverging": (
176
+ "roma",
177
+ "broc",
178
+ "cork",
179
+ "vik",
180
+ "bam",
181
+ "lisbon",
182
+ "tofino",
183
+ "berlin",
184
+ "vanimo",
185
+ ),
186
+ "Scientific colour maps cyclic": (
187
+ "romaO",
188
+ "brocO",
189
+ "corkO",
190
+ "vikO",
191
+ "bamO",
192
+ ),
193
+ "ColorBrewer2.0 sequential": (
194
+ "Purples",
195
+ "Blues",
196
+ "Greens",
197
+ "Oranges",
198
+ "Reds",
199
+ "YlOrBr",
200
+ "YlOrRd",
201
+ "OrRd",
202
+ "PuRd",
203
+ "RdPu",
204
+ "BuPu",
205
+ "PuBu",
206
+ "PuBuGn",
207
+ "BuGn",
208
+ "GnBu",
209
+ "YlGnBu",
210
+ "YlGn",
211
+ ),
212
+ "ColorBrewer2.0 diverging": (
213
+ "Spectral",
214
+ "PiYG",
215
+ "PRGn",
216
+ "BrBG",
217
+ "PuOr",
218
+ "RdGY",
219
+ "RdBu",
220
+ "RdYlBu",
221
+ "RdYlGn",
222
+ ),
223
+ "SciVisColor blues": (
224
+ "Blues1",
225
+ "Blues2",
226
+ "Blues3",
227
+ "Blues4",
228
+ "Blues5",
229
+ "Blues6",
230
+ "Blues7",
231
+ "Blues8",
232
+ "Blues9",
233
+ "Blues10",
234
+ "Blues11",
235
+ ),
236
+ "SciVisColor greens": (
237
+ "Greens1",
238
+ "Greens2",
239
+ "Greens3",
240
+ "Greens4",
241
+ "Greens5",
242
+ "Greens6",
243
+ "Greens7",
244
+ "Greens8",
245
+ ),
246
+ "SciVisColor yellows": (
247
+ "Yellows1",
248
+ "Yellows2",
249
+ "Yellows3",
250
+ "Yellows4",
251
+ ),
252
+ "SciVisColor oranges": (
253
+ "Oranges1",
254
+ "Oranges2",
255
+ "Oranges3",
256
+ "Oranges4",
257
+ ),
258
+ "SciVisColor browns": (
259
+ "Browns1",
260
+ "Browns2",
261
+ "Browns3",
262
+ "Browns4",
263
+ "Browns5",
264
+ "Browns6",
265
+ "Browns7",
266
+ "Browns8",
267
+ "Browns9",
268
+ ),
269
+ "SciVisColor reds": (
270
+ "Reds1",
271
+ "Reds2",
272
+ "Reds3",
273
+ "Reds4",
274
+ "Reds5",
275
+ ),
276
+ "SciVisColor purples": (
277
+ "Purples1",
278
+ "Purples2",
279
+ "Purples3",
280
+ ),
281
+ # Builtin colormaps that re hidden by default. Some are really bad, some
282
+ # are segmented maps that should be cycles, and some are just uninspiring.
283
+ "MATLAB": (
284
+ "bone",
285
+ "cool",
286
+ "copper",
287
+ "autumn",
288
+ "flag",
289
+ "prism",
290
+ "jet",
291
+ "hsv",
292
+ "hot",
293
+ "spring",
294
+ "summer",
295
+ "winter",
296
+ "pink",
297
+ "gray",
298
+ ),
299
+ "GNUplot": (
300
+ "gnuplot",
301
+ "gnuplot2",
302
+ "ocean",
303
+ "afmhot",
304
+ "rainbow",
305
+ ),
306
+ "GIST": (
307
+ "gist_earth",
308
+ "gist_gray",
309
+ "gist_heat",
310
+ "gist_ncar",
311
+ "gist_rainbow",
312
+ "gist_stern",
313
+ "gist_yarg",
314
+ ),
315
+ "Other": (
316
+ "binary",
317
+ "bwr",
318
+ "brg", # appear to be custom matplotlib
319
+ "Wistia",
320
+ "CMRmap", # individually released
321
+ "seismic",
322
+ "terrain",
323
+ "nipy_spectral", # origin ambiguous
324
+ "tab10",
325
+ "tab20",
326
+ "tab20b",
327
+ "tab20c", # merged colormap cycles
328
+ ),
329
+ }
330
+
331
+ # Docstring snippets
332
+ _colorbar_docstring = """
333
+ length : unit-spec, optional
334
+ The length of each colorbar.
335
+ %(units.in)s
336
+ width : float or str, optional
337
+ The width of each colorbar.
338
+ %(units.in)s
339
+ rasterized : bool, default: :rc:`colorbar.rasterized`
340
+ Whether to rasterize the colorbar solids. This increases rendering
341
+ time and decreases file sizes for vector graphics.
342
+ """
343
+ docstring._snippet_manager["demos.cmaps"] = ", ".join(f"``{s!r}``" for s in CMAP_TABLE)
344
+ docstring._snippet_manager["demos.cycles"] = ", ".join(
345
+ f"``{s!r}``" for s in CYCLE_TABLE
346
+ ) # noqa: E501
347
+ docstring._snippet_manager["demos.colors"] = ", ".join(
348
+ f"``{s!r}``" for s in COLOR_TABLE
349
+ ) # noqa: E501
350
+ docstring._snippet_manager["demos.colorbar"] = _colorbar_docstring
351
+
352
+
353
+ def show_channels(
354
+ *args,
355
+ N=100,
356
+ rgb=False,
357
+ saturation=True,
358
+ minhue=0,
359
+ maxsat=500,
360
+ width=100,
361
+ refwidth=1.7,
362
+ ):
363
+ """
364
+ Show how arbitrary colormap(s) vary with respect to the hue, chroma,
365
+ luminance, HSL saturation, and HPL saturation channels, and optionally
366
+ the red, blue and green channels. Adapted from `this example \
367
+ <https://matplotlib.org/stable/tutorials/colors/colormaps.html#lightness-of-matplotlib-colormaps>`__.
368
+
369
+ Parameters
370
+ ----------
371
+ *args : colormap-spec, default: :rc:`image.cmap`
372
+ Positional arguments are colormap names or objects.
373
+ N : int, optional
374
+ The number of markers to draw for each colormap.
375
+ rgb : bool, optional
376
+ Whether to also show the red, green, and blue channels in the bottom row.
377
+ saturation : bool, optional
378
+ Whether to show the HSL and HPL saturation channels alongside the raw chroma.
379
+ minhue : float, optional
380
+ The minimum hue. This lets you rotate the hue plot cyclically.
381
+ maxsat : float, optional
382
+ The maximum saturation. Use this to truncate large saturation values.
383
+ width : int, optional
384
+ The width of each colormap line in points.
385
+ refwidth : int or str, optional
386
+ The width of each subplot. Passed to `~ultraplot.ui.subplots`.
387
+
388
+ Returns
389
+ -------
390
+ ultraplot.figure.Figure
391
+ The figure.
392
+ ultraplot.gridspec.SubplotGrid
393
+ The subplot grid.
394
+
395
+ See also
396
+ --------
397
+ show_cmaps
398
+ show_colorspaces
399
+ """
400
+ # Figure and plot
401
+ if not args:
402
+ raise ValueError("At least one positional argument required.")
403
+ array = [[1, 1, 2, 2, 3, 3]]
404
+ labels = ("Hue", "Chroma", "Luminance")
405
+ if saturation:
406
+ array += [[0, 4, 4, 5, 5, 0]]
407
+ labels += ("HSL saturation", "HPL saturation")
408
+ if rgb:
409
+ array += [np.array([4, 4, 5, 5, 6, 6]) + 2 * int(saturation)]
410
+ labels += ("Red", "Green", "Blue")
411
+ fig, axs = ui.subplots(
412
+ array=array,
413
+ refwidth=refwidth,
414
+ wratios=(1.5, 1, 1, 1, 1, 1.5),
415
+ share="labels",
416
+ span=False,
417
+ innerpad=1,
418
+ )
419
+ # Iterate through colormaps
420
+ mc = ms = mp = 0
421
+ cmaps = []
422
+ for cmap in args:
423
+ # Get colormap and avoid registering new names
424
+ name = cmap if isinstance(cmap, str) else getattr(cmap, "name", None)
425
+ cmap = constructor.Colormap(cmap, N=N) # arbitrary cmap argument
426
+ if name is not None:
427
+ cmap.name = name
428
+ cmap._init()
429
+ cmaps.append(cmap)
430
+
431
+ # Get clipped RGB table
432
+ x = np.linspace(0, 1, N)
433
+ lut = cmap._lut[:-3, :3].copy()
434
+ rgb_data = lut.T # 3 by N
435
+ hcl_data = np.array([to_xyz(color, space="hcl") for color in lut]).T # 3 by N
436
+ hsl_data = [to_xyz(color, space="hsl")[1] for color in lut]
437
+ hpl_data = [to_xyz(color, space="hpl")[1] for color in lut]
438
+
439
+ # Plot channels
440
+ # If rgb is False, the zip will just truncate the other iterables
441
+ data = tuple(hcl_data)
442
+ if saturation:
443
+ data += (hsl_data, hpl_data)
444
+ if rgb:
445
+ data += tuple(rgb_data)
446
+ for ax, y, label in zip(axs, data, labels):
447
+ ylim, ylocator = None, None
448
+ if label in ("Red", "Green", "Blue"):
449
+ ylim = (0, 1)
450
+ ylocator = 0.2
451
+ elif label == "Luminance":
452
+ ylim = (0, 100)
453
+ ylocator = 20
454
+ elif label == "Hue":
455
+ ylim = (minhue, minhue + 360)
456
+ ylocator = 90
457
+ y = y - 720
458
+ for _ in range(3): # rotate up to 1080 degrees
459
+ y[y < minhue] += 360
460
+ else:
461
+ if "HSL" in label:
462
+ m = ms = max(min(max(ms, max(y)), maxsat), 100)
463
+ elif "HPL" in label:
464
+ m = mp = max(min(max(mp, max(y)), maxsat), 100)
465
+ else:
466
+ m = mc = max(min(max(mc, max(y)), maxsat), 100)
467
+ ylim = (0, m)
468
+ ylocator = ("maxn", 5)
469
+ ax.scatter(x, y, c=x, cmap=cmap, s=width, linewidths=0)
470
+ ax.format(title=label, ylim=ylim, ylocator=ylocator)
471
+
472
+ # Formatting
473
+ suptitle = (
474
+ ", ".join(repr(cmap.name) for cmap in cmaps[:-1])
475
+ + (", and " if len(cmaps) > 2 else " and " if len(cmaps) == 2 else " ")
476
+ + f"{repr(cmaps[-1].name)} colormap"
477
+ + ("s" if len(cmaps) > 1 else "")
478
+ )
479
+ axs.format(
480
+ xlocator=0.25,
481
+ xformatter="null",
482
+ suptitle=f"{suptitle} by channel",
483
+ ylim=None,
484
+ ytickminor=False,
485
+ )
486
+
487
+ # Colorbar on the bottom
488
+ for cmap in cmaps:
489
+ fig.colorbar(
490
+ cmap,
491
+ loc="b",
492
+ span=(2, 5),
493
+ locator="null",
494
+ label=cmap.name,
495
+ labelweight="bold",
496
+ )
497
+ return fig, axs
498
+
499
+
500
+ def show_colorspaces(*, luminance=None, saturation=None, hue=None, refwidth=2):
501
+ """
502
+ Generate hue-saturation, hue-luminance, and luminance-saturation
503
+ cross-sections for the HCL, HSL, and HPL colorspaces.
504
+
505
+ Parameters
506
+ ----------
507
+ luminance : float, default: 50
508
+ If passed, saturation-hue cross-sections are drawn for
509
+ this luminance. Must be between ``0`` and ``100``.
510
+ saturation : float, optional
511
+ If passed, luminance-hue cross-sections are drawn for this
512
+ saturation. Must be between ``0`` and ``100``.
513
+ hue : float, optional
514
+ If passed, luminance-saturation cross-sections
515
+ are drawn for this hue. Must be between ``0`` and ``360``.
516
+ refwidth : str or float, optional
517
+ Average width of each subplot. Units are interpreted by
518
+ `~ultraplot.utils.units`.
519
+
520
+ Returns
521
+ -------
522
+ ultraplot.figure.Figure
523
+ The figure.
524
+ ultraplot.gridspec.SubplotGrid
525
+ The subplot grid.
526
+
527
+ See also
528
+ --------
529
+ show_cmaps
530
+ show_channels
531
+ """
532
+ # Get colorspace properties
533
+ hues = np.linspace(0, 360, 361)
534
+ sats = np.linspace(0, 120, 120)
535
+ lums = np.linspace(0, 99.99, 101)
536
+ if luminance is None and saturation is None and hue is None:
537
+ luminance = 50
538
+ _not_none(luminance=luminance, saturation=saturation, hue=hue) # warning
539
+ if luminance is not None:
540
+ hsl = np.concatenate(
541
+ (
542
+ np.repeat(hues[:, None], len(sats), axis=1)[..., None],
543
+ np.repeat(sats[None, :], len(hues), axis=0)[..., None],
544
+ np.ones((len(hues), len(sats)))[..., None] * luminance,
545
+ ),
546
+ axis=2,
547
+ )
548
+ suptitle = f"Hue-saturation cross-section for luminance {luminance}"
549
+ xlabel, ylabel = "hue", "saturation"
550
+ xloc, yloc = 60, 20
551
+ elif saturation is not None:
552
+ hsl = np.concatenate(
553
+ (
554
+ np.repeat(hues[:, None], len(lums), axis=1)[..., None],
555
+ np.ones((len(hues), len(lums)))[..., None] * saturation,
556
+ np.repeat(lums[None, :], len(hues), axis=0)[..., None],
557
+ ),
558
+ axis=2,
559
+ )
560
+ suptitle = f"Hue-luminance cross-section for saturation {saturation}"
561
+ xlabel, ylabel = "hue", "luminance"
562
+ xloc, yloc = 60, 20
563
+ elif hue is not None:
564
+ hsl = np.concatenate(
565
+ (
566
+ np.ones((len(lums), len(sats)))[..., None] * hue,
567
+ np.repeat(sats[None, :], len(lums), axis=0)[..., None],
568
+ np.repeat(lums[:, None], len(sats), axis=1)[..., None],
569
+ ),
570
+ axis=2,
571
+ )
572
+ suptitle = "Luminance-saturation cross-section"
573
+ xlabel, ylabel = "luminance", "saturation"
574
+ xloc, yloc = 20, 20
575
+
576
+ # Make figure, with black indicating invalid values
577
+ # Note we invert the x-y ordering for imshow
578
+ fig, axs = ui.subplots(refwidth=refwidth, ncols=3, share=False, innerpad=0.5)
579
+ for ax, space in zip(axs, ("hcl", "hsl", "hpl")):
580
+ rgba = np.ones((*hsl.shape[:2][::-1], 4)) # RGBA
581
+ for j in range(hsl.shape[0]):
582
+ for k in range(hsl.shape[1]):
583
+ rgb_jk = to_rgb(hsl[j, k, :], space)
584
+ if not all(0 <= c <= 1 for c in rgb_jk):
585
+ rgba[k, j, 3] = 0 # black cell
586
+ else:
587
+ rgba[k, j, :3] = rgb_jk
588
+ ax.imshow(rgba, origin="lower", aspect="auto")
589
+ ax.format(
590
+ xlabel=xlabel,
591
+ ylabel=ylabel,
592
+ suptitle=suptitle,
593
+ grid=False,
594
+ xtickminor=False,
595
+ ytickminor=False,
596
+ xlocator=xloc,
597
+ ylocator=yloc,
598
+ facecolor="k",
599
+ title=space.upper(),
600
+ )
601
+ return fig, axs
602
+
603
+
604
+ @warnings._rename_kwargs("0.8.0", categories="include")
605
+ @warnings._rename_kwargs("0.10.0", rasterize="rasterized")
606
+ def _draw_bars(
607
+ cmaps,
608
+ *,
609
+ source,
610
+ unknown="User",
611
+ include=None,
612
+ ignore=None,
613
+ length=4.0,
614
+ width=0.2,
615
+ N=None,
616
+ rasterized=None,
617
+ ):
618
+ """
619
+ Draw colorbars for "colormaps" and "color cycles". This is called by
620
+ `show_cycles` and `show_cmaps`.
621
+ """
622
+ # Categorize the input names
623
+ table = {unknown: []} if unknown else {}
624
+ table.update({cat: [None] * len(names) for cat, names in source.items()})
625
+ for cmap in cmaps:
626
+ cat = None
627
+ name = cmap.name or "_no_name"
628
+ name = name.lower()
629
+ for opt, names in source.items():
630
+ names = list(map(str.lower, names))
631
+ if name in names:
632
+ i, cat = names.index(name), opt
633
+ if cat:
634
+ table[cat][i] = cmap
635
+ elif unknown:
636
+ table[unknown].append(cmap)
637
+
638
+ # Filter out certain categories
639
+ options = set(map(str.lower, source))
640
+ if ignore is None:
641
+ ignore = ("matlab", "gnuplot", "gist", "other")
642
+ if isinstance(include, str):
643
+ include = (include,)
644
+ if isinstance(ignore, str):
645
+ ignore = (ignore,)
646
+ if include is None:
647
+ include = options - set(map(str.lower, ignore))
648
+ else:
649
+ include = set(map(str.lower, include))
650
+ if any(cat not in options and cat != unknown for cat in include):
651
+ raise ValueError(
652
+ f"Invalid categories {include!r}. Options are: "
653
+ + ", ".join(map(repr, source))
654
+ + "."
655
+ )
656
+ for cat in tuple(table):
657
+ table[cat][:] = [cmap for cmap in table[cat] if cmap is not None]
658
+ if not table[cat] or cat.lower() not in include and cat != unknown:
659
+ del table[cat]
660
+
661
+ # Draw figure
662
+ # Allocate two colorbar widths for each title of sections
663
+ naxs = 2 * len(table) + sum(map(len, table.values()))
664
+ fig, axs = ui.subplots(
665
+ refwidth=length,
666
+ refheight=width,
667
+ nrows=naxs,
668
+ share=False,
669
+ hspace="2pt",
670
+ top="-1em",
671
+ )
672
+ i = -1
673
+ nheads = nbars = 0 # for deciding which axes to plot in
674
+ for cat, cmaps in table.items():
675
+ nheads += 1
676
+ for j, cmap in enumerate(cmaps):
677
+ i += 1
678
+ if j + nheads + nbars > naxs:
679
+ break
680
+ if j == 0: # allocate this axes for title
681
+ i += 2
682
+ for ax in axs[i - 2 : i]:
683
+ ax.set_visible(False)
684
+ ax = axs[i]
685
+ if N is not None:
686
+ cmap = cmap.copy(N=N)
687
+ label = cmap.name
688
+ label = re.sub(r"\A_*", "", label)
689
+ label = re.sub(r"(_copy)*\Z", "", label)
690
+ ax.colorbar(
691
+ cmap,
692
+ loc="fill",
693
+ orientation="horizontal",
694
+ locator="null",
695
+ linewidth=0,
696
+ rasterized=rasterized,
697
+ )
698
+ ax.text(
699
+ 0 - (rc["axes.labelpad"] / 72) / length,
700
+ 0.45,
701
+ label,
702
+ ha="right",
703
+ va="center",
704
+ transform="axes",
705
+ )
706
+ if j == 0:
707
+ ax.set_title(cat, weight="bold")
708
+ nbars += len(cmaps)
709
+
710
+ return fig, axs
711
+
712
+
713
+ @docstring._snippet_manager
714
+ def show_cmaps(*args, **kwargs):
715
+ """
716
+ Generate a table of the registered colormaps or the input colormaps
717
+ categorized by source. Adapted from `this example \
718
+ <http://matplotlib.org/stable/gallery/color/colormap_reference.html>`__.
719
+
720
+ Parameters
721
+ ----------
722
+ *args : colormap-spec, optional
723
+ Colormap names or objects.
724
+ N : int, default: :rc:`image.lut`
725
+ The number of levels in each colorbar.
726
+ unknown : str, default: 'User'
727
+ Category name for colormaps that are unknown to ultraplot.
728
+ Set this to ``False`` to hide unknown colormaps.
729
+ include : str or sequence of str, default: None
730
+ Category names to be shown in the table. Use this to limit
731
+ the table to a subset of categories. Valid categories are
732
+ %(demos.cmaps)s.
733
+ ignore : str or sequence of str, default: 'MATLAB', 'GNUplot', 'GIST', 'Other'
734
+ Used only if `include` was not passed. Category names to be removed from the
735
+ table. Use of the default ignored colormaps is discouraged because they contain
736
+ non-uniform color transitions (see the :ref:`user guide <ug_perceptual>`).
737
+ %(demos.colorbar)s
738
+
739
+ Returns
740
+ -------
741
+ ultraplot.figure.Figure
742
+ The figure.
743
+ ultraplot.gridspec.SubplotGrid
744
+ The subplot grid.
745
+
746
+ See also
747
+ --------
748
+ show_colorspaces
749
+ show_channels
750
+ show_cycles
751
+ show_colors
752
+ show_fonts
753
+ """
754
+ # Get the list of colormaps
755
+ if args:
756
+ cmaps = list(map(constructor.Colormap, args))
757
+ cmaps = [
758
+ (
759
+ cmap
760
+ if isinstance(cmap, mcolors.LinearSegmentedColormap)
761
+ else pcolors._get_cmap_subtype(cmap, "continuous")
762
+ )
763
+ for cmap in args
764
+ ]
765
+ ignore = ()
766
+ else:
767
+ cmaps = [
768
+ cmap
769
+ for cmap in pcolors._cmap_database.values()
770
+ if isinstance(cmap, pcolors.ContinuousColormap)
771
+ and not (cmap.name or "_")[:1] == "_"
772
+ ]
773
+ ignore = None
774
+
775
+ # Return figure of colorbars
776
+ kwargs.setdefault("source", CMAP_TABLE)
777
+ kwargs.setdefault("ignore", ignore)
778
+ return _draw_bars(cmaps, **kwargs)
779
+
780
+
781
+ @docstring._snippet_manager
782
+ def show_cycles(*args, **kwargs):
783
+ """
784
+ Generate a table of registered color cycles or the input color cycles
785
+ categorized by source. Adapted from `this example \
786
+ <http://matplotlib.org/stable/gallery/color/colormap_reference.html>`__.
787
+
788
+ Parameters
789
+ ----------
790
+ *args : colormap-spec, optional
791
+ Cycle names or objects.
792
+ unknown : str, default: 'User'
793
+ Category name for cycles that are unknown to ultraplot.
794
+ Set this to ``False`` to hide unknown colormaps.
795
+ include : str or sequence of str, default: None
796
+ Category names to be shown in the table. Use this to limit
797
+ the table to a subset of categories. Valid categories are
798
+ %(demos.cycles)s.
799
+ ignore : str or sequence of str, default: None
800
+ Used only if `include` was not passed. Category names to be removed
801
+ from the table.
802
+ %(demos.colorbar)s
803
+
804
+ Returns
805
+ -------
806
+ ultraplot.figure.Figure
807
+ The figure.
808
+ ultraplot.gridspec.SubplotGrid
809
+ The subplot grid.
810
+
811
+ See also
812
+ --------
813
+ show_cmaps
814
+ show_colors
815
+ show_fonts
816
+ """
817
+ # Get the list of cycles
818
+ if args:
819
+ cycles = [
820
+ (
821
+ pcolors.DiscreteColormap(
822
+ cmap.by_key().get("color", ["k"]), name=getattr(cmap, "name", None)
823
+ )
824
+ if isinstance(cmap, cycler.Cycler)
825
+ else (
826
+ cmap
827
+ if isinstance(cmap, mcolors.ListedColormap)
828
+ else pcolors._get_cmap_subtype(cmap, "discrete")
829
+ )
830
+ )
831
+ for cmap in args
832
+ ]
833
+ ignore = ()
834
+ else:
835
+ cycles = [
836
+ cmap
837
+ for cmap in pcolors._cmap_database.values()
838
+ if isinstance(cmap, pcolors.DiscreteColormap)
839
+ and not (cmap.name or "_")[:1] == "_"
840
+ ]
841
+ ignore = None
842
+
843
+ # Return figure of colorbars
844
+ kwargs.setdefault("source", CYCLE_TABLE)
845
+ kwargs.setdefault("ignore", ignore)
846
+ return _draw_bars(cycles, **kwargs)
847
+
848
+
849
+ def _filter_colors(hcl, ihue, nhues, minsat):
850
+ """
851
+ Filter colors into categories.
852
+
853
+ Parameters
854
+ ----------
855
+ hcl : tuple
856
+ The data.
857
+ ihue : int
858
+ The hue column.
859
+ nhues : int
860
+ The total number of hues.
861
+ minsat : float
862
+ The minimum saturation used for the "grays" column.
863
+ """
864
+ breakpoints = np.linspace(0, 360, nhues)
865
+ gray = hcl[1] <= minsat
866
+ if ihue == 0:
867
+ return gray
868
+ color = breakpoints[ihue - 1] <= hcl[0] < breakpoints[ihue]
869
+ if ihue == nhues - 1:
870
+ color = color or color == breakpoints[ihue] # endpoint inclusive
871
+ return not gray and color
872
+
873
+
874
+ @docstring._snippet_manager
875
+ def show_colors(*, nhues=17, minsat=10, unknown="User", include=None, ignore=None):
876
+ """
877
+ Generate tables of the registered color names. Adapted from
878
+ `this example <https://matplotlib.org/examples/color/named_colors.html>`__.
879
+
880
+ Parameters
881
+ ----------
882
+ nhues : int, optional
883
+ The number of breaks between hues for grouping "like colors" in the
884
+ color table.
885
+ minsat : float, optional
886
+ The threshold saturation, between ``0`` and ``100``, for designating
887
+ "gray colors" in the color table.
888
+ unknown : str, default: 'User'
889
+ Category name for color names that are unknown to ultraplot.
890
+ Set this to ``False`` to hide unknown color names.
891
+ include : str or sequence of str, default: None
892
+ Category names to be shown in the table. Use this to limit
893
+ the table to a subset of categories. Valid categories are
894
+ %(demos.colors)s.
895
+ ignore : str or sequence of str, default: 'CSS4'
896
+ Used only if `include` was not passed. Category names to be removed
897
+ from the colormap table.
898
+
899
+ Returns
900
+ -------
901
+ ultraplot.figure.Figure
902
+ The figure.
903
+ ultraplot.gridspec.SubplotGrid
904
+ The subplot grid.
905
+ """
906
+ # Tables of known colors to be plotted
907
+ colordict = {}
908
+ if ignore is None:
909
+ ignore = "css4"
910
+ if isinstance(include, str):
911
+ include = (include.lower(),)
912
+ if isinstance(ignore, str):
913
+ ignore = (ignore.lower(),)
914
+ if include is None:
915
+ include = COLOR_TABLE.keys()
916
+ include -= set(map(str.lower, ignore))
917
+ for cat in sorted(include):
918
+ if cat not in COLOR_TABLE:
919
+ raise ValueError(
920
+ f"Invalid categories {include!r}. Options are: "
921
+ + ", ".join(map(repr, COLOR_TABLE))
922
+ + "."
923
+ )
924
+ colordict[cat] = list(COLOR_TABLE[cat]) # copy the names
925
+
926
+ # Add "unknown" colors
927
+ if unknown:
928
+ unknown_colors = [
929
+ color
930
+ for color in map(repr, pcolors._color_database)
931
+ if "xkcd:" not in color
932
+ and "tableau:" not in color
933
+ and not any(color in list_ for list_ in COLOR_TABLE)
934
+ ]
935
+ if unknown_colors:
936
+ colordict[unknown] = unknown_colors
937
+
938
+ # Divide colors into columns and rows
939
+ # For base and open colors, tables are already organized into like
940
+ # colors, so just reshape them into grids. For other colors, we group
941
+ # them by hue in descending order of luminance.
942
+ namess = {}
943
+ for cat in sorted(include):
944
+ if cat == "base":
945
+ names = np.asarray(colordict[cat])
946
+ ncols, nrows = len(names), 1
947
+ elif cat == "opencolor":
948
+ names = np.asarray(colordict[cat])
949
+ ncols, nrows = 7, 20
950
+ else:
951
+ hclpairs = [(name, to_xyz(name, "hcl")) for name in colordict[cat]]
952
+ hclpairs = [
953
+ sorted(
954
+ [
955
+ pair
956
+ for pair in hclpairs
957
+ if _filter_colors(pair[1], ihue, nhues, minsat)
958
+ ],
959
+ key=lambda x: x[1][2], # sort by luminance
960
+ )
961
+ for ihue in range(nhues)
962
+ ]
963
+ names = np.array([name for ipairs in hclpairs for name, _ in ipairs])
964
+ ncols, nrows = 4, len(names) // 4 + 1
965
+
966
+ names.resize((ncols, nrows)) # fill empty slots with empty string
967
+ namess[cat] = names
968
+
969
+ # Draw figures for different groups of colors
970
+ # NOTE: Aspect ratios should be number of columns divided by number
971
+ # of rows, times the aspect ratio of the slot for each swatch-name
972
+ # pair, which we set to 5.
973
+ shape = tuple(namess.values())[0].shape # sample *first* group
974
+ figwidth = 6.5
975
+ refaspect = (figwidth * 72) / (10 * shape[1]) # points
976
+ maxcols = max(names.shape[0] for names in namess.values())
977
+ hratios = tuple(names.shape[1] for names in namess.values())
978
+ fig, axs = ui.subplots(
979
+ figwidth=figwidth,
980
+ refaspect=refaspect,
981
+ nrows=len(include),
982
+ hratios=hratios,
983
+ )
984
+ title_dict = {
985
+ "css4": "CSS4 colors",
986
+ "base": "Base colors",
987
+ "opencolor": "Open color",
988
+ "xkcd": "XKCD colors",
989
+ }
990
+ for ax, (cat, names) in zip(axs, namess.items()):
991
+ # Format axes
992
+ ax.format(
993
+ title=title_dict.get(cat, cat),
994
+ titleweight="bold",
995
+ xlim=(0, maxcols - 1),
996
+ ylim=(0, names.shape[1]),
997
+ grid=False,
998
+ yloc="neither",
999
+ xloc="neither",
1000
+ alpha=0,
1001
+ )
1002
+
1003
+ # Draw swatches as lines
1004
+ lw = 8 # best to just use trial and error
1005
+ swatch = 0.45 # percent of column reserved for swatch
1006
+ ncols, nrows = names.shape
1007
+ for col, inames in enumerate(names):
1008
+ for row, name in enumerate(inames):
1009
+ if not name:
1010
+ continue
1011
+ y = nrows - row - 1 # start at top
1012
+ x1 = col * (maxcols - 1) / ncols # e.g. idx 3 --> idx 7
1013
+ x2 = x1 + swatch # portion of column
1014
+ xtext = x1 + 1.1 * swatch
1015
+ ax.text(
1016
+ xtext,
1017
+ y,
1018
+ name,
1019
+ ha="left",
1020
+ va="center",
1021
+ transform="data",
1022
+ clip_on=False,
1023
+ )
1024
+ ax.plot(
1025
+ [x1, x2],
1026
+ [y, y],
1027
+ color=name,
1028
+ lw=lw,
1029
+ solid_capstyle="butt", # do not stick out
1030
+ clip_on=False,
1031
+ )
1032
+
1033
+ return fig, axs
1034
+
1035
+
1036
+ def show_fonts(
1037
+ *args, family=None, user=None, text=None, math=False, fallback=False, **kwargs
1038
+ ):
1039
+ """
1040
+ Generate a table of fonts. If a glyph for a particular font is unavailable,
1041
+ it is replaced with the "¤" dummy character.
1042
+
1043
+ Parameters
1044
+ ----------
1045
+ *args : str or `~matplotlib.font_manager.FontProperties`
1046
+ The font specs, font names, or `~matplotlib.font_manager.FontProperties`\\ s
1047
+ to show. If no positional arguments are passed and the `family` argument is
1048
+ not passed, then the fonts found in `~ultraplot.config.Configurator.user_folder`
1049
+ and `~ultraplot.config.Configurator.local_folders` and the *available*
1050
+ :rcraw:`font.sans-serif` fonts are shown.
1051
+ family \
1052
+ : {'tex-gyre', 'sans-serif', 'serif', 'monospace', 'cursive', 'fantasy'}, optional
1053
+ The family from which *available* fonts are shown. Default is ``'sans-serif'``
1054
+ if no arguments were provided. Otherwise the default is to not show family
1055
+ fonts. The fonts belonging to each family are listed under :rcraw:`font.serif`,
1056
+ :rcraw:`font.sans-serif`, :rcraw:`font.monospace`, :rcraw:`font.cursive`, and
1057
+ :rcraw:`font.fantasy`. The special family ``'tex-gyre'`` includes the
1058
+ `TeX Gyre <http://www.gust.org.pl/projects/e-foundry/tex-gyre>`__ fonts.
1059
+ user : bool, optional
1060
+ Whether to include fonts in `~ultraplot.config.Configurator.user_folder` and
1061
+ `~ultraplot.config.Configurator.local_folders` at the top of the table. Default
1062
+ is ``True`` if called without any arguments and ``False`` otherwise.
1063
+ text : str, optional
1064
+ The sample text shown for each font. If not passed then default math or
1065
+ non-math sample text is used.
1066
+ math : bool, default: False
1067
+ Whether the default sample text should show non-math Latin characters or
1068
+ or math equations and Greek letters.
1069
+ fallback : bool, default: False
1070
+ Whether to use the fallback font :rcraw:`mathtext.fallback` for unavailable
1071
+ characters. If ``False`` the dummy glyph "¤" is shown for missing characters.
1072
+ **kwargs
1073
+ Additional font properties passed to `~matplotlib.font_manager.FontProperties`.
1074
+ Default size is ``12`` and default weight, style, and strength are ``'normal'``.
1075
+
1076
+ Other parameters
1077
+ ----------------
1078
+ size : float, default: 12
1079
+ The font size.
1080
+ weight : str, default: 'normal'
1081
+ The font weight.
1082
+ style : str, default: 'normal'
1083
+ The font style.
1084
+ stretch : str, default: 'normal'
1085
+ The font stretch.
1086
+
1087
+ Returns
1088
+ -------
1089
+ ultraplot.figure.Figure
1090
+ The figure.
1091
+ ultraplot.gridspec.SubplotGrid
1092
+ The subplot grid.
1093
+
1094
+ See also
1095
+ --------
1096
+ show_cmaps
1097
+ show_cycles
1098
+ show_colors
1099
+ """
1100
+ # Parse user input fonts and translate into FontProperties.
1101
+ s = set()
1102
+ props = [] # should be string names
1103
+ all_fonts = sorted(mfonts.fontManager.ttflist, key=lambda font: font.name)
1104
+ all_fonts = [
1105
+ font for font in all_fonts if font.name not in s and not s.add(font.name)
1106
+ ] # noqa: E501
1107
+ all_names = [font.name for font in all_fonts]
1108
+ for arg in args:
1109
+ if isinstance(arg, str):
1110
+ arg = mfonts.FontProperties(arg, **kwargs) # possibly a fontspec
1111
+ elif not isinstance(arg, mfonts.FontProperties):
1112
+ raise TypeError(f"Expected string or FontProperties but got {type(arg)}.")
1113
+ opts = arg.get_family() # usually a singleton list
1114
+ if opts and opts[0] in all_names:
1115
+ props.append(arg)
1116
+ else:
1117
+ warnings._warn_ultraplot(f"Input font name {opts[:1]!r} not found. Skipping.")
1118
+
1119
+ # Add user and family FontProperties.
1120
+ user = _not_none(user, not args and family is None)
1121
+ family = _not_none(family, None if args else "sans-serif")
1122
+ if user:
1123
+ paths = _get_data_folders("fonts", default=False)
1124
+ for font in all_fonts: # fonts sorted by unique name
1125
+ if os.path.dirname(font.fname) in paths:
1126
+ props.append(mfonts.FontProperties(font.name, **kwargs))
1127
+ if family is not None:
1128
+ options = ("serif", "sans-serif", "monospace", "cursive", "fantasy", "tex-gyre")
1129
+ if family not in options:
1130
+ raise ValueError(
1131
+ f"Invalid font family {family!r}. Options are: "
1132
+ + ", ".join(map(repr, options))
1133
+ + "."
1134
+ )
1135
+ names = FAMILY_TEXGYRE if family == "tex-gyre" else rc["font." + family]
1136
+ for name in names:
1137
+ if name in all_names: # valid font name
1138
+ props.append(mfonts.FontProperties(name, **kwargs))
1139
+
1140
+ # The default sample text
1141
+ linespacing = 0.8 if text is None and math else 1.2
1142
+ if text is None:
1143
+ if not math:
1144
+ text = (
1145
+ "the quick brown fox jumps over a lazy dog 01234 ; . , + - * ^ () ||"
1146
+ "\n"
1147
+ "THE QUICK BROWN FOX JUMPS OVER A LAZY DOG 56789 : ! ? & # % $ [] {}"
1148
+ )
1149
+ else:
1150
+ text = (
1151
+ "\n"
1152
+ r"$\alpha\beta$ $\Gamma\gamma$ $\Delta\delta$ "
1153
+ r"$\epsilon\zeta\eta$ $\Theta\theta$ $\kappa\mu\nu$ "
1154
+ r"$\Lambda\lambda$ $\Pi\pi$ $\xi\rho\tau\chi$ $\Sigma\sigma$ "
1155
+ r"$\Phi\phi$ $\Psi\psi$ $\Omega\omega$ "
1156
+ r"$\{ \; \}^i$ $[ \; ]_j$ $( \; )^k$ $\left< \right>_n$"
1157
+ "\n"
1158
+ r"$0^a + 1_b - 2^c \times 3_d = "
1159
+ r"4.0^e \equiv 5.0_f \approx 6.0^g \sim 7_h \leq 8^i \geq 9_j"
1160
+ r"\ll \prod \, P \gg \sum \, Q \, "
1161
+ r"\int \, Y \mathrm{d}y \propto \oint \;\, Z \mathrm{d}z$"
1162
+ )
1163
+
1164
+ # Settings for rendering math text
1165
+ ctx = {"mathtext.fontset": "custom"}
1166
+ if not fallback:
1167
+ if _version_mpl < "3.4":
1168
+ ctx["mathtext.fallback_to_cm"] = False
1169
+ else:
1170
+ ctx["mathtext.fallback"] = None
1171
+ if "size" not in kwargs:
1172
+ for prop in props:
1173
+ if prop.get_size() == rc["font.size"]:
1174
+ prop.set_size(12) # only if fontspec did not change the size
1175
+
1176
+ # Create figure
1177
+ refsize = props[0].get_size_in_points() if props else rc["font.size"]
1178
+ refheight = 1.2 * (text.count("\n") + 2.5) * refsize / 72
1179
+ fig, axs = ui.subplots(
1180
+ refwidth=4.5,
1181
+ refheight=refheight,
1182
+ nrows=len(props),
1183
+ ncols=1,
1184
+ space=0,
1185
+ )
1186
+ fig._render_context.update(ctx)
1187
+ fig.format(
1188
+ xloc="neither", yloc="neither", xlocator="null", ylocator="null", alpha=0
1189
+ )
1190
+ for ax, prop in zip(axs, props):
1191
+ name = prop.get_family()[0]
1192
+ ax.text(
1193
+ 0,
1194
+ 0.5,
1195
+ f"{name}:\n{text} ",
1196
+ ha="left",
1197
+ va="center",
1198
+ linespacing=linespacing,
1199
+ fontproperties=prop,
1200
+ )
1201
+ return fig, axs