quantized-lab 0.8.1__tar.gz → 0.9.0__tar.gz

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 (238) hide show
  1. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/PKG-INFO +1 -1
  2. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/pyproject.toml +1 -1
  3. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/__init__.py +1 -1
  4. quantized_lab-0.9.0/src/quantized/calc/figure_labels.py +127 -0
  5. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_overrides.py +24 -0
  6. quantized_lab-0.9.0/src/quantized/calc/figure_shapes.py +153 -0
  7. quantized_lab-0.9.0/src/quantized/web/assets/index-D8RNGjHO.js +27 -0
  8. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/web/index.html +1 -1
  9. quantized_lab-0.8.1/src/quantized/calc/figure_labels.py +0 -62
  10. quantized_lab-0.8.1/src/quantized/web/assets/index-BHmmCL-x.js +0 -27
  11. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/.gitignore +0 -0
  12. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/LICENSE +0 -0
  13. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/NOTICE +0 -0
  14. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/README.md +0 -0
  15. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/__main__.py +0 -0
  16. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/api.py +0 -0
  17. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/app.py +0 -0
  18. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/__init__.py +0 -0
  19. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/_clipfit.py +0 -0
  20. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/_natural_neighbor.py +0 -0
  21. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/aggregate.py +0 -0
  22. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/backgrounds.py +0 -0
  23. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/baseline.py +0 -0
  24. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/batch_fit.py +0 -0
  25. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/constants.py +0 -0
  26. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/corrections.py +0 -0
  27. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/crystallography.py +0 -0
  28. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/diffusion.py +0 -0
  29. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/electrical.py +0 -0
  30. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/electrochemistry.py +0 -0
  31. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/element_data.json +0 -0
  32. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/element_data.py +0 -0
  33. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/errors.py +0 -0
  34. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure.py +0 -0
  35. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_break.py +0 -0
  36. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_categorical.py +0 -0
  37. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_corner.py +0 -0
  38. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_facets.py +0 -0
  39. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_field.py +0 -0
  40. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_hitmap.py +0 -0
  41. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_map.py +0 -0
  42. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_page.py +0 -0
  43. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_scale.py +0 -0
  44. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_statplots.py +0 -0
  45. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_styles.py +0 -0
  46. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_ternary.py +0 -0
  47. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/figure_ticks.py +0 -0
  48. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_autoguess.py +0 -0
  49. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_bootstrap.py +0 -0
  50. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_bumps.py +0 -0
  51. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_constraints.py +0 -0
  52. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_equation.py +0 -0
  53. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_findxy.py +0 -0
  54. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_models.py +0 -0
  55. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_models_special.py +0 -0
  56. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_odr.py +0 -0
  57. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_scan.py +0 -0
  58. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fit_stats.py +0 -0
  59. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/fitting.py +0 -0
  60. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/formula.py +0 -0
  61. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/global_curve_fit.py +0 -0
  62. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/global_fit.py +0 -0
  63. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/interp2d.py +0 -0
  64. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/linecut.py +0 -0
  65. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/magnetic.py +0 -0
  66. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/magnetometry.py +0 -0
  67. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/map.py +0 -0
  68. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/mcmc.py +0 -0
  69. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/optics.py +0 -0
  70. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/pawley.py +0 -0
  71. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/peak_batch.py +0 -0
  72. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/peak_fit.py +0 -0
  73. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/peak_integrate.py +0 -0
  74. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/peak_multifit.py +0 -0
  75. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/peak_track.py +0 -0
  76. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/peaks.py +0 -0
  77. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/peakshapes.py +0 -0
  78. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/plotting.py +0 -0
  79. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/processing.py +0 -0
  80. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/qspace.py +0 -0
  81. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/reductions.py +0 -0
  82. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/reductions_fft.py +0 -0
  83. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/refl_sld_presets.json +0 -0
  84. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/reflectivity.py +0 -0
  85. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/registry.py +0 -0
  86. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/relaxation.py +0 -0
  87. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/report.py +0 -0
  88. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/report_emit.py +0 -0
  89. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/resample.py +0 -0
  90. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/rsm.py +0 -0
  91. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/rsm_analyze.py +0 -0
  92. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/semiconductor.py +0 -0
  93. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/sld.py +0 -0
  94. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/sld_formula.py +0 -0
  95. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/spectral.py +0 -0
  96. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/statplots.py +0 -0
  97. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats.py +0 -0
  98. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats_anova2.py +0 -0
  99. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats_anova_ext.py +0 -0
  100. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats_dist.py +0 -0
  101. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats_glm.py +0 -0
  102. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats_multivar.py +0 -0
  103. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats_roc.py +0 -0
  104. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats_survival.py +0 -0
  105. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/stats_tests.py +0 -0
  106. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/substrates.py +0 -0
  107. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/superconductor.py +0 -0
  108. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/surface_fit.py +0 -0
  109. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/surface_models.py +0 -0
  110. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/thermal.py +0 -0
  111. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/thin_film.py +0 -0
  112. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/unit_convert.py +0 -0
  113. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/units.py +0 -0
  114. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/vacuum.py +0 -0
  115. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/calc/xray.py +0 -0
  116. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/cli.py +0 -0
  117. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/datastruct.py +0 -0
  118. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/__init__.py +0 -0
  119. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/_hdf5_layout.py +0 -0
  120. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/_jcamp_asdf.py +0 -0
  121. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/_xrdml_scan.py +0 -0
  122. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/base.py +0 -0
  123. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/bruker_brml.py +0 -0
  124. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/bruker_raw.py +0 -0
  125. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/cif.py +0 -0
  126. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/consolidated.py +0 -0
  127. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/delimited.py +0 -0
  128. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/excel.py +0 -0
  129. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/hdf5.py +0 -0
  130. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/import_filters.py +0 -0
  131. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/import_preview.py +0 -0
  132. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/jcamp.py +0 -0
  133. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/lakeshore.py +0 -0
  134. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/ncnr.py +0 -0
  135. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/netcdf.py +0 -0
  136. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/opus.py +0 -0
  137. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin.py +0 -0
  138. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_com.py +0 -0
  139. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/__init__.py +0 -0
  140. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/annotation_marks.py +0 -0
  141. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/container.py +0 -0
  142. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/curve_style_color.py +0 -0
  143. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/figure_geometry.py +0 -0
  144. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/figure_layers.py +0 -0
  145. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/figure_text.py +0 -0
  146. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/figures.py +0 -0
  147. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/figures_opju.py +0 -0
  148. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/notes.py +0 -0
  149. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opj.py +0 -0
  150. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opj_curves.py +0 -0
  151. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opj_shapes.py +0 -0
  152. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju.py +0 -0
  153. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju_axis_real_form.py +0 -0
  154. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju_axis_specimen_form.py +0 -0
  155. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju_codec.py +0 -0
  156. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju_curves.py +0 -0
  157. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju_curves_allcols.py +0 -0
  158. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju_figure_curves.py +0 -0
  159. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju_figure_text.py +0 -0
  160. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/opju_reports.py +0 -0
  161. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/origin_richtext.py +0 -0
  162. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/preview.py +0 -0
  163. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/templates.py +0 -0
  164. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/tree.py +0 -0
  165. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/tree_opju.py +0 -0
  166. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/windows.py +0 -0
  167. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/windows_opju.py +0 -0
  168. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/writer.py +0 -0
  169. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/origin_project/writer_blocks.py +0 -0
  170. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/qd.py +0 -0
  171. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/refl1d.py +0 -0
  172. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/registry.py +0 -0
  173. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/report_export.py +0 -0
  174. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/rigaku.py +0 -0
  175. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/sims.py +0 -0
  176. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/spc.py +0 -0
  177. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/xrd_csv.py +0 -0
  178. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/io/xrdml.py +0 -0
  179. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/jobs.py +0 -0
  180. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/plugins/__init__.py +0 -0
  181. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/plugins/contract.py +0 -0
  182. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/plugins/loader.py +0 -0
  183. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/plugins/steps.py +0 -0
  184. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/__init__.py +0 -0
  185. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/_bookcache.py +0 -0
  186. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/_export_common.py +0 -0
  187. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/_payload.py +0 -0
  188. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/_uploadcache.py +0 -0
  189. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/aggregate.py +0 -0
  190. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/baseline.py +0 -0
  191. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/books.py +0 -0
  192. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/calc.py +0 -0
  193. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/corrections.py +0 -0
  194. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/crystallography.py +0 -0
  195. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/diffusion.py +0 -0
  196. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/electrical.py +0 -0
  197. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/electrochemistry.py +0 -0
  198. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/export.py +0 -0
  199. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/export_facets.py +0 -0
  200. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/export_figures.py +0 -0
  201. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/export_page.py +0 -0
  202. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/fitting.py +0 -0
  203. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/fitting_bumps.py +0 -0
  204. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/import_template.py +0 -0
  205. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/import_wizard.py +0 -0
  206. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/jobs_api.py +0 -0
  207. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/magnetic.py +0 -0
  208. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/magnetometry.py +0 -0
  209. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/optics.py +0 -0
  210. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/parsers.py +0 -0
  211. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/peaks.py +0 -0
  212. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/plot.py +0 -0
  213. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/reductions.py +0 -0
  214. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/reference.py +0 -0
  215. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/reflectivity.py +0 -0
  216. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/report_export.py +0 -0
  217. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/rsm.py +0 -0
  218. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/samples.py +0 -0
  219. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/semiconductor.py +0 -0
  220. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/sld.py +0 -0
  221. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/spectral.py +0 -0
  222. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/statplots.py +0 -0
  223. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/stats.py +0 -0
  224. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/stats_design.py +0 -0
  225. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/substrates.py +0 -0
  226. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/superconductor.py +0 -0
  227. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/thermal.py +0 -0
  228. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/thin_film.py +0 -0
  229. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/vacuum.py +0 -0
  230. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/routes/xray.py +0 -0
  231. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/samples/demo_vsm.csv +0 -0
  232. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/server_launch.py +0 -0
  233. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/web/assets/JetBrainsMono-Bold-CUogYd9I.woff2 +0 -0
  234. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/web/assets/JetBrainsMono-Regular-CA-Os4ii.woff2 +0 -0
  235. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/web/assets/index-BiZzN7J6.css +0 -0
  236. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/src/quantized/web/loading.html +0 -0
  237. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/tools/origin_compare/README.md +0 -0
  238. {quantized_lab-0.8.1 → quantized_lab-0.9.0}/tools/visual/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantized-lab
3
- Version: 0.8.1
3
+ Version: 0.9.0
4
4
  Summary: Plot, analyze, and publish lab data - magnetometry, XRD, reflectometry - with OriginPro file interop, golden-verified analysis, and reproducible pipelines.
5
5
  Project-URL: Homepage, https://github.com/pquarterman17/quantized
6
6
  Project-URL: Documentation, https://github.com/pquarterman17/quantized/wiki
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "quantized-lab"
3
- version = "0.8.1"
3
+ version = "0.9.0"
4
4
  description = "Plot, analyze, and publish lab data - magnetometry, XRD, reflectometry - with OriginPro file interop, golden-verified analysis, and reproducible pipelines."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -7,5 +7,5 @@ Layered, enforced architecture (see CLAUDE.md):
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- __version__ = "0.8.1"
10
+ __version__ = "0.9.0"
11
11
  __all__ = ["__version__"]
@@ -0,0 +1,127 @@
1
+ """Mathtext label guard for figure export (GOTO #5 rich-text labels).
2
+
3
+ Labels flow from the UI as plain text with optional ``$...$`` mathtext
4
+ regions (the frontend's ``lib/richtext`` micro-syntax is a strict subset of
5
+ matplotlib mathtext, so passthrough is the rendering mechanism). matplotlib
6
+ parses math regions at DRAW time, which means an invalid label would raise
7
+ inside ``fig.savefig`` and turn an export into a 500. This module is the
8
+ shared chokepoint every ``calc.figure*`` renderer routes its user-supplied
9
+ strings through: it pre-validates with matplotlib's own mathtext parser and,
10
+ on failure, escapes the dollar signs so the label renders as literal text
11
+ (matplotlib renders ``\\$`` as a plain ``$``) -- an invalid label must NEVER
12
+ error an export.
13
+
14
+ Screen/export WYSIWYG (bug-hunt fix): the frontend's parser
15
+ (``frontend/src/lib/richtext.ts``) only accepts a STRICT SUBSET of
16
+ mathtext -- Greek letters, ``\\AA \\circ \\times \\cdot \\pm \\prime \\,
17
+ \\mathrm \\mathit``, and literal Unicode -- and rejects everything else
18
+ (e.g. ``\\frac``, ``\\sqrt``, ``\\sum``) as invalid markup, rendering it
19
+ literally on screen. Raw matplotlib accepts a much larger command set, so
20
+ without this gate a label like ``$\\frac{1}{2}$`` would render literal text
21
+ ("Invalid markup") on screen but an actual fraction in the PDF/SVG export --
22
+ a WYSIWYG violation. `_uses_only_supported_commands` enumerates the SAME
23
+ command set the frontend parser accepts and rejects (falls back to literal)
24
+ any ``$...$`` region using a command outside it, BEFORE the matplotlib trial
25
+ parse below ever runs. Keep `SUPPORTED_MATHTEXT_COMMANDS` in sync with
26
+ richtext.ts's ``GREEK``/``SYMBOLS`` tables + ``mathrm``/``mathit`` handling.
27
+
28
+ Pure layer: string in -> string out. matplotlib is imported lazily (same
29
+ convention as the figure modules -- the heavy import is paid only on export).
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ import re
35
+ from functools import lru_cache
36
+ from typing import Any
37
+
38
+ __all__ = ["safe_mathtext_label", "SUPPORTED_MATHTEXT_COMMANDS"]
39
+
40
+ # A "$" not preceded by a backslash -- matplotlib's own math-region rule
41
+ # (matplotlib.cbook.is_math_text counts these; an odd count means the string
42
+ # is rendered as literal text, dollars visible, no mathtext at all).
43
+ _UNESCAPED_DOLLAR = re.compile(r"(?<!\\)\$")
44
+
45
+ # A backslash command name (`\foo`) inside a math region. `\,` (thin space)
46
+ # is handled separately by richtext.ts before its name-based dispatch and
47
+ # has no letters, so it never matches this and is implicitly always allowed.
48
+ _COMMAND = re.compile(r"\\([a-zA-Z]+)")
49
+
50
+ # Mirrors frontend/src/lib/richtext.ts's `GREEK` table: lowercase (+ \var*
51
+ # variants) render italic, uppercase upright -- irrelevant here, we only
52
+ # need the NAME set, not the styling.
53
+ _GREEK_COMMANDS = frozenset(
54
+ {
55
+ "alpha", "beta", "gamma", "delta", "epsilon", "varepsilon", "zeta",
56
+ "eta", "theta", "vartheta", "iota", "kappa", "lambda", "mu", "nu",
57
+ "xi", "pi", "rho", "sigma", "varsigma", "tau", "upsilon", "phi",
58
+ "varphi", "chi", "psi", "omega",
59
+ "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon",
60
+ "Phi", "Psi", "Omega",
61
+ }
62
+ )
63
+ # Mirrors richtext.ts's `SYMBOLS` table (non-Greek symbol commands).
64
+ _SYMBOL_COMMANDS = frozenset({"AA", "circ", "times", "cdot", "pm", "prime"})
65
+ # Mirrors richtext.ts's `\mathrm{...}` / `\mathit{...}` style-group handling.
66
+ _STYLE_COMMANDS = frozenset({"mathrm", "mathit"})
67
+
68
+ SUPPORTED_MATHTEXT_COMMANDS = _GREEK_COMMANDS | _SYMBOL_COMMANDS | _STYLE_COMMANDS
69
+
70
+
71
+ def _uses_only_supported_commands(label: str) -> bool:
72
+ """True when every backslash command inside every ``$...$`` region of
73
+ `label` is in `SUPPORTED_MATHTEXT_COMMANDS`. Text OUTSIDE `$...$` is
74
+ never scanned -- a stray backslash there is the caller's problem, not
75
+ this gate's (and richtext.ts itself only ever considers commands inside
76
+ math regions). Assumes a balanced (even) unescaped-`$` count, as
77
+ guaranteed by `safe_mathtext_label` calling this only after that check.
78
+ """
79
+ segments = _UNESCAPED_DOLLAR.split(label)
80
+ for i, segment in enumerate(segments):
81
+ if i % 2 == 0:
82
+ continue # literal text outside $...$
83
+ for m in _COMMAND.finditer(segment):
84
+ if m.group(1) not in SUPPORTED_MATHTEXT_COMMANDS:
85
+ return False
86
+ return True
87
+
88
+
89
+ @lru_cache(maxsize=1)
90
+ def _parser() -> Any:
91
+ """The mathtext trial parser (cached -- construction is not free)."""
92
+ from matplotlib.mathtext import MathTextParser
93
+
94
+ return MathTextParser("agg")
95
+
96
+
97
+ def safe_mathtext_label(label: str) -> str:
98
+ """Return ``label`` unchanged when it renders safely; else de-math it.
99
+
100
+ - No ``$`` at all: fast path, returned as-is (byte-identical to today).
101
+ - Odd count of unescaped ``$``: matplotlib already treats the whole
102
+ string as literal text -- returned as-is.
103
+ - Balanced ``$...$`` regions using only commands the frontend's
104
+ richtext.ts subset also accepts (`SUPPORTED_MATHTEXT_COMMANDS`), AND
105
+ that trial-parse successfully with matplotlib's mathtext parser ->
106
+ unchanged (mathtext renders it at export, matching the screen).
107
+ Otherwise (an out-of-subset command, e.g. ``\\frac``/``\\sqrt``/
108
+ ``\\sum``, OR a parse failure even within the subset, e.g. unbalanced
109
+ braces) -> every unescaped ``$`` is escaped to ``\\$`` so matplotlib
110
+ renders the literal string (dollars visible) instead of raising at
111
+ savefig time OR silently rendering richer math than the screen ever
112
+ showed.
113
+ """
114
+ if not label or "$" not in label:
115
+ return label
116
+ n_math = len(_UNESCAPED_DOLLAR.findall(label))
117
+ if n_math == 0 or n_math % 2 == 1:
118
+ # Zero unescaped $ (all \$-escaped) or an odd count: matplotlib
119
+ # already renders the whole string as literal text -- leave it be.
120
+ return label
121
+ if not _uses_only_supported_commands(label):
122
+ return _UNESCAPED_DOLLAR.sub(r"\\$", label)
123
+ try:
124
+ _parser().parse(label)
125
+ except Exception: # ANY parse failure means "render literal", never raise
126
+ return _UNESCAPED_DOLLAR.sub(r"\\$", label)
127
+ return label
@@ -17,6 +17,7 @@ from collections.abc import Mapping
17
17
  from typing import Any
18
18
 
19
19
  from quantized.calc.figure_labels import safe_mathtext_label
20
+ from quantized.calc.figure_shapes import _apply_shapes, _validate_shapes
20
21
 
21
22
  __all__ = ["_apply_overrides", "_validate_overrides"]
22
23
 
@@ -63,6 +64,7 @@ def _validate_overrides(ov: Mapping[str, Any]) -> None:
63
64
  if prev_hi is not None and lo < prev_hi:
64
65
  raise ValueError("x_breaks entries must be sorted and non-overlapping")
65
66
  prev_hi = hi
67
+ _validate_shapes(ov.get("shapes"))
66
68
 
67
69
 
68
70
  def _apply_overrides(
@@ -142,6 +144,23 @@ def _apply_overrides(
142
144
  # pixel-identical placement between screen and export.
143
145
  ann_kw["xycoords"] = "figure fraction"
144
146
  y = 1.0 - y
147
+ frame = ann.get("frame")
148
+ if frame:
149
+ # MAIN #27 "text box": a bbox behind the annotation text. `pad`
150
+ # (screen CSS px around the measured text) has no exact
151
+ # matplotlib equivalent (`boxstyle="square,pad=N"`'s pad is in
152
+ # font-size units, not px) -- divided by a fixed factor so the
153
+ # box reads as padded rather than pixel-identical, the same
154
+ # "Origin-parity-in-spirit, not pixel-identical" caveat the
155
+ # page-anchor y-flip above documents. fc/ec default to a plain
156
+ # white-card-on-black-border look (independent of the screen's
157
+ # own dark-canvas ink default -- publication export is white-bg).
158
+ ann_kw["bbox"] = dict(
159
+ boxstyle=f"square,pad={float(frame.get('pad', 4)) / 4.0}",
160
+ fc=frame.get("fill") or "white",
161
+ ec=frame.get("stroke") or "black",
162
+ alpha=frame.get("opacity", 1.0),
163
+ )
145
164
  ax.annotate(
146
165
  safe_mathtext_label(str(ann.get("text", ""))),
147
166
  xy=(x, y),
@@ -157,3 +176,8 @@ def _apply_overrides(
157
176
  top=None if margins.get("top") is None else 1.0 - float(margins["top"]),
158
177
  bottom=margins.get("bottom"),
159
178
  )
179
+
180
+ # MAIN #27: shapes paint LAST -- on top of everything else this sweep
181
+ # drew (annotations included), matching export intent: shapes mark up
182
+ # the finished figure.
183
+ _apply_shapes(fig, ax, ov.get("shapes"))
@@ -0,0 +1,153 @@
1
+ """Drawn-shape overrides (MAIN #27) -- export parity for the screen's
2
+ ``lib/uplotShapes.ts``. Split out of ``figure_overrides.py`` purely to stay
3
+ under each module's line-count discipline (same reasoning as
4
+ ``figure_labels.py`` / ``figure_break.py``) -- the behavioural contract is
5
+ still ``figure_overrides``'s; ``_apply_overrides`` calls ``_apply_shapes``
6
+ as its last step, AFTER the annotation sweep, so shapes paint on TOP of
7
+ everything else the override sweep drew (annotations included) -- matching
8
+ export intent: shapes mark up the finished figure. Pure layer: mapping in ->
9
+ mutates the passed matplotlib Figure/Axes, no return value.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from collections.abc import Mapping, Sequence
15
+ from typing import Any, Literal
16
+
17
+ from matplotlib.lines import Line2D
18
+ from matplotlib.patches import Ellipse, FancyArrowPatch, Rectangle
19
+
20
+ __all__ = ["_apply_shapes", "_validate_shapes"]
21
+
22
+ _SHAPE_KINDS = frozenset({"arrow", "line", "rect", "ellipse"})
23
+
24
+ # Default whole-shape opacity (fill AND stroke, ONE knob) mirroring the
25
+ # screen's `defaultShapeOpacity` (lib/uplotShapes.ts): 1 for line/arrow, 0.35
26
+ # for rect/ellipse (a freshly drawn box reads as visibly translucent OVER
27
+ # the data it marks).
28
+ _DEFAULT_OPACITY = {"arrow": 1.0, "line": 1.0, "rect": 0.35, "ellipse": 0.35}
29
+ _DEFAULT_WIDTH = 1.5
30
+ _DEFAULT_STROKE = "black"
31
+
32
+
33
+ def _validate_shapes(shapes: Sequence[Mapping[str, Any]] | None) -> None:
34
+ """Raise ``ValueError`` on a malformed shape (bad kind, non-finite
35
+ coords); a shape with an unknown/missing key inside is otherwise
36
+ tolerant (unknown keys ignored), mirroring ``_validate_overrides``."""
37
+ if not shapes:
38
+ return
39
+ for sh in shapes:
40
+ kind = sh.get("kind")
41
+ if kind not in _SHAPE_KINDS:
42
+ raise ValueError(f"shape kind must be one of {sorted(_SHAPE_KINDS)}")
43
+ for key in ("x1", "y1", "x2", "y2"):
44
+ v = sh.get(key)
45
+ if not isinstance(v, (int, float)) or isinstance(v, bool):
46
+ raise ValueError(f"shape {key} must be a number")
47
+
48
+
49
+ def _shape_endpoints(
50
+ sh: Mapping[str, Any], ax: Any, fig: Any
51
+ ) -> tuple[tuple[float, float], tuple[float, float], Any]:
52
+ """(p1, p2, transform) for one shape, resolving its anchor -- DATA (the
53
+ default: ``ax.transData``, applied implicitly by omitting ``transform``
54
+ and adding via ``ax.add_patch``/``ax.add_line``) or PAGE (explicit
55
+ ``fig.transFigure``, Y FLIPPED -- canvas y grows downward, matplotlib
56
+ figure fraction grows upward -- the SAME convention
57
+ ``_apply_overrides``'s page-anchored annotation uses)."""
58
+ x1, y1 = float(sh["x1"]), float(sh["y1"])
59
+ x2, y2 = float(sh["x2"]), float(sh["y2"])
60
+ if sh.get("anchor") == "page":
61
+ return (x1, 1.0 - y1), (x2, 1.0 - y2), fig.transFigure
62
+ return (x1, y1), (x2, y2), ax.transData
63
+
64
+
65
+ def _apply_shapes(fig: Any, ax: Any, shapes: Sequence[Mapping[str, Any]] | None) -> None:
66
+ """Draw MAIN #27 shapes (arrow/line/rect/ellipse). Arrows use
67
+ ``FancyArrowPatch``; plain lines ``Line2D``; rect/ellipse the matching
68
+ matplotlib patch with ``alpha`` -- all added via ``ax.add_patch``/
69
+ ``ax.add_line`` (data-anchored, the default -- no explicit ``transform``
70
+ needed there; matplotlib resolves an artist added this way against
71
+ ``ax.transData``) or with an EXPLICIT ``transform=fig.transFigure`` for
72
+ a page-anchored shape (``ax.add_patch``/``add_line`` never override an
73
+ already-set transform -- verified empirically, see the porting notes).
74
+ """
75
+ if not shapes:
76
+ return
77
+ for sh in shapes:
78
+ kind = sh.get("kind")
79
+ if kind not in _SHAPE_KINDS:
80
+ continue
81
+ p1, p2, transform = _shape_endpoints(sh, ax, fig)
82
+ stroke = sh.get("stroke") or _DEFAULT_STROKE
83
+ # `is not None` (not `or`): an explicit `width: 0` is falsy in Python
84
+ # and `... or _DEFAULT_WIDTH` was silently replacing it with the
85
+ # default (1.5) -- unlike the correct `opacity` idiom two lines below.
86
+ width = float(sh["width"]) if sh.get("width") is not None else _DEFAULT_WIDTH
87
+ dash: Literal["-", "--"] = "--" if sh.get("dash") else "-"
88
+ opacity = sh.get("opacity")
89
+ opacity = float(opacity) if opacity is not None else _DEFAULT_OPACITY[kind]
90
+ fill = sh.get("fill") or stroke
91
+ patch: Any
92
+
93
+ if kind == "arrow":
94
+ patch = FancyArrowPatch(
95
+ p1,
96
+ p2,
97
+ transform=transform,
98
+ arrowstyle="-|>",
99
+ mutation_scale=12 + width * 4,
100
+ # matplotlib's FancyArrowPatch default shrinkA/shrinkB=2pt
101
+ # insets BOTH ends from the given points (meant for
102
+ # "annotate near, not touching, an object") -- WYSIWYG with
103
+ # the screen's canvas draw (no shrink at all) needs the
104
+ # endpoints to land EXACTLY where dragged.
105
+ shrinkA=0,
106
+ shrinkB=0,
107
+ color=stroke,
108
+ linewidth=width,
109
+ linestyle=dash,
110
+ alpha=opacity,
111
+ )
112
+ ax.add_patch(patch)
113
+ elif kind == "line":
114
+ line = Line2D(
115
+ [p1[0], p2[0]],
116
+ [p1[1], p2[1]],
117
+ transform=transform,
118
+ color=stroke,
119
+ linewidth=width,
120
+ linestyle=dash,
121
+ alpha=opacity,
122
+ )
123
+ ax.add_line(line)
124
+ elif kind == "rect":
125
+ x0, x1v = min(p1[0], p2[0]), max(p1[0], p2[0])
126
+ y0, y1v = min(p1[1], p2[1]), max(p1[1], p2[1])
127
+ patch = Rectangle(
128
+ (x0, y0),
129
+ x1v - x0,
130
+ y1v - y0,
131
+ transform=transform,
132
+ edgecolor=stroke,
133
+ facecolor=fill,
134
+ linewidth=width,
135
+ linestyle=dash,
136
+ alpha=opacity,
137
+ )
138
+ ax.add_patch(patch)
139
+ else: # ellipse
140
+ cx, cy = (p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2
141
+ w, h = abs(p2[0] - p1[0]), abs(p2[1] - p1[1])
142
+ patch = Ellipse(
143
+ (cx, cy),
144
+ w,
145
+ h,
146
+ transform=transform,
147
+ edgecolor=stroke,
148
+ facecolor=fill,
149
+ linewidth=width,
150
+ linestyle=dash,
151
+ alpha=opacity,
152
+ )
153
+ ax.add_patch(patch)