batplot 1.8.46__tar.gz → 1.8.48__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 (234) hide show
  1. {batplot-1.8.46 → batplot-1.8.48}/PKG-INFO +1 -5
  2. {batplot-1.8.46 → batplot-1.8.48}/README.md +0 -4
  3. {batplot-1.8.46 → batplot-1.8.48}/batplot/__init__.py +1 -1
  4. {batplot-1.8.46 → batplot-1.8.48}/batplot/_mpl_backend.py +10 -7
  5. {batplot-1.8.46 → batplot-1.8.48}/batplot/batch.py +22 -387
  6. {batplot-1.8.46 → batplot-1.8.48}/batplot/batplot.py +0 -1
  7. {batplot-1.8.46 → batplot-1.8.48}/batplot/color_utils.py +14 -0
  8. {batplot-1.8.46 → batplot-1.8.48}/batplot/data/CHANGELOG.md +13 -0
  9. batplot-1.8.48/batplot/data/latest_release_notes.json +7 -0
  10. {batplot-1.8.46 → batplot-1.8.48}/batplot/dev_upgrade.py +144 -96
  11. {batplot-1.8.46 → batplot-1.8.48}/batplot/ec_common.py +51 -0
  12. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/batch_session/batch_commands.py +11 -18
  13. batplot-1.8.48/batplot/plot_modes/batch_session/batch_crosshair.py +165 -0
  14. batplot-1.8.48/batplot/plot_modes/batch_session/batch_figure_io.py +261 -0
  15. batplot-1.8.48/batplot/plot_modes/batch_session/batch_geom_helpers.py +229 -0
  16. batplot-1.8.48/batplot/plot_modes/batch_session/batch_io.py +389 -0
  17. batplot-1.8.48/batplot/plot_modes/batch_session/batch_menu_helpers.py +339 -0
  18. batplot-1.8.48/batplot/plot_modes/batch_session/batch_menu_io.py +103 -0
  19. batplot-1.8.48/batplot/plot_modes/batch_session/batch_panel_state.py +304 -0
  20. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/batch_session/common.py +64 -28
  21. batplot-1.8.48/batplot/plot_modes/batch_session/cpc_batch_helpers.py +418 -0
  22. batplot-1.8.48/batplot/plot_modes/batch_session/ec_batch_helpers.py +457 -0
  23. batplot-1.8.48/batplot/plot_modes/batch_session/histo_batch_helpers.py +228 -0
  24. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/batch_session/kinds.py +3 -0
  25. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/batch_session/load.py +6 -0
  26. batplot-1.8.48/batplot/plot_modes/batch_session/menu_cpc.py +730 -0
  27. batplot-1.8.48/batplot/plot_modes/batch_session/menu_ec.py +680 -0
  28. batplot-1.8.48/batplot/plot_modes/batch_session/menu_histo.py +511 -0
  29. batplot-1.8.48/batplot/plot_modes/batch_session/menu_operando.py +750 -0
  30. batplot-1.8.48/batplot/plot_modes/batch_session/menu_xy.py +568 -0
  31. batplot-1.8.48/batplot/plot_modes/batch_session/operando_batch_helpers.py +472 -0
  32. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/batch_session/routing.py +7 -0
  33. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/batch_session/xy_batch_helpers.py +106 -4
  34. batplot-1.8.48/batplot/plot_modes/common/batch_font.py +137 -0
  35. batplot-1.8.48/batplot/plot_modes/common/crosshair_export.py +116 -0
  36. batplot-1.8.48/batplot/plot_modes/common/font_extras.py +380 -0
  37. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/fonts.py +102 -2
  38. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/menu_rendering.py +7 -0
  39. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/menus.py +248 -36
  40. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/palettes.py +6 -1
  41. batplot-1.8.48/batplot/plot_modes/common/session_helpers.py +251 -0
  42. batplot-1.8.48/batplot/plot_modes/common/session_key_smoke.py +510 -0
  43. batplot-1.8.48/batplot/plot_modes/common/size_spec.py +72 -0
  44. batplot-1.8.48/batplot/plot_modes/common/sources.py +184 -0
  45. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/spines.py +44 -37
  46. batplot-1.8.48/batplot/plot_modes/common/state_capture.py +98 -0
  47. batplot-1.8.48/batplot/plot_modes/common/style_routing.py +128 -0
  48. batplot-1.8.48/batplot/plot_modes/common/terminal.py +294 -0
  49. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/__init__.py +2 -2
  50. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/actions.py +12 -5
  51. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/colors.py +111 -39
  52. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/interactive.py +244 -1344
  53. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/labels.py +68 -64
  54. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/legend.py +25 -6
  55. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/routing.py +13 -4
  56. batplot-1.8.48/batplot/plot_modes/cpc/session.py +1006 -0
  57. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/snapshots.py +13 -7
  58. batplot-1.8.48/batplot/plot_modes/cpc/style.py +1274 -0
  59. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/__init__.py +2 -2
  60. batplot-1.8.48/batplot/plot_modes/electrochem/actions.py +673 -0
  61. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/colors.py +134 -4
  62. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/dqdv_2d.py +43 -34
  63. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/export.py +3 -1
  64. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/interactive.py +326 -209
  65. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/labels.py +61 -47
  66. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/legend.py +3 -0
  67. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/line_style.py +53 -46
  68. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/routing.py +29 -10
  69. batplot-1.8.48/batplot/plot_modes/electrochem/session.py +1207 -0
  70. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/spine_colors.py +9 -9
  71. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/style.py +184 -138
  72. batplot-1.8.48/batplot/plot_modes/electrochem/style_apply.py +795 -0
  73. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/actions.py +23 -7
  74. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/colors.py +72 -9
  75. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/density_curve.py +57 -32
  76. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/fonts.py +64 -0
  77. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/interactive.py +181 -62
  78. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/labels.py +29 -27
  79. batplot-1.8.48/batplot/plot_modes/histo/line_style.py +176 -0
  80. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/plot.py +187 -22
  81. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/routing.py +2 -0
  82. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/session.py +32 -2
  83. batplot-1.8.48/batplot/plot_modes/histo/spines.py +581 -0
  84. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/toggles.py +24 -16
  85. batplot-1.8.48/batplot/plot_modes/histo/y_range.py +112 -0
  86. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/__init__.py +2 -2
  87. batplot-1.8.48/batplot/plot_modes/operando/actions.py +872 -0
  88. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/grid.py +27 -18
  89. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/interactive.py +492 -465
  90. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/labels.py +66 -58
  91. batplot-1.8.48/batplot/plot_modes/operando/layout_menu.py +494 -0
  92. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/line_style.py +42 -39
  93. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/menu.py +0 -5
  94. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/peaks.py +94 -95
  95. batplot-1.8.48/batplot/plot_modes/operando/session.py +1056 -0
  96. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/style.py +40 -23
  97. batplot-1.8.48/batplot/plot_modes/operando/style_apply.py +970 -0
  98. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/visibility.py +93 -77
  99. batplot-1.8.48/batplot/plot_modes/session_routing.py +341 -0
  100. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/__init__.py +2 -2
  101. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/actions.py +10 -3
  102. batplot-1.8.48/batplot/plot_modes/xy/axis_range.py +568 -0
  103. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/cif.py +11 -10
  104. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/colors.py +25 -13
  105. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/derivative.py +60 -1
  106. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/interactive.py +101 -155
  107. batplot-1.8.48/batplot/plot_modes/xy/labels.py +160 -0
  108. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/line_style.py +80 -58
  109. batplot-1.8.48/batplot/plot_modes/xy/session.py +1336 -0
  110. batplot-1.8.48/batplot/plot_modes/xy/spines.py +258 -0
  111. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/style.py +195 -44
  112. {batplot-1.8.46 → batplot-1.8.48}/batplot/readers.py +9 -374
  113. batplot-1.8.48/batplot/readers_xrd.py +401 -0
  114. batplot-1.8.48/batplot/session.py +107 -0
  115. {batplot-1.8.46 → batplot-1.8.48}/batplot/ui.py +855 -164
  116. {batplot-1.8.46 → batplot-1.8.48}/batplot/version_check.py +2 -2
  117. {batplot-1.8.46 → batplot-1.8.48}/batplot.egg-info/PKG-INFO +1 -5
  118. {batplot-1.8.46 → batplot-1.8.48}/batplot.egg-info/SOURCES.txt +53 -1
  119. {batplot-1.8.46 → batplot-1.8.48}/pyproject.toml +1 -1
  120. batplot-1.8.48/tests/test_batch_all_modes_sync.py +134 -0
  121. batplot-1.8.48/tests/test_batch_crosshair.py +68 -0
  122. batplot-1.8.48/tests/test_batch_ec_cycles_status.py +42 -0
  123. batplot-1.8.48/tests/test_batch_font_menu.py +108 -0
  124. batplot-1.8.48/tests/test_batch_geom_menu.py +38 -0
  125. batplot-1.8.48/tests/test_batch_menu_parity.py +442 -0
  126. batplot-1.8.48/tests/test_batch_panel_status.py +77 -0
  127. batplot-1.8.48/tests/test_batch_pisb_contract.py +183 -0
  128. batplot-1.8.48/tests/test_batch_session.py +674 -0
  129. batplot-1.8.48/tests/test_batch_spine_sync.py +73 -0
  130. batplot-1.8.48/tests/test_cli_all_flags.py +154 -0
  131. batplot-1.8.48/tests/test_color_listing_visible.py +138 -0
  132. {batplot-1.8.46 → batplot-1.8.48}/tests/test_common_palettes.py +20 -0
  133. {batplot-1.8.46 → batplot-1.8.48}/tests/test_contracts.py +16 -12
  134. {batplot-1.8.46 → batplot-1.8.48}/tests/test_cpc_roundtrip.py +1 -0
  135. batplot-1.8.48/tests/test_critical_stability_fixes.py +90 -0
  136. batplot-1.8.48/tests/test_cross_platform_parity.py +81 -0
  137. batplot-1.8.48/tests/test_crosshair_export.py +49 -0
  138. {batplot-1.8.46 → batplot-1.8.48}/tests/test_dev_upgrade.py +32 -0
  139. batplot-1.8.48/tests/test_dqdv_contour_session_keys.py +106 -0
  140. {batplot-1.8.46 → batplot-1.8.48}/tests/test_ec_roundtrip.py +236 -1
  141. batplot-1.8.48/tests/test_histo.py +1514 -0
  142. batplot-1.8.48/tests/test_histo_interactive_imports.py +64 -0
  143. batplot-1.8.48/tests/test_imk_stderr_guard.py +22 -0
  144. {batplot-1.8.46 → batplot-1.8.48}/tests/test_interactive_menu_smoke.py +22 -4
  145. {batplot-1.8.46 → batplot-1.8.48}/tests/test_interactive_state.py +172 -3
  146. batplot-1.8.48/tests/test_menu_handler_imports.py +202 -0
  147. batplot-1.8.48/tests/test_menu_prompt_order.py +58 -0
  148. batplot-1.8.48/tests/test_operando_batch_menu.py +143 -0
  149. batplot-1.8.48/tests/test_operando_layout_menu.py +75 -0
  150. {batplot-1.8.46 → batplot-1.8.48}/tests/test_operando_roundtrip.py +8 -4
  151. batplot-1.8.48/tests/test_session_backward_compat.py +81 -0
  152. batplot-1.8.48/tests/test_session_font_restore.py +155 -0
  153. batplot-1.8.48/tests/test_state_capture.py +55 -0
  154. batplot-1.8.48/tests/test_style_routing.py +115 -0
  155. {batplot-1.8.46 → batplot-1.8.48}/tests/test_xy_modules.py +115 -0
  156. {batplot-1.8.46 → batplot-1.8.48}/tests/test_xy_roundtrip.py +50 -0
  157. batplot-1.8.48/tests/test_xy_source_files.py +46 -0
  158. batplot-1.8.46/batplot/data/latest_release_notes.json +0 -7
  159. batplot-1.8.46/batplot/plot_modes/batch_session/batch_io.py +0 -178
  160. batplot-1.8.46/batplot/plot_modes/batch_session/menu_cpc.py +0 -291
  161. batplot-1.8.46/batplot/plot_modes/batch_session/menu_ec.py +0 -318
  162. batplot-1.8.46/batplot/plot_modes/batch_session/menu_histo.py +0 -407
  163. batplot-1.8.46/batplot/plot_modes/batch_session/menu_operando.py +0 -292
  164. batplot-1.8.46/batplot/plot_modes/batch_session/menu_xy.py +0 -429
  165. batplot-1.8.46/batplot/plot_modes/common/sources.py +0 -68
  166. batplot-1.8.46/batplot/plot_modes/common/terminal.py +0 -128
  167. batplot-1.8.46/batplot/plot_modes/cpc/session.py +0 -15
  168. batplot-1.8.46/batplot/plot_modes/electrochem/actions.py +0 -1256
  169. batplot-1.8.46/batplot/plot_modes/electrochem/session.py +0 -15
  170. batplot-1.8.46/batplot/plot_modes/histo/spines.py +0 -291
  171. batplot-1.8.46/batplot/plot_modes/operando/actions.py +0 -1571
  172. batplot-1.8.46/batplot/plot_modes/operando/session.py +0 -15
  173. batplot-1.8.46/batplot/plot_modes/session_routing.py +0 -1086
  174. batplot-1.8.46/batplot/plot_modes/xy/axis_range.py +0 -624
  175. batplot-1.8.46/batplot/plot_modes/xy/labels.py +0 -160
  176. batplot-1.8.46/batplot/plot_modes/xy/session.py +0 -15
  177. batplot-1.8.46/batplot/session.py +0 -4691
  178. batplot-1.8.46/tests/test_batch_session.py +0 -241
  179. batplot-1.8.46/tests/test_histo.py +0 -598
  180. {batplot-1.8.46 → batplot-1.8.48}/DEVELOPING.md +0 -0
  181. {batplot-1.8.46 → batplot-1.8.48}/LICENSE +0 -0
  182. {batplot-1.8.46 → batplot-1.8.48}/MANIFEST.in +0 -0
  183. {batplot-1.8.46 → batplot-1.8.48}/NOTICE +0 -0
  184. {batplot-1.8.46 → batplot-1.8.48}/batplot/args.py +0 -0
  185. {batplot-1.8.46 → batplot-1.8.48}/batplot/canvas_interactive.py +0 -0
  186. {batplot-1.8.46 → batplot-1.8.48}/batplot/cif.py +0 -0
  187. {batplot-1.8.46 → batplot-1.8.48}/batplot/cli.py +0 -0
  188. {batplot-1.8.46 → batplot-1.8.48}/batplot/cli_save.py +0 -0
  189. {batplot-1.8.46 → batplot-1.8.48}/batplot/config.py +0 -0
  190. {batplot-1.8.46 → batplot-1.8.48}/batplot/converters.py +0 -0
  191. {batplot-1.8.46 → batplot-1.8.48}/batplot/modes.py +0 -0
  192. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/__init__.py +0 -0
  193. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/batch_session/__init__.py +0 -0
  194. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/__init__.py +0 -0
  195. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/axis_state.py +0 -0
  196. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/files.py +0 -0
  197. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/interactive_state.py +0 -0
  198. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/smoothing.py +0 -0
  199. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/common/title_offsets.py +0 -0
  200. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/cpc/menu.py +0 -0
  201. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/legend_order.py +0 -0
  202. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/electrochem/menu.py +0 -0
  203. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/__init__.py +0 -0
  204. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/load.py +0 -0
  205. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/histo/wizard.py +0 -0
  206. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/colors.py +0 -0
  207. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/ions_axis.py +0 -0
  208. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/layout.py +0 -0
  209. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/plot.py +0 -0
  210. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/operando/routing.py +0 -0
  211. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/arrange.py +0 -0
  212. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/data_ops.py +0 -0
  213. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/game.py +0 -0
  214. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/menu.py +0 -0
  215. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/peaks.py +0 -0
  216. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/pipeline.py +0 -0
  217. {batplot-1.8.46 → batplot-1.8.48}/batplot/plot_modes/xy/smoothing.py +0 -0
  218. {batplot-1.8.46 → batplot-1.8.48}/batplot/plotting.py +0 -0
  219. {batplot-1.8.46 → batplot-1.8.48}/batplot/showcol.py +0 -0
  220. {batplot-1.8.46 → batplot-1.8.48}/batplot/style.py +0 -0
  221. {batplot-1.8.46 → batplot-1.8.48}/batplot/utils.py +0 -0
  222. {batplot-1.8.46 → batplot-1.8.48}/batplot.egg-info/dependency_links.txt +0 -0
  223. {batplot-1.8.46 → batplot-1.8.48}/batplot.egg-info/entry_points.txt +0 -0
  224. {batplot-1.8.46 → batplot-1.8.48}/batplot.egg-info/requires.txt +0 -0
  225. {batplot-1.8.46 → batplot-1.8.48}/batplot.egg-info/top_level.txt +0 -0
  226. {batplot-1.8.46 → batplot-1.8.48}/setup.cfg +0 -0
  227. {batplot-1.8.46 → batplot-1.8.48}/setup.py +0 -0
  228. {batplot-1.8.46 → batplot-1.8.48}/tests/test_bruker_intensity.py +0 -0
  229. {batplot-1.8.46 → batplot-1.8.48}/tests/test_cli_save.py +0 -0
  230. {batplot-1.8.46 → batplot-1.8.48}/tests/test_cli_smoke.py +0 -0
  231. {batplot-1.8.46 → batplot-1.8.48}/tests/test_color_utils.py +0 -0
  232. {batplot-1.8.46 → batplot-1.8.48}/tests/test_common_files.py +0 -0
  233. {batplot-1.8.46 → batplot-1.8.48}/tests/test_csv_readers.py +0 -0
  234. {batplot-1.8.46 → batplot-1.8.48}/tests/test_mpl_backend.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: batplot
3
- Version: 1.8.46
3
+ Version: 1.8.48
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
@@ -448,10 +448,6 @@ batplot --v # Version and release notes
448
448
  batplot --m # Open illustrated manual
449
449
  ```
450
450
 
451
- - [USER_MANUAL.md](USER_MANUAL.md) — Detailed usage and workflows
452
- - [FLAGS_REFERENCE.md](FLAGS_REFERENCE.md) — Complete flag reference by mode
453
- - [DEVELOPING.md](DEVELOPING.md) — Developer guide for extending Batplot
454
-
455
451
  ---
456
452
 
457
453
  ## Requirements
@@ -394,10 +394,6 @@ batplot --v # Version and release notes
394
394
  batplot --m # Open illustrated manual
395
395
  ```
396
396
 
397
- - [USER_MANUAL.md](USER_MANUAL.md) — Detailed usage and workflows
398
- - [FLAGS_REFERENCE.md](FLAGS_REFERENCE.md) — Complete flag reference by mode
399
- - [DEVELOPING.md](DEVELOPING.md) — Developer guide for extending Batplot
400
-
401
397
  ---
402
398
 
403
399
  ## Requirements
@@ -7,7 +7,7 @@ import importlib.abc
7
7
  import importlib.machinery
8
8
  import sys
9
9
 
10
- __version__ = "1.8.46"
10
+ __version__ = "1.8.48"
11
11
 
12
12
 
13
13
  _LEGACY_MODULE_ALIASES = {
@@ -252,20 +252,23 @@ def prime_interactive_figure(fig=None) -> None:
252
252
  """Prepare a matplotlib window before an interactive menu (non-blocking)."""
253
253
  import matplotlib.pyplot as plt
254
254
 
255
+ from .plot_modes.common.terminal import imk_stderr_guard
256
+
255
257
  try:
256
258
  plt.ion()
257
259
  except Exception:
258
260
  pass
259
- if fig is not None:
261
+ with imk_stderr_guard():
262
+ if fig is not None:
263
+ try:
264
+ fig.canvas.draw_idle()
265
+ fig.canvas.flush_events()
266
+ except Exception:
267
+ pass
260
268
  try:
261
- fig.canvas.draw_idle()
262
- fig.canvas.flush_events()
269
+ plt.show(block=False)
263
270
  except Exception:
264
271
  pass
265
- try:
266
- plt.show(block=False)
267
- except Exception:
268
- pass
269
272
 
270
273
 
271
274
  def hold_figure_open() -> None:
@@ -10,7 +10,9 @@ import matplotlib.pyplot as plt # type: ignore[import]
10
10
  import numpy as np # type: ignore[import]
11
11
 
12
12
  from .color_utils import get_colormap
13
+ from .plot_modes.common.fonts import sync_legend_title_fontsize
13
14
 
15
+ from .ec_common import _resolve_mass
14
16
  from .readers import (
15
17
  read_gr_file,
16
18
  read_xrd_vendor_file,
@@ -37,19 +39,7 @@ def _is_mpt_like_ext(ext: str) -> bool:
37
39
  return (ext or '').lower() in _MPT_LIKE_EXTS
38
40
 
39
41
 
40
- def _resolve_mass(mass_arg, file_idx: int = 0):
41
- """Return mass (mg) for file at file_idx from a --mass list or single value."""
42
- if mass_arg is None:
43
- return None
44
- if isinstance(mass_arg, (int, float)):
45
- return float(mass_arg)
46
- if isinstance(mass_arg, list):
47
- if len(mass_arg) == 1:
48
- return float(mass_arg[0])
49
- if file_idx < len(mass_arg):
50
- return float(mass_arg[file_idx])
51
- return float(mass_arg[-1])
52
- return None
42
+ from .ec_common import _resolve_mass
53
43
  from .utils import _confirm_overwrite, natural_sort_key, ensure_subdirectory
54
44
 
55
45
 
@@ -72,364 +62,24 @@ def _load_style_file(style_path: str) -> dict | None:
72
62
 
73
63
 
74
64
  def _apply_xy_style(fig, ax, cfg: dict):
75
- """Apply style configuration to an XY batch plot.
76
-
77
- Applies formatting from .bps/.bpsg files including fonts, colors,
78
- tick parameters, and geometry (if present in .bpsg files).
79
-
80
- Args:
81
- fig: Matplotlib figure object
82
- ax: Matplotlib axes object
83
- cfg: Style configuration dictionary
84
- """
85
- try:
86
- # Apply fonts
87
- font_cfg = cfg.get('font', {})
88
- if font_cfg:
89
- family = font_cfg.get('family')
90
- size = font_cfg.get('size')
91
- if family:
92
- plt.rcParams['font.sans-serif'] = [family] if isinstance(family, str) else family
93
- if size is not None:
94
- plt.rcParams['font.size'] = size
95
-
96
- # Apply figure size if present
97
- fig_cfg = cfg.get('figure', {})
98
- if fig_cfg:
99
- canvas_size = fig_cfg.get('canvas_size')
100
- if canvas_size and isinstance(canvas_size, (list, tuple)) and len(canvas_size) == 2:
101
- try:
102
- fig.set_size_inches(canvas_size[0], canvas_size[1])
103
- except Exception:
104
- pass
105
-
106
- # Apply tick parameters
107
- ticks_cfg = cfg.get('ticks', {})
108
- if ticks_cfg:
109
- # Tick widths
110
- widths = ticks_cfg.get('widths', {})
111
- if widths.get('x_major') is not None:
112
- ax.tick_params(axis='x', which='major', width=widths['x_major'])
113
- if widths.get('x_minor') is not None:
114
- ax.tick_params(axis='x', which='minor', width=widths['x_minor'])
115
- if widths.get('y_major') is not None:
116
- ax.tick_params(axis='y', which='major', width=widths['y_major'])
117
- if widths.get('y_minor') is not None:
118
- ax.tick_params(axis='y', which='minor', width=widths['y_minor'])
119
-
120
- # Tick lengths
121
- lengths = ticks_cfg.get('lengths', {})
122
- if lengths.get('major') is not None:
123
- ax.tick_params(axis='both', which='major', length=lengths['major'])
124
- if lengths.get('minor') is not None:
125
- ax.tick_params(axis='both', which='minor', length=lengths['minor'])
126
-
127
- # Tick direction
128
- direction = ticks_cfg.get('direction')
129
- if direction:
130
- ax.tick_params(axis='both', which='both', direction=direction)
131
-
132
- # Apply geometry if present (for .bpsg files)
133
- kind = cfg.get('kind', '')
134
- if 'geom' in kind.lower() and 'geometry' in cfg:
135
- geom = cfg.get('geometry', {})
136
- if geom.get('xlabel'):
137
- ax.set_xlabel(geom['xlabel'])
138
- if geom.get('ylabel'):
139
- ax.set_ylabel(geom['ylabel'])
140
- if 'xlim' in geom and isinstance(geom['xlim'], (list, tuple)) and len(geom['xlim']) == 2:
141
- try:
142
- ax.set_xlim(geom['xlim'][0], geom['xlim'][1])
143
- except Exception:
144
- pass
145
- if 'ylim' in geom and isinstance(geom['ylim'], (list, tuple)) and len(geom['ylim']) == 2:
146
- try:
147
- ax.set_ylim(geom['ylim'][0], geom['ylim'][1])
148
- except Exception:
149
- pass
150
-
151
- # Apply line colors if available
152
- lines_cfg = cfg.get('lines', [])
153
- if lines_cfg and len(ax.lines) > 0:
154
- for entry in lines_cfg:
155
- idx = entry.get('index')
156
- if idx is not None and 0 <= idx < len(ax.lines):
157
- ln = ax.lines[idx]
158
- if 'color' in entry:
159
- try:
160
- ln.set_color(entry['color'])
161
- except Exception:
162
- pass
163
- if 'linewidth' in entry:
164
- try:
165
- ln.set_linewidth(entry['linewidth'])
166
- except Exception:
167
- pass
168
- if 'linestyle' in entry:
169
- try:
170
- ln.set_linestyle(entry['linestyle'])
171
- except Exception:
172
- pass
173
-
174
- # Apply spine configuration
175
- spines_cfg = cfg.get('spines', {})
176
- for spine_name, spine_props in spines_cfg.items():
177
- if spine_name in ax.spines:
178
- sp = ax.spines[spine_name]
179
- if 'lw' in spine_props or 'linewidth' in spine_props:
180
- try:
181
- lw = spine_props.get('lw') or spine_props.get('linewidth')
182
- sp.set_linewidth(lw)
183
- except Exception:
184
- pass
185
- if 'color' in spine_props:
186
- try:
187
- sp.set_edgecolor(spine_props['color'])
188
- except Exception:
189
- pass
190
- if 'visible' in spine_props:
191
- try:
192
- sp.set_visible(spine_props['visible'])
193
- except Exception:
194
- pass
195
-
196
- # Enforce compatibility between style/geom ro state and current figure ro state.
197
- # Styles saved from a plot using --ro (swapped x/y) must not be applied to a non-ro plot, and vice versa.
198
- file_ro = bool(cfg.get('ro_active', False))
199
- current_ro = bool(getattr(fig, '_ro_active', False))
200
- if file_ro != current_ro:
201
- if file_ro:
202
- print("Warning: XY style/geometry file was saved with --ro (swapped x/y axes); batch plot is not using --ro.")
203
- else:
204
- print("Warning: XY style/geometry file was saved without --ro; batch plot is treated as non-ro.")
205
- print("Skipping style/geometry in batch mode to avoid corrupting axis orientation.")
206
- return
65
+ """Apply XY style/geometry via the canonical style module (batch/CLI path)."""
66
+ from .plot_modes.common.style_routing import apply_xy_style_dict
207
67
 
208
- # Apply WASD state (tick visibility)
209
- wasd_cfg = cfg.get('wasd_state', {})
210
- if wasd_cfg:
211
- # Top ticks (W)
212
- if 'top' in wasd_cfg:
213
- top_cfg = wasd_cfg['top']
214
- if isinstance(top_cfg, dict):
215
- ticks_on = top_cfg.get('ticks', False)
216
- labels_on = top_cfg.get('labels', False)
217
- ax.tick_params(axis='x', top=ticks_on, labeltop=labels_on)
218
- # Left ticks (A)
219
- if 'left' in wasd_cfg:
220
- left_cfg = wasd_cfg['left']
221
- if isinstance(left_cfg, dict):
222
- ticks_on = left_cfg.get('ticks', False)
223
- labels_on = left_cfg.get('labels', False)
224
- ax.tick_params(axis='y', left=ticks_on, labelleft=labels_on)
225
- # Bottom ticks (S)
226
- if 'bottom' in wasd_cfg:
227
- bottom_cfg = wasd_cfg['bottom']
228
- if isinstance(bottom_cfg, dict):
229
- ticks_on = bottom_cfg.get('ticks', True)
230
- labels_on = bottom_cfg.get('labels', True)
231
- ax.tick_params(axis='x', bottom=ticks_on, labelbottom=labels_on)
232
- # Right ticks (D)
233
- if 'right' in wasd_cfg:
234
- right_cfg = wasd_cfg['right']
235
- if isinstance(right_cfg, dict):
236
- ticks_on = right_cfg.get('ticks', False)
237
- labels_on = right_cfg.get('labels', False)
238
- ax.tick_params(axis='y', right=ticks_on, labelright=labels_on)
239
-
240
- # Apply rotation
241
- rotation_cfg = cfg.get('rotation', {})
242
- if rotation_cfg:
243
- x_rotation = rotation_cfg.get('x')
244
- y_rotation = rotation_cfg.get('y')
245
- if x_rotation is not None:
246
- try:
247
- for label in ax.get_xticklabels():
248
- label.set_rotation(x_rotation)
249
- except Exception:
250
- pass
251
- if y_rotation is not None:
252
- try:
253
- for label in ax.get_yticklabels():
254
- label.set_rotation(y_rotation)
255
- except Exception:
256
- pass
257
-
258
- except Exception as e:
259
- print(f"Warning: Error applying style: {e}")
68
+ apply_xy_style_dict(cfg, fig, ax)
260
69
 
261
70
 
262
- def _apply_ec_style(fig, ax, cfg: dict):
263
- """Apply style configuration to an EC batch plot.
264
-
265
- Applies formatting from .bps/.bpsg files including fonts, colors,
266
- tick parameters, and geometry (if present in .bpsg files).
267
-
268
- Args:
269
- fig: Matplotlib figure object
270
- ax: Matplotlib axes object
271
- cfg: Style configuration dictionary
272
- """
273
- try:
274
- # Enforce compatibility between style/geom ro state and current figure ro state.
275
- file_ro = bool(cfg.get('ro_active', False))
276
- current_ro = bool(getattr(fig, '_ro_active', False))
277
- if file_ro != current_ro:
278
- if file_ro:
279
- print("Warning: EC style/geometry file was saved with --ro (swapped x/y axes); batch EC plot is not using --ro.")
280
- else:
281
- print("Warning: EC style/geometry file was saved without --ro; batch EC plot is treated as non-ro.")
282
- print("Skipping EC style/geometry in batch mode to avoid corrupting axis orientation.")
283
- return
71
+ def _apply_ec_style(fig, ax, cfg: dict, *, cycle_lines=None, file_data=None, is_multi_file: bool = False):
72
+ """Apply EC style/geometry via the canonical style module (batch/CLI path)."""
73
+ from .plot_modes.common.style_routing import apply_ec_style_dict
284
74
 
285
- # Apply fonts
286
- font_cfg = cfg.get('font', {})
287
- if font_cfg:
288
- family = font_cfg.get('family')
289
- size = font_cfg.get('size')
290
- if family:
291
- plt.rcParams['font.sans-serif'] = [family] if isinstance(family, str) else family
292
- if size is not None:
293
- plt.rcParams['font.size'] = size
294
-
295
- # Apply figure size if present
296
- fig_cfg = cfg.get('figure', {})
297
- if fig_cfg:
298
- canvas_size = fig_cfg.get('canvas_size')
299
- if canvas_size and isinstance(canvas_size, (list, tuple)) and len(canvas_size) == 2:
300
- try:
301
- fig.set_size_inches(canvas_size[0], canvas_size[1])
302
- except Exception:
303
- pass
304
-
305
- # Apply tick parameters
306
- ticks_cfg = cfg.get('ticks', {})
307
- if ticks_cfg:
308
- # Tick widths
309
- widths = ticks_cfg.get('widths', {})
310
- if widths.get('x_major') is not None:
311
- ax.tick_params(axis='x', which='major', width=widths['x_major'])
312
- if widths.get('x_minor') is not None:
313
- ax.tick_params(axis='x', which='minor', width=widths['x_minor'])
314
- if widths.get('y_major') is not None or widths.get('ly_major') is not None:
315
- w = widths.get('y_major') or widths.get('ly_major')
316
- ax.tick_params(axis='y', which='major', width=w)
317
- if widths.get('y_minor') is not None or widths.get('ly_minor') is not None:
318
- w = widths.get('y_minor') or widths.get('ly_minor')
319
- ax.tick_params(axis='y', which='minor', width=w)
320
-
321
- # Tick lengths
322
- lengths = ticks_cfg.get('lengths', {})
323
- if lengths.get('major') is not None:
324
- ax.tick_params(axis='both', which='major', length=lengths['major'])
325
- if lengths.get('minor') is not None:
326
- ax.tick_params(axis='both', which='minor', length=lengths['minor'])
327
-
328
- # Tick direction
329
- direction = ticks_cfg.get('direction')
330
- if direction:
331
- ax.tick_params(axis='both', which='both', direction=direction)
332
-
333
- # Apply geometry if present (for .bpsg files)
334
- kind = cfg.get('kind', '')
335
- if 'geom' in kind.lower() and 'geometry' in cfg:
336
- geom = cfg.get('geometry', {})
337
- if geom.get('xlabel'):
338
- ax.set_xlabel(geom['xlabel'])
339
- if geom.get('ylabel'):
340
- ax.set_ylabel(geom['ylabel'])
341
- if 'xlim' in geom and isinstance(geom['xlim'], (list, tuple)) and len(geom['xlim']) == 2:
342
- try:
343
- ax.set_xlim(geom['xlim'][0], geom['xlim'][1])
344
- except Exception:
345
- pass
346
- if 'ylim' in geom and isinstance(geom['ylim'], (list, tuple)) and len(geom['ylim']) == 2:
347
- try:
348
- ax.set_ylim(geom['ylim'][0], geom['ylim'][1])
349
- except Exception:
350
- pass
351
-
352
- # Apply line colors if available (for GC/CV/dQdV modes)
353
- lines_cfg = cfg.get('lines', [])
354
- if lines_cfg and len(ax.lines) > 0:
355
- for entry in lines_cfg:
356
- idx = entry.get('index')
357
- if idx is not None and 0 <= idx < len(ax.lines):
358
- ln = ax.lines[idx]
359
- if 'color' in entry:
360
- try:
361
- ln.set_color(entry['color'])
362
- except Exception:
363
- pass
364
- if 'linewidth' in entry:
365
- try:
366
- ln.set_linewidth(entry['linewidth'])
367
- except Exception:
368
- pass
369
- if 'linestyle' in entry:
370
- try:
371
- ln.set_linestyle(entry['linestyle'])
372
- except Exception:
373
- pass
374
-
375
- # Apply spine configuration
376
- spines_cfg = cfg.get('spines', {})
377
- for spine_name, spine_props in spines_cfg.items():
378
- if spine_name in ax.spines:
379
- sp = ax.spines[spine_name]
380
- if 'lw' in spine_props or 'linewidth' in spine_props:
381
- try:
382
- lw = spine_props.get('lw') or spine_props.get('linewidth')
383
- sp.set_linewidth(lw)
384
- except Exception:
385
- pass
386
- if 'color' in spine_props:
387
- try:
388
- sp.set_edgecolor(spine_props['color'])
389
- except Exception:
390
- pass
391
- if 'visible' in spine_props:
392
- try:
393
- sp.set_visible(spine_props['visible'])
394
- except Exception:
395
- pass
396
-
397
- # Apply WASD state (tick visibility)
398
- wasd_cfg = cfg.get('wasd_state', {})
399
- if wasd_cfg:
400
- # Top ticks (W)
401
- if 'top' in wasd_cfg:
402
- ax.tick_params(top=wasd_cfg['top'], labeltop=wasd_cfg['top'])
403
- # Left ticks (A)
404
- if 'left' in wasd_cfg:
405
- ax.tick_params(left=wasd_cfg['left'], labelleft=wasd_cfg['left'])
406
- # Bottom ticks (S)
407
- if 'bottom' in wasd_cfg:
408
- ax.tick_params(bottom=wasd_cfg['bottom'], labelbottom=wasd_cfg['bottom'])
409
- # Right ticks (D)
410
- if 'right' in wasd_cfg:
411
- ax.tick_params(right=wasd_cfg['right'], labelright=wasd_cfg['right'])
412
-
413
- # Apply rotation
414
- rotation_cfg = cfg.get('rotation', {})
415
- if rotation_cfg:
416
- x_rotation = rotation_cfg.get('x')
417
- y_rotation = rotation_cfg.get('y')
418
- if x_rotation is not None:
419
- try:
420
- for label in ax.get_xticklabels():
421
- label.set_rotation(x_rotation)
422
- except Exception:
423
- pass
424
- if y_rotation is not None:
425
- try:
426
- for label in ax.get_yticklabels():
427
- label.set_rotation(y_rotation)
428
- except Exception:
429
- pass
430
-
431
- except Exception as e:
432
- print(f"Warning: Error applying style: {e}")
75
+ apply_ec_style_dict(
76
+ cfg,
77
+ fig,
78
+ ax,
79
+ cycle_lines=cycle_lines,
80
+ file_data=file_data,
81
+ is_multi_file=is_multi_file,
82
+ )
433
83
 
434
84
 
435
85
  def batch_process(directory: str, args):
@@ -1105,7 +755,7 @@ def batch_process_ec(directory: str, args):
1105
755
  ax_b.set_ylabel('Potential (V)')
1106
756
  ax_b.set_title(f"{fname}")
1107
757
  legend = ax_b.legend(loc='best', fontsize='small', framealpha=0.8, title='Cycle')
1108
- legend.get_title().set_fontsize('small')
758
+ sync_legend_title_fontsize(legend)
1109
759
 
1110
760
  # ---- CV Mode ----
1111
761
  elif mode == 'cv':
@@ -1143,7 +793,7 @@ def batch_process_ec(directory: str, args):
1143
793
  ax_b.set_ylabel('Current (mA)')
1144
794
  ax_b.set_title(f"{fname}")
1145
795
  legend = ax_b.legend(loc='best', fontsize='small', framealpha=0.8, title='Cycle')
1146
- legend.get_title().set_fontsize('small')
796
+ sync_legend_title_fontsize(legend)
1147
797
 
1148
798
  # ---- dQdV Mode ----
1149
799
  elif mode == 'dqdv':
@@ -1251,7 +901,7 @@ def batch_process_ec(directory: str, args):
1251
901
  ax_b.set_ylabel(y_label)
1252
902
  ax_b.set_title(f"{fname}")
1253
903
  legend = ax_b.legend(loc='best', fontsize='small', framealpha=0.8, title='Cycle')
1254
- legend.get_title().set_fontsize('small')
904
+ sync_legend_title_fontsize(legend)
1255
905
 
1256
906
  # ---- CPC / EPC Mode ----
1257
907
  elif mode in ('cpc', 'epc'):
@@ -1458,21 +1108,9 @@ def _load_histo_style_file(style_path: str) -> dict | None:
1458
1108
 
1459
1109
  def _apply_histo_batch_style(fig, ax, state, cfg: dict) -> None:
1460
1110
  """Apply visual settings from a .bpsh file without replacing histogram data."""
1461
- from .plot_modes.histo.interactive import _restore_snapshot
1462
- from .plot_modes.histo.spines import apply_histo_spine_snapshot
1463
- from .plot_modes.histo.fonts import sync_histo_font_rcparams
1464
- from .plot_modes.histo.plot import apply_histo_geometry, refresh_histo_figure
1111
+ from .plot_modes.histo.session import apply_histo_style_snapshot
1465
1112
 
1466
- saved_setup = state.setup
1467
- saved_source = state.source_path
1468
- restored = _restore_snapshot(cfg)
1469
- state.style = restored.style
1470
- state.setup = saved_setup
1471
- state.source_path = saved_source
1472
- sync_histo_font_rcparams(state)
1473
- apply_histo_spine_snapshot(fig, ax, cfg)
1474
- apply_histo_geometry(fig, ax, state)
1475
- refresh_histo_figure(fig, ax, state)
1113
+ apply_histo_style_snapshot(fig, ax, state, cfg)
1476
1114
 
1477
1115
 
1478
1116
  def _save_histo_batch_figure(fig, ax, out_path: str) -> None:
@@ -1627,9 +1265,6 @@ def batch_process_histo(directory: str, args, *, only_files: list[str] | None =
1627
1265
  print(f" Applying style from {base_name}.bpsh")
1628
1266
  _apply_histo_batch_style(fig_b, ax_b, state, file_style_cfg)
1629
1267
 
1630
- if not state.style.title:
1631
- ax_b.set_title(fname)
1632
-
1633
1268
  out_name = os.path.splitext(fname)[0] + f"_histo.{output_format}"
1634
1269
  out_path = os.path.join(out_dir, out_name)
1635
1270
  target = _confirm_overwrite(out_path)
@@ -99,7 +99,6 @@ import matplotlib.cm as cm # type: ignore[import-untyped]
99
99
  import matplotlib.colors as mcolors # type: ignore[import-untyped]
100
100
  from matplotlib.ticker import AutoMinorLocator, NullFormatter # type: ignore[import-untyped]
101
101
  from matplotlib.colors import to_rgb, rgb_to_hsv, hsv_to_rgb # type: ignore[import-untyped]
102
- from matplotlib.colors import to_rgb # type: ignore[import-untyped]
103
102
 
104
103
  # Try to import optional interactive menus
105
104
  try:
@@ -272,6 +272,20 @@ def color_block(color: Optional[str]) -> str:
272
272
  return "[??]"
273
273
 
274
274
 
275
+ def format_color_listing(color) -> str:
276
+ """Return ``<swatch> <hex>`` for menu listings (curves, saved colors, etc.)."""
277
+ if color is None:
278
+ 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:
283
+ text = str(color).strip()
284
+ if not text:
285
+ return f"{color_block(None)} --"
286
+ return f"{color_block(text)} {text}"
287
+
288
+
275
289
  def color_bar(colors: Sequence[str]) -> str:
276
290
  """Return a string of adjacent color blocks."""
277
291
  blocks = [color_block(col) for col in colors if col]
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.8.48] - 2026-07-29
4
+ - Bug fixes on session reload
5
+
6
+
7
+ ## [1.8.47] - 2026-07-21
8
+ - Added Batch Interactive mode, loading multiple saved .pkl sessions
9
+ (must be the same type, e.g All are GC) to edit basic styles and
10
+ geometries of all files at once.
11
+ Example:
12
+ batplot gc1.pkl gc2.pkl gc3.pkl
13
+ - Bug fixes
14
+
15
+
3
16
  ## [1.8.46] - 2026-07-07
4
17
  - Added Histogram mode, use batplot -h to learn more
5
18
 
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": "1.8.48",
3
+ "custom_message": "- Bug fixes on session reload",
4
+ "update_notes": [
5
+ "- Bug fixes on session reload"
6
+ ]
7
+ }