hilbertplot 0.1.0__tar.gz → 1.0.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.
- hilbertplot-1.0.0/CHANGELOG.md +149 -0
- hilbertplot-1.0.0/PKG-INFO +255 -0
- hilbertplot-1.0.0/README.md +222 -0
- hilbertplot-1.0.0/examples/groups.py +14 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/examples/plot_catalog.py +20 -10
- hilbertplot-1.0.0/examples/plot_data.py +34 -0
- hilbertplot-1.0.0/examples/readme_figures.py +127 -0
- hilbertplot-1.0.0/examples/show_curve.py +30 -0
- hilbertplot-1.0.0/examples/try_api.py +135 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/pyproject.toml +34 -22
- hilbertplot-1.0.0/scripts/build_release.sh +17 -0
- hilbertplot-1.0.0/scripts/check_release.py +102 -0
- hilbertplot-1.0.0/src/hilbertplot/__init__.py +37 -0
- hilbertplot-1.0.0/src/hilbertplot/_api.py +404 -0
- hilbertplot-1.0.0/src/hilbertplot/_core/arbitrary.py +378 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_core/catalog.py +47 -12
- hilbertplot-1.0.0/src/hilbertplot/_core/curve.py +915 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_core/generation.py +25 -4
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_core/geometry.py +64 -21
- hilbertplot-1.0.0/src/hilbertplot/_core/indexing.py +146 -0
- hilbertplot-1.0.0/src/hilbertplot/_core/limits.py +100 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_core/symmetry.py +9 -17
- hilbertplot-1.0.0/src/hilbertplot/_data/conversion.py +165 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_data/mapping.py +106 -29
- hilbertplot-1.0.0/src/hilbertplot/_viz/hilbert_plot.py +580 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_viz/render.py +127 -41
- hilbertplot-1.0.0/src/hilbertplot/config.py +10 -0
- hilbertplot-1.0.0/src/hilbertplot/curves.py +53 -0
- hilbertplot-1.0.0/src/hilbertplot/data.py +15 -0
- hilbertplot-1.0.0/tests/conftest.py +40 -0
- hilbertplot-1.0.0/tests/test_api.py +243 -0
- hilbertplot-1.0.0/tests/test_arbitrary.py +145 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/tests/test_catalog.py +51 -46
- hilbertplot-1.0.0/tests/test_conversion.py +161 -0
- hilbertplot-1.0.0/tests/test_curve_shapes.py +86 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/tests/test_data.py +43 -41
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/tests/test_geometry.py +25 -8
- hilbertplot-1.0.0/tests/test_indexing.py +162 -0
- hilbertplot-1.0.0/tests/test_performance.py +109 -0
- hilbertplot-1.0.0/tests/test_plotting.py +281 -0
- hilbertplot-1.0.0/tests/test_readme.py +62 -0
- hilbertplot-1.0.0/tests/test_robustness.py +597 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/tests/test_symmetry.py +1 -1
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/tests/test_words.py +10 -10
- hilbertplot-0.1.0/PKG-INFO +0 -285
- hilbertplot-0.1.0/README.md +0 -257
- hilbertplot-0.1.0/examples/groups.py +0 -29
- hilbertplot-0.1.0/examples/plot_data.py +0 -119
- hilbertplot-0.1.0/examples/show_curve.py +0 -48
- hilbertplot-0.1.0/src/hilbertplot/__init__.py +0 -69
- hilbertplot-0.1.0/src/hilbertplot/_core/arbitrary.py +0 -114
- hilbertplot-0.1.0/src/hilbertplot/_core/curve.py +0 -604
- hilbertplot-0.1.0/src/hilbertplot/_viz/hilbert_plot.py +0 -413
- hilbertplot-0.1.0/tests/test_arbitrary.py +0 -95
- hilbertplot-0.1.0/tests/test_plotting.py +0 -161
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/.gitignore +0 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/LICENSE +0 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_core/__init__.py +0 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_data/__init__.py +0 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/_viz/__init__.py +0 -0
- {hilbertplot-0.1.0 → hilbertplot-1.0.0}/src/hilbertplot/py.typed +0 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **hilbertplot** are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/), and the project aims to adhere to
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
Released versions below are generated automatically by python-semantic-release;
|
|
8
|
+
new entries are inserted at the marker.
|
|
9
|
+
|
|
10
|
+
## Local API redesign (unreleased)
|
|
11
|
+
|
|
12
|
+
- Make array conversion lossless for dtypes, large integers, complex values and
|
|
13
|
+
masks; keep padding masked where NaN would require lossy integer conversion.
|
|
14
|
+
- Convert supported square and quasisquare arrays to flat 1-D sequences,
|
|
15
|
+
retaining RGB/RGBA channel order; restore with `to_grid(..., shape=original.shape)`.
|
|
16
|
+
Reject general rectangles and unsupported curve/shape combinations without a
|
|
17
|
+
fallback. Add explicit `from_grid(..., length=...)` prefix handling.
|
|
18
|
+
- Run the release build hook after semantic version stamping to regenerate and
|
|
19
|
+
commit `uv.lock` automatically. Verify title-driven patch/minor/breaking releases
|
|
20
|
+
in disposable repositories in CI; versions remain semantic-release-owned.
|
|
21
|
+
- Allow `plot_curve(..., shape=(rows, columns))` to draw supported arbitrary
|
|
22
|
+
squares and quasisquares directly as lines. Select a connected quasisquare
|
|
23
|
+
orientation internally. `curves.grid` also accepts the same shape pair.
|
|
24
|
+
- Use `hp.data.to_grid` / `from_grid` and `hp.curves.index_to_xy` /
|
|
25
|
+
`xy_to_index` for explicit mapping directions. Remove the former `image`,
|
|
26
|
+
`unroll`, `encode`, and `decode` aliases from these namespaces.
|
|
27
|
+
- Keep top-level completion to `plot`, `plot_curve`, `gallery`, `curves`, `data`,
|
|
28
|
+
and `config`. Move metadata/geometry, array operations, and resource controls
|
|
29
|
+
into their respective module namespaces; remove their top-level aliases.
|
|
30
|
+
- Add `examples/try_api.py` to exercise the complete function-based interface.
|
|
31
|
+
- Add data-first `plot(data, curve=...)` and `plot_curve(curve, order=...)`.
|
|
32
|
+
Each call returns a standard Matplotlib Figure, without opening a window.
|
|
33
|
+
- Keep `fourier=False` and `difference=False` as mutually exclusive flags on
|
|
34
|
+
`plot`; difference mode displays the full geometric field instead of a threshold overlay.
|
|
35
|
+
- Keep custom classes internal. Remove the `Curve`, `CurveList`, `HilbertPlot`,
|
|
36
|
+
and `hilbert_plot` exports. Curve metadata and groups return plain dicts/lists.
|
|
37
|
+
- Expose array, coordinate, and indexing operations as functions; retain the
|
|
38
|
+
numpy-only computational path. See the README migration table for replacements.
|
|
39
|
+
- Default new data functions to power-of-two padding; require explicit truncation
|
|
40
|
+
when an order is too small. Reject ambiguous multidimensional/complex input,
|
|
41
|
+
handle masked integer data, and report invalid Fourier inputs without warnings.
|
|
42
|
+
- Normalize the memory regression test's RSS units on macOS as well as Linux.
|
|
43
|
+
|
|
44
|
+
These changes are under local review and have not been released.
|
|
45
|
+
|
|
46
|
+
## Migrating from 0.1.0
|
|
47
|
+
|
|
48
|
+
`hilbertplot` is on `0.x`, where [semver §4](https://semver.org/#spec-item-4) allows the
|
|
49
|
+
interface to change in a minor release. Two spellings changed; both fail loudly rather
|
|
50
|
+
than silently, and nothing else in the 0.1.0 surface was removed.
|
|
51
|
+
|
|
52
|
+
| 0.1.0 | now | why |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| `curve.plot(order)` | `curve.draw(order)` | one verb for "render onto axes", shared with `HilbertPlot.draw` |
|
|
55
|
+
| `curve.save(order, path)` | `curve.save(path, order)` | matches `HilbertPlot.save(path, ...)`; the old order raises a `TypeError` naming the fix |
|
|
56
|
+
| `repr(curve)` → `'Hilbert'` | `repr(curve)` → `'<Curve 0H Hilbert (proper)>'` | `repr` is now unambiguous; `str(curve)` is still `'Hilbert'` |
|
|
57
|
+
|
|
58
|
+
Behaviour that was buggy and is now stricter: `curve(True)` and `curve(3.0)` raise
|
|
59
|
+
`TypeError` instead of silently meaning `curve(1)` / `curve(3)`; an out-of-range index
|
|
60
|
+
raises `IndexError` rather than `KeyError` (both are `LookupError`); `plot.data` is
|
|
61
|
+
genuinely immutable rather than merely flagged; and `image(order=..., fit=...)` now
|
|
62
|
+
validates `fit` instead of ignoring it.
|
|
63
|
+
|
|
64
|
+
<!-- version list -->
|
|
65
|
+
|
|
66
|
+
## v1.0.0 (2026-11-01)
|
|
67
|
+
|
|
68
|
+
### Features
|
|
69
|
+
|
|
70
|
+
- Simplify plotting and add lossless curve conversions
|
|
71
|
+
([`f45f2a6`](https://github.com/El3ssar/hilbertplot/commit/f45f2a6219bfc1f6259d72a64d01c8b19ae7d28e))
|
|
72
|
+
|
|
73
|
+
### Breaking Changes
|
|
74
|
+
|
|
75
|
+
- Replace public curve/plot objects and top-level numerical helpers with function-based plotting and
|
|
76
|
+
namespaced to_grid/from_grid/index_to_xy/xy_to_index operations. Data plots default to
|
|
77
|
+
power-of-two padding; difference=True renders the full locality-loss field. General rectangles are
|
|
78
|
+
intentionally unsupported.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
## v0.2.0 (2026-07-25)
|
|
82
|
+
|
|
83
|
+
### Bug Fixes
|
|
84
|
+
|
|
85
|
+
- Close the gaps found by the second review round
|
|
86
|
+
([`9df64f4`](https://github.com/El3ssar/hilbertplot/commit/9df64f463b2619d0d19ca7d3d818a16e2c25d7d8))
|
|
87
|
+
|
|
88
|
+
- Keep the new guards from costing more than they save
|
|
89
|
+
([`bbaa464`](https://github.com/El3ssar/hilbertplot/commit/bbaa4646af8ca401aa27174277cbae22910cd34f))
|
|
90
|
+
|
|
91
|
+
### Continuous Integration
|
|
92
|
+
|
|
93
|
+
- Bump actions, exempt dependabot from title check, curb ruff bumps
|
|
94
|
+
([`aa74d78`](https://github.com/El3ssar/hilbertplot/commit/aa74d7810fa542e259dfcee77c23ad9aa491374a))
|
|
95
|
+
|
|
96
|
+
- Stop Dependabot from bumping ruff
|
|
97
|
+
([`f639fc0`](https://github.com/El3ssar/hilbertplot/commit/f639fc0aa5ab67c615bf31470cfd1bd10f5248b5))
|
|
98
|
+
|
|
99
|
+
- Stop the floors job re-resolving the pins it exists to test
|
|
100
|
+
([`106b08f`](https://github.com/El3ssar/hilbertplot/commit/106b08f8bedcf0d6c2c0ff023a60c2ff020265e4))
|
|
101
|
+
|
|
102
|
+
### Documentation
|
|
103
|
+
|
|
104
|
+
- Add status badges and tidy the 0.1.0 changelog entry
|
|
105
|
+
([`7d967ca`](https://github.com/El3ssar/hilbertplot/commit/7d967caae998903d0885a81c4801b50b974aef62))
|
|
106
|
+
|
|
107
|
+
- Illustrate the README with generated figures
|
|
108
|
+
([`0f245b9`](https://github.com/El3ssar/hilbertplot/commit/0f245b941fbb933141b10d60ee16157c463b8501))
|
|
109
|
+
|
|
110
|
+
- Streamline the README to install + two examples
|
|
111
|
+
([`fb53eab`](https://github.com/El3ssar/hilbertplot/commit/fb53eab38129a8e60c42160d5bfa3959677a37db))
|
|
112
|
+
|
|
113
|
+
### Features
|
|
114
|
+
|
|
115
|
+
- Make the arbitrary-square path fast, harden the public surface, add encode/decode
|
|
116
|
+
([`a6ce0da`](https://github.com/El3ssar/hilbertplot/commit/a6ce0da3463acaacc6c69d349a1ef06804a817f4))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
## v0.1.0 (2026-07-25)
|
|
120
|
+
|
|
121
|
+
First public release — the complete set of 40 two-dimensional Hilbert curves,
|
|
122
|
+
with fast numpy generation and data-visualisation tooling.
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
- The complete set of **40** two-dimensional Hilbert curves (Estevez-Rams et al., 2017):
|
|
126
|
+
`curve(i)` by index, name or symbol; `points(order)`, `word(order)`; family groups
|
|
127
|
+
`homogeneous` / `inhomogeneous` / `proper` / `improper` / `closed` / `by_kernels`,
|
|
128
|
+
returned as a `CurveList` that prints as a table.
|
|
129
|
+
- Fast numpy stroke-code generation (no per-stroke Python loop); order-10 curve (~1M
|
|
130
|
+
points) in tens of milliseconds.
|
|
131
|
+
- Curve rendering: `curve.show/save/plot(order)` with automatic line→fill mode by order,
|
|
132
|
+
colour-graded traversal, and `gallery()` for grids of curves.
|
|
133
|
+
- **Data visualisation** ("Hilbert plots", Estevez-Rams et al., 2015): `hilbert_plot`
|
|
134
|
+
/ `curve.plot_data` return a `HilbertPlot` that maps a 1-D vector onto 2-D on demand,
|
|
135
|
+
with colormap-by-name or colour-list interpolation, the `l`-granularity transform,
|
|
136
|
+
and `pad` / `truncate` fits.
|
|
137
|
+
- **Difference map** overlay (`difference=True`, tunable threshold) marking where a curve
|
|
138
|
+
breaks locality (Pérez-Demydenko et al., 2014); `curve.difference_map(order)`.
|
|
139
|
+
- **2-D Fourier map** (`fourier=True`; `HilbertPlot.fourier()`) revealing hidden periodic
|
|
140
|
+
and self-similar structure.
|
|
141
|
+
- **`unroll`**: read a 2-D square array back into a 1-D vector in curve order.
|
|
142
|
+
- **Arbitrary `n x n` squares** for the eight curves that support it
|
|
143
|
+
(`curve.grid(n)`, `curve.generalizes`, `hilbertplot.generalizing()`); the data mapping
|
|
144
|
+
square-fits to a tight `ceil(sqrt(N))` grid by default for those curves. The full
|
|
145
|
+
feasibility classification and impossibility proofs are in `research/quasisquares/`.
|
|
146
|
+
|
|
147
|
+
### Notes
|
|
148
|
+
- Requires Python 3.10+. `numpy` is the only runtime dependency; `matplotlib` is the
|
|
149
|
+
optional `[plot]` extra.
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: hilbertplot
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The complete set of 40 two-dimensional Hilbert curves, and data plots on them.
|
|
5
|
+
Project-URL: Homepage, https://github.com/El3ssar/hilbertplot
|
|
6
|
+
Project-URL: Source, https://github.com/El3ssar/hilbertplot
|
|
7
|
+
Project-URL: Issues, https://github.com/El3ssar/hilbertplot/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/El3ssar/hilbertplot/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Daniel Estevez <kemossabee@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: dimensionality-reduction,hilbert-curve,locality,moore-curve,space-filling-curve,visualization
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: numpy>=1.21
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: matplotlib>=3.5; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff==0.15.13; extra == 'dev'
|
|
30
|
+
Provides-Extra: plot
|
|
31
|
+
Requires-Dist: matplotlib>=3.5; extra == 'plot'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# hilbertplot
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/hilbertplot/)
|
|
37
|
+
[](https://github.com/El3ssar/hilbertplot/actions/workflows/ci.yml)
|
|
38
|
+
[](https://pypi.org/project/hilbertplot/)
|
|
39
|
+
[](LICENSE)
|
|
40
|
+
|
|
41
|
+
Plot long numeric sequences on any of **40 two-dimensional Hilbert-type curves**.
|
|
42
|
+
Choose a curve by number, label, or paper symbol. The interface is functions returning
|
|
43
|
+
ordinary arrays, dictionaries, lists, and Matplotlib figures; custom classes stay internal.
|
|
44
|
+
|
|
45
|
+
Top-level completion has just six entries: `plot`, `plot_curve`, `gallery`,
|
|
46
|
+
`curves`, `data`, and `config`. Specialist functions live under those three namespaces:
|
|
47
|
+
`hp.curves` for the catalog and geometry, `hp.data` for arrays, and `hp.config` for
|
|
48
|
+
optional cache and allocation controls.
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install "hilbertplot[plot]" # omit [plot] for numpy-only operations
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Plot your data
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import numpy as np
|
|
60
|
+
import matplotlib.pyplot as plt
|
|
61
|
+
import hilbertplot as hp
|
|
62
|
+
|
|
63
|
+
data = np.sin(np.arange(1000) / 10)
|
|
64
|
+
fig = hp.plot(data) # standard Hilbert curve
|
|
65
|
+
fig = hp.plot(data, curve=12) # any curve index 0..39
|
|
66
|
+
fig = hp.plot(data, curve="Moore") # or a label; "12H" also works
|
|
67
|
+
fig.savefig("data.png", dpi=200)
|
|
68
|
+
plt.show() # display figures in a script
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Each call makes **one plot** and returns a Matplotlib `Figure`. No window is opened
|
|
72
|
+
implicitly. Use `ax=` to draw on your own Matplotlib axes. Figures remain open until
|
|
73
|
+
you close them with `plt.close(fig)`.
|
|
74
|
+
|
|
75
|
+
## Fourier, difference, and granularity maps
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
fig = hp.plot(data, fourier=True) # centred 2-D Fourier magnitude
|
|
79
|
+
fig = hp.plot(data, difference=True) # full locality-loss field
|
|
80
|
+
fig = hp.plot(data, granularity=16) # average consecutive blocks of 16
|
|
81
|
+
fig = hp.plot(data, fourier=True, granularity=16, window=True)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`fourier` and `difference` are boolean flags, both off by default (`False` / `0`).
|
|
85
|
+
They are **mutually exclusive**: setting both raises `ValueError`.
|
|
86
|
+
|
|
87
|
+
- **Fourier:** transforms the mapped 2-D image, not the original 1-D signal. Defaults
|
|
88
|
+
to `log1p(abs(FFT))` with the mean subtracted. Use `log=False` for raw magnitude,
|
|
89
|
+
`remove_dc=False` to retain the mean, or `window=True` for a Hann window.
|
|
90
|
+
- **Difference:** displays the mean absolute visit-index distance to each cell's up-to-eight
|
|
91
|
+
neighbours. It describes the curve's geometry, independently of data values.
|
|
92
|
+
- **Granularity:** replaces each consecutive sequence block by copies of its mean.
|
|
93
|
+
The sequence and image retain their sizes; this is not image downsampling. It affects
|
|
94
|
+
the data and its Fourier transform. Geometry-based difference maps stay unchanged.
|
|
95
|
+
|
|
96
|
+
## Draw a curve
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
fig = hp.plot_curve(12, order=4)
|
|
100
|
+
fig = hp.plot_curve("Moore", order=4, color="steelblue")
|
|
101
|
+
fig = hp.plot_curve(0, order=8, mode="fill")
|
|
102
|
+
|
|
103
|
+
# Arbitrary square and quasisquare: draw the path itself, with no data.
|
|
104
|
+
fig = hp.plot_curve(3, shape=(15, 15), mode="line")
|
|
105
|
+
fig = hp.plot_curve(3, shape=(15, 16), mode="line")
|
|
106
|
+
fig = hp.plot_curve(3, shape=(16, 15), mode="line")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`order=k` visits `4**k` cells in a `2**k` square. Curve drawing automatically switches
|
|
110
|
+
from coloured lines to a filled visit-order image at order 8. Explicit `mode="line"`
|
|
111
|
+
or `"fill"`, `linewidth`, and endpoint markers are also available.
|
|
112
|
+
|
|
113
|
+
`shape=(rows, columns)` selects explicit dimensions instead of an order. A
|
|
114
|
+
quasisquare's sides differ by one. Arbitrary squares and quasisquares require one
|
|
115
|
+
of curves **0, 3, 4, 5, 24, 29, 30, 31**. Quasisquare orientation is selected
|
|
116
|
+
automatically to keep every step connected. Use either `shape` or `order`, not both.
|
|
117
|
+
`hp.curves.grid((rows, columns), curve=...)` returns the same path as coordinates.
|
|
118
|
+
|
|
119
|
+
## Colour and fitting
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from matplotlib.colors import LogNorm
|
|
123
|
+
|
|
124
|
+
fig = hp.plot(np.arange(1, 1001), norm=LogNorm(), colorbar=True)
|
|
125
|
+
fig = hp.plot(data, cmap=["navy", "white", "firebrick"], vmin=-1, vmax=1)
|
|
126
|
+
compact = hp.data.to_grid(data, fit="square") # supported curves only
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`hp.plot()` and `hp.data.to_grid()` share these layout choices:
|
|
130
|
+
|
|
131
|
+
| `fit` | Behaviour |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| `"pad"` (default) | Smallest enclosing power-of-two square; works with every curve |
|
|
134
|
+
| `"square"` | Tight `ceil(sqrt(N))` square; only the eight generalizing curves |
|
|
135
|
+
| `"auto"` | Tight square where supported, otherwise power-of-two padding |
|
|
136
|
+
| `"truncate"` | Largest power-of-two square inside the data; explicitly discards the tail |
|
|
137
|
+
|
|
138
|
+
Padding is NaN and appears transparent. `order=` fixes the grid; if it is too small,
|
|
139
|
+
the call raises unless you explicitly choose `fit="truncate"`. Pass either `norm=`
|
|
140
|
+
or `vmin`/`vmax`, not both. Extra Matplotlib image options such as `alpha` are supported.
|
|
141
|
+
|
|
142
|
+
## Arrays and index maths (no Matplotlib needed)
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
img = hp.data.to_grid(data, curve=12)
|
|
146
|
+
spectrum = hp.data.fourier(data, curve=12, window=True)
|
|
147
|
+
recovered = hp.data.from_grid(img, curve=12, length=len(data))
|
|
148
|
+
labels = hp.curves.label_map(12, side=img.shape[0])
|
|
149
|
+
differences = hp.curves.difference_map(12, side=img.shape[0])
|
|
150
|
+
|
|
151
|
+
pts = hp.curves.points(12, order=4) # (256, 2) array of (x, y) cells
|
|
152
|
+
word = hp.curves.word(12, order=4) # u/d/l/r strokes
|
|
153
|
+
arbitrary = hp.curves.grid(100, curve=0) # arbitrary square, supported curves only
|
|
154
|
+
xy = hp.curves.index_to_xy(10**18, 40, curve=12) # O(order), no full-grid allocation
|
|
155
|
+
assert hp.curves.xy_to_index(*xy, 40, curve=12) == 10**18
|
|
156
|
+
assert hp.curves.is_space_filling(pts, 16)
|
|
157
|
+
key = hp.curves.canonical_form(pts) # compare paths up to symmetry/reversal
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Images are indexed `[y, x]`; coordinates are `(x, y)`. Plotting and Fourier maps
|
|
161
|
+
accept real, nonempty scalar sequences; choose magnitude, phase, real or imaginary
|
|
162
|
+
values explicitly for complex data. Plotting rejects infinities. NaNs propagate
|
|
163
|
+
through granularity block means; Fourier maps mean-fill missing cells and require
|
|
164
|
+
at least one finite value.
|
|
165
|
+
|
|
166
|
+
Array conversion is separate from display: `to_grid()` / `from_grid()` preserve
|
|
167
|
+
numeric dtypes, complex values, large integers, and masks. With no padding or
|
|
168
|
+
averaging, conversion is exact. Default NaN padding keeps floating/complex dtypes;
|
|
169
|
+
integer and boolean padding uses a NumPy masked array to retain precision. Use
|
|
170
|
+
`fill=0` for ordinary integer padding. `length=` explicitly selects a prefix without
|
|
171
|
+
deleting legitimate NaNs or masked values.
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
# A square RGB image becomes a truly 1-D sequence. Each pixel's channels
|
|
175
|
+
# stay consecutive; use the full original shape when reconstructing.
|
|
176
|
+
rgb = np.arange(16 * 16 * 3, dtype=np.uint16).reshape(16, 16, 3)
|
|
177
|
+
sequence = hp.data.from_grid(rgb, curve=12)
|
|
178
|
+
assert sequence.ndim == 1 and sequence.size == rgb.size
|
|
179
|
+
restored = hp.data.to_grid(sequence, curve=12, shape=rgb.shape)
|
|
180
|
+
np.testing.assert_array_equal(restored, rgb)
|
|
181
|
+
assert restored.dtype == rgb.dtype
|
|
182
|
+
|
|
183
|
+
# The same functions use exact quasisquare paths for supported curves.
|
|
184
|
+
square_or_quasisquare = np.arange(15 * 16).reshape(15, 16)
|
|
185
|
+
sequence = hp.data.from_grid(square_or_quasisquare, curve=3)
|
|
186
|
+
restored = hp.data.to_grid(sequence, curve=3, shape=square_or_quasisquare.shape)
|
|
187
|
+
np.testing.assert_array_equal(restored, square_or_quasisquare)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Conversion uses the same connected path as `plot_curve(shape=...)`. Spatial
|
|
191
|
+
shapes must be supported squares or quasisquares; general rectangles are not
|
|
192
|
+
supported. Unsupported shapes raise an error without padding or cropping them
|
|
193
|
+
into a different traversal. `shape=` specifies the output's original dimensions;
|
|
194
|
+
it cannot be combined with `order=`. Converting a grid with another curve gives a
|
|
195
|
+
reversible reordering; keep all entries, including padding, when reversing it.
|
|
196
|
+
|
|
197
|
+
## Discover curves
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
info = hp.curves.info(12) # ordinary metadata dictionary
|
|
201
|
+
print(info["name"], info["index"], info["kernels"])
|
|
202
|
+
print([(c["index"], c["name"]) for c in hp.curves.catalog()])
|
|
203
|
+
print([c["index"] for c in hp.curves.generalizing()])
|
|
204
|
+
fig = hp.gallery(hp.curves.by_kernels(3, 5), order=3)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Under `hp.curves`, `catalog()` lists all 40 curves: 6 `proper()`, 6 `improper()` (together 12
|
|
208
|
+
`homogeneous()`), and 28 `inhomogeneous()`. Groups return ordinary lists of metadata
|
|
209
|
+
dictionaries. `closed()` lists the four loops; `generalizing()` lists curves
|
|
210
|
+
0, 3, 4, 5, 24, 29, 30, and 31, which support arbitrary square sizes.
|
|
211
|
+
|
|
212
|
+
Under `hp.config`, `clear_cache()` releases cached generation data, and `cache_info()`
|
|
213
|
+
reports its use.
|
|
214
|
+
`cell_limit()` / `set_cell_limit(n)` control the allocation guard. Grid size grows
|
|
215
|
+
exponentially with order; the default limit is a ceiling, not a memory reservation.
|
|
216
|
+
|
|
217
|
+
More runnable examples are in [examples/](examples/). The curve classification follows
|
|
218
|
+
Estevez-Rams et al., *Hilbert curves in two dimensions*, Rev. Cub. Fís. **34**, 9 (2017).
|
|
219
|
+
The arbitrary-square research is in [research/quasisquares/](research/quasisquares/).
|
|
220
|
+
|
|
221
|
+
## Try all the features
|
|
222
|
+
|
|
223
|
+
The [complete runnable example](examples/try_api.py) draws separate figures for the
|
|
224
|
+
curve, data, coarse-grained data, Fourier and difference maps, colour options, fitting
|
|
225
|
+
modes, and a gallery. It also checks numeric round trips, geometry, indexing and groups.
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
python examples/try_api.py
|
|
229
|
+
# Save figures and run all checks without opening windows:
|
|
230
|
+
MPLBACKEND=Agg python examples/try_api.py --save-only
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Figures are saved in `examples/output/try_api/`.
|
|
234
|
+
|
|
235
|
+
## Local API migration
|
|
236
|
+
|
|
237
|
+
This working-tree redesign replaces the object-based 0.2.0 interface:
|
|
238
|
+
|
|
239
|
+
| Previous | New |
|
|
240
|
+
| --- | --- |
|
|
241
|
+
| `hilbert_plot(12, data).draw()` | `plot(data, curve=12)` |
|
|
242
|
+
| `curve(12).draw(4)` | `plot_curve(12, order=4)` |
|
|
243
|
+
| `plot.save(path)` | `fig = plot(data); fig.savefig(path)` |
|
|
244
|
+
| `curve(12).points(4)` | `hp.curves.points(12, order=4)` |
|
|
245
|
+
| `curve(12).unroll(img)` | `hp.data.from_grid(img, curve=12)` |
|
|
246
|
+
| `curve(12).name` | `hp.curves.info(12)["name"]` |
|
|
247
|
+
| `proper().names` | `[c["name"] for c in hp.curves.proper()]` |
|
|
248
|
+
|
|
249
|
+
The old `Curve`, `CurveList`, `HilbertPlot`, and `hilbert_plot` exports are removed.
|
|
250
|
+
`difference=True` now renders the complete difference map. Rendering defaults to
|
|
251
|
+
power-of-two padding. These are intentional interface changes under local review.
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
MIT © Daniel Estevez — [LICENSE](LICENSE).
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# hilbertplot
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/hilbertplot/)
|
|
4
|
+
[](https://github.com/El3ssar/hilbertplot/actions/workflows/ci.yml)
|
|
5
|
+
[](https://pypi.org/project/hilbertplot/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Plot long numeric sequences on any of **40 two-dimensional Hilbert-type curves**.
|
|
9
|
+
Choose a curve by number, label, or paper symbol. The interface is functions returning
|
|
10
|
+
ordinary arrays, dictionaries, lists, and Matplotlib figures; custom classes stay internal.
|
|
11
|
+
|
|
12
|
+
Top-level completion has just six entries: `plot`, `plot_curve`, `gallery`,
|
|
13
|
+
`curves`, `data`, and `config`. Specialist functions live under those three namespaces:
|
|
14
|
+
`hp.curves` for the catalog and geometry, `hp.data` for arrays, and `hp.config` for
|
|
15
|
+
optional cache and allocation controls.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install "hilbertplot[plot]" # omit [plot] for numpy-only operations
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Plot your data
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import numpy as np
|
|
27
|
+
import matplotlib.pyplot as plt
|
|
28
|
+
import hilbertplot as hp
|
|
29
|
+
|
|
30
|
+
data = np.sin(np.arange(1000) / 10)
|
|
31
|
+
fig = hp.plot(data) # standard Hilbert curve
|
|
32
|
+
fig = hp.plot(data, curve=12) # any curve index 0..39
|
|
33
|
+
fig = hp.plot(data, curve="Moore") # or a label; "12H" also works
|
|
34
|
+
fig.savefig("data.png", dpi=200)
|
|
35
|
+
plt.show() # display figures in a script
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Each call makes **one plot** and returns a Matplotlib `Figure`. No window is opened
|
|
39
|
+
implicitly. Use `ax=` to draw on your own Matplotlib axes. Figures remain open until
|
|
40
|
+
you close them with `plt.close(fig)`.
|
|
41
|
+
|
|
42
|
+
## Fourier, difference, and granularity maps
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
fig = hp.plot(data, fourier=True) # centred 2-D Fourier magnitude
|
|
46
|
+
fig = hp.plot(data, difference=True) # full locality-loss field
|
|
47
|
+
fig = hp.plot(data, granularity=16) # average consecutive blocks of 16
|
|
48
|
+
fig = hp.plot(data, fourier=True, granularity=16, window=True)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`fourier` and `difference` are boolean flags, both off by default (`False` / `0`).
|
|
52
|
+
They are **mutually exclusive**: setting both raises `ValueError`.
|
|
53
|
+
|
|
54
|
+
- **Fourier:** transforms the mapped 2-D image, not the original 1-D signal. Defaults
|
|
55
|
+
to `log1p(abs(FFT))` with the mean subtracted. Use `log=False` for raw magnitude,
|
|
56
|
+
`remove_dc=False` to retain the mean, or `window=True` for a Hann window.
|
|
57
|
+
- **Difference:** displays the mean absolute visit-index distance to each cell's up-to-eight
|
|
58
|
+
neighbours. It describes the curve's geometry, independently of data values.
|
|
59
|
+
- **Granularity:** replaces each consecutive sequence block by copies of its mean.
|
|
60
|
+
The sequence and image retain their sizes; this is not image downsampling. It affects
|
|
61
|
+
the data and its Fourier transform. Geometry-based difference maps stay unchanged.
|
|
62
|
+
|
|
63
|
+
## Draw a curve
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
fig = hp.plot_curve(12, order=4)
|
|
67
|
+
fig = hp.plot_curve("Moore", order=4, color="steelblue")
|
|
68
|
+
fig = hp.plot_curve(0, order=8, mode="fill")
|
|
69
|
+
|
|
70
|
+
# Arbitrary square and quasisquare: draw the path itself, with no data.
|
|
71
|
+
fig = hp.plot_curve(3, shape=(15, 15), mode="line")
|
|
72
|
+
fig = hp.plot_curve(3, shape=(15, 16), mode="line")
|
|
73
|
+
fig = hp.plot_curve(3, shape=(16, 15), mode="line")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`order=k` visits `4**k` cells in a `2**k` square. Curve drawing automatically switches
|
|
77
|
+
from coloured lines to a filled visit-order image at order 8. Explicit `mode="line"`
|
|
78
|
+
or `"fill"`, `linewidth`, and endpoint markers are also available.
|
|
79
|
+
|
|
80
|
+
`shape=(rows, columns)` selects explicit dimensions instead of an order. A
|
|
81
|
+
quasisquare's sides differ by one. Arbitrary squares and quasisquares require one
|
|
82
|
+
of curves **0, 3, 4, 5, 24, 29, 30, 31**. Quasisquare orientation is selected
|
|
83
|
+
automatically to keep every step connected. Use either `shape` or `order`, not both.
|
|
84
|
+
`hp.curves.grid((rows, columns), curve=...)` returns the same path as coordinates.
|
|
85
|
+
|
|
86
|
+
## Colour and fitting
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from matplotlib.colors import LogNorm
|
|
90
|
+
|
|
91
|
+
fig = hp.plot(np.arange(1, 1001), norm=LogNorm(), colorbar=True)
|
|
92
|
+
fig = hp.plot(data, cmap=["navy", "white", "firebrick"], vmin=-1, vmax=1)
|
|
93
|
+
compact = hp.data.to_grid(data, fit="square") # supported curves only
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`hp.plot()` and `hp.data.to_grid()` share these layout choices:
|
|
97
|
+
|
|
98
|
+
| `fit` | Behaviour |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| `"pad"` (default) | Smallest enclosing power-of-two square; works with every curve |
|
|
101
|
+
| `"square"` | Tight `ceil(sqrt(N))` square; only the eight generalizing curves |
|
|
102
|
+
| `"auto"` | Tight square where supported, otherwise power-of-two padding |
|
|
103
|
+
| `"truncate"` | Largest power-of-two square inside the data; explicitly discards the tail |
|
|
104
|
+
|
|
105
|
+
Padding is NaN and appears transparent. `order=` fixes the grid; if it is too small,
|
|
106
|
+
the call raises unless you explicitly choose `fit="truncate"`. Pass either `norm=`
|
|
107
|
+
or `vmin`/`vmax`, not both. Extra Matplotlib image options such as `alpha` are supported.
|
|
108
|
+
|
|
109
|
+
## Arrays and index maths (no Matplotlib needed)
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
img = hp.data.to_grid(data, curve=12)
|
|
113
|
+
spectrum = hp.data.fourier(data, curve=12, window=True)
|
|
114
|
+
recovered = hp.data.from_grid(img, curve=12, length=len(data))
|
|
115
|
+
labels = hp.curves.label_map(12, side=img.shape[0])
|
|
116
|
+
differences = hp.curves.difference_map(12, side=img.shape[0])
|
|
117
|
+
|
|
118
|
+
pts = hp.curves.points(12, order=4) # (256, 2) array of (x, y) cells
|
|
119
|
+
word = hp.curves.word(12, order=4) # u/d/l/r strokes
|
|
120
|
+
arbitrary = hp.curves.grid(100, curve=0) # arbitrary square, supported curves only
|
|
121
|
+
xy = hp.curves.index_to_xy(10**18, 40, curve=12) # O(order), no full-grid allocation
|
|
122
|
+
assert hp.curves.xy_to_index(*xy, 40, curve=12) == 10**18
|
|
123
|
+
assert hp.curves.is_space_filling(pts, 16)
|
|
124
|
+
key = hp.curves.canonical_form(pts) # compare paths up to symmetry/reversal
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Images are indexed `[y, x]`; coordinates are `(x, y)`. Plotting and Fourier maps
|
|
128
|
+
accept real, nonempty scalar sequences; choose magnitude, phase, real or imaginary
|
|
129
|
+
values explicitly for complex data. Plotting rejects infinities. NaNs propagate
|
|
130
|
+
through granularity block means; Fourier maps mean-fill missing cells and require
|
|
131
|
+
at least one finite value.
|
|
132
|
+
|
|
133
|
+
Array conversion is separate from display: `to_grid()` / `from_grid()` preserve
|
|
134
|
+
numeric dtypes, complex values, large integers, and masks. With no padding or
|
|
135
|
+
averaging, conversion is exact. Default NaN padding keeps floating/complex dtypes;
|
|
136
|
+
integer and boolean padding uses a NumPy masked array to retain precision. Use
|
|
137
|
+
`fill=0` for ordinary integer padding. `length=` explicitly selects a prefix without
|
|
138
|
+
deleting legitimate NaNs or masked values.
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
# A square RGB image becomes a truly 1-D sequence. Each pixel's channels
|
|
142
|
+
# stay consecutive; use the full original shape when reconstructing.
|
|
143
|
+
rgb = np.arange(16 * 16 * 3, dtype=np.uint16).reshape(16, 16, 3)
|
|
144
|
+
sequence = hp.data.from_grid(rgb, curve=12)
|
|
145
|
+
assert sequence.ndim == 1 and sequence.size == rgb.size
|
|
146
|
+
restored = hp.data.to_grid(sequence, curve=12, shape=rgb.shape)
|
|
147
|
+
np.testing.assert_array_equal(restored, rgb)
|
|
148
|
+
assert restored.dtype == rgb.dtype
|
|
149
|
+
|
|
150
|
+
# The same functions use exact quasisquare paths for supported curves.
|
|
151
|
+
square_or_quasisquare = np.arange(15 * 16).reshape(15, 16)
|
|
152
|
+
sequence = hp.data.from_grid(square_or_quasisquare, curve=3)
|
|
153
|
+
restored = hp.data.to_grid(sequence, curve=3, shape=square_or_quasisquare.shape)
|
|
154
|
+
np.testing.assert_array_equal(restored, square_or_quasisquare)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Conversion uses the same connected path as `plot_curve(shape=...)`. Spatial
|
|
158
|
+
shapes must be supported squares or quasisquares; general rectangles are not
|
|
159
|
+
supported. Unsupported shapes raise an error without padding or cropping them
|
|
160
|
+
into a different traversal. `shape=` specifies the output's original dimensions;
|
|
161
|
+
it cannot be combined with `order=`. Converting a grid with another curve gives a
|
|
162
|
+
reversible reordering; keep all entries, including padding, when reversing it.
|
|
163
|
+
|
|
164
|
+
## Discover curves
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
info = hp.curves.info(12) # ordinary metadata dictionary
|
|
168
|
+
print(info["name"], info["index"], info["kernels"])
|
|
169
|
+
print([(c["index"], c["name"]) for c in hp.curves.catalog()])
|
|
170
|
+
print([c["index"] for c in hp.curves.generalizing()])
|
|
171
|
+
fig = hp.gallery(hp.curves.by_kernels(3, 5), order=3)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Under `hp.curves`, `catalog()` lists all 40 curves: 6 `proper()`, 6 `improper()` (together 12
|
|
175
|
+
`homogeneous()`), and 28 `inhomogeneous()`. Groups return ordinary lists of metadata
|
|
176
|
+
dictionaries. `closed()` lists the four loops; `generalizing()` lists curves
|
|
177
|
+
0, 3, 4, 5, 24, 29, 30, and 31, which support arbitrary square sizes.
|
|
178
|
+
|
|
179
|
+
Under `hp.config`, `clear_cache()` releases cached generation data, and `cache_info()`
|
|
180
|
+
reports its use.
|
|
181
|
+
`cell_limit()` / `set_cell_limit(n)` control the allocation guard. Grid size grows
|
|
182
|
+
exponentially with order; the default limit is a ceiling, not a memory reservation.
|
|
183
|
+
|
|
184
|
+
More runnable examples are in [examples/](examples/). The curve classification follows
|
|
185
|
+
Estevez-Rams et al., *Hilbert curves in two dimensions*, Rev. Cub. Fís. **34**, 9 (2017).
|
|
186
|
+
The arbitrary-square research is in [research/quasisquares/](research/quasisquares/).
|
|
187
|
+
|
|
188
|
+
## Try all the features
|
|
189
|
+
|
|
190
|
+
The [complete runnable example](examples/try_api.py) draws separate figures for the
|
|
191
|
+
curve, data, coarse-grained data, Fourier and difference maps, colour options, fitting
|
|
192
|
+
modes, and a gallery. It also checks numeric round trips, geometry, indexing and groups.
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
python examples/try_api.py
|
|
196
|
+
# Save figures and run all checks without opening windows:
|
|
197
|
+
MPLBACKEND=Agg python examples/try_api.py --save-only
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Figures are saved in `examples/output/try_api/`.
|
|
201
|
+
|
|
202
|
+
## Local API migration
|
|
203
|
+
|
|
204
|
+
This working-tree redesign replaces the object-based 0.2.0 interface:
|
|
205
|
+
|
|
206
|
+
| Previous | New |
|
|
207
|
+
| --- | --- |
|
|
208
|
+
| `hilbert_plot(12, data).draw()` | `plot(data, curve=12)` |
|
|
209
|
+
| `curve(12).draw(4)` | `plot_curve(12, order=4)` |
|
|
210
|
+
| `plot.save(path)` | `fig = plot(data); fig.savefig(path)` |
|
|
211
|
+
| `curve(12).points(4)` | `hp.curves.points(12, order=4)` |
|
|
212
|
+
| `curve(12).unroll(img)` | `hp.data.from_grid(img, curve=12)` |
|
|
213
|
+
| `curve(12).name` | `hp.curves.info(12)["name"]` |
|
|
214
|
+
| `proper().names` | `[c["name"] for c in hp.curves.proper()]` |
|
|
215
|
+
|
|
216
|
+
The old `Curve`, `CurveList`, `HilbertPlot`, and `hilbert_plot` exports are removed.
|
|
217
|
+
`difference=True` now renders the complete difference map. Rendering defaults to
|
|
218
|
+
power-of-two padding. These are intentional interface changes under local review.
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
MIT © Daniel Estevez — [LICENSE](LICENSE).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Print the curve groups using ordinary dictionaries: python examples/groups.py."""
|
|
2
|
+
|
|
3
|
+
import hilbertplot as hp
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
for group in (hp.curves.proper(), hp.curves.improper(), hp.curves.inhomogeneous()):
|
|
8
|
+
for c in group:
|
|
9
|
+
print(f"{c['index']:2} {c['name']:24} {c['kind']:15} kernels={c['kernels']}")
|
|
10
|
+
print()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if __name__ == "__main__":
|
|
14
|
+
main()
|