batplot 1.8.48__tar.gz → 1.8.50__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 (235) hide show
  1. {batplot-1.8.48 → batplot-1.8.50}/PKG-INFO +31 -2
  2. {batplot-1.8.48 → batplot-1.8.50}/README.md +30 -1
  3. {batplot-1.8.48 → batplot-1.8.50}/batplot/__init__.py +1 -1
  4. {batplot-1.8.48 → batplot-1.8.50}/batplot/args.py +20 -3
  5. {batplot-1.8.48 → batplot-1.8.50}/batplot/batch.py +6 -4
  6. {batplot-1.8.48 → batplot-1.8.50}/batplot/batplot.py +47 -8
  7. {batplot-1.8.48 → batplot-1.8.50}/batplot/canvas_interactive.py +17 -2
  8. {batplot-1.8.48 → batplot-1.8.50}/batplot/color_utils.py +34 -15
  9. {batplot-1.8.48 → batplot-1.8.50}/batplot/data/CHANGELOG.md +12 -0
  10. batplot-1.8.50/batplot/data/latest_release_notes.json +9 -0
  11. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/ec_batch_helpers.py +15 -3
  12. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/load.py +3 -0
  13. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/menu_cpc.py +23 -1
  14. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/menu_ec.py +28 -7
  15. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/menu_histo.py +1 -1
  16. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/menu_operando.py +54 -10
  17. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/menu_xy.py +107 -4
  18. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/menu_rendering.py +56 -2
  19. batplot-1.8.50/batplot/plot_modes/common/overview_metrics.py +782 -0
  20. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/spines.py +3 -0
  21. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/terminal.py +12 -1
  22. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/actions.py +38 -9
  23. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/interactive.py +20 -0
  24. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/menu.py +3 -2
  25. batplot-1.8.50/batplot/plot_modes/cpc/overview.py +202 -0
  26. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/session.py +2 -0
  27. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/style.py +17 -2
  28. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/actions.py +7 -4
  29. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/colors.py +10 -5
  30. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/interactive.py +26 -0
  31. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/menu.py +11 -2
  32. batplot-1.8.50/batplot/plot_modes/electrochem/overview.py +185 -0
  33. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/session.py +2 -0
  34. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/style.py +5 -1
  35. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/style_apply.py +6 -3
  36. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/actions.py +8 -7
  37. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/colors.py +10 -8
  38. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/interactive.py +3 -4
  39. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/plot.py +12 -4
  40. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/session.py +23 -2
  41. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/actions.py +8 -5
  42. batplot-1.8.50/batplot/plot_modes/operando/axis_units.py +424 -0
  43. batplot-1.8.50/batplot/plot_modes/operando/colors.py +353 -0
  44. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/interactive.py +352 -162
  45. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/layout.py +20 -1
  46. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/menu.py +17 -2
  47. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/plot.py +287 -25
  48. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/session.py +67 -4
  49. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/style.py +62 -13
  50. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/style_apply.py +187 -49
  51. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/visibility.py +4 -0
  52. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/actions.py +7 -1
  53. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/axis_range.py +34 -24
  54. batplot-1.8.50/batplot/plot_modes/xy/axis_units.py +770 -0
  55. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/cif.py +572 -27
  56. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/colors.py +8 -1
  57. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/data_ops.py +24 -8
  58. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/interactive.py +345 -49
  59. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/labels.py +8 -0
  60. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/menu.py +16 -2
  61. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/pipeline.py +202 -74
  62. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/session.py +152 -36
  63. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/style.py +312 -28
  64. {batplot-1.8.48 → batplot-1.8.50}/batplot/readers_xrd.py +28 -4
  65. {batplot-1.8.48 → batplot-1.8.50}/batplot/utils.py +85 -31
  66. {batplot-1.8.48 → batplot-1.8.50}/batplot/version_check.py +4 -2
  67. {batplot-1.8.48 → batplot-1.8.50}/batplot.egg-info/PKG-INFO +31 -2
  68. {batplot-1.8.48 → batplot-1.8.50}/batplot.egg-info/SOURCES.txt +20 -0
  69. {batplot-1.8.48 → batplot-1.8.50}/pyproject.toml +1 -1
  70. batplot-1.8.50/tests/test_all_menus_smoke.py +1977 -0
  71. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_menu_parity.py +3 -1
  72. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_session.py +7 -1
  73. batplot-1.8.50/tests/test_bc_new_fields_defaults.py +101 -0
  74. batplot-1.8.50/tests/test_cif_tick_crystallography.py +82 -0
  75. batplot-1.8.50/tests/test_color_display_hex.py +59 -0
  76. batplot-1.8.50/tests/test_deep_noninteractive_bugs.py +282 -0
  77. {batplot-1.8.48 → batplot-1.8.50}/tests/test_ec_roundtrip.py +1 -1
  78. {batplot-1.8.48 → batplot-1.8.50}/tests/test_histo.py +1 -1
  79. batplot-1.8.50/tests/test_interactive_menu_smoke.py +545 -0
  80. {batplot-1.8.48 → batplot-1.8.50}/tests/test_interactive_state.py +29 -0
  81. batplot-1.8.50/tests/test_operando_axis_units.py +258 -0
  82. batplot-1.8.50/tests/test_operando_cif_add.py +213 -0
  83. batplot-1.8.50/tests/test_operando_cif_color.py +183 -0
  84. {batplot-1.8.48 → batplot-1.8.50}/tests/test_operando_roundtrip.py +2 -1
  85. batplot-1.8.50/tests/test_operando_submenu_smoke.py +226 -0
  86. batplot-1.8.50/tests/test_overview_metrics.py +216 -0
  87. batplot-1.8.50/tests/test_pi_axis_units_persistence.py +140 -0
  88. batplot-1.8.50/tests/test_pisb_deep_all_modes.py +656 -0
  89. batplot-1.8.50/tests/test_undo_deep_all_modes.py +177 -0
  90. batplot-1.8.50/tests/test_xy_axis_units.py +466 -0
  91. batplot-1.8.50/tests/test_xy_cif_add.py +408 -0
  92. {batplot-1.8.48 → batplot-1.8.50}/tests/test_xy_modules.py +16 -2
  93. {batplot-1.8.48 → batplot-1.8.50}/tests/test_xy_roundtrip.py +43 -0
  94. batplot-1.8.48/batplot/data/latest_release_notes.json +0 -7
  95. batplot-1.8.48/batplot/plot_modes/operando/colors.py +0 -173
  96. batplot-1.8.48/tests/test_interactive_menu_smoke.py +0 -254
  97. {batplot-1.8.48 → batplot-1.8.50}/DEVELOPING.md +0 -0
  98. {batplot-1.8.48 → batplot-1.8.50}/LICENSE +0 -0
  99. {batplot-1.8.48 → batplot-1.8.50}/MANIFEST.in +0 -0
  100. {batplot-1.8.48 → batplot-1.8.50}/NOTICE +0 -0
  101. {batplot-1.8.48 → batplot-1.8.50}/batplot/_mpl_backend.py +0 -0
  102. {batplot-1.8.48 → batplot-1.8.50}/batplot/cif.py +0 -0
  103. {batplot-1.8.48 → batplot-1.8.50}/batplot/cli.py +0 -0
  104. {batplot-1.8.48 → batplot-1.8.50}/batplot/cli_save.py +0 -0
  105. {batplot-1.8.48 → batplot-1.8.50}/batplot/config.py +0 -0
  106. {batplot-1.8.48 → batplot-1.8.50}/batplot/converters.py +0 -0
  107. {batplot-1.8.48 → batplot-1.8.50}/batplot/dev_upgrade.py +0 -0
  108. {batplot-1.8.48 → batplot-1.8.50}/batplot/ec_common.py +0 -0
  109. {batplot-1.8.48 → batplot-1.8.50}/batplot/modes.py +0 -0
  110. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/__init__.py +0 -0
  111. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/__init__.py +0 -0
  112. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/batch_commands.py +0 -0
  113. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/batch_crosshair.py +0 -0
  114. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/batch_figure_io.py +0 -0
  115. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/batch_geom_helpers.py +0 -0
  116. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/batch_io.py +0 -0
  117. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/batch_menu_helpers.py +0 -0
  118. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/batch_menu_io.py +0 -0
  119. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/batch_panel_state.py +0 -0
  120. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/common.py +0 -0
  121. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/cpc_batch_helpers.py +0 -0
  122. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/histo_batch_helpers.py +0 -0
  123. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/kinds.py +0 -0
  124. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/operando_batch_helpers.py +0 -0
  125. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/routing.py +0 -0
  126. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/batch_session/xy_batch_helpers.py +0 -0
  127. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/__init__.py +0 -0
  128. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/axis_state.py +0 -0
  129. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/batch_font.py +0 -0
  130. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/crosshair_export.py +0 -0
  131. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/files.py +0 -0
  132. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/font_extras.py +0 -0
  133. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/fonts.py +0 -0
  134. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/interactive_state.py +0 -0
  135. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/menus.py +0 -0
  136. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/palettes.py +0 -0
  137. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/session_helpers.py +0 -0
  138. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/session_key_smoke.py +0 -0
  139. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/size_spec.py +0 -0
  140. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/smoothing.py +0 -0
  141. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/sources.py +0 -0
  142. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/state_capture.py +0 -0
  143. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/style_routing.py +0 -0
  144. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/common/title_offsets.py +0 -0
  145. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/__init__.py +0 -0
  146. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/colors.py +0 -0
  147. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/labels.py +0 -0
  148. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/legend.py +0 -0
  149. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/routing.py +0 -0
  150. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/cpc/snapshots.py +0 -0
  151. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/__init__.py +0 -0
  152. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/dqdv_2d.py +0 -0
  153. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/export.py +0 -0
  154. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/labels.py +0 -0
  155. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/legend.py +0 -0
  156. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/legend_order.py +0 -0
  157. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/line_style.py +0 -0
  158. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/routing.py +0 -0
  159. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/electrochem/spine_colors.py +0 -0
  160. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/__init__.py +0 -0
  161. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/density_curve.py +0 -0
  162. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/fonts.py +0 -0
  163. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/labels.py +0 -0
  164. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/line_style.py +0 -0
  165. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/load.py +0 -0
  166. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/routing.py +0 -0
  167. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/spines.py +0 -0
  168. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/toggles.py +0 -0
  169. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/wizard.py +0 -0
  170. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/histo/y_range.py +0 -0
  171. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/__init__.py +0 -0
  172. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/grid.py +0 -0
  173. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/ions_axis.py +0 -0
  174. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/labels.py +0 -0
  175. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/layout_menu.py +0 -0
  176. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/line_style.py +0 -0
  177. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/peaks.py +0 -0
  178. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/operando/routing.py +0 -0
  179. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/session_routing.py +0 -0
  180. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/__init__.py +0 -0
  181. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/arrange.py +0 -0
  182. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/derivative.py +0 -0
  183. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/game.py +0 -0
  184. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/line_style.py +0 -0
  185. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/peaks.py +0 -0
  186. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/smoothing.py +0 -0
  187. {batplot-1.8.48 → batplot-1.8.50}/batplot/plot_modes/xy/spines.py +0 -0
  188. {batplot-1.8.48 → batplot-1.8.50}/batplot/plotting.py +0 -0
  189. {batplot-1.8.48 → batplot-1.8.50}/batplot/readers.py +0 -0
  190. {batplot-1.8.48 → batplot-1.8.50}/batplot/session.py +0 -0
  191. {batplot-1.8.48 → batplot-1.8.50}/batplot/showcol.py +0 -0
  192. {batplot-1.8.48 → batplot-1.8.50}/batplot/style.py +0 -0
  193. {batplot-1.8.48 → batplot-1.8.50}/batplot/ui.py +0 -0
  194. {batplot-1.8.48 → batplot-1.8.50}/batplot.egg-info/dependency_links.txt +0 -0
  195. {batplot-1.8.48 → batplot-1.8.50}/batplot.egg-info/entry_points.txt +0 -0
  196. {batplot-1.8.48 → batplot-1.8.50}/batplot.egg-info/requires.txt +0 -0
  197. {batplot-1.8.48 → batplot-1.8.50}/batplot.egg-info/top_level.txt +0 -0
  198. {batplot-1.8.48 → batplot-1.8.50}/setup.cfg +0 -0
  199. {batplot-1.8.48 → batplot-1.8.50}/setup.py +0 -0
  200. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_all_modes_sync.py +0 -0
  201. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_crosshair.py +0 -0
  202. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_ec_cycles_status.py +0 -0
  203. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_font_menu.py +0 -0
  204. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_geom_menu.py +0 -0
  205. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_panel_status.py +0 -0
  206. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_pisb_contract.py +0 -0
  207. {batplot-1.8.48 → batplot-1.8.50}/tests/test_batch_spine_sync.py +0 -0
  208. {batplot-1.8.48 → batplot-1.8.50}/tests/test_bruker_intensity.py +0 -0
  209. {batplot-1.8.48 → batplot-1.8.50}/tests/test_cli_all_flags.py +0 -0
  210. {batplot-1.8.48 → batplot-1.8.50}/tests/test_cli_save.py +0 -0
  211. {batplot-1.8.48 → batplot-1.8.50}/tests/test_cli_smoke.py +0 -0
  212. {batplot-1.8.48 → batplot-1.8.50}/tests/test_color_listing_visible.py +0 -0
  213. {batplot-1.8.48 → batplot-1.8.50}/tests/test_color_utils.py +0 -0
  214. {batplot-1.8.48 → batplot-1.8.50}/tests/test_common_files.py +0 -0
  215. {batplot-1.8.48 → batplot-1.8.50}/tests/test_common_palettes.py +0 -0
  216. {batplot-1.8.48 → batplot-1.8.50}/tests/test_contracts.py +0 -0
  217. {batplot-1.8.48 → batplot-1.8.50}/tests/test_cpc_roundtrip.py +0 -0
  218. {batplot-1.8.48 → batplot-1.8.50}/tests/test_critical_stability_fixes.py +0 -0
  219. {batplot-1.8.48 → batplot-1.8.50}/tests/test_cross_platform_parity.py +0 -0
  220. {batplot-1.8.48 → batplot-1.8.50}/tests/test_crosshair_export.py +0 -0
  221. {batplot-1.8.48 → batplot-1.8.50}/tests/test_csv_readers.py +0 -0
  222. {batplot-1.8.48 → batplot-1.8.50}/tests/test_dev_upgrade.py +0 -0
  223. {batplot-1.8.48 → batplot-1.8.50}/tests/test_dqdv_contour_session_keys.py +0 -0
  224. {batplot-1.8.48 → batplot-1.8.50}/tests/test_histo_interactive_imports.py +0 -0
  225. {batplot-1.8.48 → batplot-1.8.50}/tests/test_imk_stderr_guard.py +0 -0
  226. {batplot-1.8.48 → batplot-1.8.50}/tests/test_menu_handler_imports.py +0 -0
  227. {batplot-1.8.48 → batplot-1.8.50}/tests/test_menu_prompt_order.py +0 -0
  228. {batplot-1.8.48 → batplot-1.8.50}/tests/test_mpl_backend.py +0 -0
  229. {batplot-1.8.48 → batplot-1.8.50}/tests/test_operando_batch_menu.py +0 -0
  230. {batplot-1.8.48 → batplot-1.8.50}/tests/test_operando_layout_menu.py +0 -0
  231. {batplot-1.8.48 → batplot-1.8.50}/tests/test_session_backward_compat.py +0 -0
  232. {batplot-1.8.48 → batplot-1.8.50}/tests/test_session_font_restore.py +0 -0
  233. {batplot-1.8.48 → batplot-1.8.50}/tests/test_state_capture.py +0 -0
  234. {batplot-1.8.48 → batplot-1.8.50}/tests/test_style_routing.py +0 -0
  235. {batplot-1.8.48 → batplot-1.8.50}/tests/test_xy_source_files.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: batplot
3
- Version: 1.8.48
3
+ Version: 1.8.50
4
4
  Summary: Interactive plotting tool for material science (1D plot) and electrochemistry (GC, CV, dQ/dV, CPC, operando) with batch processing
5
5
  Author-email: Tian Dai <tianda@uio.no>
6
6
  License: MIT License
@@ -64,6 +64,7 @@ With a single line of command to easily plot publication-ready plots with custom
64
64
  - **Electrochemistry Plot**: Galvanostatic cycling (GC), cyclic voltammetry (CV), differential capacity (dQdV), capacity per cycle (CPC) with multi-file support
65
65
  - **1D XY plot**: Designed for XRD, PDF, XAS (XANES/EXAFS) but also support other types
66
66
  - **Operando Contour plot**: Correlate in-situ characterizations (XRD/PDF/XAS) with electrochemical data
67
+ - **XRD axis units**: Interactive Options `u` converts 2θ ↔ Q ↔ d (XY and operando); CIF phase ticks follow the current domain
67
68
  - **Histogram mode**: Column histograms from tabular `.csv`/`.txt` data (e.g. particle-size lists)
68
69
  - **Interactive plotting**: Real-time editing customized for each type of plottings
69
70
  - **Session Persistence**: Save and reload complete plot states with `.pkl` files
@@ -94,11 +95,12 @@ In batplot, --xaxis is frequently used to indicate the data type.
94
95
 
95
96
  ```bash
96
97
 
97
- # Specify X-axis type (Q, 2theta, r, k, energy, time or any user defined names)
98
+ # Specify X-axis type (Q, 2theta, d, r, k, energy, time or any user defined names)
98
99
  # By defauly, batplot will skip the header lines, plot the first and second columns as x and y
99
100
  # Q and q are equivalent (case-insensitive)
100
101
  batplot pattern.xye --xaxis 2theta --i
101
102
  batplot data.qye --xaxis q --i
103
+ batplot data.xye --xaxis d --wl 1.54 --i
102
104
  batplot data.txt --xaxis whatever --i
103
105
 
104
106
  # Set X-axis range
@@ -191,6 +193,27 @@ batplot file1.xy file2.xy --stack --i
191
193
  batplot allfiles --xaxis 2theta --xrange 15 75 --i
192
194
  ```
193
195
 
196
+ **XRD Options `u` (axis units):** On diffraction plots only, press `u` to convert the x-axis among **2θ ↔ Q ↔ d**. Conversions that involve 2θ need a wavelength (`--wl`, `file:wl`, or a prompt). Data, axis labels/limits, and CIF ticks stay in sync. Not available for PDF/XAS or other non-XRD axes.
197
+
198
+ ```bash
199
+ # Launch in 2θ, then use Options u → q (or d) inside the menu
200
+ batplot data.xye:0.709 --xaxis 2theta --i
201
+ batplot data.xye --xaxis 2theta --wl 1.5406 --i
202
+ ```
203
+
204
+ ### CIF phase ticks
205
+
206
+ Add one or more `.cif` files to overlay Bragg reflection markers. Peaks are stored in Q and drawn in the current axis domain (2θ / Q / d). Use `cif` in the interactive menu to add, rename, or hide sets; after Options `u`, ticks redraw in the new units.
207
+
208
+ ```bash
209
+ # Q plot + CIF ticks
210
+ batplot scan.xye:1.54 phase.cif --i
211
+
212
+ # 2θ plot: give λ for data and/or CIF (file.cif:wl)
213
+ batplot scan.xye phase.cif:0.709 --xaxis 2theta --wl 0.709 --i
214
+ batplot scan.xye:1.54 phase.cif --stack --i
215
+ ```
216
+
194
217
  ### Session save without interactive menu (`--save`)
195
218
 
196
219
  ```bash
@@ -306,6 +329,12 @@ batplot --operando --1d --i
306
329
  batplot folder phase.cif:1.54 --operando --i
307
330
  ```
308
331
 
332
+ **XRD Options `u`:** In the operando interactive menu, press `u` to convert the contour x-axis among **2θ ↔ Q ↔ d** (XRD only; needs λ for 2θ). CIF ticks follow the new domain. Prefer an explicit `--xaxis` when combining with `--wl` (e.g. `--xaxis 2theta --wl 0.709` keeps degrees; `--wl` alone still defaults to Q).
333
+
334
+ ```bash
335
+ batplot folder phase.cif --operando --xaxis 2theta --wl 0.709 --i
336
+ ```
337
+
309
338
  Operando column selection:
310
339
  - `--readcolc <x> <y>`: columns for the contour plot (from .xy/.xye/.qye/.dat files)
311
340
  - `--readcols <x> <y>`: columns for the side panel (from .mpt file)
@@ -10,6 +10,7 @@ With a single line of command to easily plot publication-ready plots with custom
10
10
  - **Electrochemistry Plot**: Galvanostatic cycling (GC), cyclic voltammetry (CV), differential capacity (dQdV), capacity per cycle (CPC) with multi-file support
11
11
  - **1D XY plot**: Designed for XRD, PDF, XAS (XANES/EXAFS) but also support other types
12
12
  - **Operando Contour plot**: Correlate in-situ characterizations (XRD/PDF/XAS) with electrochemical data
13
+ - **XRD axis units**: Interactive Options `u` converts 2θ ↔ Q ↔ d (XY and operando); CIF phase ticks follow the current domain
13
14
  - **Histogram mode**: Column histograms from tabular `.csv`/`.txt` data (e.g. particle-size lists)
14
15
  - **Interactive plotting**: Real-time editing customized for each type of plottings
15
16
  - **Session Persistence**: Save and reload complete plot states with `.pkl` files
@@ -40,11 +41,12 @@ In batplot, --xaxis is frequently used to indicate the data type.
40
41
 
41
42
  ```bash
42
43
 
43
- # Specify X-axis type (Q, 2theta, r, k, energy, time or any user defined names)
44
+ # Specify X-axis type (Q, 2theta, d, r, k, energy, time or any user defined names)
44
45
  # By defauly, batplot will skip the header lines, plot the first and second columns as x and y
45
46
  # Q and q are equivalent (case-insensitive)
46
47
  batplot pattern.xye --xaxis 2theta --i
47
48
  batplot data.qye --xaxis q --i
49
+ batplot data.xye --xaxis d --wl 1.54 --i
48
50
  batplot data.txt --xaxis whatever --i
49
51
 
50
52
  # Set X-axis range
@@ -137,6 +139,27 @@ batplot file1.xy file2.xy --stack --i
137
139
  batplot allfiles --xaxis 2theta --xrange 15 75 --i
138
140
  ```
139
141
 
142
+ **XRD Options `u` (axis units):** On diffraction plots only, press `u` to convert the x-axis among **2θ ↔ Q ↔ d**. Conversions that involve 2θ need a wavelength (`--wl`, `file:wl`, or a prompt). Data, axis labels/limits, and CIF ticks stay in sync. Not available for PDF/XAS or other non-XRD axes.
143
+
144
+ ```bash
145
+ # Launch in 2θ, then use Options u → q (or d) inside the menu
146
+ batplot data.xye:0.709 --xaxis 2theta --i
147
+ batplot data.xye --xaxis 2theta --wl 1.5406 --i
148
+ ```
149
+
150
+ ### CIF phase ticks
151
+
152
+ Add one or more `.cif` files to overlay Bragg reflection markers. Peaks are stored in Q and drawn in the current axis domain (2θ / Q / d). Use `cif` in the interactive menu to add, rename, or hide sets; after Options `u`, ticks redraw in the new units.
153
+
154
+ ```bash
155
+ # Q plot + CIF ticks
156
+ batplot scan.xye:1.54 phase.cif --i
157
+
158
+ # 2θ plot: give λ for data and/or CIF (file.cif:wl)
159
+ batplot scan.xye phase.cif:0.709 --xaxis 2theta --wl 0.709 --i
160
+ batplot scan.xye:1.54 phase.cif --stack --i
161
+ ```
162
+
140
163
  ### Session save without interactive menu (`--save`)
141
164
 
142
165
  ```bash
@@ -252,6 +275,12 @@ batplot --operando --1d --i
252
275
  batplot folder phase.cif:1.54 --operando --i
253
276
  ```
254
277
 
278
+ **XRD Options `u`:** In the operando interactive menu, press `u` to convert the contour x-axis among **2θ ↔ Q ↔ d** (XRD only; needs λ for 2θ). CIF ticks follow the new domain. Prefer an explicit `--xaxis` when combining with `--wl` (e.g. `--xaxis 2theta --wl 0.709` keeps degrees; `--wl` alone still defaults to Q).
279
+
280
+ ```bash
281
+ batplot folder phase.cif --operando --xaxis 2theta --wl 0.709 --i
282
+ ```
283
+
255
284
  Operando column selection:
256
285
  - `--readcolc <x> <y>`: columns for the contour plot (from .xy/.xye/.qye/.dat files)
257
286
  - `--readcols <x> <y>`: columns for the side panel (from .mpt file)
@@ -7,7 +7,7 @@ import importlib.abc
7
7
  import importlib.machinery
8
8
  import sys
9
9
 
10
- __version__ = "1.8.48"
10
+ __version__ = "1.8.50"
11
11
 
12
12
 
13
13
  _LEGACY_MODULE_ALIASES = {
@@ -172,6 +172,8 @@ def _print_general_help() -> None:
172
172
  "Features:\n"
173
173
  " • Interactive (--i): styling, ranges, fonts, export, sessions\n"
174
174
  " • XRD wavelength: --wl 1.54 or file.xye:1.5406 for Q conversion\n"
175
+ " • XRD axis units (interactive): Options u converts 2θ ↔ Q ↔ d (XY + operando; needs λ for 2θ)\n"
176
+ " • CIF phase ticks: add .cif (or file.cif:wl); ticks follow the current axis (2θ / Q / d)\n"
175
177
  " • X-axis range: --xrange min max\n"
176
178
  " • Save figure: --out filename (default .svg)\n"
177
179
  " • Save session: --save (choose folder + name; default stem for single file / --all batch)\n"
@@ -204,10 +206,21 @@ def _print_xy_help() -> None:
204
206
  msg = (
205
207
  "XY plots (XRD/PDF/XAS and many more)\n\n"
206
208
  "Supported files: .xye .xy .qye .dat .csv .gr .nor .chik .chir .txt .brml .raw .xrdml .rasx and other formats. CIF overlays supported.\n\n"
207
- "Axis detection: .qye→Q, .gr→r, .nor→energy, .chik→k, .chir→r, else use --xaxis (Q, 2theta, r, k, energy, time or user defined).\n"
209
+ "Axis detection: .qye→Q, .gr→r, .nor→energy, .chik→k, .chir→r, else use --xaxis (Q, 2theta, d, r, k, energy, time or user defined).\n"
208
210
  "If mixing 2θ data in Q, give wavelength per-file (file.xye:1.5406) or global flag --wl.\n"
209
211
  "A wavelength can be converted into a different wave length by file.xye:1.54:0.709.\n"
210
212
  "For electrochemistry CSV/MPT time-potential plots, use --xaxis time.\n\n"
213
+ "Interactive XRD axis units (Options u):\n"
214
+ " In --i, press u to convert the plotted XRD axis among 2θ ↔ Q ↔ d (XRD data only).\n"
215
+ " Conversions involving 2θ need λ (--wl, file:wl, or prompt). CIF ticks stay Bragg-aligned.\n"
216
+ " Not for PDF (.gr), XAS (.nor/.chik/.chir), or other non-diffraction axes.\n"
217
+ " Example: batplot data.xye:0.709 --xaxis 2theta --i then u → q (uses λ=0.709 Å).\n\n"
218
+ "CIF phase ticks:\n"
219
+ " Add .cif files on the command line (optional :wl for 2θ). Peaks are stored in Q and\n"
220
+ " drawn in the current domain (2θ / Q / d). In --i use cif to add/reorder/hide ticks;\n"
221
+ " after Options u, ticks redraw in the new units. Example:\n"
222
+ " batplot scan.xye:1.54 phase.cif --i\n"
223
+ " batplot scan.xye phase.cif:0.709 --xaxis 2theta --wl 0.709 --i\n\n"
211
224
  "Examples:\n"
212
225
  " batplot file.xy file2.xye --xaxis 2theta --i # Plot XRD data in 2theta space\n"
213
226
  " batplot file1.xye:1.5406 file2.txt:0.709 --i # Plot XRD data in different wavelengths in q space\n"
@@ -225,6 +238,7 @@ def _print_xy_help() -> None:
225
238
  "Tips and options:\n"
226
239
  "[XY plot]\n"
227
240
  " --i : open interactive menu for styling, ranges, fonts, export, sessions\n"
241
+ " (XRD: Options u = convert axis 2θ ↔ Q ↔ d; cif = phase tick overlay)\n"
228
242
  " --delta <float> : spacing between curves, e.g. --delta 0.1\n"
229
243
  " --norm : normalize intensity to 0-1 range. Stack mode (--stack) auto-normalizes\n"
230
244
  " --chik : EXAFS χ(k) plot (sets labels to k (Å⁻¹) vs χ(k))\n"
@@ -236,8 +250,8 @@ def _print_xy_help() -> None:
236
250
  " --xrange <min> <max> : set x-axis range, e.g. --xrange 0 10\n"
237
251
  " --out <filename> : save figure to file, e.g. --out file.svg\n"
238
252
  " --save : save .pkl session (prompt folder + name; no --i menu)\n"
239
- " --xaxis <type> : set x-axis type (Q, 2theta, r, k, energy, rft, time, or user defined)\n"
240
- " Q and q are equivalent (case-insensitive). e.g. --xaxis 2theta, --xaxis Q, --xaxis time\n"
253
+ " --xaxis <type> : set x-axis type (Q, 2theta, d, r, k, energy, rft, time, or user defined)\n"
254
+ " Q and q are equivalent (case-insensitive). e.g. --xaxis 2theta, --xaxis Q, --xaxis d\n"
241
255
  " --ro : swap x and y axes (exchange x and y values before plotting)\n"
242
256
  " e.g. --xaxis time --ro plots time as y-axis and potential as x-axis\n"
243
257
  " --wl <float> : set wavelength for Q conversion for all files, e.g. --wl 1.5406\n"
@@ -426,6 +440,9 @@ def _print_op_help() -> None:
426
440
  "Interactive (--i): menu has (Styles), (Operando), (Side Panel), (Options) columns.\n"
427
441
  "Resize axes/canvas, change colormap, set intensity range (oz), side-panel options,\n"
428
442
  "geometry tweaks, toggle spines/ticks/labels, print/export/import style, save session.\n"
443
+ "XRD only — Options u: convert contour X among 2θ ↔ Q ↔ d (needs λ for 2θ; CIF ticks follow).\n"
444
+ "CIF: add .cif on the command line or via the CIF submenu; ticks stay Bragg-aligned after u.\n"
445
+ " Example: batplot folder phase.cif --operando --xaxis 2theta --wl 0.709 --i\n"
429
446
  "Session save without menu: --save (combined operando plot — session name required).\n"
430
447
  )
431
448
  _print_help(msg)
@@ -255,6 +255,7 @@ def batch_process(directory: str, args):
255
255
  # We detect the format from the file extension and use the
256
256
  # appropriate reader function.
257
257
  # ============================================================
258
+ file_wl = getattr(args, "wl", None)
258
259
 
259
260
  if ext == '.gr':
260
261
  x, y = read_gr_file(fpath); e = None
@@ -281,8 +282,9 @@ def batch_process(directory: str, args):
281
282
  elif ext in ('.brml', '.xrdml', '.rasx') or (ext == '.raw' and is_bruker_raw(fpath)):
282
283
  x, y, e, wl_from_file = read_xrd_vendor_file(fpath)
283
284
  axis_mode = '2theta'
284
- if args.wl is None and wl_from_file is not None:
285
- args.wl = wl_from_file
285
+ if file_wl is None and wl_from_file is not None:
286
+ # Per-file wavelength only — do not mutate shared args.wl
287
+ file_wl = wl_from_file
286
288
  elif ext == '.raw':
287
289
  # .raw from non-Bruker instrument: load as generic text
288
290
  data = robust_loadtxt_skipheader(fpath)
@@ -374,12 +376,12 @@ def batch_process(directory: str, args):
374
376
 
375
377
  # Convert to Q if needed
376
378
  if axis_mode == 'Q' and ext not in ('.qye', '.gr', '.nor'):
377
- if args.wl is None:
379
+ if file_wl is None:
378
380
  axis_mode = '2theta'
379
381
  x_plot = x
380
382
  else:
381
383
  theta_rad = np.radians(x/2)
382
- x_plot = 4*np.pi*np.sin(theta_rad)/args.wl
384
+ x_plot = 4*np.pi*np.sin(theta_rad)/file_wl
383
385
  else:
384
386
  x_plot = x
385
387
 
@@ -414,6 +414,8 @@ def batplot_main() -> int: # type: ignore
414
414
  getattr(args, 'histo', False), # Histogram mode
415
415
  getattr(args, 'all', None) is not None, # Batch mode flag
416
416
  getattr(args, 'convert', None) is not None, # Conversion mode
417
+ getattr(args, 'canvas', False), # Canvas combine mode
418
+ getattr(args, 'extract_brml_scans', None) is not None, # BRML scan extract
417
419
  ])
418
420
 
419
421
  # If no files AND no special flags, nothing to do
@@ -422,12 +424,37 @@ def batplot_main() -> int: # type: ignore
422
424
  print("Use 'batplot --v' for version and release info, 'batplot --h' for CLI help, or 'batplot --m' to open the user manual.")
423
425
  return 0 # Exit successfully (not an error, just nothing to do)
424
426
 
427
+ # --extract-brml-scans: extract each XRD scan from .brml to .xy files, then exit
428
+ if getattr(args, "extract_brml_scans", None) is not None:
429
+ from .readers_xrd import extract_bruker_brml_scans
430
+
431
+ brml_files = [f for f in (args.files or []) if str(f).lower().endswith(".brml")]
432
+ if not brml_files:
433
+ print("batplot --extract-brml-scans: provide at least one .brml file.")
434
+ return 1
435
+ out_opt = getattr(args, "extract_brml_scans", "")
436
+ status = 0
437
+ for brml in brml_files:
438
+ try:
439
+ stem = os.path.splitext(os.path.basename(brml))[0]
440
+ out_dir = out_opt if out_opt else f"{stem}_scans"
441
+ if not os.path.isabs(out_dir):
442
+ out_dir = os.path.join(os.path.dirname(os.path.abspath(brml)) or ".", out_dir)
443
+ scans = extract_bruker_brml_scans(brml, out_dir=out_dir)
444
+ print(f"Extracted {len(scans)} scan(s) from {brml} → {out_dir}")
445
+ except Exception as exc:
446
+ print(f"Error extracting {brml}: {exc}")
447
+ status = 1
448
+ return status
449
+
425
450
  from ._mpl_backend import ensure_gui_backend
426
451
 
427
452
  ensure_gui_backend(args)
428
453
 
429
- # Histogram mode (tabular CSV/TXT)
430
- if getattr(args, 'histo', False):
454
+ # Histogram mode (tabular CSV/TXT) — after convert so --histo --convert still converts
455
+ # (convert is handled below after allfiles expansion when both flags appear).
456
+ # Prefer convert when both are set.
457
+ if getattr(args, 'histo', False) and getattr(args, 'convert', None) is None:
431
458
  from .plot_modes.histo.routing import handle_histo_mode
432
459
  return handle_histo_mode(args)
433
460
 
@@ -550,20 +577,32 @@ def batplot_main() -> int: # type: ignore
550
577
  if len(args.files) == 1:
551
578
  sole = args.files[0]
552
579
  if sole.lower() == 'all':
553
- batch_process(os.getcwd(), args)
554
- exit()
580
+ if getattr(args, "interactive", False):
581
+ _prepare_allfiles_directory(os.getcwd(), args, use_relative_paths=True)
582
+ # Continue to interactive multi-file plotting
583
+ else:
584
+ batch_process(os.getcwd(), args)
585
+ raise SystemExit(0)
555
586
  elif sole.lower() == 'allfiles':
556
587
  _prepare_allfiles_directory(os.getcwd(), args, use_relative_paths=True)
557
588
  # Continue to normal plotting mode with all files
558
589
  elif os.path.isdir(sole):
559
- batch_process(os.path.abspath(sole), args)
560
- exit()
590
+ if getattr(args, "interactive", False):
591
+ _prepare_allfiles_directory(os.path.abspath(sole), args, use_relative_paths=False)
592
+ # Continue to interactive multi-file plotting of directory contents
593
+ else:
594
+ batch_process(os.path.abspath(sole), args)
595
+ raise SystemExit(0)
561
596
 
562
597
  # --- XY Batch Mode: check for --all flag for XY files ---
563
598
  # Handle --all flag for XY batch processing (consistent with EC batch mode)
564
599
  if not ec_mode_active and getattr(args, 'all', None) is not None:
565
- batch_process(os.getcwd(), args)
566
- exit()
600
+ if getattr(args, "interactive", False):
601
+ # --all --i: expand cwd files into interactive session instead of SVG batch
602
+ _prepare_allfiles_directory(os.getcwd(), args, use_relative_paths=True)
603
+ else:
604
+ batch_process(os.getcwd(), args)
605
+ raise SystemExit(0)
567
606
 
568
607
  # ---------------- Canvas mode: combine multiple .pkl sessions ----------------
569
608
  canvas_status = _run_canvas_route(args)
@@ -103,10 +103,16 @@ def _load_panel_session(path: str) -> Optional[Tuple[str, Any, Dict[str, Any]]]:
103
103
  return None
104
104
  fig, ax, menu_kwargs = res
105
105
  return ('xy', (fig, ax, menu_kwargs), {'menu_kwargs': menu_kwargs})
106
+ if kind == 'histo':
107
+ from .plot_modes.histo.session import load_histo_session
108
+ res = load_histo_session(path)
109
+ if not res:
110
+ return None
111
+ return ('histo', res, {})
106
112
  except Exception as e:
107
113
  print(f" Error loading {path}: {e}")
108
114
  return None
109
- print(f" {path}: unknown session format (supported: XY/1D, EC/GC/CV/dQdV, CPC/EPC, operando)")
115
+ print(f" {path}: unknown session format (supported: XY/1D, EC/GC/CV/dQdV, CPC/EPC, operando, histo)")
110
116
  return None
111
117
 
112
118
 
@@ -158,7 +164,11 @@ def _default_positions_from_sizes(
158
164
 
159
165
  def _print_canvas_menu(panels: List[Tuple[str, str]]):
160
166
  """Print canvas menu with panel numbers and filenames."""
161
- print("\n\033[1mCanvas Interactive Menu:\033[0m")
167
+ from batplot.plot_modes.common.menu_rendering import menu_block_begin, menu_block_end
168
+
169
+ print()
170
+ menu_block_begin(force_new=True)
171
+ print("\033[1mCanvas Interactive Menu:\033[0m")
162
172
  for i, (_, path) in enumerate(panels):
163
173
  name = os.path.basename(path)
164
174
  print(f" \033[93m{i+1}\033[0m: {name}")
@@ -167,6 +177,7 @@ def _print_canvas_menu(panels: List[Tuple[str, str]]):
167
177
  print(" 1-9: edit panel • p: insert image • t: add text • Backspace: delete selected annotation")
168
178
  print(" e: export • s: save (includes images/text) • q q: quit")
169
179
  print(" (Click canvas first for keys; orange box = picture or text overlay)")
180
+ menu_block_end()
170
181
 
171
182
 
172
183
  def _event_to_figure_coords(fig, event) -> Optional[Tuple[float, float]]:
@@ -664,6 +675,10 @@ def run_canvas_mode(pkl_paths: List[str]) -> None:
664
675
  elif kind == 'xy':
665
676
  fig, ax, menu_kwargs = data
666
677
  interactive_menu(fig, ax, **normalize_xy_menu_kwargs({**menu_kwargs, 'canvas_mode': True}))
678
+ elif kind == 'histo':
679
+ from .plot_modes.histo.interactive import histo_interactive_menu
680
+ fig, ax, state = data
681
+ histo_interactive_menu(fig, ax, state)
667
682
  except Exception as e:
668
683
  print(f"Panel menu failed: {e}")
669
684
  finally:
@@ -261,6 +261,16 @@ def _ansi_color_block_from_rgba(rgba) -> str:
261
261
  return "[??]"
262
262
 
263
263
 
264
+ def to_display_hex(color) -> Optional[str]:
265
+ """Normalize any matplotlib-accepted color to lowercase ``#rrggbb`` (no alpha)."""
266
+ if color is None:
267
+ return None
268
+ try:
269
+ return str(mcolors.to_hex(mcolors.to_rgba(color), keep_alpha=False)).lower()
270
+ except Exception:
271
+ return None
272
+
273
+
264
274
  def color_block(color: Optional[str]) -> str:
265
275
  """Return a colored block (ANSI) for the supplied color string."""
266
276
  if not color:
@@ -273,17 +283,21 @@ def color_block(color: Optional[str]) -> str:
273
283
 
274
284
 
275
285
  def format_color_listing(color) -> str:
276
- """Return ``<swatch> <hex>`` for menu listings (curves, saved colors, etc.)."""
286
+ """Return ``<swatch> <hex>`` for menu listings (curves, saved colors, etc.).
287
+
288
+ Always prefers a hex code next to the ANSI color cube so every mode shows
289
+ the same readable form (e.g. ``██ #1f77b4``), including named colors,
290
+ ``C0`` cycle colors, and RGBA tuples from matplotlib artists.
291
+ """
277
292
  if color is None:
278
293
  return f"{color_block(None)} --"
279
- try:
280
- rgba = mcolors.to_rgba(color)
281
- return f"{color_block(color)} {mcolors.to_hex(rgba)}"
282
- except Exception:
294
+ hex_code = to_display_hex(color)
295
+ if hex_code is None:
283
296
  text = str(color).strip()
284
297
  if not text:
285
298
  return f"{color_block(None)} --"
286
- return f"{color_block(text)} {text}"
299
+ return f"{color_block(None)} {text}"
300
+ return f"{color_block(hex_code)} {hex_code}"
287
301
 
288
302
 
289
303
  def color_bar(colors: Sequence[str]) -> str:
@@ -543,21 +557,23 @@ def resolve_color_token(token: str, fig=None) -> str:
543
557
  colors = get_user_color_list(fig)
544
558
  # Check if index is valid (within bounds of color list)
545
559
  if 0 <= idx < len(colors):
546
- return colors[idx] # Return the actual color code
547
-
548
- # Not a reference, or invalid index - return token as-is
549
- return token
560
+ token = colors[idx]
561
+
562
+ # Normalize named / cycle / RGBA colors to lowercase hex for consistent
563
+ # display and storage across modes. Unknown tokens pass through unchanged.
564
+ hex_code = to_display_hex(token)
565
+ return hex_code if hex_code is not None else token
550
566
 
551
567
 
552
568
  def print_user_colors(fig=None) -> None:
553
- """Print saved colors with indices and color blocks."""
569
+ """Print saved colors with indices, color cubes, and hex codes."""
554
570
  colors = get_user_color_list(fig)
555
571
  if not colors:
556
572
  print("No saved user colors.")
557
573
  return
558
574
  print("Saved colors:")
559
575
  for idx, color in enumerate(colors, 1):
560
- print(f" {idx}: {color_block(color)} {color}")
576
+ print(f" {idx}: {format_color_listing(color)}")
561
577
 
562
578
 
563
579
  def manage_user_colors(fig=None) -> None:
@@ -567,7 +583,7 @@ def manage_user_colors(fig=None) -> None:
567
583
  print("\n\033[1mUser color list:\033[0m")
568
584
  if colors:
569
585
  for idx, color in enumerate(colors, 1):
570
- print(f" {idx}: {color_block(color)} {color}")
586
+ print(f" {idx}: {format_color_listing(color)}")
571
587
  else:
572
588
  print(" (empty)")
573
589
  print("Options: \033[96ma\033[0m=add colors \033[96md\033[0m=delete numbers \033[96mc\033[0m=clear \033[96mq\033[0m=back")
@@ -588,8 +604,9 @@ def manage_user_colors(fig=None) -> None:
588
604
  colors = get_user_color_list(fig)
589
605
  added = 0
590
606
  for col in new_colors:
591
- if col not in colors:
592
- colors.append(col)
607
+ hex_col = to_display_hex(col) or col
608
+ if hex_col not in colors and col not in colors:
609
+ colors.append(hex_col)
593
610
  added += 1
594
611
  _save_user_colors(colors, fig)
595
612
  print(f"Added {added} color(s).")
@@ -640,11 +657,13 @@ __all__ = [
640
657
  'color_bar',
641
658
  'color_block',
642
659
  'ensure_colormap',
660
+ 'format_color_listing',
643
661
  'get_colormap',
644
662
  'manage_user_colors',
645
663
  'palette_preview',
646
664
  'print_user_colors',
647
665
  'remove_user_color',
666
+ 'to_display_hex',
648
667
  'resolve_color_token',
649
668
  'get_user_color_list',
650
669
  ]
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.8.50] - 2026-08-02
4
+ - Cosmetic changes of interactive interface
5
+ - Better CIF file handling
6
+ - Bug fixes
7
+
8
+
9
+ ## [1.8.49] - 2026-07-30
10
+ - GC/CPC interactive overview key `o`: per-cycle capacity & CE table
11
+ (respects CPC invert-efficiency), capacity retention over a cycle range,
12
+ summary stats, and CSV/TXT export. Also available in batch EC/CPC menus.
13
+
14
+
3
15
  ## [1.8.48] - 2026-07-29
4
16
  - Bug fixes on session reload
5
17
 
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": "1.8.50",
3
+ "custom_message": "- Cosmetic changes of interactive interface",
4
+ "update_notes": [
5
+ "- Cosmetic changes of interactive interface",
6
+ "- Better CIF file handling",
7
+ "- Bug fixes"
8
+ ]
9
+ }
@@ -75,9 +75,19 @@ def default_ec_tick_state() -> dict:
75
75
  }
76
76
 
77
77
 
78
- def ec_tick_state_from_fig(fig: Any) -> dict:
79
- """Rebuild the flat EC tick_state dict from the stored WASD state."""
78
+ def ec_tick_state_from_fig(fig: Any, ax: Any | None = None) -> dict:
79
+ """Rebuild the flat EC tick_state dict from the stored WASD state.
80
+
81
+ Falls back to ``ax._saved_tick_state`` when ``fig._ec_wasd_state`` is missing
82
+ (older sessions / loaders that only seeded the axis attribute).
83
+ """
80
84
  wasd = getattr(fig, "_ec_wasd_state", None)
85
+ if not isinstance(wasd, dict) and ax is not None:
86
+ saved = getattr(ax, "_saved_tick_state", None)
87
+ if isinstance(saved, dict) and saved:
88
+ out = default_ec_tick_state()
89
+ out.update(saved)
90
+ return out
81
91
  if isinstance(wasd, dict):
82
92
  top = wasd.get("top", {})
83
93
  bot = wasd.get("bottom", {})
@@ -148,6 +158,8 @@ def ensure_ec_fig_state(panel: EcPanel, file_data: list[dict], is_multi_file: bo
148
158
  try:
149
159
  fig._ec_file_data = file_data
150
160
  fig._ec_is_multi_file = is_multi_file
161
+ # Batch EC sessions are GC-only (kind=ec_gc)
162
+ fig._ec_overview_enabled = True
151
163
  if is_multi_file and not hasattr(fig, "_ec_legend_file_order"):
152
164
  fig._ec_legend_file_order = list(range(len(file_data)))
153
165
  except Exception:
@@ -304,7 +316,7 @@ def run_ec_batch_spine_menu(
304
316
  """Full WASD spine/tick editor on the reference panel, synced to all panels."""
305
317
  ax = ref.ax
306
318
  fig = ref.fig
307
- tick_state = ec_tick_state_from_fig(fig)
319
+ tick_state = ec_tick_state_from_fig(fig, ax)
308
320
 
309
321
  def _get_spine_visible(side: str) -> bool:
310
322
  sp = ax.spines.get(side)
@@ -170,6 +170,9 @@ def _load_one_panel(kind: str, path: str):
170
170
  "mly": False,
171
171
  "mry": False,
172
172
  }
173
+ saved = getattr(ax, "_saved_tick_state", None) or getattr(fig, "_saved_tick_state", None)
174
+ if isinstance(saved, dict) and saved:
175
+ tick_state.update(saved)
173
176
  return CpcPanel(
174
177
  path=path,
175
178
  fig=fig,
@@ -11,13 +11,14 @@ from ...ui import finalize_spine_colors_cpc
11
11
  from ..common.batch_font import run_batch_font_menu
12
12
  from ..common.files import confirm_previous_path
13
13
  from ..common.fonts import collect_fig_font_artists
14
- from ..common.menu_rendering import colorize_menu_item as _colorize_menu, print_menu_columns, prompt_menu_key
14
+ from ..common.menu_rendering import colorize_menu as _colorize_menu, print_menu_columns, prompt_menu_key
15
15
  from ..common.menus import run_legend_position_menu
16
16
  from ..common.spines import apply_frame_and_tick_widths, parse_frame_tick_widths
17
17
  from ..common.terminal import colorize_prompt, safe_input
18
18
  from ..cpc.colors import run_cpc_color_menu
19
19
  from ..cpc.style import _apply_style, _style_snapshot
20
20
  from ..cpc.labels import run_cpc_rename_menu
21
+ from ..cpc.overview import run_cpc_overview
21
22
  from ..cpc.legend import (
22
23
  _rebuild_legend,
23
24
  _sanitize_legend_offset,
@@ -72,6 +73,7 @@ def _print_cpc_batch_menu(panels: List[CpcPanel]) -> None:
72
73
  "ie: invert efficiency",
73
74
  ]
74
75
  col3 = batch_options_menu_column(panels)
76
+ col3.insert(1, "o: overview")
75
77
  print_menu_columns(
76
78
  title=f"Batch CPC Menu ({len(panels)} plots)",
77
79
  columns=[("Styles", col1), ("Geometries", col2), ("Options", col3)],
@@ -268,6 +270,7 @@ def _invert_efficiency_all(panels: List[CpcPanel]) -> None:
268
270
  xs = offsets[:, 0]
269
271
  ys = offsets[:, 1]
270
272
  sc.set_offsets(list(zip(xs, 200.0 - ys)))
273
+ f["eff_inverted"] = not bool(f.get("eff_inverted", False))
271
274
  except Exception as exc:
272
275
  print(f"Invert efficiency failed: {exc}")
273
276
 
@@ -614,6 +617,25 @@ def run_cpc_batch_menu(panels: List[CpcPanel]) -> None:
614
617
  print("Inverted efficiency around 100% on all plots.")
615
618
  continue
616
619
 
620
+ if cmd == "o":
621
+ # Overview for each batch panel (reference first, then remaining)
622
+ for i, p in enumerate(panels):
623
+ file_data, _ = cpc_normalize_file_data(p)
624
+ print(f"\n--- Plot {i + 1}: {os.path.basename(p.path)} ---")
625
+ try:
626
+ run_cpc_overview(
627
+ file_data,
628
+ ax=p.ax,
629
+ safe_input=safe_input,
630
+ colorize_menu=_colorize_menu,
631
+ colorize_prompt=colorize_prompt,
632
+ print_file_list=None,
633
+ include_hidden=False,
634
+ )
635
+ except Exception as exc:
636
+ print(f"Error in overview: {exc}")
637
+ continue
638
+
617
639
  if cmd == "i":
618
640
  def _on_style_imported(indices: list[int], _path: str) -> None:
619
641
  draw_panels(panels)