rootfig 0.2.2__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. {rootfig-0.2.2 → rootfig-0.4.0}/CONTRIBUTING.md +29 -18
  2. {rootfig-0.2.2 → rootfig-0.4.0}/PKG-INFO +62 -25
  3. {rootfig-0.2.2 → rootfig-0.4.0}/README.md +61 -24
  4. {rootfig-0.2.2 → rootfig-0.4.0}/docs/api.md +3 -0
  5. {rootfig-0.2.2 → rootfig-0.4.0}/docs/composable.md +23 -9
  6. rootfig-0.4.0/docs/gallery/index.md +67 -0
  7. rootfig-0.4.0/docs/hooks/gallery.py +251 -0
  8. rootfig-0.4.0/docs/images/gallery/arrays-alice-dark.png +0 -0
  9. rootfig-0.4.0/docs/images/gallery/arrays-alice.png +0 -0
  10. rootfig-0.4.0/docs/images/gallery/arrays-atlas-dark.png +0 -0
  11. rootfig-0.4.0/docs/images/gallery/arrays-atlas.png +0 -0
  12. rootfig-0.4.0/docs/images/gallery/arrays-cms-dark.png +0 -0
  13. rootfig-0.4.0/docs/images/gallery/arrays-cms.png +0 -0
  14. rootfig-0.4.0/docs/images/gallery/arrays-dark.png +0 -0
  15. rootfig-0.4.0/docs/images/gallery/arrays-dune-dark.png +0 -0
  16. rootfig-0.4.0/docs/images/gallery/arrays-dune.png +0 -0
  17. rootfig-0.4.0/docs/images/gallery/arrays-lhcb-dark.png +0 -0
  18. rootfig-0.4.0/docs/images/gallery/arrays-lhcb.png +0 -0
  19. rootfig-0.4.0/docs/images/gallery/arrays.png +0 -0
  20. rootfig-0.4.0/docs/images/gallery/correlation-alice-dark.png +0 -0
  21. rootfig-0.4.0/docs/images/gallery/correlation-alice.png +0 -0
  22. rootfig-0.4.0/docs/images/gallery/correlation-atlas-dark.png +0 -0
  23. rootfig-0.4.0/docs/images/gallery/correlation-atlas.png +0 -0
  24. rootfig-0.4.0/docs/images/gallery/correlation-cms-dark.png +0 -0
  25. rootfig-0.4.0/docs/images/gallery/correlation-cms.png +0 -0
  26. rootfig-0.4.0/docs/images/gallery/correlation-dark.png +0 -0
  27. rootfig-0.4.0/docs/images/gallery/correlation-dune-dark.png +0 -0
  28. rootfig-0.4.0/docs/images/gallery/correlation-dune.png +0 -0
  29. rootfig-0.4.0/docs/images/gallery/correlation-lhcb-dark.png +0 -0
  30. rootfig-0.4.0/docs/images/gallery/correlation-lhcb.png +0 -0
  31. rootfig-0.4.0/docs/images/gallery/density_flow-alice-dark.png +0 -0
  32. rootfig-0.4.0/docs/images/gallery/density_flow-alice.png +0 -0
  33. rootfig-0.4.0/docs/images/gallery/density_flow-atlas-dark.png +0 -0
  34. rootfig-0.4.0/docs/images/gallery/density_flow-atlas.png +0 -0
  35. rootfig-0.4.0/docs/images/gallery/density_flow-cms-dark.png +0 -0
  36. rootfig-0.4.0/docs/images/gallery/density_flow-cms.png +0 -0
  37. rootfig-0.4.0/docs/images/gallery/density_flow-dark.png +0 -0
  38. rootfig-0.4.0/docs/images/gallery/density_flow-dune-dark.png +0 -0
  39. rootfig-0.4.0/docs/images/gallery/density_flow-dune.png +0 -0
  40. rootfig-0.4.0/docs/images/gallery/density_flow-lhcb-dark.png +0 -0
  41. rootfig-0.4.0/docs/images/gallery/density_flow-lhcb.png +0 -0
  42. rootfig-0.4.0/docs/images/gallery/density_flow.png +0 -0
  43. rootfig-0.4.0/docs/images/gallery/efficiency-alice-dark.png +0 -0
  44. rootfig-0.4.0/docs/images/gallery/efficiency-alice.png +0 -0
  45. rootfig-0.4.0/docs/images/gallery/efficiency-atlas-dark.png +0 -0
  46. rootfig-0.4.0/docs/images/gallery/efficiency-atlas.png +0 -0
  47. rootfig-0.4.0/docs/images/gallery/efficiency-cms-dark.png +0 -0
  48. rootfig-0.4.0/docs/images/gallery/efficiency-cms.png +0 -0
  49. rootfig-0.4.0/docs/images/gallery/efficiency-dark.png +0 -0
  50. rootfig-0.4.0/docs/images/gallery/efficiency-dune-dark.png +0 -0
  51. rootfig-0.4.0/docs/images/gallery/efficiency-dune.png +0 -0
  52. rootfig-0.4.0/docs/images/gallery/efficiency-lhcb-dark.png +0 -0
  53. rootfig-0.4.0/docs/images/gallery/efficiency-lhcb.png +0 -0
  54. rootfig-0.4.0/docs/images/gallery/expressions-alice-dark.png +0 -0
  55. rootfig-0.4.0/docs/images/gallery/expressions-alice.png +0 -0
  56. rootfig-0.4.0/docs/images/gallery/expressions-atlas-dark.png +0 -0
  57. rootfig-0.4.0/docs/images/gallery/expressions-atlas.png +0 -0
  58. rootfig-0.4.0/docs/images/gallery/expressions-cms-dark.png +0 -0
  59. rootfig-0.4.0/docs/images/gallery/expressions-cms.png +0 -0
  60. rootfig-0.4.0/docs/images/gallery/expressions-dark.png +0 -0
  61. rootfig-0.4.0/docs/images/gallery/expressions-dune-dark.png +0 -0
  62. rootfig-0.4.0/docs/images/gallery/expressions-dune.png +0 -0
  63. rootfig-0.4.0/docs/images/gallery/expressions-lhcb-dark.png +0 -0
  64. rootfig-0.4.0/docs/images/gallery/expressions-lhcb.png +0 -0
  65. rootfig-0.4.0/docs/images/gallery/expressions.png +0 -0
  66. rootfig-0.4.0/docs/images/gallery/fill_stats-alice-dark.png +0 -0
  67. rootfig-0.4.0/docs/images/gallery/fill_stats-alice.png +0 -0
  68. rootfig-0.4.0/docs/images/gallery/fill_stats-atlas-dark.png +0 -0
  69. rootfig-0.4.0/docs/images/gallery/fill_stats-atlas.png +0 -0
  70. rootfig-0.4.0/docs/images/gallery/fill_stats-cms-dark.png +0 -0
  71. rootfig-0.4.0/docs/images/gallery/fill_stats-cms.png +0 -0
  72. rootfig-0.4.0/docs/images/gallery/fill_stats-dark.png +0 -0
  73. rootfig-0.4.0/docs/images/gallery/fill_stats-dune-dark.png +0 -0
  74. rootfig-0.4.0/docs/images/gallery/fill_stats-dune.png +0 -0
  75. rootfig-0.4.0/docs/images/gallery/fill_stats-lhcb-dark.png +0 -0
  76. rootfig-0.4.0/docs/images/gallery/fill_stats-lhcb.png +0 -0
  77. rootfig-0.4.0/docs/images/gallery/fill_stats.png +0 -0
  78. rootfig-0.4.0/docs/images/gallery/hist2d-alice-dark.png +0 -0
  79. rootfig-0.4.0/docs/images/gallery/hist2d-alice.png +0 -0
  80. rootfig-0.4.0/docs/images/gallery/hist2d-atlas-dark.png +0 -0
  81. rootfig-0.4.0/docs/images/gallery/hist2d-atlas.png +0 -0
  82. rootfig-0.4.0/docs/images/gallery/hist2d-cms-dark.png +0 -0
  83. rootfig-0.4.0/docs/images/gallery/hist2d-cms.png +0 -0
  84. rootfig-0.4.0/docs/images/gallery/hist2d-dark.png +0 -0
  85. rootfig-0.4.0/docs/images/gallery/hist2d-dune-dark.png +0 -0
  86. rootfig-0.4.0/docs/images/gallery/hist2d-dune.png +0 -0
  87. rootfig-0.4.0/docs/images/gallery/hist2d-lhcb-dark.png +0 -0
  88. rootfig-0.4.0/docs/images/gallery/hist2d-lhcb.png +0 -0
  89. rootfig-0.4.0/docs/images/gallery/hist2d.png +0 -0
  90. rootfig-0.4.0/docs/images/gallery/log_axes-alice-dark.png +0 -0
  91. rootfig-0.4.0/docs/images/gallery/log_axes-alice.png +0 -0
  92. rootfig-0.4.0/docs/images/gallery/log_axes-atlas-dark.png +0 -0
  93. rootfig-0.4.0/docs/images/gallery/log_axes-atlas.png +0 -0
  94. rootfig-0.4.0/docs/images/gallery/log_axes-cms-dark.png +0 -0
  95. rootfig-0.4.0/docs/images/gallery/log_axes-cms.png +0 -0
  96. rootfig-0.4.0/docs/images/gallery/log_axes-dark.png +0 -0
  97. rootfig-0.4.0/docs/images/gallery/log_axes-dune-dark.png +0 -0
  98. rootfig-0.4.0/docs/images/gallery/log_axes-dune.png +0 -0
  99. rootfig-0.4.0/docs/images/gallery/log_axes-lhcb-dark.png +0 -0
  100. rootfig-0.4.0/docs/images/gallery/log_axes-lhcb.png +0 -0
  101. rootfig-0.4.0/docs/images/gallery/log_axes.png +0 -0
  102. rootfig-0.4.0/docs/images/gallery/luminosity-dark.png +0 -0
  103. rootfig-0.4.0/docs/images/gallery/luminosity.png +0 -0
  104. rootfig-0.4.0/docs/images/gallery/many_plots-dark.png +0 -0
  105. rootfig-0.4.0/docs/images/gallery/many_plots.png +0 -0
  106. rootfig-0.4.0/docs/images/gallery/object_vs_event-alice-dark.png +0 -0
  107. rootfig-0.4.0/docs/images/gallery/object_vs_event-alice.png +0 -0
  108. rootfig-0.4.0/docs/images/gallery/object_vs_event-atlas-dark.png +0 -0
  109. rootfig-0.4.0/docs/images/gallery/object_vs_event-atlas.png +0 -0
  110. rootfig-0.4.0/docs/images/gallery/object_vs_event-cms-dark.png +0 -0
  111. rootfig-0.4.0/docs/images/gallery/object_vs_event-cms.png +0 -0
  112. rootfig-0.4.0/docs/images/gallery/object_vs_event-dark.png +0 -0
  113. rootfig-0.4.0/docs/images/gallery/object_vs_event-dune-dark.png +0 -0
  114. rootfig-0.4.0/docs/images/gallery/object_vs_event-dune.png +0 -0
  115. rootfig-0.4.0/docs/images/gallery/object_vs_event-lhcb-dark.png +0 -0
  116. rootfig-0.4.0/docs/images/gallery/object_vs_event-lhcb.png +0 -0
  117. rootfig-0.4.0/docs/images/gallery/object_vs_event.png +0 -0
  118. rootfig-0.4.0/docs/images/gallery/overlay_ratio-alice-dark.png +0 -0
  119. rootfig-0.4.0/docs/images/gallery/overlay_ratio-alice.png +0 -0
  120. rootfig-0.4.0/docs/images/gallery/overlay_ratio-atlas-dark.png +0 -0
  121. rootfig-0.4.0/docs/images/gallery/overlay_ratio-atlas.png +0 -0
  122. rootfig-0.4.0/docs/images/gallery/overlay_ratio-cms-dark.png +0 -0
  123. rootfig-0.4.0/docs/images/gallery/overlay_ratio-cms.png +0 -0
  124. rootfig-0.4.0/docs/images/gallery/overlay_ratio-dark.png +0 -0
  125. rootfig-0.4.0/docs/images/gallery/overlay_ratio-dune-dark.png +0 -0
  126. rootfig-0.4.0/docs/images/gallery/overlay_ratio-dune.png +0 -0
  127. rootfig-0.4.0/docs/images/gallery/overlay_ratio-lhcb-dark.png +0 -0
  128. rootfig-0.4.0/docs/images/gallery/overlay_ratio-lhcb.png +0 -0
  129. rootfig-0.4.0/docs/images/gallery/overlay_ratio.png +0 -0
  130. rootfig-0.4.0/docs/images/gallery/profile-alice-dark.png +0 -0
  131. rootfig-0.4.0/docs/images/gallery/profile-alice.png +0 -0
  132. rootfig-0.4.0/docs/images/gallery/profile-atlas-dark.png +0 -0
  133. rootfig-0.4.0/docs/images/gallery/profile-atlas.png +0 -0
  134. rootfig-0.4.0/docs/images/gallery/profile-cms-dark.png +0 -0
  135. rootfig-0.4.0/docs/images/gallery/profile-cms.png +0 -0
  136. rootfig-0.4.0/docs/images/gallery/profile-dark.png +0 -0
  137. rootfig-0.4.0/docs/images/gallery/profile-dune-dark.png +0 -0
  138. rootfig-0.4.0/docs/images/gallery/profile-dune.png +0 -0
  139. rootfig-0.4.0/docs/images/gallery/profile-lhcb-dark.png +0 -0
  140. rootfig-0.4.0/docs/images/gallery/profile-lhcb.png +0 -0
  141. rootfig-0.4.0/docs/images/gallery/quick-alice-dark.png +0 -0
  142. rootfig-0.4.0/docs/images/gallery/quick-alice.png +0 -0
  143. rootfig-0.4.0/docs/images/gallery/quick-atlas-dark.png +0 -0
  144. rootfig-0.4.0/docs/images/gallery/quick-atlas.png +0 -0
  145. rootfig-0.4.0/docs/images/gallery/quick-cms-dark.png +0 -0
  146. rootfig-0.4.0/docs/images/gallery/quick-cms.png +0 -0
  147. rootfig-0.4.0/docs/images/gallery/quick-dark.png +0 -0
  148. rootfig-0.4.0/docs/images/gallery/quick-dune-dark.png +0 -0
  149. rootfig-0.4.0/docs/images/gallery/quick-dune.png +0 -0
  150. rootfig-0.4.0/docs/images/gallery/quick-lhcb-dark.png +0 -0
  151. rootfig-0.4.0/docs/images/gallery/quick-lhcb.png +0 -0
  152. rootfig-0.4.0/docs/images/gallery/quick.png +0 -0
  153. rootfig-0.4.0/docs/images/gallery/ratio_reference-alice-dark.png +0 -0
  154. rootfig-0.4.0/docs/images/gallery/ratio_reference-alice.png +0 -0
  155. rootfig-0.4.0/docs/images/gallery/ratio_reference-atlas-dark.png +0 -0
  156. rootfig-0.4.0/docs/images/gallery/ratio_reference-atlas.png +0 -0
  157. rootfig-0.4.0/docs/images/gallery/ratio_reference-cms-dark.png +0 -0
  158. rootfig-0.4.0/docs/images/gallery/ratio_reference-cms.png +0 -0
  159. rootfig-0.4.0/docs/images/gallery/ratio_reference-dark.png +0 -0
  160. rootfig-0.4.0/docs/images/gallery/ratio_reference-dune-dark.png +0 -0
  161. rootfig-0.4.0/docs/images/gallery/ratio_reference-dune.png +0 -0
  162. rootfig-0.4.0/docs/images/gallery/ratio_reference-lhcb-dark.png +0 -0
  163. rootfig-0.4.0/docs/images/gallery/ratio_reference-lhcb.png +0 -0
  164. rootfig-0.4.0/docs/images/gallery/ratio_reference.png +0 -0
  165. rootfig-0.4.0/docs/images/gallery/robust_range-dark.png +0 -0
  166. rootfig-0.4.0/docs/images/gallery/robust_range.png +0 -0
  167. rootfig-0.4.0/docs/images/gallery/stack_data-alice-dark.png +0 -0
  168. rootfig-0.4.0/docs/images/gallery/stack_data-alice.png +0 -0
  169. rootfig-0.4.0/docs/images/gallery/stack_data-atlas-dark.png +0 -0
  170. rootfig-0.4.0/docs/images/gallery/stack_data-atlas.png +0 -0
  171. rootfig-0.4.0/docs/images/gallery/stack_data-cms-dark.png +0 -0
  172. rootfig-0.4.0/docs/images/gallery/stack_data-cms.png +0 -0
  173. rootfig-0.4.0/docs/images/gallery/stack_data-dark.png +0 -0
  174. rootfig-0.4.0/docs/images/gallery/stack_data-dune-dark.png +0 -0
  175. rootfig-0.4.0/docs/images/gallery/stack_data-dune.png +0 -0
  176. rootfig-0.4.0/docs/images/gallery/stack_data-lhcb-dark.png +0 -0
  177. rootfig-0.4.0/docs/images/gallery/stack_data-lhcb.png +0 -0
  178. rootfig-0.4.0/docs/images/gallery/stack_data.png +0 -0
  179. rootfig-0.4.0/docs/images/gallery/style_colors-dark.png +0 -0
  180. rootfig-0.4.0/docs/images/gallery/style_colors.png +0 -0
  181. rootfig-0.4.0/docs/images/gallery/systematics-alice-dark.png +0 -0
  182. rootfig-0.4.0/docs/images/gallery/systematics-alice.png +0 -0
  183. rootfig-0.4.0/docs/images/gallery/systematics-atlas-dark.png +0 -0
  184. rootfig-0.4.0/docs/images/gallery/systematics-atlas.png +0 -0
  185. rootfig-0.4.0/docs/images/gallery/systematics-cms-dark.png +0 -0
  186. rootfig-0.4.0/docs/images/gallery/systematics-cms.png +0 -0
  187. rootfig-0.4.0/docs/images/gallery/systematics-dark.png +0 -0
  188. rootfig-0.4.0/docs/images/gallery/systematics-dune-dark.png +0 -0
  189. rootfig-0.4.0/docs/images/gallery/systematics-dune.png +0 -0
  190. rootfig-0.4.0/docs/images/gallery/systematics-lhcb-dark.png +0 -0
  191. rootfig-0.4.0/docs/images/gallery/systematics-lhcb.png +0 -0
  192. rootfig-0.4.0/docs/images/gallery/systematics.png +0 -0
  193. rootfig-0.4.0/docs/images/gallery/variable_bins-alice-dark.png +0 -0
  194. rootfig-0.4.0/docs/images/gallery/variable_bins-alice.png +0 -0
  195. rootfig-0.4.0/docs/images/gallery/variable_bins-atlas-dark.png +0 -0
  196. rootfig-0.4.0/docs/images/gallery/variable_bins-atlas.png +0 -0
  197. rootfig-0.4.0/docs/images/gallery/variable_bins-cms-dark.png +0 -0
  198. rootfig-0.4.0/docs/images/gallery/variable_bins-cms.png +0 -0
  199. rootfig-0.4.0/docs/images/gallery/variable_bins-dark.png +0 -0
  200. rootfig-0.4.0/docs/images/gallery/variable_bins-dune-dark.png +0 -0
  201. rootfig-0.4.0/docs/images/gallery/variable_bins-dune.png +0 -0
  202. rootfig-0.4.0/docs/images/gallery/variable_bins-lhcb-dark.png +0 -0
  203. rootfig-0.4.0/docs/images/gallery/variable_bins-lhcb.png +0 -0
  204. rootfig-0.4.0/docs/images/gallery/variable_bins.png +0 -0
  205. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-alice-dark.png +0 -0
  206. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-alice.png +0 -0
  207. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-atlas-dark.png +0 -0
  208. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-atlas.png +0 -0
  209. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-cms-dark.png +0 -0
  210. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-cms.png +0 -0
  211. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-dark.png +0 -0
  212. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-dune-dark.png +0 -0
  213. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-dune.png +0 -0
  214. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-lhcb-dark.png +0 -0
  215. rootfig-0.4.0/docs/images/gallery/xbreak_ratio-lhcb.png +0 -0
  216. rootfig-0.4.0/docs/images/gallery/xbreak_ratio.png +0 -0
  217. {rootfig-0.2.2 → rootfig-0.4.0}/docs/index.md +4 -2
  218. rootfig-0.4.0/docs/plotting.md +452 -0
  219. {rootfig-0.2.2 → rootfig-0.4.0}/docs/quickstart.md +5 -0
  220. rootfig-0.4.0/docs/stylesheets/gallery.css +58 -0
  221. {rootfig-0.2.2 → rootfig-0.4.0}/examples/gallery/__init__.py +300 -187
  222. {rootfig-0.2.2 → rootfig-0.4.0}/examples/gallery/__main__.py +8 -4
  223. {rootfig-0.2.2 → rootfig-0.4.0}/examples/gallery/data.py +12 -2
  224. {rootfig-0.2.2 → rootfig-0.4.0}/examples/gallery/registry.py +59 -11
  225. {rootfig-0.2.2 → rootfig-0.4.0}/mkdocs.yml +17 -1
  226. {rootfig-0.2.2 → rootfig-0.4.0}/pyproject.toml +2 -1
  227. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/__init__.py +9 -3
  228. rootfig-0.4.0/src/rootfig/_mapping.py +43 -0
  229. rootfig-0.4.0/src/rootfig/api/__init__.py +28 -0
  230. rootfig-0.4.0/src/rootfig/api/_common.py +59 -0
  231. rootfig-0.4.0/src/rootfig/api/data.py +186 -0
  232. rootfig-0.4.0/src/rootfig/api/measures.py +302 -0
  233. rootfig-0.4.0/src/rootfig/api/plots1d.py +610 -0
  234. rootfig-0.4.0/src/rootfig/api/plots2d.py +208 -0
  235. rootfig-0.4.0/src/rootfig/api/tables.py +135 -0
  236. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/errors.py +4 -0
  237. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/histograms/__init__.py +4 -0
  238. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/histograms/build.py +125 -8
  239. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/histograms/normalize.py +27 -3
  240. rootfig-0.4.0/src/rootfig/histograms/pipeline.py +476 -0
  241. rootfig-0.4.0/src/rootfig/histograms/ratio.py +241 -0
  242. rootfig-0.4.0/src/rootfig/histograms/systematics.py +175 -0
  243. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/io/sources.py +4 -0
  244. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/model/__init__.py +20 -1
  245. rootfig-0.4.0/src/rootfig/model/binning.py +465 -0
  246. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/model/samples.py +42 -3
  247. rootfig-0.4.0/src/rootfig/model/systematics.py +254 -0
  248. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/model/variables.py +8 -5
  249. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/__init__.py +8 -1
  250. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/annotations.py +2 -2
  251. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/correlation.py +14 -1
  252. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/figure.py +10 -4
  253. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/hist1d.py +118 -70
  254. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/ratio.py +73 -30
  255. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/result.py +52 -2
  256. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/style.py +289 -58
  257. {rootfig-0.2.2 → rootfig-0.4.0}/tests/test_api.py +546 -2
  258. rootfig-0.4.0/tests/test_gallery.py +266 -0
  259. {rootfig-0.2.2 → rootfig-0.4.0}/tests/test_histograms.py +536 -2
  260. {rootfig-0.2.2 → rootfig-0.4.0}/tests/test_model.py +373 -6
  261. {rootfig-0.2.2 → rootfig-0.4.0}/tests/test_plotting.py +118 -7
  262. rootfig-0.4.0/tests/type_checks/systematics.py +20 -0
  263. rootfig-0.2.2/docs/gallery.md +0 -74
  264. rootfig-0.2.2/docs/hooks/gallery.py +0 -98
  265. rootfig-0.2.2/docs/images/gallery/arrays.png +0 -0
  266. rootfig-0.2.2/docs/images/gallery/cms_density.png +0 -0
  267. rootfig-0.2.2/docs/images/gallery/expressions.png +0 -0
  268. rootfig-0.2.2/docs/images/gallery/fill_stats.png +0 -0
  269. rootfig-0.2.2/docs/images/gallery/hist2d.png +0 -0
  270. rootfig-0.2.2/docs/images/gallery/log_axes.png +0 -0
  271. rootfig-0.2.2/docs/images/gallery/luminosity.png +0 -0
  272. rootfig-0.2.2/docs/images/gallery/many_plots.png +0 -0
  273. rootfig-0.2.2/docs/images/gallery/object_vs_event.png +0 -0
  274. rootfig-0.2.2/docs/images/gallery/overlay_ratio.png +0 -0
  275. rootfig-0.2.2/docs/images/gallery/quick.png +0 -0
  276. rootfig-0.2.2/docs/images/gallery/ratio_reference.png +0 -0
  277. rootfig-0.2.2/docs/images/gallery/robust_range.png +0 -0
  278. rootfig-0.2.2/docs/images/gallery/stack_data.png +0 -0
  279. rootfig-0.2.2/docs/images/gallery/style_colors.png +0 -0
  280. rootfig-0.2.2/docs/images/gallery/variable_bins.png +0 -0
  281. rootfig-0.2.2/docs/images/gallery/xbreak_ratio.png +0 -0
  282. rootfig-0.2.2/docs/plotting.md +0 -231
  283. rootfig-0.2.2/src/rootfig/api.py +0 -1339
  284. rootfig-0.2.2/src/rootfig/histograms/pipeline.py +0 -228
  285. rootfig-0.2.2/src/rootfig/histograms/ratio.py +0 -161
  286. rootfig-0.2.2/src/rootfig/model/binning.py +0 -242
  287. rootfig-0.2.2/tests/test_gallery.py +0 -173
  288. {rootfig-0.2.2 → rootfig-0.4.0}/.gitignore +0 -0
  289. {rootfig-0.2.2 → rootfig-0.4.0}/LICENSE +0 -0
  290. {rootfig-0.2.2 → rootfig-0.4.0}/docs/ecosystem.md +0 -0
  291. {rootfig-0.2.2 → rootfig-0.4.0}/docs/expressions.md +0 -0
  292. {rootfig-0.2.2 → rootfig-0.4.0}/docs/images/gallery/correlation.png +0 -0
  293. {rootfig-0.2.2 → rootfig-0.4.0}/docs/images/gallery/efficiency.png +0 -0
  294. {rootfig-0.2.2 → rootfig-0.4.0}/docs/images/gallery/profile.png +0 -0
  295. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/_typing.py +0 -0
  296. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/expressions/__init__.py +0 -0
  297. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/expressions/functions.py +0 -0
  298. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/expressions/parser.py +0 -0
  299. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/histograms/cutflow.py +0 -0
  300. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/histograms/efficiency.py +0 -0
  301. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/histograms/stats.py +0 -0
  302. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/io/__init__.py +0 -0
  303. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/model/cuts.py +0 -0
  304. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/model/style.py +0 -0
  305. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/model/units.py +0 -0
  306. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/hist2d.py +0 -0
  307. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/plotting/points.py +0 -0
  308. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/py.typed +0 -0
  309. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/selection/__init__.py +0 -0
  310. {rootfig-0.2.2 → rootfig-0.4.0}/src/rootfig/selection/columns.py +0 -0
  311. {rootfig-0.2.2 → rootfig-0.4.0}/tests/conftest.py +0 -0
  312. {rootfig-0.2.2 → rootfig-0.4.0}/tests/data/split_collection.root +0 -0
  313. {rootfig-0.2.2 → rootfig-0.4.0}/tests/test_expressions.py +0 -0
  314. {rootfig-0.2.2 → rootfig-0.4.0}/tests/test_io.py +0 -0
  315. {rootfig-0.2.2 → rootfig-0.4.0}/tests/test_selection.py +0 -0
  316. {rootfig-0.2.2 → rootfig-0.4.0}/tests/test_tutorials.py +0 -0
@@ -36,7 +36,7 @@ tests that require ROOT or network access.
36
36
 
37
37
  ```
38
38
  src/rootfig/
39
- api.py plot(), histogram(), load(), ... (orchestration only)
39
+ api/ plot(), histogram(), load(), ... (orchestration only)
40
40
  errors.py exception hierarchy
41
41
  expressions/ parse, validate and evaluate expression strings
42
42
  io/ file and in-memory data sources
@@ -90,32 +90,43 @@ f.Close()
90
90
  ## Figures and the gallery
91
91
 
92
92
  The `examples/gallery` package is both the showcase and the image-regression
93
- suite: `__init__.py` holds the shared `define()` block and the examples, `data.py`
94
- writes the toy files and `registry.py` extracts the source shown in the docs. Each
95
- example is a small function returning a `Plot`; `docs/gallery.md` shows every
96
- figure next to that function's source (a MkDocs hook, `docs/hooks/gallery.py`),
97
- and `tests/test_gallery.py` renders all of them and, with `--mpl`, compares
93
+ suite: `__init__.py` holds the shared `define()` block, the `STYLES` and the
94
+ examples, `data.py` writes the toy files and `registry.py` extracts the source
95
+ shown in the docs. Each example is a small function returning a `Plot`. The
96
+ MkDocs hook `docs/hooks/gallery.py` turns them into the gallery: an overview
97
+ (`docs/gallery/index.md`, a card per example, section by section) and a
98
+ generated page per example with its figure and complete code, one tab per
99
+ style. `tests/test_gallery.py` renders all of them and, with `--mpl`, compares
98
100
  them pixel-wise (pytest-mpl, RMS tolerance 2) against `docs/images/gallery/`.
99
- Those PNGs are therefore the documentation images *and* the baselines.
101
+ An example whose function takes a `style` is rendered in every entry of
102
+ `STYLES` (the neutral default, ATLAS, CMS, LHCb, ALICE, DUNE) as
103
+ `<name>-<style>.png`, `<name>.png` for the default; every rendering is made
104
+ twice, as shown and inside `rf.dark_theme()` (`-dark`), and the docs pick one
105
+ per palette. Those PNGs are therefore the documentation images *and* the
106
+ baselines. The experiment styles are drawn only when images are compared or
107
+ generated, and `-n auto` runs that on every core.
100
108
 
101
109
  ```bash
102
- MPLBACKEND=Agg uv run python examples/gallery # look at examples/out/*.png
103
- uv run pytest tests/test_gallery.py --mpl # compare against the baselines
104
- uv run pytest tests/test_gallery.py --mpl-generate-path=docs/images/gallery # accept changes
110
+ MPLBACKEND=Agg uv run python examples/gallery # look at examples/out/*.png
111
+ MPLBACKEND=Agg uv run python examples/gallery --style CMS # ... in another style
112
+ uv run pytest tests/test_gallery.py --mpl -n auto # compare against the baselines
113
+ uv run pytest tests/test_gallery.py -n auto --mpl-generate-path=docs/images/gallery # accept changes
105
114
  ```
106
115
 
107
116
  After any visual change: regenerate the baselines, open the PNGs and check
108
117
  them by eye, and commit them with the code. CI compares on Linux only (fonts
109
118
  differ elsewhere) and, when a comparison fails, uploads an HTML report with
110
119
  baseline, result and difference images as the `mpl-results-*` artifact. To add
111
- an example, register a function with `@example(name, title)` and give it a
112
- docstring; the test suite fails until its baseline image exists. Its parameters
113
- are attribute names of `Dataset`, it runs inside the directory holding the toy
114
- files (so name them `"signal.root"`, never through a variable), and the hook
115
- prints only the body (blank lines and comments included) — write it as a user
116
- would. Put an object into `define()` — the *Setup* block of the docs page — only
117
- when several examples use it; anything a single example needs belongs in that
118
- example.
120
+ an example, register a function with `@example(name, title, section=...)` and
121
+ give it a docstring; the test suite fails until its baseline images exist. Its
122
+ parameters are attribute names of `Dataset`, plus `style` when the figure should
123
+ be shown in every style (pass it on as `style=style`; leave it out when a style
124
+ is the point of the example or the figure goes into axes of your own). It runs
125
+ inside the directory holding the toy files (so name them `"signal.root"`, never
126
+ through a variable), and the hook prints only the body (blank lines and
127
+ comments included) — write it as a user would. Put an object into `define()` —
128
+ the *Setup* block of the example pages — only when several examples use it;
129
+ anything a single example needs belongs in that example.
119
130
 
120
131
  ## Pull requests
121
132
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: rootfig
3
- Version: 0.2.2
3
+ Version: 0.4.0
4
4
  Summary: Publication-quality figures straight from ROOT trees, without ROOT: uproot + Awkward + hist + mplhep with a TTree::Draw-like API.
5
5
  Project-URL: Homepage, https://github.com/jbeirer/rootfig
6
6
  Project-URL: Documentation, https://jbeirer.github.io/rootfig/
@@ -31,22 +31,35 @@ Requires-Dist: numpy>=1.26
31
31
  Requires-Dist: uproot>=5.7.4
32
32
  Description-Content-Type: text/markdown
33
33
 
34
- # rootfig
34
+ <p align="center">
35
+ <picture>
36
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jbeirer/rootfig/main/.github/assets/rootfig-logo-dark.svg">
37
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/jbeirer/rootfig/main/.github/assets/rootfig-logo-light.svg">
38
+ <img src="https://raw.githubusercontent.com/jbeirer/rootfig/main/.github/assets/rootfig-logo-light.svg" alt="rootfig" width="560">
39
+ </picture>
40
+ </p>
35
41
 
36
- **Publication-quality figures straight from ROOT trees, without ROOT.**
42
+ <p align="center">
43
+ <strong>Publication-quality figures straight from ROOT trees, without ROOT.</strong>
44
+ </p>
37
45
 
38
- [![Docs](https://img.shields.io/badge/docs-online-blue)](https://jbeirer.github.io/rootfig/)
39
- [![CI](https://github.com/jbeirer/rootfig/actions/workflows/ci.yml/badge.svg)](https://github.com/jbeirer/rootfig/actions/workflows/ci.yml)
40
- [![codecov](https://codecov.io/gh/jbeirer/rootfig/branch/main/graph/badge.svg)](https://codecov.io/gh/jbeirer/rootfig)
41
- [![PyPI](https://img.shields.io/pypi/v/rootfig.svg)](https://pypi.org/project/rootfig/)
42
- [![Python](https://img.shields.io/pypi/pyversions/rootfig.svg)](https://pypi.org/project/rootfig/)
43
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
46
+ <p align="center">
47
+ <a href="https://jbeirer.github.io/rootfig/">Documentation</a> ·
48
+ <a href="https://jbeirer.github.io/rootfig/gallery/">Gallery</a> ·
49
+ <a href="https://jbeirer.github.io/rootfig/quickstart/">Quick start</a>
50
+ </p>
44
51
 
45
- **[Documentation](https://jbeirer.github.io/rootfig/) ·
46
- [Gallery](https://jbeirer.github.io/rootfig/gallery/) ·
47
- [Quick start](https://jbeirer.github.io/rootfig/quickstart/)**
52
+ <p align="center">
53
+ <a href="https://jbeirer.github.io/rootfig/"><img src="https://img.shields.io/badge/docs-online-blue" alt="Documentation"></a>
54
+ <a href="https://doi.org/10.5281/zenodo.22726311"><img src="https://zenodo.org/badge/1366702602.svg" alt="DOI"></a>
55
+ <a href="https://github.com/jbeirer/rootfig/actions/workflows/ci.yml"><img src="https://github.com/jbeirer/rootfig/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
56
+ <a href="https://codecov.io/gh/jbeirer/rootfig"><img src="https://codecov.io/gh/jbeirer/rootfig/branch/main/graph/badge.svg" alt="codecov"></a>
57
+ <a href="https://pypi.org/project/rootfig/"><img src="https://img.shields.io/pypi/v/rootfig.svg" alt="PyPI"></a>
58
+ <a href="https://pypi.org/project/rootfig/"><img src="https://img.shields.io/pypi/pyversions/rootfig.svg" alt="Python"></a>
59
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
60
+ </p>
48
61
 
49
- Go from ROOT files to a styled figure in one call. Choose a variable, add a
62
+ Go from a ROOT file to a styled figure in one call. Choose a variable, add a
50
63
  selection, and plot:
51
64
 
52
65
  ```python
@@ -57,20 +70,23 @@ rf.plot("events.root", "Muon_pt", tree="events", selection="Muon_pt > 20", bins=
57
70
 
58
71
  Start with a single distribution; add samples, weights, stacks and ratio
59
72
  panels as your analysis grows. Every plot gives you a matplotlib figure to
60
- customise and save. No ROOT installation required.
73
+ customise and save.
61
74
 
62
75
  <p align="center">
63
- <a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/stack_data.png" alt="Stacked simulation with data and a ratio panel" width="48%"></a>
64
- <a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/xbreak_ratio.png" alt="Broken x axis with a ratio panel" width="48%"></a>
76
+ <a href="https://jbeirer.github.io/rootfig/gallery/log_axes/"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/gallery/log_axes-dark.png"><img src="docs/images/gallery/log_axes.png" alt="Logarithmic axes with log-spaced bins" width="46%"></picture></a>
77
+ &nbsp;&nbsp;
78
+ <a href="https://jbeirer.github.io/rootfig/gallery/hist2d/"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/gallery/hist2d-dark.png"><img src="docs/images/gallery/hist2d.png" alt="Two-dimensional histogram" width="46%"></picture></a>
65
79
  </p>
66
80
  <p align="center">
67
- <a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/object_vs_event.png" alt="Per-object versus per-event selections" width="48%"></a>
68
- <a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/hist2d.png" alt="Two-dimensional histogram" width="48%"></a>
81
+ <a href="https://jbeirer.github.io/rootfig/gallery/xbreak_ratio/#atlas"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/gallery/xbreak_ratio-atlas-dark.png"><img src="docs/images/gallery/xbreak_ratio-atlas.png" alt="Broken x axis with a ratio panel" width="46%"></picture></a>
82
+ &nbsp;&nbsp;
83
+ <a href="https://jbeirer.github.io/rootfig/gallery/luminosity/"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/gallery/luminosity-dark.png"><img src="docs/images/gallery/luminosity.png" alt="FCC-ee stack scaled to luminosity with a significance panel" width="43%"></picture></a>
69
84
  </p>
70
85
 
71
86
  **[Explore the gallery →](https://jbeirer.github.io/rootfig/gallery/)**
72
87
  See each figure alongside the code that makes it, from simple overlays to
73
- stacked data/MC comparisons, broken axes and 2D histograms.
88
+ stacked data/MC comparisons, broken axes and 2D histograms, in the neutral
89
+ style or in that of ATLAS, CMS, LHCb, ALICE or DUNE.
74
90
 
75
91
  ## Installation
76
92
 
@@ -88,16 +104,16 @@ files are both supported.
88
104
  ```python
89
105
  import rootfig as rf
90
106
 
91
- # Overlay two samples, normalised to unity, with a ratio panel.
107
+ # Overlay two samples, each normalised to unity, with a Signal / Background panel.
92
108
  rf.plot(
93
- ["signal.root", "background.root"],
109
+ {"Signal": "signal.root", "Background": "background.root"},
94
110
  "Muon_pt",
95
111
  tree="events",
96
112
  selection="abs(Muon_eta) < 2.5",
97
113
  weight="event_weight",
98
114
  bins=(50, 0, 200),
99
115
  normalize=True,
100
- ratio=True,
116
+ ratio="Background",
101
117
  )
102
118
  ```
103
119
 
@@ -140,8 +156,14 @@ matplotlib `Figure`/`Axes`, `p.hists` are `hist.Hist` objects, and
140
156
  `count(Jet_pt) >= 2` or `Muon_pt > 20`; event and object selections have
141
157
  explicit rules, and event weights carry through to each selected object.
142
158
  - **Compare samples with a few keywords.** Overlays, stacks, data points and
143
- ratio panels share binning and propagate histogram uncertainties.
144
- Normalise to unity, density, bin width or luminosity.
159
+ ratio panels share binning and propagate histogram uncertainties; bin edges
160
+ and `(n, low, high)` are used as given, while a range inferred from the data
161
+ ignores far outliers, so `-999` sentinels do not set the axis. Normalise to
162
+ unity, density, bin width or luminosity.
163
+ - **Show systematic uncertainties.** Attach weight, branch, file or
164
+ normalisation variations to a sample; stacks and ratio panels draw the
165
+ combined statistical and systematic band, and every component stays
166
+ accessible.
145
167
  - **Style figures for your analysis.** Add experiment labels, units, log axes
146
168
  and broken axes, then refine the result with matplotlib.
147
169
  - **Go beyond 1D plots.** Draw 2D histograms, correlations, efficiencies,
@@ -172,7 +194,7 @@ stack, building on familiar libraries:
172
194
  | --- | --- | --- |
173
195
  | Reading ROOT files | [uproot](https://github.com/scikit-hep/uproot5) | file globs, tree auto-detection, reading only the required branches |
174
196
  | Jagged arrays | [Awkward Array](https://github.com/scikit-hep/awkward) | the per-event/per-object rules for cuts and weights |
175
- | Histograms | [hist](https://github.com/scikit-hep/hist) / boost-histogram | shared binning, automatic ranges, normalisation, ratios |
197
+ | Histograms | [hist](https://github.com/scikit-hep/hist) / boost-histogram | shared binning, robust automatic ranges, normalisation, ratios |
176
198
  | Drawing | [mplhep](https://github.com/scikit-hep/mplhep) + matplotlib | overlays, stacks, ratio panels, labels and legends with good defaults |
177
199
 
178
200
  If you already have `hist.Hist` objects, `rf.plot_histograms` draws them with
@@ -192,6 +214,21 @@ uv run mypy
192
214
 
193
215
  See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
194
216
 
217
+ ## Citation
218
+
219
+ If `rootfig` is useful in your research, please cite it:
220
+
221
+ ```bibtex
222
+ @software{rootfig,
223
+ author = {Beirer, Joshua Falco},
224
+ doi = {10.5281/zenodo.22726311},
225
+ license = {MIT},
226
+ title = {{rootfig}},
227
+ url = {https://github.com/jbeirer/rootfig},
228
+ year = {2026}
229
+ }
230
+ ```
231
+
195
232
  ## License
196
233
 
197
234
  MIT. See [LICENSE](LICENSE).
@@ -1,19 +1,32 @@
1
- # rootfig
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jbeirer/rootfig/main/.github/assets/rootfig-logo-dark.svg">
4
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/jbeirer/rootfig/main/.github/assets/rootfig-logo-light.svg">
5
+ <img src="https://raw.githubusercontent.com/jbeirer/rootfig/main/.github/assets/rootfig-logo-light.svg" alt="rootfig" width="560">
6
+ </picture>
7
+ </p>
2
8
 
3
- **Publication-quality figures straight from ROOT trees, without ROOT.**
9
+ <p align="center">
10
+ <strong>Publication-quality figures straight from ROOT trees, without ROOT.</strong>
11
+ </p>
4
12
 
5
- [![Docs](https://img.shields.io/badge/docs-online-blue)](https://jbeirer.github.io/rootfig/)
6
- [![CI](https://github.com/jbeirer/rootfig/actions/workflows/ci.yml/badge.svg)](https://github.com/jbeirer/rootfig/actions/workflows/ci.yml)
7
- [![codecov](https://codecov.io/gh/jbeirer/rootfig/branch/main/graph/badge.svg)](https://codecov.io/gh/jbeirer/rootfig)
8
- [![PyPI](https://img.shields.io/pypi/v/rootfig.svg)](https://pypi.org/project/rootfig/)
9
- [![Python](https://img.shields.io/pypi/pyversions/rootfig.svg)](https://pypi.org/project/rootfig/)
10
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
13
+ <p align="center">
14
+ <a href="https://jbeirer.github.io/rootfig/">Documentation</a> ·
15
+ <a href="https://jbeirer.github.io/rootfig/gallery/">Gallery</a> ·
16
+ <a href="https://jbeirer.github.io/rootfig/quickstart/">Quick start</a>
17
+ </p>
11
18
 
12
- **[Documentation](https://jbeirer.github.io/rootfig/) ·
13
- [Gallery](https://jbeirer.github.io/rootfig/gallery/) ·
14
- [Quick start](https://jbeirer.github.io/rootfig/quickstart/)**
19
+ <p align="center">
20
+ <a href="https://jbeirer.github.io/rootfig/"><img src="https://img.shields.io/badge/docs-online-blue" alt="Documentation"></a>
21
+ <a href="https://doi.org/10.5281/zenodo.22726311"><img src="https://zenodo.org/badge/1366702602.svg" alt="DOI"></a>
22
+ <a href="https://github.com/jbeirer/rootfig/actions/workflows/ci.yml"><img src="https://github.com/jbeirer/rootfig/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
23
+ <a href="https://codecov.io/gh/jbeirer/rootfig"><img src="https://codecov.io/gh/jbeirer/rootfig/branch/main/graph/badge.svg" alt="codecov"></a>
24
+ <a href="https://pypi.org/project/rootfig/"><img src="https://img.shields.io/pypi/v/rootfig.svg" alt="PyPI"></a>
25
+ <a href="https://pypi.org/project/rootfig/"><img src="https://img.shields.io/pypi/pyversions/rootfig.svg" alt="Python"></a>
26
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
27
+ </p>
15
28
 
16
- Go from ROOT files to a styled figure in one call. Choose a variable, add a
29
+ Go from a ROOT file to a styled figure in one call. Choose a variable, add a
17
30
  selection, and plot:
18
31
 
19
32
  ```python
@@ -24,20 +37,23 @@ rf.plot("events.root", "Muon_pt", tree="events", selection="Muon_pt > 20", bins=
24
37
 
25
38
  Start with a single distribution; add samples, weights, stacks and ratio
26
39
  panels as your analysis grows. Every plot gives you a matplotlib figure to
27
- customise and save. No ROOT installation required.
40
+ customise and save.
28
41
 
29
42
  <p align="center">
30
- <a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/stack_data.png" alt="Stacked simulation with data and a ratio panel" width="48%"></a>
31
- <a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/xbreak_ratio.png" alt="Broken x axis with a ratio panel" width="48%"></a>
43
+ <a href="https://jbeirer.github.io/rootfig/gallery/log_axes/"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/gallery/log_axes-dark.png"><img src="docs/images/gallery/log_axes.png" alt="Logarithmic axes with log-spaced bins" width="46%"></picture></a>
44
+ &nbsp;&nbsp;
45
+ <a href="https://jbeirer.github.io/rootfig/gallery/hist2d/"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/gallery/hist2d-dark.png"><img src="docs/images/gallery/hist2d.png" alt="Two-dimensional histogram" width="46%"></picture></a>
32
46
  </p>
33
47
  <p align="center">
34
- <a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/object_vs_event.png" alt="Per-object versus per-event selections" width="48%"></a>
35
- <a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/hist2d.png" alt="Two-dimensional histogram" width="48%"></a>
48
+ <a href="https://jbeirer.github.io/rootfig/gallery/xbreak_ratio/#atlas"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/gallery/xbreak_ratio-atlas-dark.png"><img src="docs/images/gallery/xbreak_ratio-atlas.png" alt="Broken x axis with a ratio panel" width="46%"></picture></a>
49
+ &nbsp;&nbsp;
50
+ <a href="https://jbeirer.github.io/rootfig/gallery/luminosity/"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/gallery/luminosity-dark.png"><img src="docs/images/gallery/luminosity.png" alt="FCC-ee stack scaled to luminosity with a significance panel" width="43%"></picture></a>
36
51
  </p>
37
52
 
38
53
  **[Explore the gallery →](https://jbeirer.github.io/rootfig/gallery/)**
39
54
  See each figure alongside the code that makes it, from simple overlays to
40
- stacked data/MC comparisons, broken axes and 2D histograms.
55
+ stacked data/MC comparisons, broken axes and 2D histograms, in the neutral
56
+ style or in that of ATLAS, CMS, LHCb, ALICE or DUNE.
41
57
 
42
58
  ## Installation
43
59
 
@@ -55,16 +71,16 @@ files are both supported.
55
71
  ```python
56
72
  import rootfig as rf
57
73
 
58
- # Overlay two samples, normalised to unity, with a ratio panel.
74
+ # Overlay two samples, each normalised to unity, with a Signal / Background panel.
59
75
  rf.plot(
60
- ["signal.root", "background.root"],
76
+ {"Signal": "signal.root", "Background": "background.root"},
61
77
  "Muon_pt",
62
78
  tree="events",
63
79
  selection="abs(Muon_eta) < 2.5",
64
80
  weight="event_weight",
65
81
  bins=(50, 0, 200),
66
82
  normalize=True,
67
- ratio=True,
83
+ ratio="Background",
68
84
  )
69
85
  ```
70
86
 
@@ -107,8 +123,14 @@ matplotlib `Figure`/`Axes`, `p.hists` are `hist.Hist` objects, and
107
123
  `count(Jet_pt) >= 2` or `Muon_pt > 20`; event and object selections have
108
124
  explicit rules, and event weights carry through to each selected object.
109
125
  - **Compare samples with a few keywords.** Overlays, stacks, data points and
110
- ratio panels share binning and propagate histogram uncertainties.
111
- Normalise to unity, density, bin width or luminosity.
126
+ ratio panels share binning and propagate histogram uncertainties; bin edges
127
+ and `(n, low, high)` are used as given, while a range inferred from the data
128
+ ignores far outliers, so `-999` sentinels do not set the axis. Normalise to
129
+ unity, density, bin width or luminosity.
130
+ - **Show systematic uncertainties.** Attach weight, branch, file or
131
+ normalisation variations to a sample; stacks and ratio panels draw the
132
+ combined statistical and systematic band, and every component stays
133
+ accessible.
112
134
  - **Style figures for your analysis.** Add experiment labels, units, log axes
113
135
  and broken axes, then refine the result with matplotlib.
114
136
  - **Go beyond 1D plots.** Draw 2D histograms, correlations, efficiencies,
@@ -139,7 +161,7 @@ stack, building on familiar libraries:
139
161
  | --- | --- | --- |
140
162
  | Reading ROOT files | [uproot](https://github.com/scikit-hep/uproot5) | file globs, tree auto-detection, reading only the required branches |
141
163
  | Jagged arrays | [Awkward Array](https://github.com/scikit-hep/awkward) | the per-event/per-object rules for cuts and weights |
142
- | Histograms | [hist](https://github.com/scikit-hep/hist) / boost-histogram | shared binning, automatic ranges, normalisation, ratios |
164
+ | Histograms | [hist](https://github.com/scikit-hep/hist) / boost-histogram | shared binning, robust automatic ranges, normalisation, ratios |
143
165
  | Drawing | [mplhep](https://github.com/scikit-hep/mplhep) + matplotlib | overlays, stacks, ratio panels, labels and legends with good defaults |
144
166
 
145
167
  If you already have `hist.Hist` objects, `rf.plot_histograms` draws them with
@@ -159,6 +181,21 @@ uv run mypy
159
181
 
160
182
  See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
161
183
 
184
+ ## Citation
185
+
186
+ If `rootfig` is useful in your research, please cite it:
187
+
188
+ ```bibtex
189
+ @software{rootfig,
190
+ author = {Beirer, Joshua Falco},
191
+ doi = {10.5281/zenodo.22726311},
192
+ license = {MIT},
193
+ title = {{rootfig}},
194
+ url = {https://github.com/jbeirer/rootfig},
195
+ year = {2026}
196
+ }
197
+ ```
198
+
162
199
  ## License
163
200
 
164
201
  MIT. See [LICENSE](LICENSE).
@@ -18,6 +18,7 @@
18
18
  ::: rootfig.ratio
19
19
  ::: rootfig.log_bins
20
20
  ::: rootfig.use_style
21
+ ::: rootfig.dark_theme
21
22
 
22
23
  ## Descriptions
23
24
 
@@ -25,12 +26,14 @@
25
26
  ::: rootfig.Variable
26
27
  ::: rootfig.Cut
27
28
  ::: rootfig.Style
29
+ ::: rootfig.Systematic
28
30
 
29
31
  ## Results
30
32
 
31
33
  ::: rootfig.Plot
32
34
  ::: rootfig.Histogram
33
35
  ::: rootfig.Ratio
36
+ ::: rootfig.Uncertainty
34
37
  ::: rootfig.Summary
35
38
  ::: rootfig.SummaryTable
36
39
  ::: rootfig.Cutflow
@@ -28,8 +28,9 @@ mem = rf.Sample({"x": awkward_array, "w": weights}, label="in memory")
28
28
  implementing the [`Source`][rootfig.io.Source] protocol.
29
29
  - `selection` and `weight` belong to the sample and combine with the ones
30
30
  given to `plot()` (`&` and `*` respectively).
31
- - `is_data=True` draws black points with error bars, keeps the sample out of
32
- stacks and makes it the numerator of ratios.
31
+ - `is_data=True` draws points with error bars (in the style's text colour
32
+ unless `color` is set), keeps the sample out of stacks and makes it the
33
+ numerator of ratios.
33
34
  - `xsec` and `ngen` describe simulated processes: the cross section (pb, or a
34
35
  string with a unit such as `"1.2 fb"`) and the number of generated events (a
35
36
  number, the name of an object in the file holding it, e.g. FCCAnalyses'
@@ -48,6 +49,13 @@ mem = rf.Sample({"x": awkward_array, "w": weights}, label="in memory")
48
49
  (a plot reads every needed branch of every file into memory at once). For a
49
50
  ready-made `FileSource`, give the range to the source itself; passing it to
50
51
  `Sample` afterwards raises a [`SourceError`][rootfig.SourceError].
52
+ - `systematics={name: variation}` lists the sample's sources of systematic
53
+ uncertainty: weight expressions (`("w_up", "w_down")`), normalisation
54
+ uncertainties (`0.05`, `(1.1, 0.95)`), varied branches
55
+ (`{"Jet_pt": ("Jet_pt_up", "Jet_pt_down")}`) and varied files
56
+ ([`Systematic.samples`][rootfig.Systematic]). Sources with
57
+ the same name are correlated across samples; see
58
+ [Systematic uncertainties](plotting.md#systematic-uncertainties).
51
59
  - `sample.with_(label="...")` returns a modified copy; replacement values are
52
60
  validated like constructor arguments.
53
61
 
@@ -61,14 +69,16 @@ What to histogram and how to present it.
61
69
  ```python
62
70
  pt = rf.Variable("Muon_pt", bins=(50, 0, 200), label=r"$p_T^{\mu}$", unit="GeV")
63
71
  met = rf.Variable(
64
- "MET / 1000", bins=40, range="robust", label=r"$E_T^{miss}$", unit="TeV", log=True, name="met"
72
+ "MET / 1000", bins=40, range="auto", label=r"$E_T^{miss}$", unit="TeV", log=True, name="met"
65
73
  )
66
74
  ```
67
75
 
68
- - `bins`: an `int` (range from the data), `(n, low, high)`, a sequence of
69
- edges (e.g. `rf.log_bins(30, 1, 1000)`), or a `hist.axis.Regular`/`Variable`.
70
- - `range`: `(low, high)`, `"auto"` (finite min/max over all samples) or
71
- `"robust"` (ignores far outliers such as `-999` sentinels).
76
+ - `bins`: an `int` (range inferred from the data), `(n, low, high)`, a sequence
77
+ of edges (e.g. `rf.log_bins(30, 1, 1000)`), or a `hist.axis.Regular`/`Variable`.
78
+ - `range`: `(low, high)`, `"robust"` (the default: ignores far outliers such as
79
+ `-999` sentinels and cuts a thin tail, both of which then land in the
80
+ under/overflow) or `"auto"` (the finite min/max over all samples). See
81
+ [Binning and range](plotting.md#binning-and-range).
72
82
  - `label` and `unit` form the axis label `label [unit]`; the unit also appears
73
83
  in the automatic y label (`Events / 4 GeV`).
74
84
  - `name` is used for file names by `Plot.save(directory)`; it must be a plain
@@ -111,8 +121,12 @@ neutral = rf.Style(
111
121
  given.
112
122
  - `base` can be any mplhep or matplotlib style name (`"ATLAS"`, `"ggplot"`,
113
123
  ...) or a mapping of rcParams; `rc` adds overrides on top; `colors` replaces
114
- the colour cycle. `label_loc` is mplhep's label position (0 above the axes,
115
- 1 to 4 inside the corners), overriding the experiment's convention.
124
+ the colour cycle. `label_loc` overrides the experiment's convention: 0 puts
125
+ the experiment and secondary text above the frame; 3 puts the experiment
126
+ above and secondary text inside; 1, 2, and 4 put both inside. Luminosity stays
127
+ above for locations 0–3 and inside for 4. 2D histograms and correlation
128
+ matrices default to location 0; only `label_loc=1`, `2`, or `4` moves the
129
+ experiment inside the frame.
116
130
  - The centre-of-mass energy and luminosity appear only when `com`/`lumi` are
117
131
  given; nothing is invented for you.
118
132
  - `legend` is `True`, `False` or a location string; `legend_kwargs` are
@@ -0,0 +1,67 @@
1
+ ---
2
+ hide:
3
+ - toc
4
+ ---
5
+
6
+ # Gallery
7
+
8
+ Every figure below is drawn by the code on its page. Most examples use a toy
9
+ ROOT dataset: three simulated processes and one "observed" sample with muons,
10
+ jets and event-level quantities. The in-memory arrays example generates its
11
+ own NumPy data.
12
+
13
+ Choose a style: examples with style tabs follow your choice here and on their
14
+ individual pages. The other examples keep their own styles.
15
+
16
+ <!-- gallery-overview -->
17
+
18
+ ## Run the examples
19
+
20
+ The examples live in
21
+ [`examples/gallery`](https://github.com/jbeirer/rootfig/blob/main/examples/gallery/__init__.py),
22
+ and one command writes the toy files and every figure in a few seconds:
23
+
24
+ ```bash
25
+ python examples/gallery # everything ends up in examples/out/
26
+ python examples/gallery --style CMS # CMS for examples with style tabs
27
+ ```
28
+
29
+ Each picture is also the reference image the test suite compares against, so
30
+ what you see is what the current release draws.
31
+
32
+ ## Beyond figures
33
+
34
+ The same inputs feed tables and arrays (`mc` and `signal` are the samples from
35
+ the setup block of the example pages):
36
+
37
+ ```python
38
+ # entries, mean, std, sem, skewness, min, max per sample and variable
39
+ print(rf.summarize(mc, ["MET", "Muon_pt"], selection="nMuon > 0"))
40
+
41
+ # a cut flow: yields, raw counts and step efficiencies per sample
42
+ print(
43
+ rf.cutflow(
44
+ mc,
45
+ ["nMuon >= 2", rf.Cut("MET > 50", label="MET > 50 GeV"), "any(Jet_btag > 0.8)"],
46
+ )
47
+ )
48
+
49
+ # evaluated expressions as an Awkward record array
50
+ events = rf.load(signal, ["MET", "count(Muon_pt)", "first(Muon_pt)"], selection="nJet >= 2")
51
+ events["MET"]
52
+
53
+ # a plain hist.Hist to feed into your own code
54
+ h = rf.histogram(signal, "MET", bins=(40, 0, 400), selection="nJet >= 2")
55
+ ```
56
+
57
+ Cuts compose with `&`, `|` and `~`, carry optional labels, and combine with
58
+ selections given to `plot()`:
59
+
60
+ ```python
61
+ base = rf.Cut("nMuon >= 2", label="2 muons")
62
+ signal_region = base & "abs(Muon_eta) < 2.4" & ~rf.Cut("any(Jet_btag > 0.8)")
63
+ control_region = base & rf.Cut("any(Jet_btag > 0.8)") | "MET > 200"
64
+ ```
65
+
66
+ See [Plotting options](../plotting.md) for every keyword and
67
+ [Expressions and selections](../expressions.md) for the per-event/per-object rules.