quantized-lab 0.8.0__py3-none-any.whl
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.
- quantized/__init__.py +11 -0
- quantized/__main__.py +14 -0
- quantized/api.py +220 -0
- quantized/app.py +206 -0
- quantized/calc/__init__.py +8 -0
- quantized/calc/_clipfit.py +76 -0
- quantized/calc/_natural_neighbor.py +219 -0
- quantized/calc/aggregate.py +159 -0
- quantized/calc/backgrounds.py +353 -0
- quantized/calc/baseline.py +349 -0
- quantized/calc/batch_fit.py +148 -0
- quantized/calc/constants.py +27 -0
- quantized/calc/corrections.py +192 -0
- quantized/calc/crystallography.py +400 -0
- quantized/calc/diffusion.py +120 -0
- quantized/calc/electrical.py +248 -0
- quantized/calc/electrochemistry.py +176 -0
- quantized/calc/element_data.json +1 -0
- quantized/calc/element_data.py +59 -0
- quantized/calc/errors.py +246 -0
- quantized/calc/figure.py +417 -0
- quantized/calc/figure_break.py +152 -0
- quantized/calc/figure_categorical.py +156 -0
- quantized/calc/figure_corner.py +229 -0
- quantized/calc/figure_facets.py +127 -0
- quantized/calc/figure_field.py +137 -0
- quantized/calc/figure_hitmap.py +116 -0
- quantized/calc/figure_labels.py +62 -0
- quantized/calc/figure_map.py +287 -0
- quantized/calc/figure_overrides.py +159 -0
- quantized/calc/figure_page.py +266 -0
- quantized/calc/figure_scale.py +125 -0
- quantized/calc/figure_statplots.py +167 -0
- quantized/calc/figure_styles.py +131 -0
- quantized/calc/figure_ternary.py +239 -0
- quantized/calc/figure_ticks.py +217 -0
- quantized/calc/fit_autoguess.py +156 -0
- quantized/calc/fit_bootstrap.py +163 -0
- quantized/calc/fit_bumps.py +258 -0
- quantized/calc/fit_constraints.py +114 -0
- quantized/calc/fit_equation.py +264 -0
- quantized/calc/fit_findxy.py +80 -0
- quantized/calc/fit_models.py +195 -0
- quantized/calc/fit_models_special.py +189 -0
- quantized/calc/fit_odr.py +99 -0
- quantized/calc/fit_scan.py +243 -0
- quantized/calc/fit_stats.py +215 -0
- quantized/calc/fitting.py +199 -0
- quantized/calc/formula.py +90 -0
- quantized/calc/global_curve_fit.py +305 -0
- quantized/calc/global_fit.py +181 -0
- quantized/calc/interp2d.py +260 -0
- quantized/calc/linecut.py +269 -0
- quantized/calc/magnetic.py +414 -0
- quantized/calc/magnetometry.py +464 -0
- quantized/calc/map.py +228 -0
- quantized/calc/mcmc.py +177 -0
- quantized/calc/optics.py +228 -0
- quantized/calc/pawley.py +251 -0
- quantized/calc/peak_batch.py +128 -0
- quantized/calc/peak_fit.py +259 -0
- quantized/calc/peak_integrate.py +104 -0
- quantized/calc/peak_multifit.py +260 -0
- quantized/calc/peak_track.py +134 -0
- quantized/calc/peaks.py +298 -0
- quantized/calc/peakshapes.py +85 -0
- quantized/calc/plotting.py +147 -0
- quantized/calc/processing.py +232 -0
- quantized/calc/qspace.py +48 -0
- quantized/calc/reductions.py +155 -0
- quantized/calc/reductions_fft.py +383 -0
- quantized/calc/refl_sld_presets.json +1 -0
- quantized/calc/reflectivity.py +80 -0
- quantized/calc/registry.py +303 -0
- quantized/calc/relaxation.py +119 -0
- quantized/calc/report.py +253 -0
- quantized/calc/report_emit.py +227 -0
- quantized/calc/resample.py +142 -0
- quantized/calc/rsm.py +91 -0
- quantized/calc/rsm_analyze.py +245 -0
- quantized/calc/semiconductor.py +488 -0
- quantized/calc/sld.py +131 -0
- quantized/calc/sld_formula.py +138 -0
- quantized/calc/spectral.py +357 -0
- quantized/calc/statplots.py +214 -0
- quantized/calc/stats.py +399 -0
- quantized/calc/stats_anova2.py +202 -0
- quantized/calc/stats_anova_ext.py +338 -0
- quantized/calc/stats_dist.py +196 -0
- quantized/calc/stats_glm.py +245 -0
- quantized/calc/stats_multivar.py +289 -0
- quantized/calc/stats_roc.py +157 -0
- quantized/calc/stats_survival.py +261 -0
- quantized/calc/stats_tests.py +380 -0
- quantized/calc/substrates.py +181 -0
- quantized/calc/superconductor.py +359 -0
- quantized/calc/surface_fit.py +290 -0
- quantized/calc/surface_models.py +156 -0
- quantized/calc/thermal.py +119 -0
- quantized/calc/thin_film.py +425 -0
- quantized/calc/unit_convert.py +259 -0
- quantized/calc/units.py +80 -0
- quantized/calc/vacuum.py +290 -0
- quantized/calc/xray.py +169 -0
- quantized/cli.py +214 -0
- quantized/datastruct.py +153 -0
- quantized/io/__init__.py +11 -0
- quantized/io/_hdf5_layout.py +308 -0
- quantized/io/_jcamp_asdf.py +135 -0
- quantized/io/_xrdml_scan.py +291 -0
- quantized/io/base.py +82 -0
- quantized/io/bruker_brml.py +177 -0
- quantized/io/bruker_raw.py +158 -0
- quantized/io/cif.py +266 -0
- quantized/io/consolidated.py +122 -0
- quantized/io/delimited.py +222 -0
- quantized/io/excel.py +135 -0
- quantized/io/hdf5.py +192 -0
- quantized/io/import_filters.py +178 -0
- quantized/io/import_preview.py +262 -0
- quantized/io/jcamp.py +179 -0
- quantized/io/lakeshore.py +163 -0
- quantized/io/ncnr.py +278 -0
- quantized/io/netcdf.py +195 -0
- quantized/io/opus.py +231 -0
- quantized/io/origin.py +346 -0
- quantized/io/origin_com.py +194 -0
- quantized/io/origin_project/__init__.py +221 -0
- quantized/io/origin_project/annotation_marks.py +288 -0
- quantized/io/origin_project/container.py +262 -0
- quantized/io/origin_project/curve_style_color.py +359 -0
- quantized/io/origin_project/figure_geometry.py +108 -0
- quantized/io/origin_project/figure_layers.py +333 -0
- quantized/io/origin_project/figure_text.py +258 -0
- quantized/io/origin_project/figures.py +210 -0
- quantized/io/origin_project/figures_opju.py +440 -0
- quantized/io/origin_project/notes.py +302 -0
- quantized/io/origin_project/opj.py +459 -0
- quantized/io/origin_project/opj_curves.py +297 -0
- quantized/io/origin_project/opj_shapes.py +148 -0
- quantized/io/origin_project/opju.py +146 -0
- quantized/io/origin_project/opju_axis_real_form.py +418 -0
- quantized/io/origin_project/opju_axis_specimen_form.py +167 -0
- quantized/io/origin_project/opju_codec.py +370 -0
- quantized/io/origin_project/opju_curves.py +497 -0
- quantized/io/origin_project/opju_curves_allcols.py +258 -0
- quantized/io/origin_project/opju_figure_curves.py +302 -0
- quantized/io/origin_project/opju_figure_text.py +245 -0
- quantized/io/origin_project/opju_reports.py +129 -0
- quantized/io/origin_project/origin_richtext.py +145 -0
- quantized/io/origin_project/preview.py +132 -0
- quantized/io/origin_project/templates.py +314 -0
- quantized/io/origin_project/tree.py +379 -0
- quantized/io/origin_project/tree_opju.py +228 -0
- quantized/io/origin_project/windows.py +238 -0
- quantized/io/origin_project/windows_opju.py +393 -0
- quantized/io/origin_project/writer.py +156 -0
- quantized/io/origin_project/writer_blocks.py +282 -0
- quantized/io/qd.py +380 -0
- quantized/io/refl1d.py +132 -0
- quantized/io/registry.py +210 -0
- quantized/io/report_export.py +347 -0
- quantized/io/rigaku.py +100 -0
- quantized/io/sims.py +398 -0
- quantized/io/spc.py +311 -0
- quantized/io/xrd_csv.py +308 -0
- quantized/io/xrdml.py +394 -0
- quantized/jobs.py +173 -0
- quantized/plugins/__init__.py +50 -0
- quantized/plugins/contract.py +111 -0
- quantized/plugins/loader.py +394 -0
- quantized/plugins/steps.py +90 -0
- quantized/routes/__init__.py +7 -0
- quantized/routes/_bookcache.py +62 -0
- quantized/routes/_export_common.py +27 -0
- quantized/routes/_payload.py +58 -0
- quantized/routes/_uploadcache.py +59 -0
- quantized/routes/aggregate.py +46 -0
- quantized/routes/baseline.py +210 -0
- quantized/routes/books.py +117 -0
- quantized/routes/calc.py +56 -0
- quantized/routes/corrections.py +78 -0
- quantized/routes/crystallography.py +80 -0
- quantized/routes/diffusion.py +58 -0
- quantized/routes/electrical.py +101 -0
- quantized/routes/electrochemistry.py +83 -0
- quantized/routes/export.py +280 -0
- quantized/routes/export_facets.py +83 -0
- quantized/routes/export_figures.py +471 -0
- quantized/routes/export_page.py +125 -0
- quantized/routes/fitting.py +379 -0
- quantized/routes/fitting_bumps.py +97 -0
- quantized/routes/import_template.py +97 -0
- quantized/routes/import_wizard.py +150 -0
- quantized/routes/jobs_api.py +59 -0
- quantized/routes/magnetic.py +135 -0
- quantized/routes/magnetometry.py +133 -0
- quantized/routes/optics.py +98 -0
- quantized/routes/parsers.py +281 -0
- quantized/routes/peaks.py +184 -0
- quantized/routes/plot.py +103 -0
- quantized/routes/reductions.py +121 -0
- quantized/routes/reference.py +58 -0
- quantized/routes/reflectivity.py +91 -0
- quantized/routes/report_export.py +119 -0
- quantized/routes/rsm.py +136 -0
- quantized/routes/samples.py +32 -0
- quantized/routes/semiconductor.py +207 -0
- quantized/routes/sld.py +42 -0
- quantized/routes/spectral.py +54 -0
- quantized/routes/statplots.py +99 -0
- quantized/routes/stats.py +418 -0
- quantized/routes/stats_design.py +321 -0
- quantized/routes/substrates.py +46 -0
- quantized/routes/superconductor.py +139 -0
- quantized/routes/thermal.py +57 -0
- quantized/routes/thin_film.py +153 -0
- quantized/routes/vacuum.py +113 -0
- quantized/routes/xray.py +32 -0
- quantized/samples/demo_vsm.csv +42 -0
- quantized/server_launch.py +251 -0
- quantized/web/assets/JetBrainsMono-Bold-CUogYd9I.woff2 +0 -0
- quantized/web/assets/JetBrainsMono-Regular-CA-Os4ii.woff2 +0 -0
- quantized/web/assets/index-BHmmCL-x.js +27 -0
- quantized/web/assets/index-BiZzN7J6.css +1 -0
- quantized/web/index.html +13 -0
- quantized/web/loading.html +69 -0
- quantized_lab-0.8.0.dist-info/METADATA +122 -0
- quantized_lab-0.8.0.dist-info/RECORD +233 -0
- quantized_lab-0.8.0.dist-info/WHEEL +4 -0
- quantized_lab-0.8.0.dist-info/entry_points.txt +4 -0
- quantized_lab-0.8.0.dist-info/licenses/LICENSE +201 -0
- quantized_lab-0.8.0.dist-info/licenses/NOTICE +11 -0
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
"""Per-curve dataset/column binding for ``.opju`` (CPYUA) graph figures (item 35).
|
|
2
|
+
|
|
3
|
+
Every curve (``DataPlot``) object carries its own copy of the generic CPYUA
|
|
4
|
+
"graph object" header (the same ``58 80 09 98 03 40 B3 <u32 bodyLen>`` shape
|
|
5
|
+
axis/legend/config objects also use — this header is NOT curve-exclusive, so
|
|
6
|
+
it cannot be located by the magic bytes alone). Immediately inside a curve's
|
|
7
|
+
own body, at a position anchored right after the object's name token
|
|
8
|
+
(auto-named ``_NNN``, mirroring ``.opj``'s convention — see ``figures.py``),
|
|
9
|
+
sits a small fixed-shape token that was diffed out of a purpose-built
|
|
10
|
+
oracle, ``fig_pairs.opju`` (one project, 4 graphs: A-B scatter, A-B scatter
|
|
11
|
+
log-Y, **A-C scatter** — the deliberate diff — and A-B line; see
|
|
12
|
+
``tools/origin_trial/generate_specimens.py``'s ``fig_pairs`` section, whose
|
|
13
|
+
LabTalk ``plotxy iy:=`` calls are the ground truth since Origin's own GT
|
|
14
|
+
exporter did not capture this — see "Missing oracle" below):
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
<flag:1> 01 <konst:1> 01 80 03 <y_ord:1> 00
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Byte-for-byte diffing all 4 fig_pairs curves against each other (2 pairs
|
|
21
|
+
share columns A,B; one pair differs only in log-Y; one differs only in plot
|
|
22
|
+
type line-vs-scatter; one — the deliberate diff — plots A,C instead of A,B)
|
|
23
|
+
isolated exactly 2 differing bytes total: ``flag`` (a per-curve
|
|
24
|
+
creation-order/style counter — increments monotonically across curves
|
|
25
|
+
regardless of column choice, confirmed unrelated) and ``y_ord`` (changes
|
|
26
|
+
from ``0x02`` to ``0x03`` in lockstep with the B->C column swap, and only
|
|
27
|
+
then). ``y_ord`` is a **1-based ordinal counted cumulatively across every
|
|
28
|
+
column of every workbook the project's FPC codec (``opju_codec.scan_columns``)
|
|
29
|
+
actually decoded, in book-appearance order** (a book with zero decodable
|
|
30
|
+
columns — e.g. an unused default "Book1" — does not participate in the
|
|
31
|
+
count; confirmed by reproducing the corpus's own book/column layout and
|
|
32
|
+
finding the decoded ordinal always lands exactly on the expected column).
|
|
33
|
+
|
|
34
|
+
**Validation.**
|
|
35
|
+
|
|
36
|
+
* ``fig_pairs`` (self-authored, by-construction ground truth — Origin's own
|
|
37
|
+
exporter has no oracle for this, see below): the byte pattern's regex
|
|
38
|
+
``.\\x01.\\x01\\x80\\x03.\\x00`` finds *exactly* the 4 expected curve
|
|
39
|
+
tokens in the whole file (no false positives), and every ``y_ord`` decodes
|
|
40
|
+
to the exact column the generation script plotted (A,B / A,B / **A,C** /
|
|
41
|
+
A,B) — all 4 survive the designation gate below unchanged.
|
|
42
|
+
``test_realdata_fig_pairs_curve_bindings`` asserts this exactly.
|
|
43
|
+
* Real corpus (RockingCurve, XAS, UnpolPlots, "Fixed Lambdas SI" — no GT
|
|
44
|
+
oracle available either, see below): a whole-file scan finds ~40 curve
|
|
45
|
+
tokens; scoped per decoded figure's window and passed through the
|
|
46
|
+
designation gate, 2-4 survive per file (12 total across the 4 files) —
|
|
47
|
+
every single one lands on a column ``windows_opju.py`` independently
|
|
48
|
+
designates ``"Y"`` (never ``"X"``/``"Y-error"``) with a physically-sensible
|
|
49
|
+
dependent-variable long-name (``Intensity``, ``Absorption``, ``R``,
|
|
50
|
+
"Theory SA"), never an independent-variable one (``Theta``, ``Energy``,
|
|
51
|
+
``Q``, ``Z``). RockingCurve's ``NbAuRocking`` figure's surviving curve
|
|
52
|
+
count also matches the independent legend-derived ``n_curves`` signal
|
|
53
|
+
exactly (2 == 2). ``test_realdata_real_corpus_curves_are_plausible``
|
|
54
|
+
asserts the designation/long-name check for all four files.
|
|
55
|
+
|
|
56
|
+
**Missing oracle.** ``tools/origin_trial/export_ground_truth.py`` was meant
|
|
57
|
+
to dump Origin's own per-plot dataset references (``layer.nplots`` +
|
|
58
|
+
``range __rp = {pi}; ... __rp.name$``) into each ``index.json``'s
|
|
59
|
+
``graphs[].layers[].plots`` list. In every project exported in this corpus
|
|
60
|
+
that list comes back **empty** (a LabTalk/COM issue in that trial-window
|
|
61
|
+
script — the ``range __rp = {pi}`` assignment does not behave as
|
|
62
|
+
documented — not something fixable here: this module is pure byte-level RE,
|
|
63
|
+
no Origin). So no direct "Origin says the answer is X" string match was
|
|
64
|
+
possible for curve bindings, for either the specimens or the real corpus;
|
|
65
|
+
validation instead rests on the by-construction specimen (still a real
|
|
66
|
+
ground truth — the script wrote the ``iy:=`` argument, we did not invent
|
|
67
|
+
it) plus the designation gate and independent-signal cross-checks above.
|
|
68
|
+
|
|
69
|
+
**Known gap — per-figure attribution (significant recall loss).** Deciding
|
|
70
|
+
*which* of a graph's curve tokens belongs to *which* decoded axis-anchor
|
|
71
|
+
window is a best-effort byte-range heuristic: a curve counts toward a figure
|
|
72
|
+
only when its token falls inside ``[anchor, next_anchor)`` AND survives the
|
|
73
|
+
designation gate. This drops the *majority* of curve tokens for composite/
|
|
74
|
+
derived real-corpus graphs — confirmed: "Fixed Lambdas SI"'s ten cleanest
|
|
75
|
+
tokens (each landing exactly on a different PNR book's reflectivity column,
|
|
76
|
+
one per book) sit entirely *outside* all four of that file's decoded
|
|
77
|
+
figures' windows, so none of them ship; what each figure gets instead is
|
|
78
|
+
whatever handful of tokens happen to sit inside its own narrow window (often
|
|
79
|
+
just 1, and not necessarily the "main" curve a user would expect). XAS's
|
|
80
|
+
``Co`` self-curve and two of UnpolPlots's curves are similarly never
|
|
81
|
+
attributed to any figure. This is an honest, *significant* recall gap, not a
|
|
82
|
+
soundness one: every curve that IS reported is independently confirmed
|
|
83
|
+
(designation + long-name), never fabricated or mis-typed. Closing it needs
|
|
84
|
+
either a real oracle (the missing ``plots`` export) or a further RE pass to
|
|
85
|
+
locate the object boundary that actually scopes a curve to its owning
|
|
86
|
+
layer (not yet found).
|
|
87
|
+
|
|
88
|
+
**Multi-curve-per-layer and multi-book layout — confirmed against two new
|
|
89
|
+
controlled specimens (item 35 recall push, 2026-07-04).** ``curves_multi.opju``
|
|
90
|
+
(one graph, one layer, three curves — MBook B/C/D vs A) and
|
|
91
|
+
``curves_2books.opju`` (one graph, curves from two different books —
|
|
92
|
+
``BookOne!B`` and ``BookTwo!C``) were purpose-built to answer two open
|
|
93
|
+
questions: how do *multiple* curve tokens sit in one layer, and does the
|
|
94
|
+
cumulative-ordinal base really carry over correctly across a book boundary?
|
|
95
|
+
Both answers turn out to be exactly what this module already implements,
|
|
96
|
+
with **zero code change required** — these specimens are validating
|
|
97
|
+
regression tests, not bug reports:
|
|
98
|
+
|
|
99
|
+
* *Multi-curve layout*: each curve is a fully self-contained, back-to-back
|
|
100
|
+
copy of the same ~750-900-byte "graph object" (the generic
|
|
101
|
+
``58 80 09 98 03 40 B3`` header + its own style/pen sub-records + its own
|
|
102
|
+
copy of the 8-byte token). ``curves_multi``'s three curves' tokens sit at
|
|
103
|
+
offsets 789 bytes apart, each with a strictly increasing ``y_ord``
|
|
104
|
+
(``0x02``, ``0x03``, ``0x04`` — MBook's B, C, D) and no shared/wrapper
|
|
105
|
+
record binding them together. There is no "run" or "count" prefix to
|
|
106
|
+
decode; the whole-file regex scan already finds all three independently,
|
|
107
|
+
and every one survives the designation gate and resolves correctly.
|
|
108
|
+
* *Cross-book base*: ``curves_2books`` plots ``BookOne!B`` (``y_ord=2``,
|
|
109
|
+
since BookOne contributes columns 1-2) and ``BookTwo!C`` (``y_ord=5``,
|
|
110
|
+
since BookOne's 2 columns are counted before BookTwo's 3 start at ordinal
|
|
111
|
+
3) — exactly what ``_global_column_map``'s cumulative, book-appearance-order
|
|
112
|
+
counting already produces. No change needed.
|
|
113
|
+
|
|
114
|
+
Both specimens decode with 100% precision *and* 100% recall via the
|
|
115
|
+
existing pipeline (regex → designation gate → BCO gate), confirmed by
|
|
116
|
+
``test_realdata_curves_multi_bindings`` and
|
|
117
|
+
``test_realdata_curves_2books_bindings``. This raises the aggregate
|
|
118
|
+
oracle-covered recall from 6/31 (19.4%) to 11/36 (30.6%) — see
|
|
119
|
+
``docs/origin_project_format.md`` §6.2.1 for the updated per-stem table.
|
|
120
|
+
|
|
121
|
+
**A second near-miss shape, found and confirmed excluded — the per-book
|
|
122
|
+
"column candidate list."** Investigating why real-corpus recall stays far
|
|
123
|
+
below what these clean specimens suggest turned up a second decoy shape,
|
|
124
|
+
structurally distinct from ``__BCO`` but with the same danger profile: a
|
|
125
|
+
run of 7-byte records, one per column of a referenced book, in column
|
|
126
|
+
order —
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
<flag:1> 01 <marker:1> 80 03 <ord:1> 00
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
— found near *every* book reference in *every* file checked, both new
|
|
133
|
+
specimens included (e.g. ``curves_multi`` shows MBook's A/B/C/D enumerated
|
|
134
|
+
this way *in addition to* the three real per-curve tokens). It is one byte
|
|
135
|
+
*shorter* than the real curve token — a single ``0x01`` (position 1) then
|
|
136
|
+
straight to ``0x80 0x03``, never the real token's ``01 .. 01 80 03`` double
|
|
137
|
+
``0x01`` — so it can **never** satisfy ``_CURVE_RE`` (which requires two
|
|
138
|
+
literal ``0x01`` bytes at positions 1 and 3); confirmed by direct
|
|
139
|
+
byte-window inspection, not just by construction. Whether this list's
|
|
140
|
+
entries carry *any* independently-decodable "this one is selected" marker
|
|
141
|
+
was checked directly (tail bytes compared item-by-item across several
|
|
142
|
+
real-corpus runs, e.g. "Fixed Lambdas SI"'s ``PNRNbAu100nm`` A-K run) — they
|
|
143
|
+
do not; the items are byte-identical in shape apart from the running
|
|
144
|
+
ordinal. In every run checked, the columns that happen to be *actually*
|
|
145
|
+
plotted are the run's *last* one to three entries, but that is a corpus
|
|
146
|
+
*convention* (derived "SA"/"dSA"/"Theory SA" analysis columns are
|
|
147
|
+
habitually appended last), not a decodable structural signal — using
|
|
148
|
+
"trust the tail of the list" would be exactly the kind of guess this
|
|
149
|
+
module's design forbids, and was rejected.
|
|
150
|
+
``test_synthetic_column_enum_list_not_mistaken_for_curve_token`` is a
|
|
151
|
+
regression guard: a future regex relaxation must not start accepting this
|
|
152
|
+
shape.
|
|
153
|
+
|
|
154
|
+
**Remaining gap, sharpened by the above.** RockingCurve's ``Graph1``
|
|
155
|
+
(``Nb!B``) and ``Graph2`` (``NbAl!B``), and essentially all of XAS's and
|
|
156
|
+
UnpolPlots's oracle-required curves, have **neither** a real 8-byte token
|
|
157
|
+
**nor** a column-candidate-list tail match anywhere in the file — an
|
|
158
|
+
exhaustive whole-file regex scan (both shapes) confirms zero candidates
|
|
159
|
+
exist for these pairs at all. These are ordinary, single-curve, default-
|
|
160
|
+
dialog graphs (unlike ``NbAuRocking``'s custom-styled multi-curve layer,
|
|
161
|
+
or "Fixed Lambdas SI"'s "Theory SA" reference-overlay curves, both of which
|
|
162
|
+
DO carry the real token) — Origin evidently encodes their column choice a
|
|
163
|
+
third way, not yet located. This — not the multi-curve/multi-book layout,
|
|
164
|
+
which is solved — is why real-corpus recall stays low; closing it needs a
|
|
165
|
+
further RE pass specifically on simple/default single-curve graphs.
|
|
166
|
+
|
|
167
|
+
**X is not decoded.** ``konst`` (the position a naive by-symmetry read would
|
|
168
|
+
expect an X-column ordinal to occupy) was observed as exactly ``0x01`` in
|
|
169
|
+
*every one* of ~44 samples across the specimen and the full real corpus —
|
|
170
|
+
zero variation, including cases whose Y column belongs to a *different*
|
|
171
|
+
workbook than the layer's other curves. That is equally consistent with
|
|
172
|
+
"X is always column A" and with "this byte is an unrelated constant,
|
|
173
|
+
unconfirmed to be a column selector at all" — no specimen ever varied X, so
|
|
174
|
+
neither reading can be confirmed and it is not reported as a decoded value.
|
|
175
|
+
Instead, ``"x"`` in this module's output is a **structural inference**: the
|
|
176
|
+
Y column's own workbook's first column — Origin's near-universal per-sheet
|
|
177
|
+
X designation, independently confirmed via ``windows_opju.py``'s validated
|
|
178
|
+
designation markers for every corpus book checked here. This may be wrong
|
|
179
|
+
for a workbook whose designated X column is not the first one; no such case
|
|
180
|
+
was observed in this corpus.
|
|
181
|
+
|
|
182
|
+
**Designation gate (precision over recall).** The whole-file regex scan is
|
|
183
|
+
not curve-exclusive enough on its own: one real-corpus file ("Fixed Lambdas
|
|
184
|
+
SI") produced a ``y_ord`` landing on a ``Y-error`` column (``dQ``, a PNR
|
|
185
|
+
uncertainty column) inside a decoded figure's window — clearly not a real
|
|
186
|
+
plotted curve. Rather than report it, every resolved ``y`` column is
|
|
187
|
+
cross-checked against ``windows_opju.opju_window_metadata``'s independently
|
|
188
|
+
validated per-column designation and **dropped unless it is exactly
|
|
189
|
+
``"Y"``** (never ``"X"``, ``"Y-error"``, or unresolved). This trades recall
|
|
190
|
+
for precision, matching the "never guess" rule: some real curves are lost
|
|
191
|
+
when a book's window-section metadata doesn't resolve (windows_opju.py's own
|
|
192
|
+
documented limitation), but nothing reported here is a mis-typed column.
|
|
193
|
+
|
|
194
|
+
**False positive found and fixed — the ``__BCO`` boilerplate (item 35
|
|
195
|
+
rework, 2026-07-04).** Once a real per-plot oracle existed (``plots.json``,
|
|
196
|
+
via ``tools/origin_trial/export_plot_refs.py``'s ``range -w`` LabTalk recipe
|
|
197
|
+
— the earlier ``layer.nplots``/``range __rp`` approach used by
|
|
198
|
+
``export_ground_truth.py`` never worked, see below), it exposed 2 false
|
|
199
|
+
positives: ``UnpolPlots`` decoded ``(PrNiO3STOprof, C)`` and
|
|
200
|
+
``(PrNiO3STOrefl, C)``, but the oracle plots neither book's column C at all
|
|
201
|
+
(the real bindings are ``B`` and ``G``/``H``/``I`` respectively). Root
|
|
202
|
+
cause: the whole-file regex also matches the *tail* of a completely
|
|
203
|
+
unrelated, fixed ~365-byte-long per-book boilerplate record that begins at a
|
|
204
|
+
length-prefixed ``__BCO2`` (occasionally ``__BCO3`` etc.) string — one per
|
|
205
|
+
book, byte-for-byte identical across every book in every file checked
|
|
206
|
+
(``XAS``, ``UnpolPlots``, ``"Fixed Lambdas SI"``) aside from a handful of
|
|
207
|
+
small varying counter/row-count fields. This record's last 8 bytes always
|
|
208
|
+
happen to fit the curve-token shape and always resolve to **local column 3
|
|
209
|
+
(index 2, i.e. always "C")** of its own book — not because it references
|
|
210
|
+
any column at all, but because that offset in the fixed template always
|
|
211
|
+
holds the literal value 3. It is *not* curve-exclusive: it exists whether or
|
|
212
|
+
not that book is plotted anywhere, and for a 3-column book whose real Y
|
|
213
|
+
column *happens* to be column C (every XAS book: ``Co``/``bl11YIGPy032``/
|
|
214
|
+
``bl11YIGPy033``, all plotting ``Intensity`` at C) the artifact is
|
|
215
|
+
coincidentally "correct" — which is how it went undetected before the
|
|
216
|
+
plots.json oracle existed. ``UnpolPlots``' books use column C for a
|
|
217
|
+
*different* quantity than what's plotted (``Absorption``/``R``, not the
|
|
218
|
+
real ``Nuclear``/``R-Rsub`` curves), exposing the coincidence as a false
|
|
219
|
+
positive.
|
|
220
|
+
|
|
221
|
+
Fix: :func:`_is_bco_boilerplate` requires **both** confirmed structural
|
|
222
|
+
signals before excluding a match — (1) the match sits 340-380 bytes past a
|
|
223
|
+
preceding ``__BCO`` marker (the exact span measured across every confirmed
|
|
224
|
+
instance: 357-360 bytes) **and** (2) the resolved column is local index 2.
|
|
225
|
+
Neither signal alone is safe to use: distance alone is untested against
|
|
226
|
+
unseen templates; "local column 3" alone would wrongly exclude a real curve
|
|
227
|
+
that legitimately plots that position (``fig_pairs``' A-C diff curve also
|
|
228
|
+
resolves to local column 3, but at a completely different, ~1288-byte
|
|
229
|
+
distance from any ``__BCO`` marker, and is correctly kept). Applying this
|
|
230
|
+
filter removes exactly the ``UnpolPlots`` false positives and, incidentally,
|
|
231
|
+
the previously "correct-by-coincidence" ``XAS`` pair (``Co``/
|
|
232
|
+
``bl11YIGPy032``/``bl11YIGPy033``, all local-column-3) — these were never
|
|
233
|
+
soundly decoded, only luckily right, and reporting them would contradict the
|
|
234
|
+
"replicate the method, not just the answer" porting principle. See
|
|
235
|
+
``tests/test_io_origin_figures_opju.py``'s realdata precision/recall suite
|
|
236
|
+
and ``docs/origin_project_format.md`` §6.2.1 for the corrected validation
|
|
237
|
+
counts.
|
|
238
|
+
|
|
239
|
+
**The "third encoding" search — negative result (item 35, 2026-07-04).**
|
|
240
|
+
A further session went looking specifically for how ordinary, single-curve,
|
|
241
|
+
*default-dialog* graphs (``RockingCurve`` ``Graph1``/``Graph2``, all of
|
|
242
|
+
``XAS``, all of ``UnpolPlots``, most of ``"Fixed Lambdas SI"``) encode their
|
|
243
|
+
Y column, since neither the real 8-byte token nor the column-candidate-list
|
|
244
|
+
shape exists anywhere in their files. Three leads were chased; none
|
|
245
|
+
validated, so **no code changed** — recall stays 30.6% / precision 100%.
|
|
246
|
+
|
|
247
|
+
1. *Version-pair diff (refuted).* ``specimens/converted/*.opju`` are the
|
|
248
|
+
same corpus projects re-saved by the trial-writer's Origin build
|
|
249
|
+
(4.3811) from the corpus's native 4.3380 — a hoped-for Rosetta stone.
|
|
250
|
+
They are not one: re-scanning ``converted/XAS.opju`` and
|
|
251
|
+
``converted/RockingCurve.opju`` with the existing regex finds matches
|
|
252
|
+
that *look* like new real tokens (e.g. an exact ``Co!C`` hit), but every
|
|
253
|
+
one is the **same ``__BCO`` boilerplate coincidence** described above,
|
|
254
|
+
just at a version-shifted distance — 383 bytes from the preceding
|
|
255
|
+
``__BCO`` marker in the 4.3811 re-save vs. the pinned 357-360 in the
|
|
256
|
+
4.3380 corpus (the boilerplate record itself grew a handful of bytes
|
|
257
|
+
between builds), which happens to fall just outside
|
|
258
|
+
``_BCO_ARTIFACT_LO``/``_HI``'s ``[340, 380)`` window. Re-saving also
|
|
259
|
+
introduces a *second*, further false-positive-shaped cluster at a
|
|
260
|
+
~1872-byte distance from a ``__BCO`` marker (seen resolving to XAS's
|
|
261
|
+
local column B in the converted file only) — the converted corpus is a
|
|
262
|
+
**noisier** source for this investigation, not a cleaner one. No
|
|
263
|
+
genuine new curve/DataPlot token appears inside any default-dialog
|
|
264
|
+
graph's own axis window in either version.
|
|
265
|
+
2. *Window-local alternate encoding (found a candidate, confirmed it does
|
|
266
|
+
not validate).* Anchoring on a length-prefixed workbook short-name
|
|
267
|
+
string embedded directly in ``RockingCurve``'s curve-object body (e.g.
|
|
268
|
+
``\x80\x03Nb\x00``, ``\x80\x06Nb/Au\x00`` — a real, confirmed landmark,
|
|
269
|
+
found 11 bytes before the real token in the *solved* ``NbAuRocking``
|
|
270
|
+
object) turned up a byte sequence at the identical relative offset in
|
|
271
|
+
the *unsolved* ``Graph1``/``Graph2`` objects that shares the real
|
|
272
|
+
token's first 5 bytes (``<flag> 01 01 01 80``) but substitutes ``0x01``
|
|
273
|
+
for the literal ``0x03`` sub-type byte, has **no fixed ``0x00``
|
|
274
|
+
terminator** (``Graph1``: ``0x83``; ``Graph2``: also non-zero), and
|
|
275
|
+
does not resync with the shared downstream template until ~30-40 bytes
|
|
276
|
+
later (unlike the real token's clean fixed 2-byte tail). The byte
|
|
277
|
+
immediately following the ``0x01`` sub-type was ``0x09`` for ``Nb``
|
|
278
|
+
(expected column B: local ordinal 2, global cumulative ordinal 8) and
|
|
279
|
+
``0x0e`` for ``NbAl`` (expected column B: local ordinal 2, global
|
|
280
|
+
ordinal 12) — matching neither numbering scheme, and the two values'
|
|
281
|
+
own difference (``14 - 9 = 5``) doesn't match the true ordinals'
|
|
282
|
+
difference (``12 - 8 = 4``) either, ruling out a fixed per-value
|
|
283
|
+
correction. **Decisive cross-check:** ``specimens/converted/
|
|
284
|
+
RockingCurve.opju`` (the same project, re-saved by 4.3811) rewrites
|
|
285
|
+
this exact slot into the *canonical* ``0x03``/``0x00`` token shape
|
|
286
|
+
while preserving the *same* numeric value (``9`` for ``Nb``, ``14`` for
|
|
287
|
+
``NbAl``) — proving the slot is a real Origin-native field, not a
|
|
288
|
+
misparse — yet decoding ``9`` through the already-validated
|
|
289
|
+
``_global_column_map`` resolves to ``Nb!C`` (wrong; the oracle wants
|
|
290
|
+
``B``) and ``14`` is out of range entirely (``RockingCurve`` has only
|
|
291
|
+
12 FPC-decoded columns total). So this slot is governed by some *other*,
|
|
292
|
+
unidentified numbering rule that default-dialog plots use — not the
|
|
293
|
+
cumulative FPC-decoded ordinal explicit multi-curve/Select-Data tokens
|
|
294
|
+
use — and accepting it would have silently produced a **wrong** answer,
|
|
295
|
+
not merely a missing one. It also doesn't generalize as a locatable
|
|
296
|
+
*shape*: the raw 4-byte prefix (``01 01 80 01``) recurs ~90 times in
|
|
297
|
+
``XAS.opju`` alone (a generic tag+small-int idiom used throughout this
|
|
298
|
+
format for style/color fields), so finding it at all required first
|
|
299
|
+
anchoring on the book-name string — and ``XAS``'s own default-dialog
|
|
300
|
+
curve objects don't embed a length-prefixed short name this way at all
|
|
301
|
+
(``\x80\x03Co\x00`` and friends: zero occurrences anywhere in the
|
|
302
|
+
file), so even the anchor technique is RockingCurve-specific, not
|
|
303
|
+
corpus-general.
|
|
304
|
+
3. *Legend / ``__FRAMESRCDATAINFOS`` backrefs (dead end).* The
|
|
305
|
+
``__FRAMESRCDATAINFOS`` marker exists exactly once each in
|
|
306
|
+
``UnpolPlots`` and ``"Fixed Lambdas SI"`` (absent from ``XAS`` and
|
|
307
|
+
``RockingCurve``) but its body decodes as a dense small-int/float64 run
|
|
308
|
+
consistent with multi-panel frame *layout geometry* (position/size),
|
|
309
|
+
not a per-curve dataset backref. The curve-object slots in that same
|
|
310
|
+
region carry Origin's generic auto-label macros (length-prefixed
|
|
311
|
+
``%(?X)``/``%(?Y)`` strings — "substitute this axis's own column short
|
|
312
|
+
name at render time"), confirming these are ordinary default-titled
|
|
313
|
+
plots whose title template doesn't fix a literal dataset reference at
|
|
314
|
+
all, let alone one we could read back out.
|
|
315
|
+
|
|
316
|
+
Conclusion: the encoding default-dialog graphs use to select their Y column
|
|
317
|
+
remains unlocated. This is reported as a confirmed negative result (not
|
|
318
|
+
merely "not yet tried") so a future pass doesn't re-spend time on the same
|
|
319
|
+
three leads — see ``docs/origin_project_format.md`` §6.2.1 for the
|
|
320
|
+
corresponding writeup.
|
|
321
|
+
|
|
322
|
+
**The third encoding — FOUND (item 35, 2026-07-04 rework).** Lead #2 above
|
|
323
|
+
("window-local alternate encoding") was the real thing after all: re-
|
|
324
|
+
anchored on the byte pattern itself rather than the book-name string that
|
|
325
|
+
made it look file-specific, ``<flag> 01 01 01 80 01 <val>`` (subtype
|
|
326
|
+
``0x01`` vs. this module's ``0x03``) is found corpus-wide. The earlier
|
|
327
|
+
rejection was a counting-convention bug, not a wrong shape: ``val`` counts
|
|
328
|
+
cumulatively over **every allocated column of every workbook**, including
|
|
329
|
+
empty/undecoded ones — not ``_global_column_map``'s FPC-decoded-only
|
|
330
|
+
ordinal. Re-resolving through that all-columns map raises aggregate
|
|
331
|
+
oracle-covered recall from 30.6% (11/36) to 100% (36/36) at unchanged 100%
|
|
332
|
+
precision. Full trail, the map builder, and why its designation gate is
|
|
333
|
+
deliberately skipped live in ``opju_curves_allcols.py`` (split out to stay
|
|
334
|
+
under the 500-line ceiling); :func:`extract_curves` below merges both
|
|
335
|
+
families per figure, deduped on ``(book, y)``.
|
|
336
|
+
"""
|
|
337
|
+
|
|
338
|
+
from __future__ import annotations
|
|
339
|
+
|
|
340
|
+
import re
|
|
341
|
+
from collections.abc import Mapping, Sequence
|
|
342
|
+
|
|
343
|
+
from quantized.io.origin_project.opj import _group
|
|
344
|
+
from quantized.io.origin_project.opju_codec import curve_plot_style, scan_columns
|
|
345
|
+
from quantized.io.origin_project.opju_curves_allcols import (
|
|
346
|
+
_allocated_column_map,
|
|
347
|
+
extract_curves_allcols,
|
|
348
|
+
)
|
|
349
|
+
from quantized.io.origin_project.windows import BookMeta
|
|
350
|
+
from quantized.io.origin_project.windows_opju import opju_window_metadata
|
|
351
|
+
|
|
352
|
+
__all__ = [
|
|
353
|
+
"allocated_columns_from_bytes",
|
|
354
|
+
"book_columns_from_bytes",
|
|
355
|
+
"book_metadata_from_bytes",
|
|
356
|
+
"extract_curves",
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
# <flag:1> 01 <konst:1> 01 80 03 <y_ord:1> 00 -- see module docstring.
|
|
360
|
+
_CURVE_RE = re.compile(rb".\x01.\x01\x80\x03.\x00")
|
|
361
|
+
|
|
362
|
+
# The "__BCO" boilerplate false positive -- see the module docstring's
|
|
363
|
+
# "False positive found and fixed" section. The span from the marker to the
|
|
364
|
+
# start of the coincidentally-matching tail token measures 357-360 bytes
|
|
365
|
+
# across every confirmed instance; the range below gives margin either side.
|
|
366
|
+
_BCO_MARKER = b"__BCO"
|
|
367
|
+
_BCO_ARTIFACT_LO = 340
|
|
368
|
+
_BCO_ARTIFACT_HI = 380
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _is_bco_boilerplate(b: bytes, match_start: int, local_index: int) -> bool:
|
|
372
|
+
"""True when a curve-token match is the tail of the fixed per-book
|
|
373
|
+
``__BCO<n>`` worksheet-window record, not a real curve/DataPlot object.
|
|
374
|
+
|
|
375
|
+
Requires both confirmed signals at once (see module docstring): the
|
|
376
|
+
resolved column is local index 2 (always "C" in the boilerplate) AND a
|
|
377
|
+
``__BCO`` marker sits 340-380 bytes before the match. Neither condition
|
|
378
|
+
alone is used -- a real curve can legitimately plot local column 3
|
|
379
|
+
(``fig_pairs``' A-C diff), and an unrelated ``__BCO`` marker could in
|
|
380
|
+
principle precede a real token at some other distance.
|
|
381
|
+
"""
|
|
382
|
+
if local_index != 2:
|
|
383
|
+
return False
|
|
384
|
+
lo = max(0, match_start - _BCO_ARTIFACT_HI)
|
|
385
|
+
hi = max(0, match_start - _BCO_ARTIFACT_LO)
|
|
386
|
+
return b.find(_BCO_MARKER, lo, hi) >= 0
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def book_columns_from_bytes(b: bytes) -> dict[str, list[str]]:
|
|
390
|
+
"""``{book: [column letter, ...]}`` in book-appearance / sheet-column order,
|
|
391
|
+
restricted to columns the FPC codec (``opju_codec.scan_columns``) actually
|
|
392
|
+
decoded — the same universe ``y_ord`` below counts over."""
|
|
393
|
+
columns = scan_columns(b)
|
|
394
|
+
books = _group(columns)
|
|
395
|
+
return {book: [c for c, _ in cols] for book, cols in books.items()}
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def book_metadata_from_bytes(
|
|
399
|
+
b: bytes, book_columns: Mapping[str, Sequence[str]]
|
|
400
|
+
) -> dict[str, BookMeta]:
|
|
401
|
+
"""Per-book column designation/label metadata (see the "Designation gate"
|
|
402
|
+
section of the module docstring) — a thin wrapper so ``figures_opju.py``
|
|
403
|
+
computes it once and threads it through, rather than every call re-scanning."""
|
|
404
|
+
return opju_window_metadata(b, book_columns)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def allocated_columns_from_bytes(b: bytes) -> dict[str, int]:
|
|
408
|
+
"""``{book: total allocated column count}`` over EVERY allocated column
|
|
409
|
+
of EVERY workbook, including empty/undecoded books and columns — the
|
|
410
|
+
universe the 0x01-subtype token's ordinal counts over (see "The third
|
|
411
|
+
encoding — FOUND" section of the module docstring and
|
|
412
|
+
``opju_curves_allcols.py``). A thin wrapper, mirroring
|
|
413
|
+
:func:`book_columns_from_bytes`, so ``figures_opju.py`` computes it once
|
|
414
|
+
per file and threads it through rather than every figure re-scanning."""
|
|
415
|
+
return dict(_allocated_column_map(b))
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def _global_column_map(
|
|
419
|
+
book_columns: Mapping[str, Sequence[str]],
|
|
420
|
+
) -> dict[int, tuple[str, str]]:
|
|
421
|
+
"""1-based cumulative ordinal -> ``(book, column letter)``, book-appearance order."""
|
|
422
|
+
out: dict[int, tuple[str, str]] = {}
|
|
423
|
+
cum = 0
|
|
424
|
+
for book, cols in book_columns.items():
|
|
425
|
+
for col in cols:
|
|
426
|
+
cum += 1
|
|
427
|
+
out[cum] = (book, col)
|
|
428
|
+
return out
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def _extract_curves_0x03(
|
|
432
|
+
b: bytes,
|
|
433
|
+
start: int,
|
|
434
|
+
end: int,
|
|
435
|
+
book_columns: Mapping[str, Sequence[str]],
|
|
436
|
+
books_meta: Mapping[str, BookMeta],
|
|
437
|
+
) -> list[dict[str, str | float]]:
|
|
438
|
+
"""The shipped 0x03-subtype curve token path — UNCHANGED (see module
|
|
439
|
+
docstring; do not modify this function, its map, or the ``__BCO`` gate).
|
|
440
|
+
|
|
441
|
+
``y`` is decoded from the curve token and gated on the "Designation gate"
|
|
442
|
+
(must independently confirm as ``"Y"``); ``x`` is inferred as ``y``'s own
|
|
443
|
+
book's first column (not decoded from the byte record — see the module
|
|
444
|
+
docstring's "X is not decoded"). A token whose ``y_ord`` doesn't resolve
|
|
445
|
+
to a known, ``Y``-designated column is silently dropped — never guessed.
|
|
446
|
+
"""
|
|
447
|
+
gmap = _global_column_map(book_columns)
|
|
448
|
+
out: list[dict[str, str | float]] = []
|
|
449
|
+
for m in _CURVE_RE.finditer(b, start, end):
|
|
450
|
+
y_ord = m.group()[6]
|
|
451
|
+
info = gmap.get(y_ord)
|
|
452
|
+
if info is None:
|
|
453
|
+
continue
|
|
454
|
+
book, y_col = info
|
|
455
|
+
cols = book_columns.get(book)
|
|
456
|
+
if not cols:
|
|
457
|
+
continue
|
|
458
|
+
if _is_bco_boilerplate(b, m.start(), cols.index(y_col)):
|
|
459
|
+
continue # the __BCO boilerplate, not a real curve -- see module docstring
|
|
460
|
+
bm = books_meta.get(book)
|
|
461
|
+
if bm is None:
|
|
462
|
+
continue # can't independently confirm the column type: drop, never guess
|
|
463
|
+
cm = bm.columns.get(y_col)
|
|
464
|
+
if cm is None or cm.designation != "Y":
|
|
465
|
+
continue
|
|
466
|
+
style = curve_plot_style(b, m.start())
|
|
467
|
+
out.append({"book": book, "x": cols[0], "y": y_col, **({"style": style} if style else {})})
|
|
468
|
+
return out
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def extract_curves(
|
|
472
|
+
b: bytes,
|
|
473
|
+
start: int,
|
|
474
|
+
end: int,
|
|
475
|
+
book_columns: Mapping[str, Sequence[str]],
|
|
476
|
+
books_meta: Mapping[str, BookMeta],
|
|
477
|
+
book_counts_all: Mapping[str, int],
|
|
478
|
+
) -> list[dict[str, str | float]]:
|
|
479
|
+
"""Every curve's ``{book, x, y}`` binding in ``b[start:end)``, merging
|
|
480
|
+
BOTH curve-token families (see "The third encoding — FOUND" above): the
|
|
481
|
+
shipped 0x03-subtype token (:func:`_extract_curves_0x03`, unchanged,
|
|
482
|
+
``"Y"``-designation gated) and the 0x01-subtype all-columns token
|
|
483
|
+
(``opju_curves_allcols.extract_curves_allcols``, deliberately not
|
|
484
|
+
designation-gated — see that module's docstring). Deduped on
|
|
485
|
+
``(book, y)`` (composite/duplicate-referencing windows, or the 0x01
|
|
486
|
+
family's own doubled hits, commonly re-emit one binding twice), first-
|
|
487
|
+
seen order (0x03 before 0x01).
|
|
488
|
+
"""
|
|
489
|
+
out = _extract_curves_0x03(b, start, end, book_columns, books_meta)
|
|
490
|
+
seen = {(c["book"], c["y"]) for c in out}
|
|
491
|
+
for c in extract_curves_allcols(b, start, end, book_counts_all):
|
|
492
|
+
key = (c["book"], c["y"])
|
|
493
|
+
if key in seen:
|
|
494
|
+
continue
|
|
495
|
+
seen.add(key)
|
|
496
|
+
out.append(c)
|
|
497
|
+
return out
|