trace-digitiser 2.1.0__tar.gz → 2.2.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.
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/CHANGELOG.md +58 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/MANIFEST.in +2 -0
- {trace_digitiser-2.1.0/src/trace_digitiser.egg-info → trace_digitiser-2.2.0}/PKG-INFO +14 -1
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/README.md +13 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/RELEASING.md +15 -2
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/pyproject.toml +1 -1
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/__init__.py +1 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/axis_labels.py +4 -1
- trace_digitiser-2.2.0/src/trace_digitiser/bars.py +591 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/frames.py +3 -1
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/markers.py +192 -4
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/panel_detection.py +60 -3
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/points.py +19 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/polar.py +10 -3
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/trace_detection.py +17 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0/src/trace_digitiser.egg-info}/PKG-INFO +14 -1
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser.egg-info/SOURCES.txt +1 -0
- trace_digitiser-2.2.0/tests/test_figure_styles.py +138 -0
- trace_digitiser-2.1.0/src/trace_digitiser/bars.py +0 -324
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/LICENSE +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/examples/README.md +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/examples/digitise_published_figure.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/examples/lopatina2014_fig4.jpg +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/examples/validate_with_known_data.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/examples/walkthrough.ipynb +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/setup.cfg +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/_figure.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/_results.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/calibration.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/cli.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/diagnostics.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/digitise.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/explore.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/geometry.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/heatmap.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/io.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/line_detection.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/models.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/ocr.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/provenance.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/resampling.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/rows.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/straighten.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/summarise.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/synthetic.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/validation.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser/x_calibration.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser.egg-info/dependency_links.txt +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser.egg-info/entry_points.txt +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser.egg-info/requires.txt +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/src/trace_digitiser.egg-info/top_level.txt +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/__init__.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/conftest.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/data/lopatina2014_fig4_reference.csv +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_axis_labels.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_calibration.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_cli.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_digitise.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_frames.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_geometry.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_integration.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_io.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_panel_detection.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_published_figure.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_readers.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_straighten.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_trace_detection.py +0 -0
- {trace_digitiser-2.1.0 → trace_digitiser-2.2.0}/tests/test_validation.py +0 -0
|
@@ -4,6 +4,63 @@ All notable changes to trace-digitiser are recorded here.
|
|
|
4
4
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
5
5
|
and the project uses [semantic versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [2.2.0] - 2026-11-15
|
|
8
|
+
|
|
9
|
+
Tested on the figures of published papers whose underlying numbers are
|
|
10
|
+
published too (Leypunskiy et al. 2017, eLife 6:e23539: markers with error
|
|
11
|
+
bars, a line over shaded bands; Foley et al. 2019, eLife 8:e50063: bar charts;
|
|
12
|
+
Pearl and Reed 1920, PNAS 6:275, a microfilm scan), 2.1.0 read what it found
|
|
13
|
+
accurately but often found nothing. This release finds much more of it, there
|
|
14
|
+
and on the figures of a paper held out until the changes were made (Andreani
|
|
15
|
+
et al. 2022, eLife 11:e74327). Line plots digitise as before: the package's
|
|
16
|
+
validation suite and the Hearn and Whitmore (2026) examples give the same
|
|
17
|
+
results.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **A test set of published figures**
|
|
22
|
+
([`validation/published-figures`](https://github.com/comparativechrono/trace-digitiser/tree/main/validation/published-figures)):
|
|
23
|
+
seven figures from those four papers, the numbers behind them from their
|
|
24
|
+
authors' data, and a script that reads them with nothing given and with the
|
|
25
|
+
help a user can give, and compares. Its README has the results of 2.1.0 and
|
|
26
|
+
2.2.0, case by case, including the few that 2.2.0 reads worse. It is run
|
|
27
|
+
before each release and is not part of the package.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **Bar charts in the style of GraphPad Prism**: black, grey, hatched and
|
|
32
|
+
outlined bars are found, on an axis that does not start at 0 (2.1.0 found 3
|
|
33
|
+
of the 35 bars of Foley et al.'s figure 2, and read those upside down; all
|
|
34
|
+
35 are now read, within 0.3 % of the axis). Bars are the columns filled from
|
|
35
|
+
the baseline, so an error bar or a significance bracket joined to a bar no
|
|
36
|
+
longer spoils it; a border of another colour (a black outline round a grey
|
|
37
|
+
bar) is part of the bar; a bar cut by the edge of the plot area is kept.
|
|
38
|
+
- **Error bars drawn in the colour of their bar or marker** (the default in
|
|
39
|
+
Prism, MATLAB and matplotlib) are followed beyond the bar's end, or from the
|
|
40
|
+
marker, to their caps; one running across a fitted line goes on beyond it.
|
|
41
|
+
Where only the half beyond a bar's end shows, a note says so.
|
|
42
|
+
- **Markers sitting on a line of their own colour** (a fitted line, their
|
|
43
|
+
error bars) are found: other sizes are tried where the lines' ridges
|
|
44
|
+
outnumber the markers, and such a colour counts as a colour of markers if
|
|
45
|
+
its markers are joined to its lines and much thicker than them. Round
|
|
46
|
+
letters of words written in the plot, and a legend's markers beside their
|
|
47
|
+
words, are left out; a marker found in two series of close colours is kept
|
|
48
|
+
in the nearer one.
|
|
49
|
+
- **A plot area given by hand** (a box drawn in the workbench, or numbers read
|
|
50
|
+
off a picture) moves to the middle of the axis lines within a few pixels of
|
|
51
|
+
it, and their thickness is measured: with a thick axis line the tick labels
|
|
52
|
+
were looked for inside it, and the axis title was read instead.
|
|
53
|
+
- Long tick marks of a small plot in a large picture are found, so that its
|
|
54
|
+
labels are anchored to them.
|
|
55
|
+
- A colour that fills areas (a shaded band behind a plot) is not taken for a
|
|
56
|
+
trace of a line plot.
|
|
57
|
+
- Tick labels that Tesseract misreads as a line of text (75 as 15, in large
|
|
58
|
+
Helvetica) are read once more as a single word when an axis is not settled.
|
|
59
|
+
- Looking at a whole page of a scanned paper (`describe_figure`, the
|
|
60
|
+
workbench's first look at a page of a PDF) took a minute and a half, nearly
|
|
61
|
+
all of it in the search for polar axes; the circles are now proposed on a
|
|
62
|
+
smaller copy of the page (16 seconds in all).
|
|
63
|
+
|
|
7
64
|
## [2.1.0] - 2026-11-14
|
|
8
65
|
|
|
9
66
|
Everything in 2.0.0 works as before. What is new is readers for other kinds of
|
|
@@ -165,6 +222,7 @@ First version tracked in this repository; identical to the 1.2.0 files on PyPI.
|
|
|
165
222
|
Releases 0.1.0 to 1.0.0 (6-7 June 2026) were uploaded to PyPI directly and are
|
|
166
223
|
not recorded here.
|
|
167
224
|
|
|
225
|
+
[2.2.0]: https://github.com/comparativechrono/trace-digitiser/compare/v2.1.0...v2.2.0
|
|
168
226
|
[2.1.0]: https://github.com/comparativechrono/trace-digitiser/compare/v2.0.0...v2.1.0
|
|
169
227
|
[2.0.0]: https://github.com/comparativechrono/trace-digitiser/compare/1d34f75...v2.0.0
|
|
170
228
|
[1.2.0]: https://pypi.org/project/trace-digitiser/1.2.0/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trace-digitiser
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Recover the data from figure images - lines, points, bars, actograms, heat maps - on your own computer: no uploads, no AI model.
|
|
5
5
|
Author: Trace Digitiser Contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -267,6 +267,18 @@ Labels under 8 pixels high are never given high confidence, however well they ag
|
|
|
267
267
|
that small is misread in consistent ways — the decimal point dropped from every label, say. If
|
|
268
268
|
your figure has such labels, enlarging the image does not help; typing in two numbers does.
|
|
269
269
|
|
|
270
|
+
**Published figures.** The tests above draw their own figures.
|
|
271
|
+
[`validation/published-figures`](https://github.com/comparativechrono/trace-digitiser/tree/main/validation/published-figures)
|
|
272
|
+
holds seven figures from four papers whose authors published the numbers behind them — markers with error bars, a
|
|
273
|
+
line over shaded bands, ten bar charts, dot plots, and a scanned page from 1920 — and reads them with nothing given
|
|
274
|
+
and with the help a user can give. With nothing given, 2.2.0 reads all 35 bars of the bar charts to within 0.3 % of
|
|
275
|
+
the axis, and the 29 points of a scatter plot of four series to within 0.5 % (2.1.0 read none of either); with two
|
|
276
|
+
ticks clicked on each axis and the dots' colour, the census dots of the 1920 figure to within 0.9 %. On the figures
|
|
277
|
+
of a paper held out until the changes were made, with the plot area drawn, it reads 24 bars to within 0.4 % once
|
|
278
|
+
two ticks are clicked, and 33 of 37 points once the ticks of a slanted axis and the colours are. Stacked plots with no gap between them, dot
|
|
279
|
+
plots whose dots overlap, and tick labels that are slanted or hand-lettered still need help or remain hard; that
|
|
280
|
+
folder's README has the details.
|
|
281
|
+
|
|
270
282
|
### Test it on data you know
|
|
271
283
|
|
|
272
284
|
The best test of a digitisation is one on data like yours. `round_trip` draws a known series as a
|
|
@@ -312,6 +324,7 @@ cd trace-digitiser
|
|
|
312
324
|
pip install -e ".[dev]"
|
|
313
325
|
pytest # the tests that need Tesseract are skipped without it
|
|
314
326
|
ruff check src tests
|
|
327
|
+
python validation/published-figures/run.py # figures from papers against their authors' data (minutes)
|
|
315
328
|
```
|
|
316
329
|
|
|
317
330
|
`src/trace_digitiser/` in the order the work is done:
|
|
@@ -227,6 +227,18 @@ Labels under 8 pixels high are never given high confidence, however well they ag
|
|
|
227
227
|
that small is misread in consistent ways — the decimal point dropped from every label, say. If
|
|
228
228
|
your figure has such labels, enlarging the image does not help; typing in two numbers does.
|
|
229
229
|
|
|
230
|
+
**Published figures.** The tests above draw their own figures.
|
|
231
|
+
[`validation/published-figures`](https://github.com/comparativechrono/trace-digitiser/tree/main/validation/published-figures)
|
|
232
|
+
holds seven figures from four papers whose authors published the numbers behind them — markers with error bars, a
|
|
233
|
+
line over shaded bands, ten bar charts, dot plots, and a scanned page from 1920 — and reads them with nothing given
|
|
234
|
+
and with the help a user can give. With nothing given, 2.2.0 reads all 35 bars of the bar charts to within 0.3 % of
|
|
235
|
+
the axis, and the 29 points of a scatter plot of four series to within 0.5 % (2.1.0 read none of either); with two
|
|
236
|
+
ticks clicked on each axis and the dots' colour, the census dots of the 1920 figure to within 0.9 %. On the figures
|
|
237
|
+
of a paper held out until the changes were made, with the plot area drawn, it reads 24 bars to within 0.4 % once
|
|
238
|
+
two ticks are clicked, and 33 of 37 points once the ticks of a slanted axis and the colours are. Stacked plots with no gap between them, dot
|
|
239
|
+
plots whose dots overlap, and tick labels that are slanted or hand-lettered still need help or remain hard; that
|
|
240
|
+
folder's README has the details.
|
|
241
|
+
|
|
230
242
|
### Test it on data you know
|
|
231
243
|
|
|
232
244
|
The best test of a digitisation is one on data like yours. `round_trip` draws a known series as a
|
|
@@ -272,6 +284,7 @@ cd trace-digitiser
|
|
|
272
284
|
pip install -e ".[dev]"
|
|
273
285
|
pytest # the tests that need Tesseract are skipped without it
|
|
274
286
|
ruff check src tests
|
|
287
|
+
python validation/published-figures/run.py # figures from papers against their authors' data (minutes)
|
|
275
288
|
```
|
|
276
289
|
|
|
277
290
|
`src/trace_digitiser/` in the order the work is done:
|
|
@@ -45,8 +45,21 @@ plans). Now that the repository is public, one can be added:
|
|
|
45
45
|
2. In `CHANGELOG.md`, give the section for the version its date in place of
|
|
46
46
|
"unreleased", and end its link at the new tag (`...vX.Y.Z` in place of
|
|
47
47
|
`...HEAD`).
|
|
48
|
-
3.
|
|
49
|
-
|
|
48
|
+
3. Run the published-figure test set
|
|
49
|
+
([`validation/published-figures`](validation/published-figures/README.md)),
|
|
50
|
+
which reads figures from papers whose data are published, and compare the
|
|
51
|
+
results with the last release's:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python validation/published-figures/run.py \
|
|
55
|
+
--json validation/published-figures/results-X.Y.Z.json \
|
|
56
|
+
--compare validation/published-figures/results-<last release>.json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Look into any case marked WORSE before going on. Commit the new results,
|
|
60
|
+
and update the table in that folder's README (`--markdown` prints it).
|
|
61
|
+
4. Merge to `main` and wait for the *Tests* workflow to pass.
|
|
62
|
+
5. On GitHub: *Releases -> Draft a new release*, create the tag `vX.Y.Z`
|
|
50
63
|
(matching the version exactly, with a leading `v`) on `main`, and publish.
|
|
51
64
|
|
|
52
65
|
Publishing the release starts the workflow. It checks that the tag matches the
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "trace-digitiser"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.2.0"
|
|
8
8
|
description = "Recover the data from figure images - lines, points, bars, actograms, heat maps - on your own computer: no uploads, no AI model."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -231,6 +231,7 @@ def digitise(
|
|
|
231
231
|
for p in panels:
|
|
232
232
|
masks = detect_trace_masks(
|
|
233
233
|
rgb, p, colours=trace_colours, exclude=exclude_boxes, achromatic=achromatic, darkness=dark,
|
|
234
|
+
lines_only=True,
|
|
234
235
|
)
|
|
235
236
|
if show_debug:
|
|
236
237
|
print(f"Panel {p['panel_id']}: detected {len(masks)} trace(s)")
|
|
@@ -176,13 +176,16 @@ class Preparation:
|
|
|
176
176
|
# settled by the first (fast) attempt are therefore read again in other ways
|
|
177
177
|
# and the readings pooled; the axis fit then keeps the readings that agree.
|
|
178
178
|
# The settings and their order were chosen on labels 5 to 7 pixels high in
|
|
179
|
-
# three typefaces: each one added reads labels that the ones before it miss.
|
|
179
|
+
# three typefaces: each one added reads labels that the ones before it miss. The last was added for large print.
|
|
180
180
|
PREPARATIONS = (
|
|
181
181
|
Preparation(44, True, 2.0, True, True, 6),
|
|
182
182
|
Preparation(64, False, 2.0, True, False, 7),
|
|
183
183
|
Preparation(64, True, 0.0, False, False, 7, gamma=0.6),
|
|
184
184
|
Preparation(32, False, 2.0, True, False, 7),
|
|
185
185
|
Preparation(64, False, 0.0, False, False, 7, gamma=0.6),
|
|
186
|
+
# Large, clean print in some typefaces (MATLAB's Helvetica at 600 dpi) is misread as a line of text (75 as 15)
|
|
187
|
+
# and read right as a single word.
|
|
188
|
+
Preparation(64, False, 0.0, True, False, 8),
|
|
186
189
|
)
|
|
187
190
|
|
|
188
191
|
|