rootfig 0.7.1__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (362) hide show
  1. {rootfig-0.7.1 → rootfig-0.9.0}/CONTRIBUTING.md +32 -7
  2. {rootfig-0.7.1 → rootfig-0.9.0}/PKG-INFO +28 -44
  3. {rootfig-0.7.1 → rootfig-0.9.0}/README.md +26 -42
  4. rootfig-0.9.0/docs/api.md +121 -0
  5. {rootfig-0.7.1 → rootfig-0.9.0}/docs/batch.md +67 -6
  6. {rootfig-0.7.1 → rootfig-0.9.0}/docs/composable.md +11 -7
  7. {rootfig-0.7.1 → rootfig-0.9.0}/docs/ecosystem.md +23 -7
  8. {rootfig-0.7.1 → rootfig-0.9.0}/docs/expressions.md +4 -1
  9. rootfig-0.9.0/docs/images/gallery/pull-alice-dark.png +0 -0
  10. rootfig-0.9.0/docs/images/gallery/pull-alice.png +0 -0
  11. rootfig-0.9.0/docs/images/gallery/pull-atlas-dark.png +0 -0
  12. rootfig-0.9.0/docs/images/gallery/pull-atlas.png +0 -0
  13. rootfig-0.9.0/docs/images/gallery/pull-cms-dark.png +0 -0
  14. rootfig-0.9.0/docs/images/gallery/pull-cms.png +0 -0
  15. rootfig-0.9.0/docs/images/gallery/pull-dark.png +0 -0
  16. rootfig-0.9.0/docs/images/gallery/pull-dune-dark.png +0 -0
  17. rootfig-0.9.0/docs/images/gallery/pull-dune.png +0 -0
  18. rootfig-0.9.0/docs/images/gallery/pull-lhcb-dark.png +0 -0
  19. rootfig-0.9.0/docs/images/gallery/pull-lhcb.png +0 -0
  20. rootfig-0.9.0/docs/images/gallery/pull.png +0 -0
  21. rootfig-0.9.0/docs/images/gallery/selective_stack-alice-dark.png +0 -0
  22. rootfig-0.9.0/docs/images/gallery/selective_stack-alice.png +0 -0
  23. rootfig-0.9.0/docs/images/gallery/selective_stack-atlas-dark.png +0 -0
  24. rootfig-0.9.0/docs/images/gallery/selective_stack-atlas.png +0 -0
  25. rootfig-0.9.0/docs/images/gallery/selective_stack-cms-dark.png +0 -0
  26. rootfig-0.9.0/docs/images/gallery/selective_stack-cms.png +0 -0
  27. rootfig-0.9.0/docs/images/gallery/selective_stack-dark.png +0 -0
  28. rootfig-0.9.0/docs/images/gallery/selective_stack-dune-dark.png +0 -0
  29. rootfig-0.9.0/docs/images/gallery/selective_stack-dune.png +0 -0
  30. rootfig-0.9.0/docs/images/gallery/selective_stack-lhcb-dark.png +0 -0
  31. rootfig-0.9.0/docs/images/gallery/selective_stack-lhcb.png +0 -0
  32. rootfig-0.9.0/docs/images/gallery/selective_stack.png +0 -0
  33. rootfig-0.9.0/docs/images/gallery/stored_histograms-dark.png +0 -0
  34. rootfig-0.9.0/docs/images/gallery/stored_histograms.png +0 -0
  35. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-alice-dark.png +0 -0
  36. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-alice.png +0 -0
  37. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-atlas-dark.png +0 -0
  38. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-atlas.png +0 -0
  39. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-cms-dark.png +0 -0
  40. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-cms.png +0 -0
  41. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-dark.png +0 -0
  42. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-dune-dark.png +0 -0
  43. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-dune.png +0 -0
  44. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-lhcb-dark.png +0 -0
  45. rootfig-0.9.0/docs/images/gallery/xbreak_ratio-lhcb.png +0 -0
  46. rootfig-0.9.0/docs/images/gallery/xbreak_ratio.png +0 -0
  47. {rootfig-0.7.1 → rootfig-0.9.0}/docs/index.md +2 -2
  48. {rootfig-0.7.1 → rootfig-0.9.0}/docs/plotting.md +222 -97
  49. {rootfig-0.7.1 → rootfig-0.9.0}/docs/quickstart.md +2 -2
  50. {rootfig-0.7.1 → rootfig-0.9.0}/examples/gallery/__init__.py +78 -15
  51. {rootfig-0.7.1 → rootfig-0.9.0}/examples/gallery/data.py +25 -2
  52. {rootfig-0.7.1 → rootfig-0.9.0}/mkdocs.yml +1 -1
  53. {rootfig-0.7.1 → rootfig-0.9.0}/pyproject.toml +4 -3
  54. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/__init__.py +6 -8
  55. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/_storage.py +15 -5
  56. rootfig-0.9.0/src/rootfig/_threads.py +65 -0
  57. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/_discover.py +2 -3
  58. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/_hists.py +7 -17
  59. rootfig-0.9.0/src/rootfig/api/_panel.py +273 -0
  60. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/_pdf.py +8 -3
  61. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/batch.py +2 -2
  62. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/measures.py +2 -2
  63. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/plots1d.py +131 -177
  64. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/plots2d.py +8 -5
  65. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/__init__.py +19 -31
  66. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/build.py +113 -108
  67. rootfig-0.9.0/src/rootfig/histograms/comparison.py +374 -0
  68. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/efficiency.py +1 -1
  69. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/pipeline.py +204 -62
  70. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/stats.py +17 -6
  71. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/stored.py +15 -11
  72. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/io/__init__.py +2 -0
  73. rootfig-0.9.0/src/rootfig/io/compat.py +51 -0
  74. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/io/sources.py +203 -37
  75. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/__init__.py +0 -6
  76. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/binning.py +161 -60
  77. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/samples.py +4 -2
  78. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/style.py +1 -1
  79. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/variables.py +6 -3
  80. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/__init__.py +9 -12
  81. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/annotations.py +9 -5
  82. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/figure.py +43 -43
  83. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/finish.py +1 -1
  84. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/hist1d.py +308 -131
  85. rootfig-0.9.0/src/rootfig/plotting/panel.py +382 -0
  86. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/result.py +34 -31
  87. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/selection/__init__.py +3 -2
  88. rootfig-0.9.0/src/rootfig/selection/chunks.py +148 -0
  89. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/selection/columns.py +67 -11
  90. {rootfig-0.7.1 → rootfig-0.9.0}/tests/conftest.py +11 -5
  91. rootfig-0.9.0/tests/data/embedded_basket.root +0 -0
  92. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_api.py +679 -133
  93. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_batch.py +42 -18
  94. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_discovery.py +19 -6
  95. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_histograms.py +526 -49
  96. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_io.py +265 -0
  97. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_model.py +79 -5
  98. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_plotting.py +475 -142
  99. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_save_pdf.py +43 -35
  100. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_selection.py +187 -1
  101. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_tutorials.py +7 -2
  102. {rootfig-0.7.1 → rootfig-0.9.0}/tests/type_checks/groups.py +2 -0
  103. rootfig-0.7.1/docs/api.md +0 -63
  104. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-alice-dark.png +0 -0
  105. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-alice.png +0 -0
  106. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-atlas-dark.png +0 -0
  107. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-atlas.png +0 -0
  108. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-cms-dark.png +0 -0
  109. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-cms.png +0 -0
  110. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-dark.png +0 -0
  111. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-dune-dark.png +0 -0
  112. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-dune.png +0 -0
  113. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-lhcb-dark.png +0 -0
  114. rootfig-0.7.1/docs/images/gallery/xbreak_ratio-lhcb.png +0 -0
  115. rootfig-0.7.1/docs/images/gallery/xbreak_ratio.png +0 -0
  116. rootfig-0.7.1/src/rootfig/histograms/ratio.py +0 -241
  117. rootfig-0.7.1/src/rootfig/plotting/ratio.py +0 -206
  118. {rootfig-0.7.1 → rootfig-0.9.0}/.gitignore +0 -0
  119. {rootfig-0.7.1 → rootfig-0.9.0}/LICENSE +0 -0
  120. {rootfig-0.7.1 → rootfig-0.9.0}/docs/gallery/index.md +0 -0
  121. {rootfig-0.7.1 → rootfig-0.9.0}/docs/hooks/gallery.py +0 -0
  122. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-alice-dark.png +0 -0
  123. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-alice.png +0 -0
  124. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-atlas-dark.png +0 -0
  125. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-atlas.png +0 -0
  126. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-cms-dark.png +0 -0
  127. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-cms.png +0 -0
  128. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-dark.png +0 -0
  129. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-dune-dark.png +0 -0
  130. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-dune.png +0 -0
  131. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-lhcb-dark.png +0 -0
  132. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays-lhcb.png +0 -0
  133. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/arrays.png +0 -0
  134. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-alice-dark.png +0 -0
  135. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-alice.png +0 -0
  136. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-atlas-dark.png +0 -0
  137. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-atlas.png +0 -0
  138. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-cms-dark.png +0 -0
  139. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-cms.png +0 -0
  140. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-dark.png +0 -0
  141. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-dune-dark.png +0 -0
  142. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-dune.png +0 -0
  143. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-lhcb-dark.png +0 -0
  144. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation-lhcb.png +0 -0
  145. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/correlation.png +0 -0
  146. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-alice-dark.png +0 -0
  147. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-alice.png +0 -0
  148. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-atlas-dark.png +0 -0
  149. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-atlas.png +0 -0
  150. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-cms-dark.png +0 -0
  151. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-cms.png +0 -0
  152. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-dark.png +0 -0
  153. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-dune-dark.png +0 -0
  154. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-dune.png +0 -0
  155. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-lhcb-dark.png +0 -0
  156. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow-lhcb.png +0 -0
  157. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/density_flow.png +0 -0
  158. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-alice-dark.png +0 -0
  159. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-alice.png +0 -0
  160. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-atlas-dark.png +0 -0
  161. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-atlas.png +0 -0
  162. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-cms-dark.png +0 -0
  163. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-cms.png +0 -0
  164. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-dark.png +0 -0
  165. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-dune-dark.png +0 -0
  166. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-dune.png +0 -0
  167. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-lhcb-dark.png +0 -0
  168. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency-lhcb.png +0 -0
  169. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/efficiency.png +0 -0
  170. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-alice-dark.png +0 -0
  171. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-alice.png +0 -0
  172. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-atlas-dark.png +0 -0
  173. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-atlas.png +0 -0
  174. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-cms-dark.png +0 -0
  175. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-cms.png +0 -0
  176. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-dark.png +0 -0
  177. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-dune-dark.png +0 -0
  178. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-dune.png +0 -0
  179. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-lhcb-dark.png +0 -0
  180. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions-lhcb.png +0 -0
  181. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/expressions.png +0 -0
  182. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-alice-dark.png +0 -0
  183. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-alice.png +0 -0
  184. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-atlas-dark.png +0 -0
  185. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-atlas.png +0 -0
  186. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-cms-dark.png +0 -0
  187. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-cms.png +0 -0
  188. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-dark.png +0 -0
  189. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-dune-dark.png +0 -0
  190. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-dune.png +0 -0
  191. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-lhcb-dark.png +0 -0
  192. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats-lhcb.png +0 -0
  193. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/fill_stats.png +0 -0
  194. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-alice-dark.png +0 -0
  195. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-alice.png +0 -0
  196. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-atlas-dark.png +0 -0
  197. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-atlas.png +0 -0
  198. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-cms-dark.png +0 -0
  199. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-cms.png +0 -0
  200. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-dark.png +0 -0
  201. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-dune-dark.png +0 -0
  202. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-dune.png +0 -0
  203. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-lhcb-dark.png +0 -0
  204. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d-lhcb.png +0 -0
  205. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/hist2d.png +0 -0
  206. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-alice-dark.png +0 -0
  207. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-alice.png +0 -0
  208. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-atlas-dark.png +0 -0
  209. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-atlas.png +0 -0
  210. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-cms-dark.png +0 -0
  211. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-cms.png +0 -0
  212. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-dark.png +0 -0
  213. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-dune-dark.png +0 -0
  214. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-dune.png +0 -0
  215. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-lhcb-dark.png +0 -0
  216. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes-lhcb.png +0 -0
  217. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/log_axes.png +0 -0
  218. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/luminosity-dark.png +0 -0
  219. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/luminosity.png +0 -0
  220. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/many_plots-dark.png +0 -0
  221. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/many_plots.png +0 -0
  222. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-alice-dark.png +0 -0
  223. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-alice.png +0 -0
  224. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-atlas-dark.png +0 -0
  225. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-atlas.png +0 -0
  226. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-cms-dark.png +0 -0
  227. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-cms.png +0 -0
  228. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-dark.png +0 -0
  229. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-dune-dark.png +0 -0
  230. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-dune.png +0 -0
  231. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-lhcb-dark.png +0 -0
  232. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event-lhcb.png +0 -0
  233. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/object_vs_event.png +0 -0
  234. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-alice-dark.png +0 -0
  235. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-alice.png +0 -0
  236. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-atlas-dark.png +0 -0
  237. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-atlas.png +0 -0
  238. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-cms-dark.png +0 -0
  239. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-cms.png +0 -0
  240. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-dark.png +0 -0
  241. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-dune-dark.png +0 -0
  242. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-dune.png +0 -0
  243. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-lhcb-dark.png +0 -0
  244. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio-lhcb.png +0 -0
  245. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/overlay_ratio.png +0 -0
  246. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-alice-dark.png +0 -0
  247. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-alice.png +0 -0
  248. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-atlas-dark.png +0 -0
  249. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-atlas.png +0 -0
  250. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-cms-dark.png +0 -0
  251. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-cms.png +0 -0
  252. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-dark.png +0 -0
  253. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-dune-dark.png +0 -0
  254. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-dune.png +0 -0
  255. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-lhcb-dark.png +0 -0
  256. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile-lhcb.png +0 -0
  257. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/profile.png +0 -0
  258. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-alice-dark.png +0 -0
  259. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-alice.png +0 -0
  260. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-atlas-dark.png +0 -0
  261. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-atlas.png +0 -0
  262. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-cms-dark.png +0 -0
  263. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-cms.png +0 -0
  264. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-dark.png +0 -0
  265. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-dune-dark.png +0 -0
  266. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-dune.png +0 -0
  267. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-lhcb-dark.png +0 -0
  268. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick-lhcb.png +0 -0
  269. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/quick.png +0 -0
  270. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-alice-dark.png +0 -0
  271. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-alice.png +0 -0
  272. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-atlas-dark.png +0 -0
  273. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-atlas.png +0 -0
  274. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-cms-dark.png +0 -0
  275. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-cms.png +0 -0
  276. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-dark.png +0 -0
  277. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-dune-dark.png +0 -0
  278. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-dune.png +0 -0
  279. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-lhcb-dark.png +0 -0
  280. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference-lhcb.png +0 -0
  281. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/ratio_reference.png +0 -0
  282. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/robust_range-dark.png +0 -0
  283. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/robust_range.png +0 -0
  284. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-alice-dark.png +0 -0
  285. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-alice.png +0 -0
  286. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-atlas-dark.png +0 -0
  287. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-atlas.png +0 -0
  288. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-cms-dark.png +0 -0
  289. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-cms.png +0 -0
  290. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-dark.png +0 -0
  291. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-dune-dark.png +0 -0
  292. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-dune.png +0 -0
  293. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-lhcb-dark.png +0 -0
  294. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data-lhcb.png +0 -0
  295. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/stack_data.png +0 -0
  296. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/style_colors-dark.png +0 -0
  297. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/style_colors.png +0 -0
  298. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-alice-dark.png +0 -0
  299. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-alice.png +0 -0
  300. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-atlas-dark.png +0 -0
  301. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-atlas.png +0 -0
  302. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-cms-dark.png +0 -0
  303. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-cms.png +0 -0
  304. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-dark.png +0 -0
  305. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-dune-dark.png +0 -0
  306. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-dune.png +0 -0
  307. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-lhcb-dark.png +0 -0
  308. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics-lhcb.png +0 -0
  309. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/systematics.png +0 -0
  310. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-alice-dark.png +0 -0
  311. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-alice.png +0 -0
  312. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-atlas-dark.png +0 -0
  313. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-atlas.png +0 -0
  314. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-cms-dark.png +0 -0
  315. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-cms.png +0 -0
  316. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-dark.png +0 -0
  317. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-dune-dark.png +0 -0
  318. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-dune.png +0 -0
  319. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-lhcb-dark.png +0 -0
  320. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins-lhcb.png +0 -0
  321. {rootfig-0.7.1 → rootfig-0.9.0}/docs/images/gallery/variable_bins.png +0 -0
  322. {rootfig-0.7.1 → rootfig-0.9.0}/docs/stylesheets/gallery.css +0 -0
  323. {rootfig-0.7.1 → rootfig-0.9.0}/examples/gallery/__main__.py +0 -0
  324. {rootfig-0.7.1 → rootfig-0.9.0}/examples/gallery/registry.py +0 -0
  325. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/_mapping.py +0 -0
  326. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/_typing.py +0 -0
  327. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/__init__.py +0 -0
  328. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/_common.py +0 -0
  329. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/data.py +0 -0
  330. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/api/tables.py +0 -0
  331. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/errors.py +0 -0
  332. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/expressions/__init__.py +0 -0
  333. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/expressions/functions.py +0 -0
  334. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/expressions/parser.py +0 -0
  335. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/cutflow.py +0 -0
  336. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/groups.py +0 -0
  337. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/normalize.py +0 -0
  338. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/prefetch.py +0 -0
  339. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/sources.py +0 -0
  340. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/histograms/systematics.py +0 -0
  341. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/io/cache.py +0 -0
  342. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/io/objects.py +0 -0
  343. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/io/schema.py +0 -0
  344. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/cuts.py +0 -0
  345. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/filenames.py +0 -0
  346. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/groups.py +0 -0
  347. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/inputs.py +0 -0
  348. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/systematics.py +0 -0
  349. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/model/units.py +0 -0
  350. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/correlation.py +0 -0
  351. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/engine.py +0 -0
  352. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/hist2d.py +0 -0
  353. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/pages.py +0 -0
  354. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/points.py +0 -0
  355. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/plotting/style.py +0 -0
  356. {rootfig-0.7.1 → rootfig-0.9.0}/src/rootfig/py.typed +0 -0
  357. {rootfig-0.7.1 → rootfig-0.9.0}/tests/data/split_collection.root +0 -0
  358. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_expressions.py +0 -0
  359. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_gallery.py +0 -0
  360. {rootfig-0.7.1 → rootfig-0.9.0}/tests/test_pages.py +0 -0
  361. {rootfig-0.7.1 → rootfig-0.9.0}/tests/type_checks/batch.py +0 -0
  362. {rootfig-0.7.1 → rootfig-0.9.0}/tests/type_checks/systematics.py +0 -0
@@ -50,7 +50,7 @@ src/rootfig/
50
50
  io/ file and in-memory data sources
51
51
  model/ Sample, Group, Variable, Cut, Style, binning
52
52
  selection/ per-event / per-object semantics -> flat columns
53
- histograms/ filling, normalisation, ratios, statistics, groups, pipeline
53
+ histograms/ filling, normalisation, comparisons, statistics, groups, pipeline
54
54
  plotting/ matplotlib/mplhep rendering, styles, annotations
55
55
  tests/ one module per layer plus end-to-end API tests
56
56
  docs/ MkDocs sources
@@ -62,12 +62,12 @@ docstrings and full type hints.
62
62
 
63
63
  ## Test data
64
64
 
65
- Almost all tests generate their ROOT files with uproot on the fly. The one
66
- committed file, `tests/data/split_collection.root`, has a split
67
- `std::vector<struct>` branch and a `TParameter` the way podio/EDM4hep and
68
- FCCAnalyses write them. uproot cannot write such a file, so it was produced
69
- with PyROOT (ROOT 6.40) by this script; rerun it only if the layout has to
70
- change, and keep the file small:
65
+ Almost all tests generate their ROOT files with uproot on the fly. Two files
66
+ that uproot cannot write are committed, produced with ROOT 6.40; rerun their
67
+ scripts only if the layout has to change, and keep the files small.
68
+
69
+ `tests/data/split_collection.root` has a split `std::vector<struct>` branch and
70
+ a `TParameter` the way podio/EDM4hep and FCCAnalyses write them (PyROOT):
71
71
 
72
72
  ```python
73
73
  import ROOT
@@ -95,6 +95,31 @@ f.Write()
95
95
  f.Close()
96
96
  ```
97
97
 
98
+ `tests/data/embedded_basket.root` holds a tree whose baskets are embedded in its
99
+ branches, without keys of their own, as a tree filled in memory and written
100
+ afterwards keeps them (`root -l -b -q embedded.C`):
101
+
102
+ ```cpp
103
+ // embedded.C
104
+ void embedded() {
105
+ TTree t("events", "events");
106
+ t.SetDirectory(nullptr); // in memory: nothing is flushed while filling
107
+ Float_t x;
108
+ std::vector<double> y;
109
+ t.Branch("x", &x);
110
+ t.Branch("y", &y);
111
+ TRandom3 r(1);
112
+ for (int i = 0; i < 500; ++i) {
113
+ x = r.Gaus(0, 1);
114
+ y.assign(i % 4, r.Uniform());
115
+ t.Fill();
116
+ }
117
+ TFile f("embedded_basket.root", "RECREATE");
118
+ f.WriteObject(&t, "events");
119
+ f.Close();
120
+ }
121
+ ```
122
+
98
123
  ## Figures and the gallery
99
124
 
100
125
  The `examples/gallery` package is both the showcase and the image-regression
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: rootfig
3
- Version: 0.7.1
4
- Summary: Publication-quality figures straight from ROOT trees, without ROOT: uproot + Awkward + hist + mplhep with a TTree::Draw-like API.
3
+ Version: 0.9.0
4
+ Summary: Publication-quality figures straight from ROOT trees and histograms, 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/
7
7
  Project-URL: Repository, https://github.com/jbeirer/rootfig
@@ -40,7 +40,7 @@ Description-Content-Type: text/markdown
40
40
  </p>
41
41
 
42
42
  <p align="center">
43
- <strong>Publication-quality figures straight from ROOT trees, without ROOT.</strong>
43
+ <strong>Publication-quality figures straight from ROOT trees and histograms, without ROOT.</strong>
44
44
  </p>
45
45
 
46
46
  <p align="center">
@@ -98,7 +98,7 @@ uv add rootfig
98
98
  ```
99
99
 
100
100
  Python 3.12 or newer. No ROOT installation is needed; `TTree` and `RNTuple`
101
- files are both supported.
101
+ files and stored `TH1`/`TH2` histograms are all supported.
102
102
 
103
103
  ## Compare samples in one call
104
104
 
@@ -114,7 +114,8 @@ rf.plot(
114
114
  weight="event_weight",
115
115
  bins=(50, 0, 200),
116
116
  normalize=True,
117
- ratio="Background",
117
+ panel="ratio",
118
+ reference="Background",
118
119
  )
119
120
  ```
120
121
 
@@ -139,7 +140,7 @@ p = rf.plot(
139
140
  observed=data,
140
141
  selection=baseline,
141
142
  stack=True,
142
- ratio=True,
143
+ panel="ratio",
143
144
  logy=True,
144
145
  style=style,
145
146
  )
@@ -151,43 +152,24 @@ Everything you get back is a standard object: `p.fig` and `p.ax` are
151
152
  matplotlib `Figure`/`Axes`, `p.hists` are `hist.Hist` objects, and
152
153
  `rf.load(...)` returns Awkward arrays.
153
154
 
154
- Samples that belong to one physics category are drawn as one histogram with
155
- `rf.Group`. Each keeps its own files, weights, cross section and systematics;
156
- they are summed only after filling:
155
+ For histogram files, `Group` sums processes and a `Variable` crops and merges
156
+ their bins just as it bins a tree. `PlotBook` draws the variants from one
157
+ preparation; `rf.ALL` discovers every shared histogram for an overview.
157
158
 
158
159
  ```python
159
- ww = rf.Sample("ww.root", tree="events", label="WW", weight="mc_weight")
160
- zz = rf.Sample("zz.root", tree="events", label="ZZ", weight="mc_weight")
161
- vv = rf.Group([ww, zz], label="VV")
160
+ # Histogram files: one per process, already scaled to 5 ab^-1
161
+ ww = rf.Sample("outputs/p8_ee_WW_ecm240.root", label="WW")
162
+ zz = rf.Sample("outputs/p8_ee_ZZ_ecm240.root", label="ZZ")
163
+ zh = rf.Sample("outputs/p8_ee_ZH_ecm240.root", label="ZH")
164
+ fcc = rf.Style(experiment="FCC-ee", status="Simulation", com="240 GeV", lumi="5 ab^-1")
162
165
 
163
- rf.plot([vv, signal], pt, observed=data, stack=True, ratio=True, style=style)
164
- ```
165
-
166
- Whole sets of plots, every variable under each selection in every drawing
167
- variant, are one `rf.PlotBook`: it runs that same `rf.plot` call per
168
- combination and writes deterministically named files:
169
-
170
- ```python
171
- book = rf.PlotBook(
172
- [vv, signal],
173
- [pt, rf.Variable("MET", bins=(40, 0, 200), unit="GeV")],
174
- selections={"baseline": baseline, "sr": baseline & "MET > 50"},
175
- variants={"lin": {}, "log": {"logy": True}},
176
- plot_kwargs={"observed": data, "stack": True, "ratio": True, "style": style},
177
- )
178
- book.save("plots/", formats=["pdf", "png"]) # plots/Muon_pt__sr__log.pdf, ...
179
- book.save_pdf("overview.pdf") # one automatically arranged multipage PDF
180
- ```
181
-
182
- `rf.ALL` discovers the variables instead, from the branch types and stored
183
- histograms of the files (metadata only), filtered by name:
184
-
185
- ```python
186
166
  book = rf.PlotBook(
187
- [vv, signal],
188
- variables=rf.ALL,
189
- exclude=["*_cov", "*Index"],
167
+ [rf.Group([ww, zz], label="VV"), zh],
168
+ [rf.Variable("zmumu_recoil_m", bins=(200, 120, 140), label="Recoil mass", unit="GeV")],
169
+ variants={"stack": {"stack": True}, "nostack": {"stack": ["VV"]}},
170
+ plot_kwargs={"style": fcc},
190
171
  )
172
+ book.save_pdf("zh.pdf") # rf.ALL in place of the list plots every histogram the files share
191
173
  ```
192
174
 
193
175
  ## What you can do
@@ -195,15 +177,17 @@ book = rf.PlotBook(
195
177
  - **Select events and objects with readable expressions.** Write cuts such as
196
178
  `count(Jet_pt) >= 2` or `Muon_pt > 20`; event and object selections have
197
179
  explicit rules, and event weights carry through to each selected object.
198
- - **Compare samples with a few keywords.** Overlays, stacks, data points and
199
- ratio panels share binning and propagate histogram uncertainties; bin edges
180
+ - **Compare samples with a few keywords.** Overlays, stacks, data points and a
181
+ lower panel (ratio, difference, relative difference, pull or significance,
182
+ against a reference you name) share binning and propagate histogram
183
+ uncertainties; bin edges
200
184
  and `(n, low, high)` are used as given, while a range inferred from the data
201
185
  ignores far outliers, so `-999` sentinels do not set the axis. Normalise to
202
- unity, density, bin width or luminosity. Draw several samples as one
203
- histogram with `rf.Group`, each keeping its own weights, cross section and
204
- systematics.
186
+ unity, density, bin width or luminosity; stack some samples and overlay the rest.
187
+ Draw several samples as one histogram with `rf.Group`, each keeping its own
188
+ weights, cross section and systematics.
205
189
  - **Show systematic uncertainties.** Attach weight, branch, file or
206
- normalisation variations to a sample; stacks and ratio panels draw the
190
+ normalisation variations to a sample; stacks and lower panels draw the
207
191
  combined statistical and systematic band, and every component stays
208
192
  accessible.
209
193
  - **Style figures for your analysis.** Add experiment labels, units, log axes
@@ -7,7 +7,7 @@
7
7
  </p>
8
8
 
9
9
  <p align="center">
10
- <strong>Publication-quality figures straight from ROOT trees, without ROOT.</strong>
10
+ <strong>Publication-quality figures straight from ROOT trees and histograms, without ROOT.</strong>
11
11
  </p>
12
12
 
13
13
  <p align="center">
@@ -65,7 +65,7 @@ uv add rootfig
65
65
  ```
66
66
 
67
67
  Python 3.12 or newer. No ROOT installation is needed; `TTree` and `RNTuple`
68
- files are both supported.
68
+ files and stored `TH1`/`TH2` histograms are all supported.
69
69
 
70
70
  ## Compare samples in one call
71
71
 
@@ -81,7 +81,8 @@ rf.plot(
81
81
  weight="event_weight",
82
82
  bins=(50, 0, 200),
83
83
  normalize=True,
84
- ratio="Background",
84
+ panel="ratio",
85
+ reference="Background",
85
86
  )
86
87
  ```
87
88
 
@@ -106,7 +107,7 @@ p = rf.plot(
106
107
  observed=data,
107
108
  selection=baseline,
108
109
  stack=True,
109
- ratio=True,
110
+ panel="ratio",
110
111
  logy=True,
111
112
  style=style,
112
113
  )
@@ -118,43 +119,24 @@ Everything you get back is a standard object: `p.fig` and `p.ax` are
118
119
  matplotlib `Figure`/`Axes`, `p.hists` are `hist.Hist` objects, and
119
120
  `rf.load(...)` returns Awkward arrays.
120
121
 
121
- Samples that belong to one physics category are drawn as one histogram with
122
- `rf.Group`. Each keeps its own files, weights, cross section and systematics;
123
- they are summed only after filling:
122
+ For histogram files, `Group` sums processes and a `Variable` crops and merges
123
+ their bins just as it bins a tree. `PlotBook` draws the variants from one
124
+ preparation; `rf.ALL` discovers every shared histogram for an overview.
124
125
 
125
126
  ```python
126
- ww = rf.Sample("ww.root", tree="events", label="WW", weight="mc_weight")
127
- zz = rf.Sample("zz.root", tree="events", label="ZZ", weight="mc_weight")
128
- vv = rf.Group([ww, zz], label="VV")
127
+ # Histogram files: one per process, already scaled to 5 ab^-1
128
+ ww = rf.Sample("outputs/p8_ee_WW_ecm240.root", label="WW")
129
+ zz = rf.Sample("outputs/p8_ee_ZZ_ecm240.root", label="ZZ")
130
+ zh = rf.Sample("outputs/p8_ee_ZH_ecm240.root", label="ZH")
131
+ fcc = rf.Style(experiment="FCC-ee", status="Simulation", com="240 GeV", lumi="5 ab^-1")
129
132
 
130
- rf.plot([vv, signal], pt, observed=data, stack=True, ratio=True, style=style)
131
- ```
132
-
133
- Whole sets of plots, every variable under each selection in every drawing
134
- variant, are one `rf.PlotBook`: it runs that same `rf.plot` call per
135
- combination and writes deterministically named files:
136
-
137
- ```python
138
- book = rf.PlotBook(
139
- [vv, signal],
140
- [pt, rf.Variable("MET", bins=(40, 0, 200), unit="GeV")],
141
- selections={"baseline": baseline, "sr": baseline & "MET > 50"},
142
- variants={"lin": {}, "log": {"logy": True}},
143
- plot_kwargs={"observed": data, "stack": True, "ratio": True, "style": style},
144
- )
145
- book.save("plots/", formats=["pdf", "png"]) # plots/Muon_pt__sr__log.pdf, ...
146
- book.save_pdf("overview.pdf") # one automatically arranged multipage PDF
147
- ```
148
-
149
- `rf.ALL` discovers the variables instead, from the branch types and stored
150
- histograms of the files (metadata only), filtered by name:
151
-
152
- ```python
153
133
  book = rf.PlotBook(
154
- [vv, signal],
155
- variables=rf.ALL,
156
- exclude=["*_cov", "*Index"],
134
+ [rf.Group([ww, zz], label="VV"), zh],
135
+ [rf.Variable("zmumu_recoil_m", bins=(200, 120, 140), label="Recoil mass", unit="GeV")],
136
+ variants={"stack": {"stack": True}, "nostack": {"stack": ["VV"]}},
137
+ plot_kwargs={"style": fcc},
157
138
  )
139
+ book.save_pdf("zh.pdf") # rf.ALL in place of the list plots every histogram the files share
158
140
  ```
159
141
 
160
142
  ## What you can do
@@ -162,15 +144,17 @@ book = rf.PlotBook(
162
144
  - **Select events and objects with readable expressions.** Write cuts such as
163
145
  `count(Jet_pt) >= 2` or `Muon_pt > 20`; event and object selections have
164
146
  explicit rules, and event weights carry through to each selected object.
165
- - **Compare samples with a few keywords.** Overlays, stacks, data points and
166
- ratio panels share binning and propagate histogram uncertainties; bin edges
147
+ - **Compare samples with a few keywords.** Overlays, stacks, data points and a
148
+ lower panel (ratio, difference, relative difference, pull or significance,
149
+ against a reference you name) share binning and propagate histogram
150
+ uncertainties; bin edges
167
151
  and `(n, low, high)` are used as given, while a range inferred from the data
168
152
  ignores far outliers, so `-999` sentinels do not set the axis. Normalise to
169
- unity, density, bin width or luminosity. Draw several samples as one
170
- histogram with `rf.Group`, each keeping its own weights, cross section and
171
- systematics.
153
+ unity, density, bin width or luminosity; stack some samples and overlay the rest.
154
+ Draw several samples as one histogram with `rf.Group`, each keeping its own
155
+ weights, cross section and systematics.
172
156
  - **Show systematic uncertainties.** Attach weight, branch, file or
173
- normalisation variations to a sample; stacks and ratio panels draw the
157
+ normalisation variations to a sample; stacks and lower panels draw the
174
158
  combined statistical and systematic band, and every component stays
175
159
  accessible.
176
160
  - **Style figures for your analysis.** Add experiment labels, units, log axes
@@ -0,0 +1,121 @@
1
+ # API reference
2
+
3
+ ## Top level
4
+
5
+ ::: rootfig.plot
6
+ ::: rootfig.plot2d
7
+ ::: rootfig.histogram
8
+ ::: rootfig.api.data.histograms
9
+ options:
10
+ heading: rootfig.histograms
11
+ ::: rootfig.load
12
+ ::: rootfig.summarize
13
+ ::: rootfig.correlation
14
+ ::: rootfig.cutflow
15
+ ::: rootfig.efficiency
16
+ ::: rootfig.profile
17
+ ::: rootfig.evaluate
18
+ ::: rootfig.compare
19
+ ::: rootfig.log_bins
20
+ ::: rootfig.use_style
21
+ ::: rootfig.dark_theme
22
+
23
+ ## Descriptions
24
+
25
+ ::: rootfig.Sample
26
+ ::: rootfig.Group
27
+ ::: rootfig.Variable
28
+ ::: rootfig.Cut
29
+ ::: rootfig.Style
30
+ ::: rootfig.Systematic
31
+
32
+ ## Batch plotting
33
+
34
+ ::: rootfig.PlotBook
35
+ ::: rootfig.PlotTask
36
+ ::: rootfig.ALL
37
+ ::: rootfig.discover_variables
38
+ ::: rootfig.model.check_file_stem
39
+ ::: rootfig.model.safe_file_stem
40
+
41
+ ## Results
42
+
43
+ ::: rootfig.Plot
44
+ ::: rootfig.Histogram
45
+ ::: rootfig.Comparison
46
+ ::: rootfig.Uncertainty
47
+ ::: rootfig.Summary
48
+ ::: rootfig.SummaryTable
49
+ ::: rootfig.Cutflow
50
+ ::: rootfig.CutflowTable
51
+ ::: rootfig.Efficiency
52
+ ::: rootfig.Profile
53
+
54
+ ## Errors and warnings
55
+
56
+ ::: rootfig.errors
57
+
58
+ ## Lower layers
59
+
60
+ These are the layers `rf.plot` is built from, usable on their own; names a module
61
+ does not list here are internal. The descriptions in `rootfig.model` are documented
62
+ above.
63
+
64
+ ::: rootfig.io
65
+ options:
66
+ members:
67
+ - FileSource
68
+ - ArraySource
69
+ - Source
70
+ - ReadCache
71
+ - as_source
72
+
73
+ ::: rootfig.expressions
74
+ options:
75
+ members:
76
+ - Expression
77
+ - parse
78
+ - FUNCTIONS
79
+ - CONSTANTS
80
+
81
+ ::: rootfig.selection
82
+ options:
83
+ members:
84
+ - prepare
85
+ - Columns
86
+ - depth_of
87
+
88
+ ::: rootfig.histograms
89
+ options:
90
+ members:
91
+ - build_histograms
92
+ - fill
93
+ - sum_histograms
94
+ - uncertainty
95
+ - summarize
96
+ - read_stored
97
+ - compatible_binning
98
+
99
+ <!-- The function shares its name with a submodule; its defining path is unambiguous. -->
100
+ ::: rootfig.histograms.normalize.normalize
101
+ options:
102
+ heading: normalize
103
+ heading_level: 3
104
+
105
+ ::: rootfig.plotting
106
+ options:
107
+ members:
108
+ - draw_histograms
109
+ - draw_panel
110
+ - draw_hist2d
111
+ - draw_correlation
112
+ - draw_efficiencies
113
+ - draw_profiles
114
+ - split_stack
115
+ - make_figure
116
+ - Layout
117
+ - figure_size
118
+ - add_legend
119
+ - add_stats_box
120
+ - add_text
121
+ - style_context
@@ -72,8 +72,12 @@ book = rf.PlotBook(
72
72
  ```
73
73
 
74
74
  draws `lin` with `stack=True, logy=False` and `log` with `stack=True, logy=True`.
75
+ With `variants={"stacked": {"stack": True}, "overlaid": {"stack": ["Background"]}}`,
76
+ every plot is drawn with the signal inside the stack and over it, from one set of
77
+ prepared histograms. With the signal last and `panel="s/sqrt(b)"` in
78
+ `plot_kwargs`, both show the same significance panel.
75
79
 
76
- Every other keyword of `rf.plot` (`observed=`, `normalize=`, `ratio=`,
80
+ Every other keyword of `rf.plot` (`observed=`, `normalize=`, `panel=`,
77
81
  `systematics=`, `style=`, ...) goes into `plot_kwargs` or a variant. The keyword
78
82
  names are checked against `rf.plot`'s signature when the book is built, so a
79
83
  misspelt `log_y` is reported, with `logy` as the suggestion, before anything is
@@ -133,7 +137,7 @@ reports it whatever the variable. A branch that a branch-replacement systematic
133
137
  replaces is kept only when its replacement is a plottable branch of the sample,
134
138
  since the replacement is read whenever the branch is. Stored histograms
135
139
  are left out whenever the book is bound to refuse them: a selection, a
136
- `weight`, `nonfinite="error"`, a `stats` box, a `range` without `bins`, or a
140
+ `weight`, `nonfinite="error"`, a `stats` box, or a
137
141
  systematic varying the weight or branches that applies to a sample (the plot's
138
142
  unless the sample's own source of that name replaces it, none for observed
139
143
  data), in the book's keywords or in any variant's. A file of stored histograms
@@ -257,7 +261,7 @@ a standalone figure.
257
261
 
258
262
  By default the grid of a page follows the plots it holds. Plots without a lower
259
263
  panel or broken axis go up to `2 × 3` on a page; when one of the plots that
260
- would land on a page has a `ratio=` panel or an `xbreak=`, which need the room,
264
+ would land on a page has a `panel=` or an `xbreak=`, which need the room,
261
265
  the page stops at `2 × 2`. The last page adapts to what is left rather than
262
266
  leaving a lone plot in the corner of a full grid: seven plain plots are a
263
267
  `2 × 3` page followed by a `1 × 1` one, eight a `2 × 3` page and a `1 × 2` one.
@@ -271,9 +275,9 @@ book.save_pdf("overview.pdf", layout=(2, 3))
271
275
  A page is as large as the grid of figures the plots would have on their own,
272
276
  plus a narrow gap between neighbouring cells, so a plot in a cell keeps its
273
277
  usual size: every cell of the document is as large as the largest figure any
274
- plot of the book would draw alone (a ratio panel makes it taller, a `Style` with
278
+ plot of the book would draw alone (a lower panel makes it taller, a `Style` with
275
279
  a `figsize` sets its own). A cell is laid out exactly as a figure of its size,
276
- whatever the grid and the style: the gap above a ratio panel, the room for
280
+ whatever the grid and the style: the gap above a lower panel, the room for
277
281
  labels, the legend and the y limits are the same on a `1 × 1` page as on an
278
282
  `8 × 8` one. The plots of a page are finished together, so a dense page takes
279
283
  about as long as the same plots on pages of their own. `figsize=` on
@@ -363,7 +367,7 @@ The book only reads less often than that call would. It runs the tasks in
363
367
  batches of a few dozen variables: the branches those variables and every
364
368
  selection need are read once per sample for the batch, the files a
365
369
  `Systematic.samples` variation fills from included, and variants that only
366
- change the drawing (`logy`, `normalize`, `ratio`, `style`, ...) are drawn from
370
+ change the drawing (`stack`, `logy`, `normalize`, `panel`, `style`, ...) are drawn from
367
371
  one set of prepared histograms, each figure from its own copy. A variant that
368
372
  changes how the histograms are prepared (`bins`, `weight`, `observed`,
369
373
  `systematics`, ...) is prepared on its own, still from the batch's read.
@@ -406,6 +410,63 @@ quietly producing an empty book.
406
410
  An axis the book was built without has the single choice `"all"` (selections)
407
411
  or `"default"` (variants); selecting it is a no-op and the axis stays implicit.
408
412
 
413
+ ## A complete example: histogram files
414
+
415
+ An analysis can write one histogram file per process. Files that already
416
+ contain expected yields are read as they are.
417
+ A `Group` combines the WW and ZZ processes into the VV background category.
418
+
419
+ ```python
420
+ import rootfig as rf
421
+
422
+ # Histogram files: one per process, already scaled to 5 ab^-1
423
+ ww = rf.Sample("outputs/p8_ee_WW_ecm240.root", label="WW")
424
+ zz = rf.Sample("outputs/p8_ee_ZZ_ecm240.root", label="ZZ")
425
+ zh = rf.Sample("outputs/p8_ee_ZH_ecm240.root", label="ZH")
426
+ samples = [rf.Group([ww, zz], label="VV"), zh]
427
+
428
+ fcc = rf.Style(experiment="FCC-ee", status="Simulation", com="240 GeV", lumi="5 ab^-1")
429
+ variants = {
430
+ "stack": {"stack": True}, # ZH on top of VV
431
+ "nostack": {"stack": ["VV"]}, # VV stacked, ZH drawn over it
432
+ "log": {"stack": ["VV"], "logy": True},
433
+ }
434
+
435
+ # every histogram the files share, at a glance
436
+ rf.PlotBook(samples, rf.ALL, variants=variants, plot_kwargs={"style": fcc}).save_pdf("overview.pdf")
437
+
438
+ # selected plots, with bins and a range for each histogram
439
+ variables = [
440
+ rf.Variable("zmumu_recoil_m", bins=(200, 120, 140), label="Recoil mass", unit="GeV"),
441
+ rf.Variable("zmumu_m", bins=(50, 86, 96), label=r"$m_{\mu\mu}$", unit="GeV"),
442
+ rf.Variable("zmumu_p", bins=(400, 0, 80), label=r"$p_{\mu\mu}$", unit="GeV"),
443
+ ]
444
+ rf.PlotBook(samples, variables, variants=variants, plot_kwargs={"style": fcc}).save_pdf("zh.pdf")
445
+ ```
446
+
447
+ The files are read once per batch of variables. The three variants of each
448
+ variable are drawn from one preparation, so changing the drawing does not
449
+ repeat the reads or the binning.
450
+
451
+ The stored 1 MeV recoil bins become 0.1 GeV bins between 120 and 140 GeV.
452
+ Everything outside that interval moves into the underflow or overflow bin,
453
+ including its uncertainty. `rf.ALL` keeps each histogram's own binning, which
454
+ suits an overview; explicit `Variable`s choose the ranges and bins to show.
455
+
456
+ The same plot can be made from ntuples storing the recoil mass as a branch. Give
457
+ the samples cross sections and generated-event counts to scale that plot to
458
+ the same luminosity:
459
+
460
+ ```python
461
+ ww = rf.Sample("ntuples/p8_ee_WW_ecm240/*.root", label="WW", xsec="16.4 pb", ngen="eventsProcessed")
462
+ zz = rf.Sample("ntuples/p8_ee_ZZ_ecm240/*.root", label="ZZ", xsec="1.36 pb", ngen="eventsProcessed")
463
+ zh = rf.Sample(
464
+ "ntuples/p8_ee_ZH_ecm240/*.root", label="ZH", xsec="0.202 pb", ngen="eventsProcessed"
465
+ )
466
+ recoil = rf.Variable("zed_leptonic_recoil_m", bins=(200, 120, 140), label="Recoil mass", unit="GeV")
467
+ rf.plot([rf.Group([ww, zz], label="VV"), zh], recoil, lumi="5 ab^-1", stack=["VV"], style=fcc)
468
+ ```
469
+
409
470
  ## What a book does not do
410
471
 
411
472
  A book runs its tasks one after another in the calling process and keeps the
@@ -29,11 +29,14 @@ mem = rf.Sample({"x": awkward_array, "w": weights}, label="in memory")
29
29
  - `selection` and `weight` belong to the sample and combine with the ones
30
30
  given to `plot()` (`&` and `*` respectively).
31
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.
32
+ unless `color` is set) and keeps the sample out of stacks. In a ratio,
33
+ relative difference, difference or pull panel it is compared with the
34
+ prediction by default; `reference=` can name it as the reference instead,
35
+ and a significance never takes data as a signal (see
36
+ [the roles](plotting.md#lower-panel)).
34
37
  - `xsec` and `ngen` describe simulated processes: the cross section (pb, or a
35
38
  string with a unit such as `"1.2 fb"`) and the number of generated events (a
36
- number, the name of an object in the file holding it, e.g. FCCAnalyses'
39
+ number, the name of an object in the file holding it, e.g.
37
40
  `"eventsProcessed"` `TParameter` or a sum-of-weights histogram, or `None`
38
41
  for the number of entries). With `lumi=` given to `plot()`, `cutflow()`,
39
42
  `summarize()`, ... every weight is multiplied by `xsec × lumi / ngen`:
@@ -49,7 +52,7 @@ mem = rf.Sample({"x": awkward_array, "w": weights}, label="in memory")
49
52
  trees; naming the histogram in place of the branch reads it (see
50
53
  [stored histograms](plotting.md#histograms-already-in-root-files)).
51
54
  - `entry_start`/`entry_stop` restrict reading for quick looks at large files
52
- (a plot reads every needed branch of every file into memory at once). For a
55
+ (a plot reads every file of the sample, a chunk of entries at a time). For a
53
56
  ready-made `FileSource`, give the range to the source itself; passing it to
54
57
  `Sample` afterwards raises a [`SourceError`][rootfig.SourceError].
55
58
  - `systematics={name: variation}` lists the sample's sources of systematic
@@ -121,7 +124,8 @@ met = rf.Variable(
121
124
  of edges (e.g. `rf.log_bins(30, 1, 1000)`), or a `hist.axis.Regular`/`Variable`.
122
125
  Applied to a histogram that already exists (stored in a file, or filled
123
126
  earlier and passed back with the variable), an `int` merges its bins down to
124
- that count and explicit edges must coincide with its own; see
127
+ that count and explicit edges must coincide with its own. The histogram is
128
+ merged and cropped to the requested edges, with the rest in flow bins; see
125
129
  [Histograms that already exist](plotting.md#histograms-that-already-exist).
126
130
  - `range`: `(low, high)`, `"robust"` (the default: ignores far outliers such as
127
131
  `-999` sentinels and cuts a thin tail, both of which then land in the
@@ -194,7 +198,7 @@ samples = [bkg, sig]
194
198
  variables = [pt, met, rf.Variable("nMuon", bins=(8, -0.5, 7.5))]
195
199
 
196
200
  for var in variables:
197
- p = rf.plot(samples, var, observed=data, selection=sr, stack=True, ratio=True, style=atlas)
201
+ p = rf.plot(samples, var, observed=data, selection=sr, stack=True, panel="ratio", style=atlas)
198
202
  p.save("plots/") # plots/Muon_pt.pdf, plots/met.pdf, plots/nMuon.pdf
199
203
  p.close()
200
204
  ```
@@ -208,6 +212,6 @@ rf.PlotBook(
208
212
  variables,
209
213
  selections={"baseline": base, "sr": sr},
210
214
  variants={"lin": {}, "log": {"logy": True}},
211
- plot_kwargs={"observed": data, "stack": True, "ratio": True, "style": atlas},
215
+ plot_kwargs={"observed": data, "stack": True, "panel": "ratio", "style": atlas},
212
216
  ).save("plots/") # plots/Muon_pt__sr__log.pdf, ...
213
217
  ```
@@ -41,8 +41,8 @@ adds the summing over files, the scaling and the drawing.
41
41
  ships the style sheets and label helpers of the LHC experiments. rootfig
42
42
  draws every histogram through `mplhep.histplot`/`hist2dplot` and uses
43
43
  mplhep's per-experiment label functions when a `Style(experiment=...)` is
44
- given. The experiment-neutral default style and the ratio panel are
45
- rootfig's.
44
+ given. The experiment-neutral default style and the lower panel (ratios,
45
+ differences, pulls, significances) are rootfig's.
46
46
 
47
47
  ## matplotlib
48
48
 
@@ -51,14 +51,30 @@ applies its style only inside a `plt.style.context` while drawing, so it does
51
51
  not change global rcParams (unless you call `rf.use_style`). Anything you
52
52
  would do to a matplotlib figure, you can do to `Plot.fig` and `Plot.ax`.
53
53
 
54
+ ## Trees and histogram files
55
+
56
+ rootfig reads trees and stored `TH1`/`TH2` histograms without ROOT, independently
57
+ of the framework that wrote them. A `Sample` identifies each input process,
58
+ a `Group` combines processes into a category, and `stack=` selects the categories
59
+ to stack. Files already scaled to expected yields are read as they are; trees
60
+ can be scaled with `Sample(xsec=..., ngen=...)` and `lumi=`.
61
+
62
+ The same `Variable` describes a stored histogram and the branch it was filled
63
+ from: its bins and range crop and merge existing bins, moving the rest into
64
+ flow bins. `PlotBook` prepares each variable once for its drawing variants and
65
+ can discover shared histograms with `rf.ALL`. See the
66
+ [complete histogram-file example](batch.md#a-complete-example-histogram-files).
67
+
54
68
  ## When to use something else
55
69
 
56
- - You already have flat NumPy columns or `boost-histogram` objects and want
57
- rich comparison panels: [plothist](https://plothist.readthedocs.io).
70
+ - You have flat NumPy columns rather than ROOT files or histograms, or want a
71
+ comparison rootfig's lower panel does not offer (an asymmetry, efficiency or
72
+ goodness-of-fit panel): [plothist](https://plothist.readthedocs.io).
58
73
  - You need a full columnar analysis framework with lazy, distributed
59
74
  processing: [coffea](https://coffeateam.github.io/coffea/). rootfig reads
60
- every branch a plot needs from every file into memory at once (only the
61
- required branches, optionally an entry range), which suits quick looks and
62
- moderate ntuples, not multi-terabyte datasets.
75
+ the branches a plot needs a chunk of entries at a time, in threads, and holds
76
+ the values it fills (see [large inputs](plotting.md#large-inputs)), all in one
77
+ process: it suits quick looks and ntuples that one machine reads in minutes,
78
+ not multi-terabyte datasets.
63
79
  - You want to build fit templates and workspaces: [cabinetry](https://cabinetry.readthedocs.io).
64
80
  - You want a quick terminal look at a branch: [histoprint](https://github.com/scikit-hep/histoprint).
@@ -120,7 +120,10 @@ weights (`hist` `Weight` storage).
120
120
  ## Missing and non-finite values
121
121
 
122
122
  `None` values (e.g. `max(Muon_pt)` of an event with no muons) never enter a
123
- histogram; in a selection they count as `False`. `nan` and `inf` values are
123
+ histogram; in a selection they count as `False`. A whole collection that is
124
+ `None` for an event, whether the variable's, the weight's or the one a
125
+ per-object selection is evaluated on, drops that event, and its objects are
126
+ counted as missing. `nan` and `inf` values are
124
127
  dropped with a [`RootfigWarning`][rootfig.RootfigWarning] telling you how
125
128
  many, or raise with `nonfinite="error"`. Both counts are recorded in the
126
129
  histogram's `stats`.