batplot 1.8.52__tar.gz → 1.8.55__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 (353) hide show
  1. {batplot-1.8.52 → batplot-1.8.55}/DEVELOPING.md +4 -1
  2. {batplot-1.8.52 → batplot-1.8.55}/PKG-INFO +12 -15
  3. {batplot-1.8.52 → batplot-1.8.55}/README.md +11 -14
  4. {batplot-1.8.52 → batplot-1.8.55}/batplot/__init__.py +1 -1
  5. {batplot-1.8.52 → batplot-1.8.55}/batplot/_mpl_backend.py +13 -2
  6. {batplot-1.8.52 → batplot-1.8.55}/batplot/args.py +89 -18
  7. {batplot-1.8.52 → batplot-1.8.55}/batplot/batch.py +35 -22
  8. {batplot-1.8.52 → batplot-1.8.55}/batplot/batplot.py +12 -3
  9. {batplot-1.8.52 → batplot-1.8.55}/batplot/cli.py +14 -1
  10. {batplot-1.8.52 → batplot-1.8.55}/batplot/config.py +2 -2
  11. {batplot-1.8.52 → batplot-1.8.55}/batplot/data/CHANGELOG.md +15 -0
  12. {batplot-1.8.52 → batplot-1.8.55}/batplot/data/latest_release_notes.json +1 -1
  13. {batplot-1.8.52 → batplot-1.8.55}/batplot/dev_upgrade.py +41 -19
  14. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_commands.py +18 -14
  15. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_geom_helpers.py +30 -19
  16. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_menu_io.py +12 -5
  17. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/cpc_batch_helpers.py +16 -4
  18. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/dqdv_2d_batch_helpers.py +11 -0
  19. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/ec_batch_helpers.py +156 -15
  20. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/histo_batch_helpers.py +23 -21
  21. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/menu_cpc.py +83 -14
  22. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/menu_dqdv_2d.py +23 -8
  23. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/menu_ec.py +110 -18
  24. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/menu_histo.py +13 -1
  25. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/menu_operando.py +65 -26
  26. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/menu_xy.py +195 -95
  27. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/operando_batch_helpers.py +87 -46
  28. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/xy_batch_helpers.py +116 -33
  29. batplot-1.8.55/batplot/plot_modes/common/color_menu_help.py +228 -0
  30. batplot-1.8.55/batplot/plot_modes/common/curve_look_help.py +140 -0
  31. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/fonts.py +16 -1
  32. batplot-1.8.55/batplot/plot_modes/common/layout_compat.py +515 -0
  33. batplot-1.8.55/batplot/plot_modes/common/menu_rendering.py +260 -0
  34. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/palettes.py +18 -0
  35. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/session_helpers.py +12 -4
  36. batplot-1.8.55/batplot/plot_modes/common/size_spec.py +217 -0
  37. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/sources.py +37 -5
  38. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/spines.py +120 -4
  39. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/style_routing.py +2 -2
  40. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/terminal.py +193 -3
  41. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/actions.py +6 -10
  42. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/add_file.py +3 -7
  43. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/colors.py +91 -39
  44. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/interactive.py +22 -10
  45. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/labels.py +39 -19
  46. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/menu.py +5 -5
  47. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/panel_menus.py +42 -12
  48. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/session.py +34 -15
  49. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/style.py +117 -30
  50. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/wasd_menu.py +9 -1
  51. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/actions.py +4 -9
  52. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/colors.py +171 -88
  53. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/interactive.py +31 -14
  54. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/labels.py +41 -18
  55. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/line_style.py +19 -10
  56. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/menu.py +5 -5
  57. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/session.py +78 -21
  58. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/spine_colors.py +26 -16
  59. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/style.py +73 -2
  60. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/style_apply.py +47 -24
  61. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/undo_state.py +15 -2
  62. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/colors.py +60 -40
  63. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/density_curve.py +10 -5
  64. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/interactive.py +33 -19
  65. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/labels.py +38 -13
  66. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/line_style.py +10 -5
  67. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/plot.py +7 -0
  68. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/session.py +2 -2
  69. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/spines.py +17 -4
  70. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/actions.py +2 -2
  71. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/axis_units.py +2 -2
  72. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/cif_menu.py +63 -47
  73. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/colors.py +72 -42
  74. batplot-1.8.55/batplot/plot_modes/operando/interactive.py +3841 -0
  75. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/labels.py +59 -65
  76. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/layout.py +19 -2
  77. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/layout_menu.py +36 -29
  78. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/line_style.py +35 -25
  79. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/menu.py +21 -21
  80. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/plot.py +92 -21
  81. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/routing.py +5 -9
  82. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/session.py +32 -2
  83. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/spine_colors.py +61 -23
  84. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/style.py +140 -24
  85. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/style_apply.py +81 -24
  86. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/undo_state.py +14 -0
  87. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/visibility.py +7 -1
  88. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/arrange.py +33 -49
  89. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/axis_range.py +80 -20
  90. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/axis_units.py +20 -11
  91. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/cif.py +243 -63
  92. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/colors.py +86 -52
  93. batplot-1.8.55/batplot/plot_modes/xy/full_data.py +693 -0
  94. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/interactive.py +19 -16
  95. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/labels.py +46 -18
  96. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/line_style.py +19 -10
  97. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/menu.py +21 -5
  98. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/pipeline.py +40 -29
  99. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/session.py +127 -41
  100. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/spines.py +71 -7
  101. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/style.py +266 -105
  102. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/undo_state.py +31 -10
  103. {batplot-1.8.52 → batplot-1.8.55}/batplot/screen_color.py +85 -11
  104. {batplot-1.8.52 → batplot-1.8.55}/batplot/showcol.py +19 -0
  105. {batplot-1.8.52 → batplot-1.8.55}/batplot/ui.py +312 -97
  106. {batplot-1.8.52 → batplot-1.8.55}/batplot/utils.py +309 -64
  107. {batplot-1.8.52 → batplot-1.8.55}/batplot/version_check.py +28 -12
  108. {batplot-1.8.52 → batplot-1.8.55}/batplot.egg-info/PKG-INFO +12 -15
  109. {batplot-1.8.52 → batplot-1.8.55}/batplot.egg-info/SOURCES.txt +26 -0
  110. {batplot-1.8.52 → batplot-1.8.55}/pyproject.toml +1 -1
  111. {batplot-1.8.52 → batplot-1.8.55}/tests/test_all_menus_smoke.py +7 -0
  112. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_all_modes_sync.py +7 -0
  113. batplot-1.8.55/tests/test_batch_cpc_key_isolation.py +340 -0
  114. batplot-1.8.55/tests/test_batch_dqdv_key_isolation.py +292 -0
  115. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_ec_cycles_status.py +8 -2
  116. batplot-1.8.55/tests/test_batch_gc_key_isolation.py +376 -0
  117. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_geometry_pisb_keys.py +0 -4
  118. batplot-1.8.55/tests/test_batch_histo_key_isolation.py +169 -0
  119. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_menu_parity.py +6 -3
  120. batplot-1.8.55/tests/test_batch_operando_key_isolation.py +161 -0
  121. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_session.py +2 -2
  122. batplot-1.8.55/tests/test_batch_spine_sync.py +204 -0
  123. batplot-1.8.55/tests/test_batch_xy_key_isolation.py +200 -0
  124. {batplot-1.8.52 → batplot-1.8.55}/tests/test_common_palettes.py +19 -2
  125. {batplot-1.8.52 → batplot-1.8.55}/tests/test_contracts.py +32 -2
  126. batplot-1.8.55/tests/test_cpc_canvas_undo.py +120 -0
  127. batplot-1.8.55/tests/test_cross_os_deeper.py +226 -0
  128. batplot-1.8.55/tests/test_curve_look_help.py +95 -0
  129. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_noninteractive_bugs.py +58 -4
  130. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round12_commercial_gates.py +2 -0
  131. {batplot-1.8.52 → batplot-1.8.55}/tests/test_dev_upgrade.py +37 -0
  132. {batplot-1.8.52 → batplot-1.8.55}/tests/test_ec_cpc_geometry_pisb_keys.py +7 -6
  133. {batplot-1.8.52 → batplot-1.8.55}/tests/test_ec_cycle_identity_roundtrip.py +27 -10
  134. batplot-1.8.55/tests/test_ec_cycles_three_color_modes.py +215 -0
  135. batplot-1.8.55/tests/test_ec_old_session_three_color_modes.py +196 -0
  136. batplot-1.8.55/tests/test_file_dialogs_os.py +257 -0
  137. batplot-1.8.55/tests/test_geom_size_highlight.py +81 -0
  138. {batplot-1.8.52 → batplot-1.8.55}/tests/test_histo_geometry_pisb_keys.py +7 -8
  139. {batplot-1.8.52 → batplot-1.8.55}/tests/test_histo_style_pisb_keys.py +7 -8
  140. batplot-1.8.55/tests/test_label_shortcuts_math_help.py +151 -0
  141. batplot-1.8.55/tests/test_line_submenu_pisb_widths.py +156 -0
  142. batplot-1.8.55/tests/test_menu_rendering_presentation.py +76 -0
  143. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_batch_menu.py +3 -2
  144. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_cif_add.py +43 -6
  145. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_cif_color.py +6 -6
  146. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_geometry_pisb_keys.py +1 -1
  147. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_roundtrip.py +2 -2
  148. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_style_pisb_keys.py +1 -1
  149. batplot-1.8.55/tests/test_quit_confirm_export_save.py +98 -0
  150. {batplot-1.8.52 → batplot-1.8.55}/tests/test_spine_colors_pisb.py +216 -0
  151. batplot-1.8.55/tests/test_spine_wasd_figure_help.py +56 -0
  152. {batplot-1.8.52 → batplot-1.8.55}/tests/test_spine_wasd_pisb_all_modes.py +57 -3
  153. batplot-1.8.55/tests/test_stack_rearrange_tick_spacing.py +229 -0
  154. batplot-1.8.55/tests/test_style_layout_compat.py +230 -0
  155. batplot-1.8.55/tests/test_tick_display_color_contract.py +331 -0
  156. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xy_axis_units.py +55 -5
  157. batplot-1.8.55/tests/test_xy_bps_bpsg_key_matrix.py +291 -0
  158. batplot-1.8.55/tests/test_xy_cif_add.py +756 -0
  159. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xy_full_data_retention.py +79 -0
  160. batplot-1.8.55/tests/test_xy_generic_xy_default.py +373 -0
  161. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xy_geometry_pisb_keys.py +119 -4
  162. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xy_style_pisb_keys.py +47 -18
  163. batplot-1.8.52/batplot/plot_modes/common/menu_rendering.py +0 -145
  164. batplot-1.8.52/batplot/plot_modes/common/size_spec.py +0 -72
  165. batplot-1.8.52/batplot/plot_modes/operando/interactive.py +0 -1924
  166. batplot-1.8.52/batplot/plot_modes/xy/full_data.py +0 -416
  167. batplot-1.8.52/tests/test_batch_spine_sync.py +0 -82
  168. batplot-1.8.52/tests/test_xy_cif_add.py +0 -408
  169. {batplot-1.8.52 → batplot-1.8.55}/LICENSE +0 -0
  170. {batplot-1.8.52 → batplot-1.8.55}/MANIFEST.in +0 -0
  171. {batplot-1.8.52 → batplot-1.8.55}/NOTICE +0 -0
  172. {batplot-1.8.52 → batplot-1.8.55}/batplot/canvas_interactive.py +0 -0
  173. {batplot-1.8.52 → batplot-1.8.55}/batplot/cif.py +0 -0
  174. {batplot-1.8.52 → batplot-1.8.55}/batplot/cli_save.py +0 -0
  175. {batplot-1.8.52 → batplot-1.8.55}/batplot/color_utils.py +0 -0
  176. {batplot-1.8.52 → batplot-1.8.55}/batplot/converters.py +0 -0
  177. {batplot-1.8.52 → batplot-1.8.55}/batplot/ec_common.py +0 -0
  178. {batplot-1.8.52 → batplot-1.8.55}/batplot/modes.py +0 -0
  179. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/__init__.py +0 -0
  180. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/__init__.py +0 -0
  181. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_crosshair.py +0 -0
  182. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_figure_io.py +0 -0
  183. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_io.py +0 -0
  184. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_menu_helpers.py +0 -0
  185. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_panel_state.py +0 -0
  186. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/batch_scoped_sync.py +0 -0
  187. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/common.py +0 -0
  188. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/kinds.py +0 -0
  189. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/load.py +0 -0
  190. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/batch_session/routing.py +0 -0
  191. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/__init__.py +0 -0
  192. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/axis_state.py +0 -0
  193. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/batch_font.py +0 -0
  194. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/crosshair_export.py +0 -0
  195. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/files.py +0 -0
  196. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/font_extras.py +0 -0
  197. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/interactive_state.py +0 -0
  198. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/line_dash.py +0 -0
  199. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/menus.py +0 -0
  200. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/overview_metrics.py +0 -0
  201. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/session_data_guarantee.py +0 -0
  202. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/session_key_smoke.py +0 -0
  203. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/smoothing.py +0 -0
  204. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/state_capture.py +0 -0
  205. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/common/title_offsets.py +0 -0
  206. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/__init__.py +0 -0
  207. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/legend.py +0 -0
  208. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/legend_order.py +0 -0
  209. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/load.py +0 -0
  210. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/overview.py +0 -0
  211. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/routing.py +0 -0
  212. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/cpc/snapshots.py +0 -0
  213. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/__init__.py +0 -0
  214. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/capacity_cum.py +0 -0
  215. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/dqdv_2d.py +0 -0
  216. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/dual_axis_menu.py +0 -0
  217. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/export.py +0 -0
  218. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/legend.py +0 -0
  219. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/legend_order.py +0 -0
  220. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/overview.py +0 -0
  221. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/routing.py +0 -0
  222. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/electrochem/smoothing_menu.py +0 -0
  223. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/__init__.py +0 -0
  224. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/actions.py +0 -0
  225. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/fonts.py +0 -0
  226. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/load.py +0 -0
  227. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/routing.py +0 -0
  228. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/toggles.py +0 -0
  229. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/wizard.py +0 -0
  230. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/histo/y_range.py +0 -0
  231. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/__init__.py +0 -0
  232. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/axes_limits_menu.py +0 -0
  233. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/grid.py +0 -0
  234. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/intensity_menu.py +0 -0
  235. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/ions_axis.py +0 -0
  236. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/operando/peaks.py +0 -0
  237. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/session_routing.py +0 -0
  238. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/__init__.py +0 -0
  239. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/actions.py +0 -0
  240. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/data_ops.py +0 -0
  241. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/derivative.py +0 -0
  242. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/game.py +0 -0
  243. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/offset_menu.py +0 -0
  244. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/peaks.py +0 -0
  245. {batplot-1.8.52 → batplot-1.8.55}/batplot/plot_modes/xy/smoothing.py +0 -0
  246. {batplot-1.8.52 → batplot-1.8.55}/batplot/plotting.py +0 -0
  247. {batplot-1.8.52 → batplot-1.8.55}/batplot/readers.py +0 -0
  248. {batplot-1.8.52 → batplot-1.8.55}/batplot/readers_common.py +0 -0
  249. {batplot-1.8.52 → batplot-1.8.55}/batplot/readers_ec.py +0 -0
  250. {batplot-1.8.52 → batplot-1.8.55}/batplot/readers_xrd.py +0 -0
  251. {batplot-1.8.52 → batplot-1.8.55}/batplot/session.py +0 -0
  252. {batplot-1.8.52 → batplot-1.8.55}/batplot/strip_header.py +0 -0
  253. {batplot-1.8.52 → batplot-1.8.55}/batplot/style.py +0 -0
  254. {batplot-1.8.52 → batplot-1.8.55}/batplot.egg-info/dependency_links.txt +0 -0
  255. {batplot-1.8.52 → batplot-1.8.55}/batplot.egg-info/entry_points.txt +0 -0
  256. {batplot-1.8.52 → batplot-1.8.55}/batplot.egg-info/requires.txt +0 -0
  257. {batplot-1.8.52 → batplot-1.8.55}/batplot.egg-info/top_level.txt +0 -0
  258. {batplot-1.8.52 → batplot-1.8.55}/setup.cfg +0 -0
  259. {batplot-1.8.52 → batplot-1.8.55}/setup.py +0 -0
  260. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_crosshair.py +0 -0
  261. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_font_menu.py +0 -0
  262. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_geom_menu.py +0 -0
  263. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_panel_status.py +0 -0
  264. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_pisb_contract.py +0 -0
  265. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_scoped_sync_modes.py +0 -0
  266. {batplot-1.8.52 → batplot-1.8.55}/tests/test_batch_style_pisb_keys.py +0 -0
  267. {batplot-1.8.52 → batplot-1.8.55}/tests/test_bc_new_fields_defaults.py +0 -0
  268. {batplot-1.8.52 → batplot-1.8.55}/tests/test_bruker_intensity.py +0 -0
  269. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cif_tick_crystallography.py +0 -0
  270. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cli_all_flags.py +0 -0
  271. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cli_save.py +0 -0
  272. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cli_smoke.py +0 -0
  273. {batplot-1.8.52 → batplot-1.8.55}/tests/test_color_display_hex.py +0 -0
  274. {batplot-1.8.52 → batplot-1.8.55}/tests/test_color_listing_visible.py +0 -0
  275. {batplot-1.8.52 → batplot-1.8.55}/tests/test_color_utils.py +0 -0
  276. {batplot-1.8.52 → batplot-1.8.55}/tests/test_common_files.py +0 -0
  277. {batplot-1.8.52 → batplot-1.8.55}/tests/test_convert_xrd.py +0 -0
  278. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cpc_add_file.py +0 -0
  279. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cpc_legend_order.py +0 -0
  280. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cpc_roundtrip.py +0 -0
  281. {batplot-1.8.52 → batplot-1.8.55}/tests/test_critical_stability_fixes.py +0 -0
  282. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cross_os_oe_paths.py +0 -0
  283. {batplot-1.8.52 → batplot-1.8.55}/tests/test_cross_platform_parity.py +0 -0
  284. {batplot-1.8.52 → batplot-1.8.55}/tests/test_crosshair_export.py +0 -0
  285. {batplot-1.8.52 → batplot-1.8.55}/tests/test_csv_readers.py +0 -0
  286. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_residual_pisb_gates.py +0 -0
  287. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round10_bc_safe.py +0 -0
  288. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round11_title_fidelity.py +0 -0
  289. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round13_final_key_audit.py +0 -0
  290. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round3_pisb_gates.py +0 -0
  291. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round4_pisb_gates.py +0 -0
  292. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round5_pisb_gates.py +0 -0
  293. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round6_session_fidelity.py +0 -0
  294. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round7_root_helpers.py +0 -0
  295. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round8_root_helpers.py +0 -0
  296. {batplot-1.8.52 → batplot-1.8.55}/tests/test_deep_round9_root_helpers.py +0 -0
  297. {batplot-1.8.52 → batplot-1.8.55}/tests/test_default_sizes_and_oe_persistence.py +0 -0
  298. {batplot-1.8.52 → batplot-1.8.55}/tests/test_dqdv_contour_session_keys.py +0 -0
  299. {batplot-1.8.52 → batplot-1.8.55}/tests/test_dqdv_smooth_status.py +0 -0
  300. {batplot-1.8.52 → batplot-1.8.55}/tests/test_dual_axis_menu_audit.py +0 -0
  301. {batplot-1.8.52 → batplot-1.8.55}/tests/test_dual_mode_pisb.py +0 -0
  302. {batplot-1.8.52 → batplot-1.8.55}/tests/test_dual_pisb_hard_gates.py +0 -0
  303. {batplot-1.8.52 → batplot-1.8.55}/tests/test_dual_tk_a_coupling.py +0 -0
  304. {batplot-1.8.52 → batplot-1.8.55}/tests/test_dual_top_wasd_both_layers.py +0 -0
  305. {batplot-1.8.52 → batplot-1.8.55}/tests/test_ec_cpc_style_pisb_keys.py +0 -0
  306. {batplot-1.8.52 → batplot-1.8.55}/tests/test_ec_multifile_color_menu.py +0 -0
  307. {batplot-1.8.52 → batplot-1.8.55}/tests/test_ec_roundtrip.py +0 -0
  308. {batplot-1.8.52 → batplot-1.8.55}/tests/test_ec_session_bc_new_keys.py +0 -0
  309. {batplot-1.8.52 → batplot-1.8.55}/tests/test_every_key_behavioral_walk.py +0 -0
  310. {batplot-1.8.52 → batplot-1.8.55}/tests/test_final_audit_residuals.py +0 -0
  311. {batplot-1.8.52 → batplot-1.8.55}/tests/test_full_menu_audit_gaps.py +0 -0
  312. {batplot-1.8.52 → batplot-1.8.55}/tests/test_gc_cumulative.py +0 -0
  313. {batplot-1.8.52 → batplot-1.8.55}/tests/test_hard_check_twin_and_batch.py +0 -0
  314. {batplot-1.8.52 → batplot-1.8.55}/tests/test_histo.py +0 -0
  315. {batplot-1.8.52 → batplot-1.8.55}/tests/test_histo_interactive_imports.py +0 -0
  316. {batplot-1.8.52 → batplot-1.8.55}/tests/test_imk_stderr_guard.py +0 -0
  317. {batplot-1.8.52 → batplot-1.8.55}/tests/test_interactive_handler_intent.py +0 -0
  318. {batplot-1.8.52 → batplot-1.8.55}/tests/test_interactive_menu_smoke.py +0 -0
  319. {batplot-1.8.52 → batplot-1.8.55}/tests/test_interactive_state.py +0 -0
  320. {batplot-1.8.52 → batplot-1.8.55}/tests/test_line_dash_styles.py +0 -0
  321. {batplot-1.8.52 → batplot-1.8.55}/tests/test_menu_handler_imports.py +0 -0
  322. {batplot-1.8.52 → batplot-1.8.55}/tests/test_menu_prompt_order.py +0 -0
  323. {batplot-1.8.52 → batplot-1.8.55}/tests/test_mpl_backend.py +0 -0
  324. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_axis_units.py +0 -0
  325. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_layout_menu.py +0 -0
  326. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_peaks_axis_units.py +0 -0
  327. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_spine_isolation.py +0 -0
  328. {batplot-1.8.52 → batplot-1.8.55}/tests/test_operando_submenu_smoke.py +0 -0
  329. {batplot-1.8.52 → batplot-1.8.55}/tests/test_overview_metrics.py +0 -0
  330. {batplot-1.8.52 → batplot-1.8.55}/tests/test_pi_axis_units_persistence.py +0 -0
  331. {batplot-1.8.52 → batplot-1.8.55}/tests/test_pisb_deep_all_modes.py +0 -0
  332. {batplot-1.8.52 → batplot-1.8.55}/tests/test_recent_axis_names.py +0 -0
  333. {batplot-1.8.52 → batplot-1.8.55}/tests/test_screen_color.py +0 -0
  334. {batplot-1.8.52 → batplot-1.8.55}/tests/test_screen_color_pisb.py +0 -0
  335. {batplot-1.8.52 → batplot-1.8.55}/tests/test_secondary_spine_colors.py +0 -0
  336. {batplot-1.8.52 → batplot-1.8.55}/tests/test_session_backward_compat.py +0 -0
  337. {batplot-1.8.52 → batplot-1.8.55}/tests/test_session_font_restore.py +0 -0
  338. {batplot-1.8.52 → batplot-1.8.55}/tests/test_session_full_data_guarantee.py +0 -0
  339. {batplot-1.8.52 → batplot-1.8.55}/tests/test_session_save_integrity.py +0 -0
  340. {batplot-1.8.52 → batplot-1.8.55}/tests/test_session_style_restore_parity.py +0 -0
  341. {batplot-1.8.52 → batplot-1.8.55}/tests/test_state_capture.py +0 -0
  342. {batplot-1.8.52 → batplot-1.8.55}/tests/test_strip_header.py +0 -0
  343. {batplot-1.8.52 → batplot-1.8.55}/tests/test_stupid_input_hardening.py +0 -0
  344. {batplot-1.8.52 → batplot-1.8.55}/tests/test_style_import_integrity.py +0 -0
  345. {batplot-1.8.52 → batplot-1.8.55}/tests/test_style_routing.py +0 -0
  346. {batplot-1.8.52 → batplot-1.8.55}/tests/test_tick_visibility_save_truth.py +0 -0
  347. {batplot-1.8.52 → batplot-1.8.55}/tests/test_undo_deep_all_modes.py +0 -0
  348. {batplot-1.8.52 → batplot-1.8.55}/tests/test_undo_stack_integrity.py +0 -0
  349. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xrd_crosshair_bragg.py +0 -0
  350. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xy_modules.py +0 -0
  351. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xy_offset_menu.py +0 -0
  352. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xy_roundtrip.py +0 -0
  353. {batplot-1.8.52 → batplot-1.8.55}/tests/test_xy_source_files.py +0 -0
@@ -460,7 +460,10 @@ Before changing release behavior:
460
460
  `--dev-upgrade` runs `sync_pyproject_package_data()` to refresh
461
461
  `[tool.setuptools.package-data]`.
462
462
  - Git: `_git_stage_release_snapshot()` stages tracked updates and all untracked
463
- non-ignored paths (no hand-maintained file list).
463
+ non-ignored paths (no hand-maintained file list), and **always** re-stages
464
+ the MkDocs user manual (`docs/`, `mkdocs.yml`, `.github/workflows/docs.yml`,
465
+ `scripts/capture_manual_figures.py`) so GitHub Pages updates on every
466
+ `--dev-upgrade` / `--dev-git` push.
464
467
  4. Keep GitHub/PyPI conflict handling explicit and testable.
465
468
 
466
469
  Canonical version files checked on every release:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: batplot
3
- Version: 1.8.52
3
+ Version: 1.8.55
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
@@ -58,22 +58,22 @@ Dynamic: license-file
58
58
 
59
59
  **Interactive plotting tool for battery and materials characterization data**
60
60
 
61
- `batplot` is a Python CLI tool for visualizing and analyzing electrochemical and structural characterization data with interactive styling and session management. The electrochemistry and operando plots were inspired from Amalie Skurtveit's python scripts (https://github.com/piieceofcake?tab=repositories).
61
+ `batplot` is a Command-line based software for quick visuallization of 1D (x,y) and 2D (x,y,z) data with interactive styling and session management. It is designed for researchers within the fields of materials sciences and electrochemistry who do not have programming skills.
62
+ The electrochemistry and operando plots were inspired from Amalie Skurtveit's python scripts (https://github.com/piieceofcake?tab=repositories).
62
63
 
63
64
  ## Features
64
65
 
65
66
  With a single line of command to easily plot publication-ready plots with customized, intuitive interactive editing features such as:
66
67
  - **Electrochemistry Plot**: Galvanostatic cycling (GC), cyclic voltammetry (CV), differential capacity (dQdV), capacity per cycle (CPC) with multi-file support
67
- - **1D XY plot**: Designed for XRD, PDF, XAS (XANES/EXAFS) but also support other types
68
+ - **1D XY plot**: Designed for 1D data such as XRD, PDF, XAS (XANES/EXAFS) but also support other types
68
69
  - **Operando Contour plot**: Correlate in-situ characterizations (XRD/PDF/XAS) with electrochemical data
69
70
  - **XRD axis units**: Interactive Options `u` converts 2θ ↔ Q ↔ d (XY and operando); CIF phase ticks follow the current domain
70
71
  - **Histogram mode**: Column histograms from tabular `.csv`/`.txt` data (e.g. particle-size lists)
71
72
  - **Interactive plotting**: Real-time editing customized for each type of plottings
72
- - **Session Persistence**: Save and reload complete plot states with `.pkl` files
73
+ - **Session Save**: Save and reload complete plot states with `.pkl` files
73
74
  - **Style Management**: Import/export plot styles as `.bps`/`.bpsg` files (histogram: `.bpsh`)
74
75
  - **Batch Processing**: Export each file separately with `--all`
75
- - **Column preview**: `--showcol` prints numbered columns, header names when found, and the first 10 values per column (CSV, Excel, text, .mpt, .brml, Bruker .raw, etc.)
76
- - **Strip header lines**: `--strip-header N` removes the first N lines from a file or a folder of files (with `--ext`) and writes copies into a `stripped/` subfolder (originals untouched)
76
+
77
77
 
78
78
  ## Installation
79
79
 
@@ -84,8 +84,9 @@ pip install batplot
84
84
 
85
85
  ## Quick Start
86
86
 
87
+ - User manual: https://chem-plot.github.io/batplot/
87
88
  - Tutorial: https://drive.google.com/file/d/1NTFJWNBbWW4mgz0H5ZelGjuOBWxoFgkr/view
88
- - Tutorial files: https://github.com/chem-plot/batplot/blob/main/batplot_tutorial.zip
89
+ - Demo files: https://github.com/chem-plot/batplot/blob/main/batplot_demo_files.zip
89
90
 
90
91
  ---
91
92
 
@@ -263,18 +264,12 @@ batplot file1.csv file2.csv --gc --save
263
264
 
264
265
  ### Galvanostatic cycling (GC)
265
266
 
266
- GC mode plots potential vs. capacity for each charge/discharge cycle—the primary visualization for battery cycling data. Batplot automatically detects cycles from Neware `.csv` or Biologic `.mpt` files, assigns each cycle a distinct color, and supports both specific capacity (mAh/g) and raw capacity. For `.mpt` files, pass `--mass` (mg) to compute specific capacity. Discontinuous or paused experiments are handled by splitting data into contiguous charge/discharge segments. Use the interactive menu to customize colors, visibility, and export.
267
-
268
- By default each half-cycle resets capacity near 0 (cycles overlaid). With `--gc --cum`, capacity is laid **end-to-end** (cumulative / throughput capacity) so charge and discharge connect from the start to the end of the experiment; cycle colors, multifile overlay, overview, display mode, style/session save, and `--ro` still apply.
267
+ GC mode plots potential vs. capacity for each charge/discharge cycle—the primary visualization for battery cycling data. *batplot* automatically detects cycles from Neware `.csv` or Biologic `.mpt` files, assigns each cycle a distinct color, and supports both specific capacity (mAh/g) and raw capacity. For `.mpt` files, pass `--mass` (mg) to compute specific capacity. Discontinuous or paused experiments are handled by splitting data into contiguous charge/discharge segments. Use the interactive menu to customize colors, visibility, and export.
269
268
 
270
269
  ```bash
271
270
  # From .csv (capacity in file)
272
271
  batplot battery.csv --gc --i
273
272
 
274
- # Cumulative capacity (charge/discharge connected end-to-end)
275
- batplot battery.csv --gc --cum --i
276
- batplot f1.csv f2.csv --gc --cum --i
277
-
278
273
  # From .mpt (requires --mass in mg)
279
274
  batplot battery.mpt --gc --mass 7.0 --i
280
275
 
@@ -496,6 +491,8 @@ With `--interactive`:
496
491
 
497
492
  ## Help & Documentation
498
493
 
494
+ Illustrated user manual (GitHub Pages): https://chem-plot.github.io/batplot/
495
+
499
496
  ```bash
500
497
  batplot --h # General help
501
498
  batplot --h xy # XY mode guide
@@ -503,7 +500,7 @@ batplot --h ec # Electrochemistry guide
503
500
  batplot --h op # Operando guide
504
501
  batplot --h histo # Histogram mode guide
505
502
  batplot --v # Version and release notes
506
- batplot --m # Open illustrated manual
503
+ batplot --m # Open online user manual (https://chem-plot.github.io/batplot/)
507
504
  ```
508
505
 
509
506
  ---
@@ -2,22 +2,22 @@
2
2
 
3
3
  **Interactive plotting tool for battery and materials characterization data**
4
4
 
5
- `batplot` is a Python CLI tool for visualizing and analyzing electrochemical and structural characterization data with interactive styling and session management. The electrochemistry and operando plots were inspired from Amalie Skurtveit's python scripts (https://github.com/piieceofcake?tab=repositories).
5
+ `batplot` is a Command-line based software for quick visuallization of 1D (x,y) and 2D (x,y,z) data with interactive styling and session management. It is designed for researchers within the fields of materials sciences and electrochemistry who do not have programming skills.
6
+ The electrochemistry and operando plots were inspired from Amalie Skurtveit's python scripts (https://github.com/piieceofcake?tab=repositories).
6
7
 
7
8
  ## Features
8
9
 
9
10
  With a single line of command to easily plot publication-ready plots with customized, intuitive interactive editing features such as:
10
11
  - **Electrochemistry Plot**: Galvanostatic cycling (GC), cyclic voltammetry (CV), differential capacity (dQdV), capacity per cycle (CPC) with multi-file support
11
- - **1D XY plot**: Designed for XRD, PDF, XAS (XANES/EXAFS) but also support other types
12
+ - **1D XY plot**: Designed for 1D data such as XRD, PDF, XAS (XANES/EXAFS) but also support other types
12
13
  - **Operando Contour plot**: Correlate in-situ characterizations (XRD/PDF/XAS) with electrochemical data
13
14
  - **XRD axis units**: Interactive Options `u` converts 2θ ↔ Q ↔ d (XY and operando); CIF phase ticks follow the current domain
14
15
  - **Histogram mode**: Column histograms from tabular `.csv`/`.txt` data (e.g. particle-size lists)
15
16
  - **Interactive plotting**: Real-time editing customized for each type of plottings
16
- - **Session Persistence**: Save and reload complete plot states with `.pkl` files
17
+ - **Session Save**: Save and reload complete plot states with `.pkl` files
17
18
  - **Style Management**: Import/export plot styles as `.bps`/`.bpsg` files (histogram: `.bpsh`)
18
19
  - **Batch Processing**: Export each file separately with `--all`
19
- - **Column preview**: `--showcol` prints numbered columns, header names when found, and the first 10 values per column (CSV, Excel, text, .mpt, .brml, Bruker .raw, etc.)
20
- - **Strip header lines**: `--strip-header N` removes the first N lines from a file or a folder of files (with `--ext`) and writes copies into a `stripped/` subfolder (originals untouched)
20
+
21
21
 
22
22
  ## Installation
23
23
 
@@ -28,8 +28,9 @@ pip install batplot
28
28
 
29
29
  ## Quick Start
30
30
 
31
+ - User manual: https://chem-plot.github.io/batplot/
31
32
  - Tutorial: https://drive.google.com/file/d/1NTFJWNBbWW4mgz0H5ZelGjuOBWxoFgkr/view
32
- - Tutorial files: https://github.com/chem-plot/batplot/blob/main/batplot_tutorial.zip
33
+ - Demo files: https://github.com/chem-plot/batplot/blob/main/batplot_demo_files.zip
33
34
 
34
35
  ---
35
36
 
@@ -207,18 +208,12 @@ batplot file1.csv file2.csv --gc --save
207
208
 
208
209
  ### Galvanostatic cycling (GC)
209
210
 
210
- GC mode plots potential vs. capacity for each charge/discharge cycle—the primary visualization for battery cycling data. Batplot automatically detects cycles from Neware `.csv` or Biologic `.mpt` files, assigns each cycle a distinct color, and supports both specific capacity (mAh/g) and raw capacity. For `.mpt` files, pass `--mass` (mg) to compute specific capacity. Discontinuous or paused experiments are handled by splitting data into contiguous charge/discharge segments. Use the interactive menu to customize colors, visibility, and export.
211
-
212
- By default each half-cycle resets capacity near 0 (cycles overlaid). With `--gc --cum`, capacity is laid **end-to-end** (cumulative / throughput capacity) so charge and discharge connect from the start to the end of the experiment; cycle colors, multifile overlay, overview, display mode, style/session save, and `--ro` still apply.
211
+ GC mode plots potential vs. capacity for each charge/discharge cycle—the primary visualization for battery cycling data. *batplot* automatically detects cycles from Neware `.csv` or Biologic `.mpt` files, assigns each cycle a distinct color, and supports both specific capacity (mAh/g) and raw capacity. For `.mpt` files, pass `--mass` (mg) to compute specific capacity. Discontinuous or paused experiments are handled by splitting data into contiguous charge/discharge segments. Use the interactive menu to customize colors, visibility, and export.
213
212
 
214
213
  ```bash
215
214
  # From .csv (capacity in file)
216
215
  batplot battery.csv --gc --i
217
216
 
218
- # Cumulative capacity (charge/discharge connected end-to-end)
219
- batplot battery.csv --gc --cum --i
220
- batplot f1.csv f2.csv --gc --cum --i
221
-
222
217
  # From .mpt (requires --mass in mg)
223
218
  batplot battery.mpt --gc --mass 7.0 --i
224
219
 
@@ -440,6 +435,8 @@ With `--interactive`:
440
435
 
441
436
  ## Help & Documentation
442
437
 
438
+ Illustrated user manual (GitHub Pages): https://chem-plot.github.io/batplot/
439
+
443
440
  ```bash
444
441
  batplot --h # General help
445
442
  batplot --h xy # XY mode guide
@@ -447,7 +444,7 @@ batplot --h ec # Electrochemistry guide
447
444
  batplot --h op # Operando guide
448
445
  batplot --h histo # Histogram mode guide
449
446
  batplot --v # Version and release notes
450
- batplot --m # Open illustrated manual
447
+ batplot --m # Open online user manual (https://chem-plot.github.io/batplot/)
451
448
  ```
452
449
 
453
450
  ---
@@ -7,7 +7,7 @@ import importlib.abc
7
7
  import importlib.machinery
8
8
  import sys
9
9
 
10
- __version__ = "1.8.52"
10
+ __version__ = "1.8.55"
11
11
 
12
12
 
13
13
  _LEGACY_MODULE_ALIASES = {
@@ -58,7 +58,7 @@ def is_interactive_backend() -> bool:
58
58
 
59
59
 
60
60
  def _headless_context() -> bool:
61
- """True when batplot must stay on a non-interactive backend (CI/pytest)."""
61
+ """True when batplot must stay on a non-interactive backend (CI/pytest/SSH)."""
62
62
  if os.environ.get("BATPLOT_HEADLESS", "").lower() in ("1", "true", "yes"):
63
63
  return True
64
64
  if os.environ.get("CI", "").lower() in ("1", "true", "yes"):
@@ -67,11 +67,16 @@ def _headless_context() -> bool:
67
67
  return True
68
68
  if "pytest" in sys.modules:
69
69
  return True
70
+ # Linux SSH / containers without a graphical session: do not try Tk/Qt.
71
+ # macOS/Windows GUI apps do not rely on DISPLAY/WAYLAND_DISPLAY.
72
+ if sys.platform.startswith("linux"):
73
+ if not (os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY")):
74
+ return True
70
75
  return False
71
76
 
72
77
 
73
78
  def running_headless() -> bool:
74
- """True under pytest, CI, or when ``BATPLOT_HEADLESS`` is set."""
79
+ """True under pytest, CI, no Linux display, or ``BATPLOT_HEADLESS``."""
75
80
  return _headless_context()
76
81
 
77
82
 
@@ -148,6 +153,12 @@ def ensure_gui_backend(args=None) -> bool:
148
153
  if _should_respect_env_agg():
149
154
  return False
150
155
 
156
+ # Linux without DISPLAY/WAYLAND: skip Tk/Qt attempts (SSH/containers).
157
+ if sys.platform.startswith("linux") and not (
158
+ os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY")
159
+ ):
160
+ return is_interactive_backend()
161
+
151
162
  if _USER_SET_MPLBACKEND:
152
163
  env_be = os.environ.get("MPLBACKEND")
153
164
  if env_be and not _is_noninteractive_backend(env_be):
@@ -173,7 +173,7 @@ def _print_general_help() -> None:
173
173
  "Features:\n"
174
174
  " • Interactive (--i): styling, ranges, fonts, export, sessions\n"
175
175
  " • XRD wavelength: --wl 1.54 or file.xye:1.5406 for Q conversion\n"
176
- " • XRD axis units (interactive): Options u converts 2θ ↔ Q ↔ d (XY + operando; needs λ for 2θ)\n"
176
+ " • XRD axis units (interactive): Options u converts 2θ ↔ Q (XY; needs λ for 2θ); operando also offers d\n"
177
177
  " • CIF phase ticks: add .cif (or file.cif:wl); ticks follow the current axis (2θ / Q / d)\n"
178
178
  " • X-axis range: --xrange min max\n"
179
179
  " • Save figure: --out filename (default .svg)\n"
@@ -191,7 +191,7 @@ def _print_general_help() -> None:
191
191
  " batplot --h ec # Electrochemistry (GC/dQdV/CV/CPC) guide\n"
192
192
  " batplot --h op # Operando contour guide (also: batplot --help contour)\n"
193
193
  " batplot --h histo # Histogram mode guide (.csv/.txt column data)\n"
194
- " batplot --m # Open the illustrated PDF manual\n\n"
194
+ " batplot --m # Open online user manual (https://chem-plot.github.io/batplot/)\n\n"
195
195
 
196
196
  "Contact & Updates:\n"
197
197
  " Subscribe to batplot-lab@kjemi.uio.no for updates\n"
@@ -200,6 +200,7 @@ def _print_general_help() -> None:
200
200
  " Email: tianda@uio.no\n"
201
201
  " Personal page: https://www.mn.uio.no/kjemi/english/people/aca/tianda/\n"
202
202
  " GitHub: https://github.com/chem-plot/batplot\n"
203
+ " User manual: https://chem-plot.github.io/batplot/\n"
203
204
  " Kindly cite Tian's github page if the plot is used for publication\n"
204
205
  )
205
206
  _print_help(msg)
@@ -209,13 +210,17 @@ def _print_xy_help() -> None:
209
210
  msg = (
210
211
  "XY plots (XRD/PDF/XAS and many more)\n\n"
211
212
  "Supported files: .xye .xy .qye .dat .csv .gr .nor .chik .chir .txt .brml .raw .xrdml .rasx and other formats. CIF overlays supported.\n\n"
212
- "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"
213
+ "Axis detection: .qye→Q, .gr→r, .nor→energy, .chik→k, .chir→r; XRD vendor/\n"
214
+ " file:wl / --wl imply Q or 2θ as documented. Otherwise (e.g. batplot file.xy)\n"
215
+ " cols 1–2 plot with labels X / Y — use --xaxis (Q, 2theta, d, r, k, energy, time\n"
216
+ " or a custom name) when you want a typed axis.\n"
213
217
  "If mixing 2θ data in Q, give wavelength per-file (file.xye:1.5406) or global flag --wl.\n"
214
218
  "A wavelength can be converted into a different wave length by file.xye:1.54:0.709.\n"
215
219
  "For electrochemistry CSV/MPT time-potential plots, use --xaxis time.\n\n"
216
220
  "Interactive XRD axis units (Options u):\n"
217
- " In --i, press u to convert the plotted XRD axis among 2θ ↔ Q ↔ d (XRD data only).\n"
221
+ " In --i, press u to convert the plotted XRD axis between 2θ ↔ Q (XRD data only).\n"
218
222
  " Conversions involving 2θ need λ (--wl, file:wl, or prompt). CIF ticks stay Bragg-aligned.\n"
223
+ " d-spacing is not offered as a plot domain in 1D Options u.\n"
219
224
  " Not for PDF (.gr), XAS (.nor/.chik/.chir), or other non-diffraction axes.\n"
220
225
  " Example: batplot data.xye:0.709 --xaxis 2theta --i then u → q (uses λ=0.709 Å).\n\n"
221
226
  "CIF phase ticks:\n"
@@ -225,6 +230,7 @@ def _print_xy_help() -> None:
225
230
  " batplot scan.xye:1.54 phase.cif --i\n"
226
231
  " batplot scan.xye phase.cif:0.709 --xaxis 2theta --wl 0.709 --i\n\n"
227
232
  "Examples:\n"
233
+ " batplot file.xy --i # Quick plot cols 1–2 as X/Y\n"
228
234
  " batplot file.xy file2.xye --xaxis 2theta --i # Plot XRD data in 2theta space\n"
229
235
  " batplot file1.xye:1.5406 file2.txt:0.709 --i # Plot XRD data in different wavelengths in q space\n"
230
236
  " batplot data1.xye data2.xye --wl 1.54 --i # Same Wavelength for Q conversion\n"
@@ -236,7 +242,8 @@ def _print_xy_help() -> None:
236
242
  " batplot file1.xy file2.xy --1d --stack --i # First derivative\n"
237
243
  " batplot allfiles --i # All files in directory\n"
238
244
  " batplot allfiles --xaxis 2theta --xrange 10 80 # All with axis and range\n"
239
- " batplot --all --xaxis 2theta --xrange 10 80 # Batch: export each file → Figures/\n"
245
+ " batplot --all # Batch: each file → Figures/ (X/Y default)\n"
246
+ " batplot --all --xaxis 2theta --xrange 10 80 # Batch with typed XRD axis\n"
240
247
  " batplot file1.xy file2.xye --xaxis 2theta style.bps # Style + export\n\n"
241
248
  "Tips and options:\n"
242
249
  "[XY plot]\n"
@@ -443,7 +450,7 @@ def _print_op_help() -> None:
443
450
  "Standard XY files:\n"
444
451
  " • Folder should contain .xy/.xye/.qye/.dat files.\n"
445
452
  " • Intensity scale is auto-adjusted between min/max values.\n"
446
- " • If no .qye present, provide --xaxis 2theta or set --wl for Q conversion.\n"
453
+ " • Default axis is 2θ when no .qye; use --xaxis Q or --wl for Q conversion.\n"
447
454
  " • If a .mpt file is present, a side panel is added for dual-panel mode (time/potential/temp/etc.).\n"
448
455
  " • Without a .mpt file, operando-only mode shows the contour plot alone.\n"
449
456
  " • --1d / --2d: plot the first derivative (dy/dx) of each scan as a contour plot.\n\n"
@@ -767,20 +774,66 @@ def parse_args(argv=None):
767
774
  # Keys use the exact file token (e.g. "file.xy:1.54") for wavelength match.
768
775
  # Style files (.bps, .bpsg, .bpcfg) are NOT treated as file tokens so that
769
776
  # "batplot --all style.bps --readcol 2 3" uses global readcol, not per-file.
777
+ #
778
+ # Values of known options (--wl 0.259, --xaxis q, --out out.svg, …) must
779
+ # NOT update last_file_token. Otherwise
780
+ # batplot TD_R02.dat --wl 0.259 --readcol 1 3
781
+ # binds readcol to "0.259" and the plot silently falls back to cols 1,2.
770
782
  # ====================================================================
771
783
  readcol_by_file = {}
772
784
  global_readcol_expanded = None
773
785
  filtered_argv = []
774
786
  last_file_token = None
775
787
  _STYLE_EXTENSIONS = ('.bps', '.bpsg', '.bpcfg')
788
+ # Exact value counts for options that take fixed nargs (after short→long).
789
+ # store_true / flag-only options are omitted (0 values).
790
+ _OPTION_VALUE_COUNTS = {
791
+ '--wl': 1,
792
+ '--xaxis': 1,
793
+ '--out': 1,
794
+ '--savefig': 1,
795
+ '--delta': 1,
796
+ '--format': 1,
797
+ '--mass': 1,
798
+ '--cd': 1,
799
+ '--average': 1,
800
+ '--sum': 1,
801
+ '--histocol': 1,
802
+ '--binwidth': 1,
803
+ '--bins': 1,
804
+ '--ext': 1,
805
+ '--convert-ext': 1,
806
+ '--xrange': 2,
807
+ '--convert': 2,
808
+ '--pw': 2,
809
+ '--b': 2,
810
+ '--readcolxy': 2,
811
+ '--readcolxye': 2,
812
+ '--readcolqye': 2,
813
+ '--readcolnor': 2,
814
+ '--readcoldat': 2,
815
+ '--readcolcsv': 2,
816
+ '--readcolc': 2,
817
+ '--readcols': 2,
818
+ }
819
+ for _ext in custom_readcol_exts:
820
+ _OPTION_VALUE_COUNTS[f'--readcol{_ext}'] = 2
821
+ # Optional single value (nargs='?'): consume at most one non-option token.
822
+ _OPTIONAL_ONE_VALUE = {'--all', '--help', '--extract-brml-scans'}
823
+
824
+ def _option_value_count(flag: str) -> int:
825
+ if flag in _OPTION_VALUE_COUNTS:
826
+ return _OPTION_VALUE_COUNTS[flag]
827
+ if flag in _OPTIONAL_ONE_VALUE:
828
+ return 1
829
+ if flag == '--fullprof':
830
+ # nargs='+': consume following non-option tokens
831
+ return 10**9
832
+ return 0
833
+
776
834
  i = 0
777
835
  while i < len(argv):
778
836
  arg = argv[i]
779
- # Track non-option tokens as potential file specs (exclude style files)
780
- if not arg.startswith('-'):
781
- arg_lower = arg.lower()
782
- if not arg_lower.endswith(_STYLE_EXTENSIONS):
783
- last_file_token = arg
784
837
  if arg == '--readcol' and i + 1 < len(argv):
785
838
  tokens = []
786
839
  j = i + 1
@@ -818,9 +871,23 @@ def parse_args(argv=None):
818
871
  global_readcol_expanded = pairs[0] if len(pairs) == 1 else pairs
819
872
  i = j
820
873
  continue
874
+ if arg.startswith('-'):
875
+ filtered_argv.append(arg)
876
+ n_vals = _option_value_count(arg)
877
+ i += 1
878
+ taken = 0
879
+ while taken < n_vals and i < len(argv) and not argv[i].startswith('-'):
880
+ filtered_argv.append(argv[i])
881
+ i += 1
882
+ taken += 1
883
+ continue
884
+ # Non-option: potential file spec (exclude style files)
885
+ arg_lower = arg.lower()
886
+ if not arg_lower.endswith(_STYLE_EXTENSIONS):
887
+ last_file_token = arg
821
888
  filtered_argv.append(arg)
822
889
  i += 1
823
-
890
+
824
891
  argv = filtered_argv
825
892
 
826
893
  # ====================================================================
@@ -852,23 +919,27 @@ def parse_args(argv=None):
852
919
  # weren't in the parser yet when we built it
853
920
  ns, _unknown = parser.parse_known_args(argv)
854
921
  if getattr(ns, "manual", False):
855
- manual_url = "https://github.com/chem-plot/batplot/blob/main/batplot_user_manual.pdf"
922
+ manual_url = "https://chem-plot.github.io/batplot/"
856
923
  try:
857
924
  opened = webbrowser.open(manual_url)
858
925
  if _HAS_RICH and _console:
859
926
  if opened:
860
- _console.print("\n[green]Opened PDF manual in browser[/green]")
927
+ _console.print("\n[green]Opened user manual in browser[/green]")
861
928
  else:
862
- _console.print(f"\n[yellow]Manual PDF:[/yellow] {manual_url}")
929
+ _console.print(f"\n[yellow]User manual:[/yellow] {manual_url}")
863
930
  else:
864
- print("\nOpened PDF manual in browser" if opened else f"\nManual PDF: {manual_url}")
931
+ print(
932
+ "\nOpened user manual in browser"
933
+ if opened
934
+ else f"\nUser manual: {manual_url}"
935
+ )
865
936
  except Exception as exc: # pragma: no cover - best effort
866
937
  if _HAS_RICH and _console:
867
938
  _console.print(f"\n[red]Failed to open manual:[/red] {exc}")
868
- _console.print(f"[yellow]Manual PDF:[/yellow] {manual_url}")
939
+ _console.print(f"[yellow]User manual:[/yellow] {manual_url}")
869
940
  else:
870
941
  print(f"\nFailed to open manual: {exc}")
871
- print(f"Manual PDF: {manual_url}")
942
+ print(f"User manual: {manual_url}")
872
943
  sys.exit(0)
873
944
 
874
945
  topic = getattr(ns, 'help', None)
@@ -110,7 +110,7 @@ def batch_process(directory: str, args):
110
110
  - .nor → Energy space (XAS, eV)
111
111
  - .chik → k-space (EXAFS, Å⁻¹)
112
112
  - .chir → r-space (Fourier transform of EXAFS, Å)
113
- - .xy, .xye, .dat, .csv, .txt → Generic 2-column data (requires --xaxis flag)
113
+ - .xy, .xye, .dat, .csv, .txt → Generic 2-column data (labels X/Y; optional --xaxis / --wl)
114
114
 
115
115
  STYLE FILE SUPPORT:
116
116
  ------------------
@@ -122,7 +122,7 @@ def batch_process(directory: str, args):
122
122
  directory: Path to directory containing data files
123
123
  args: Argument namespace with batch processing options:
124
124
  - all: Style file path (if provided) or 'all' string
125
- - xaxis: X-axis type for unknown extensions (Q, 2theta, r, energy, k, rft)
125
+ - xaxis: Optional X-axis type (Q, 2theta, r, energy, k, rft); omit for X/Y
126
126
  - xrange: Optional X-axis range (min, max)
127
127
  - yrange: Optional Y-axis range (min, max)
128
128
  - format: Output format ('svg' or 'png', default 'svg')
@@ -137,7 +137,7 @@ def batch_process(directory: str, args):
137
137
  # ====================================================================
138
138
  # We classify file extensions into three categories:
139
139
  # 1. Known extensions with automatic axis detection (don't need --xaxis)
140
- # 2. Known generic extensions (need --xaxis if axis type unclear)
140
+ # 2. Generic / unknown extensions → X/Y unless --xaxis / --wl given
141
141
  # 3. Excluded extensions (not data files, skip them)
142
142
  # ====================================================================
143
143
 
@@ -209,7 +209,7 @@ def batch_process(directory: str, args):
209
209
  if ext in known_ext:
210
210
  files.append(f)
211
211
  else:
212
- # Include unknown extensions (require --xaxis)
212
+ # Include unknown extensions (default X/Y; optional --xaxis / --wl)
213
213
  files.append(f)
214
214
  unknown_ext_files.append(f)
215
215
 
@@ -221,20 +221,15 @@ def batch_process(directory: str, args):
221
221
  batch_save_xy_directory(directory, args, files)
222
222
  return
223
223
 
224
- # Check if --xaxis is required for unknown extensions
225
- if unknown_ext_files and not args.xaxis:
226
- print(f"Error: Found {len(unknown_ext_files)} file(s) with unknown extension(s) that require --xaxis:")
227
- for uf in unknown_ext_files[:5]: # Show first 5
228
- print(f" - {uf}")
229
- if len(unknown_ext_files) > 5:
230
- print(f" ... and {len(unknown_ext_files) - 5} more")
231
- print("\nKnown extensions that don't require --xaxis: .qye, .gr, .nor, .chik, .chir")
232
- print("Please specify x-axis type with --xaxis (options: 2theta, Q, r, energy, k, rft)")
233
- print("Example: batplot --all --xaxis 2theta")
234
- return
235
-
236
- if unknown_ext_files:
224
+ # Unknown extensions: without --xaxis/--wl → generic X/Y (same as interactive
225
+ # ``batplot file.xy``). With --xaxis, note the chosen type.
226
+ if unknown_ext_files and args.xaxis:
237
227
  print(f"Note: Processing {len(unknown_ext_files)} file(s) with unknown extension(s) using --xaxis {args.xaxis}")
228
+ elif unknown_ext_files and getattr(args, "wl", None) is None:
229
+ print(
230
+ f"Note: Processing {len(unknown_ext_files)} file(s) as generic X/Y "
231
+ "(cols 1–2). Use --xaxis or --wl for XRD/PDF/XAS axis types."
232
+ )
238
233
 
239
234
  print(f"Found {len(files)} files. Exporting SVG plots to Figures/")
240
235
 
@@ -315,8 +310,16 @@ def batch_process(directory: str, args):
315
310
  else:
316
311
  x, y = data[:, 0], data[:, 1]
317
312
  e = data[:, 2] if data.shape[1] >= 3 else None
318
- ax = (args.xaxis or '').strip()
319
- axis_mode = 'Q' if ax.upper() == 'Q' else (args.xaxis if args.xaxis else '2theta')
313
+ # Preserve historic --xaxis / --wl behavior for non-Bruker .raw:
314
+ # --xaxis Q → Q; other --xaxis → that type; --wl alone → 2θ
315
+ # Only the no-flag path is new (generic X/Y).
316
+ if args.xaxis:
317
+ ax = (args.xaxis or "").strip()
318
+ axis_mode = "Q" if ax.upper() == "Q" else args.xaxis
319
+ elif getattr(args, "wl", None) is not None:
320
+ axis_mode = "2theta"
321
+ else:
322
+ axis_mode = "generic"
320
323
  else:
321
324
  data = robust_loadtxt_skipheader(fpath)
322
325
  if data.ndim == 1: data = data.reshape(1, -1)
@@ -370,10 +373,11 @@ def batch_process(directory: str, args):
370
373
  args._batch_warned_extensions.add(ext)
371
374
  print(f" Note: Reading '{ext}' files as 2-column (x, y) data with x-axis = {args.xaxis}")
372
375
  elif getattr(args, 'wl', None) is not None:
373
- # .txt / generic text: --wl implies XRD Q conversion (matches main batplot.py)
376
+ # .txt / generic text: --wl implies XRD Q conversion (matches main pipeline)
374
377
  axis_mode = 'Q'
375
378
  else:
376
- raise ValueError(f"Unknown file type: {fname}. Use --xaxis [Q|2theta|r|k|energy|rft], or --wl for XRD Q, or batplot --help for help.")
379
+ # Quick plot: cols 1–2 with labels X / Y (matches interactive)
380
+ axis_mode = 'generic'
377
381
 
378
382
  # Convert to Q if needed
379
383
  if axis_mode == 'Q' and ext not in ('.qye', '.gr', '.nor'):
@@ -446,9 +450,18 @@ def batch_process(directory: str, args):
446
450
  ax_b.set_xlabel(r"k ($\mathrm{\AA}^{-1}$)")
447
451
  elif axis_mode == 'rft':
448
452
  ax_b.set_xlabel("Radial distance (Å)")
453
+ elif axis_mode == 'generic':
454
+ ax_b.set_xlabel("X")
455
+ elif args.xaxis and str(args.xaxis).lower() not in (
456
+ "2theta", "two_theta", "tth", "q", "d", "r", "energy", "k", "rft", "time",
457
+ ):
458
+ ax_b.set_xlabel(str(args.xaxis))
449
459
  else:
450
460
  ax_b.set_xlabel("2θ (deg)")
451
- ax_b.set_ylabel("Normalized intensity (a.u.)" if getattr(args, 'norm', False) else "Intensity")
461
+ if axis_mode == 'generic' and not getattr(args, 'norm', False):
462
+ ax_b.set_ylabel("Y")
463
+ else:
464
+ ax_b.set_ylabel("Normalized intensity (a.u.)" if getattr(args, 'norm', False) else "Intensity")
452
465
  ax_b.set_title(fname)
453
466
  fig_b.subplots_adjust(left=0.18, right=0.97, bottom=0.16, top=0.90)
454
467
  # Get output format from args, default to svg
@@ -201,9 +201,12 @@ def _prepare_allfiles_directory(target_dir: str, args, use_relative_paths: bool
201
201
  print(f" - {uf}")
202
202
  if len(unknown_ext_files) > 5:
203
203
  print(f" ... and {len(unknown_ext_files) - 5} more")
204
- print("These will be read as 2-column (x, y) data.")
205
- if not args.xaxis:
206
- print("Tip: Use --xaxis to specify the x-axis type (e.g., --xaxis 2theta, --xaxis Q, --xaxis r)")
204
+ print("These will be read as 2-column (x, y) data with labels X / Y by default.")
205
+ if not args.xaxis and getattr(args, "wl", None) is None:
206
+ print(
207
+ "Tip: Optional --xaxis / --wl for typed axes "
208
+ "(e.g. --xaxis 2theta, --xaxis Q); omit them for quick X/Y plots."
209
+ )
207
210
 
208
211
  print(f"Found {len(all_xy_files)} files to plot together")
209
212
  args.files = all_xy_files
@@ -373,6 +376,12 @@ def batplot_main() -> int: # type: ignore
373
376
  Exit code: 0 for success, non-zero for error
374
377
  (Follows Unix convention: 0 = success, non-zero = error)
375
378
  """
379
+ # Defense in depth: also install when called without cli.main().
380
+ try:
381
+ from .plot_modes.common.terminal import install_safe_builtins
382
+ install_safe_builtins()
383
+ except Exception:
384
+ pass
376
385
  # ====================================================================
377
386
  # STEP 1: PARSE COMMAND-LINE ARGUMENTS
378
387
  # ====================================================================
@@ -61,6 +61,12 @@ def main(argv: Optional[list] = None) -> int:
61
61
  >>> main()
62
62
  0
63
63
  """
64
+ # Windows cp1252-safe print/input for all interactive menus and errors.
65
+ try:
66
+ from .plot_modes.common.terminal import install_safe_builtins
67
+ install_safe_builtins()
68
+ except Exception:
69
+ pass
64
70
  # ====================================================================
65
71
  # STEP 0.5: CHECK FOR DEVELOPER UPGRADE COMMAND
66
72
  # ====================================================================
@@ -163,7 +169,14 @@ def main(argv: Optional[list] = None) -> int:
163
169
  # Other exceptions (unexpected bugs) will still show full traceback
164
170
  # for debugging purposes.
165
171
  # ====================================================================
166
- print(f"Error: {e}", file=sys.stderr)
172
+ try:
173
+ from .plot_modes.common.terminal import safe_console_print
174
+ safe_console_print(f"Error: {e}", file=sys.stderr)
175
+ except Exception:
176
+ try:
177
+ sys.stderr.write(f"Error: {e}\n")
178
+ except Exception:
179
+ sys.stderr.write("Error: (message not printable on this console)\n")
167
180
  return 1 # Non-zero exit code indicates error
168
181
 
169
182
  finally:
@@ -112,7 +112,7 @@ def load_config() -> Dict[str, Any]:
112
112
 
113
113
  # Try to read and parse JSON file
114
114
  try:
115
- with open(config_file, 'r') as f:
115
+ with open(config_file, 'r', encoding='utf-8') as f:
116
116
  return json.load(f) # Parse JSON string into Python dictionary
117
117
  except (json.JSONDecodeError, IOError):
118
118
  # File exists but is corrupted or unreadable
@@ -128,7 +128,7 @@ def save_config(config: Dict[str, Any]) -> bool:
128
128
  """
129
129
  config_file = get_config_file()
130
130
  try:
131
- with open(config_file, 'w') as f:
131
+ with open(config_file, 'w', encoding='utf-8') as f:
132
132
  # indent=2 makes JSON file human-readable (pretty-printed)
133
133
  json.dump(config, f, indent=2)
134
134
  return True
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.8.55] - 2026-09-15
4
+ - Bug fixes
5
+
6
+
7
+ ## [1.8.54] - 2026-09-14
8
+ - Fix --readcol after --wl / other option values (cols no longer stuck on 1–2)
9
+ - Quit prompt: e=export and s=save work in every interactive / batch menu
10
+ - Color menus (c/k): WASD side rectangle like spines t, for all modes
11
+ - User manual homepage: GitHub repo + tutorial zip links
12
+
13
+
14
+ ## [1.8.53] - 2026-09-09
15
+ - Bug fixes
16
+
17
+
3
18
  ## [1.8.52] - 2026-08-08
4
19
  - Bug fixes
5
20