eofigs 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. eofigs-0.1.0/.gitignore +29 -0
  2. eofigs-0.1.0/CHANGELOG.md +128 -0
  3. eofigs-0.1.0/CITATION.cff +29 -0
  4. eofigs-0.1.0/LICENSE +21 -0
  5. eofigs-0.1.0/PKG-INFO +202 -0
  6. eofigs-0.1.0/README.md +136 -0
  7. eofigs-0.1.0/conftest.py +24 -0
  8. eofigs-0.1.0/pyproject.toml +110 -0
  9. eofigs-0.1.0/src/eofigs/__init__.py +52 -0
  10. eofigs-0.1.0/src/eofigs/_colour.py +258 -0
  11. eofigs-0.1.0/src/eofigs/_countries.py +157 -0
  12. eofigs-0.1.0/src/eofigs/_presets.py +147 -0
  13. eofigs-0.1.0/src/eofigs/accuracy.py +716 -0
  14. eofigs-0.1.0/src/eofigs/check.py +766 -0
  15. eofigs-0.1.0/src/eofigs/data/journals.json +126 -0
  16. eofigs-0.1.0/src/eofigs/data/ne_110m_countries.geojson +1 -0
  17. eofigs-0.1.0/src/eofigs/data/variables.json +270 -0
  18. eofigs-0.1.0/src/eofigs/events.py +1090 -0
  19. eofigs-0.1.0/src/eofigs/export.py +193 -0
  20. eofigs-0.1.0/src/eofigs/figures.py +313 -0
  21. eofigs-0.1.0/src/eofigs/maps.py +1510 -0
  22. eofigs-0.1.0/src/eofigs/palettes.py +90 -0
  23. eofigs-0.1.0/src/eofigs/py.typed +0 -0
  24. eofigs-0.1.0/src/eofigs/raster.py +383 -0
  25. eofigs-0.1.0/src/eofigs/stats.py +251 -0
  26. eofigs-0.1.0/src/eofigs/styling.py +521 -0
  27. eofigs-0.1.0/src/eofigs/trends.py +873 -0
  28. eofigs-0.1.0/src/eofigs/variables.py +329 -0
  29. eofigs-0.1.0/tests/baseline/test_accuracy_scatter_density_image.png +0 -0
  30. eofigs-0.1.0/tests/baseline/test_accuracy_scatter_groups_image.png +0 -0
  31. eofigs-0.1.0/tests/baseline/test_event_composite_image.png +0 -0
  32. eofigs-0.1.0/tests/baseline/test_event_composite_two_phases_image.png +0 -0
  33. eofigs-0.1.0/tests/baseline/test_north_arrow_and_scale_bar_image.png +0 -0
  34. eofigs-0.1.0/tests/baseline/test_study_area_map_inside_image.png +0 -0
  35. eofigs-0.1.0/tests/baseline/test_study_area_map_side_image.png +0 -0
  36. eofigs-0.1.0/tests/baseline/test_trend_map_dots_image.png +0 -0
  37. eofigs-0.1.0/tests/baseline/test_trend_map_hatch_image.png +0 -0
  38. eofigs-0.1.0/tests/baseline/test_trend_map_profile_image.png +0 -0
  39. eofigs-0.1.0/tests/conftest.py +7 -0
  40. eofigs-0.1.0/tests/test_accuracy.py +267 -0
  41. eofigs-0.1.0/tests/test_check.py +242 -0
  42. eofigs-0.1.0/tests/test_colour.py +74 -0
  43. eofigs-0.1.0/tests/test_docs_presets.py +30 -0
  44. eofigs-0.1.0/tests/test_docs_variables.py +20 -0
  45. eofigs-0.1.0/tests/test_events.py +385 -0
  46. eofigs-0.1.0/tests/test_export.py +120 -0
  47. eofigs-0.1.0/tests/test_figures.py +128 -0
  48. eofigs-0.1.0/tests/test_glyphs.py +45 -0
  49. eofigs-0.1.0/tests/test_house_style.py +413 -0
  50. eofigs-0.1.0/tests/test_import.py +40 -0
  51. eofigs-0.1.0/tests/test_map_images.py +171 -0
  52. eofigs-0.1.0/tests/test_maps.py +735 -0
  53. eofigs-0.1.0/tests/test_presets.py +68 -0
  54. eofigs-0.1.0/tests/test_raster.py +280 -0
  55. eofigs-0.1.0/tests/test_stats.py +202 -0
  56. eofigs-0.1.0/tests/test_style.py +164 -0
  57. eofigs-0.1.0/tests/test_trends.py +491 -0
  58. eofigs-0.1.0/tests/test_variables.py +200 -0
@@ -0,0 +1,29 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+
10
+ # Tests and coverage
11
+ .pytest_cache/
12
+ .coverage
13
+ coverage.xml
14
+ coverage.json
15
+ htmlcov/
16
+ result_images/
17
+
18
+ # Tools
19
+ .ruff_cache/
20
+ .mypy_cache/
21
+ .ipynb_checkpoints/
22
+
23
+ # Docs
24
+ site/
25
+
26
+ # OS
27
+ .DS_Store
28
+ Thumbs.db
29
+ desktop.ini
@@ -0,0 +1,128 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
5
+ uses [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-11-08
10
+
11
+ First release: journal styles and one-call export, the figure check, figure sets, the
12
+ variable library, print-size raster handling and trend statistics, with four recipe
13
+ figures: study area map, trend map, event composite and accuracy scatter.
14
+
15
+ ### Added
16
+
17
+ - `study_area_map`: study area outline over a grey hillshade with semi-transparent
18
+ elevation colours (light `lapaz` under an overlay, `batlow` otherwise), a single-colour
19
+ overlay (for example tree cover) that lets the hillshade show through, labelled points,
20
+ graticule (at most four labels per side), north arrow to true north above or beside the
21
+ scale bar, legend and locator inset. The figure height follows the study area's shape up
22
+ to 75 % of the journal maximum; inset, legend and furniture go to the emptiest part of
23
+ the map, clear of the outline, points and labels, or below or beside the map; point
24
+ labels avoid each other and the outline. `subfigure=` draws the map as one panel of a
25
+ larger figure.
26
+ - `add_north_arrow` (rotated by the grid convergence), `add_scale_bar` (true distance at
27
+ the map centre, round lengths) and `add_inset` (Natural Earth countries, default de facto
28
+ boundaries bundled; Natural Earth worldviews downloaded on request with a pinned version
29
+ and checksum, and cached).
30
+ - `trend_map`: per-pixel trends (Theil–Sen, Mann–Kendall, computed at full resolution and
31
+ then reduced to print size; p-values are never averaged) with zero-centred colours,
32
+ symmetric limits at the rounded 98th percentile, significance dots or hatching where at
33
+ least half of the pixels in each 1.6 mm cell are significant, hatched grey for
34
+ non-vegetated and no-data pixels, an optional latitude profile from the full-resolution
35
+ slope, and a ready caption sentence with the colour limits, the clipped share and the
36
+ significance rule (`fig.eofigs_layout["caption"]`).
37
+ - `event_composite`: anomaly maps before, during and after a set of events (date pairs or a
38
+ boolean series), averaged over the events, with a composite series. Events whose window
39
+ runs past the record or overlaps another are dropped with a warning; a per-pixel linear
40
+ trend is removed first; anomalies are taken from a monthly climatology of the non-event
41
+ steps at full resolution (or z-scores); significance by a t-test (or Wilcoxon test) across
42
+ events, marked as in `trend_map`; shared colour limits and a ready caption sentence,
43
+ which notes the low power of a test with fewer than 5 events. The series shades the event
44
+ period, darker while all events are ongoing and lighter while only some are.
45
+ - `accuracy_scatter`: observed against predicted values (predicted on the x axis and the
46
+ least-squares line of observed on predicted by default, after Piñeiro et al. 2008; or
47
+ the reverse, or a reduced major axis line) with the 1:1 line, a statistics box (R² as the
48
+ squared Pearson correlation, RMSE, rRMSE, NMAD after Höhle and Höhle 2009, MAE, bias,
49
+ rBias, NSE, slope, intercept, n)
50
+ with units from the variable library, square axes with shared ticks, groups in Okabe-Ito
51
+ colours with distinct markers, density colours above 1 000 pairs (rasterised in vector
52
+ files), `ax=` for multi-panel figures and a ready caption sentence.
53
+ - Swat ICESat-2 ATL08 terrain heights 2019–2024 (a slope-independent quality rule and a
54
+ random sample of 25 000 segments), converted to EGM2008 heights and paired with the
55
+ Copernicus DEM (built by `docs/scripts/build_swat_icesat2.py`); gallery entries for the
56
+ ICESat-2 comparison, with the DEM error by slope class, and for synthetic calibration and
57
+ validation plots.
58
+ - Swat hot-dry events 2001–2021 from TerraClimate (built by `docs/scripts/build_swat_events.py`)
59
+ and a monthly 1 km NDVI series from MODIS MOD13A1 in `docs/data/swat/`; gallery entries
60
+ for the Swat event composite and a synthetic composite with eight events.
61
+ - Swat growing-season NDVI 2001–2024 (MODIS MOD13A1, 500 m) in `docs/data/swat/`, built by
62
+ `docs/scripts/build_swat_ndvi.py`; gallery entries for the Swat trend map with and
63
+ without the latitude profile.
64
+ - `check_figure` checks that single-colour overlays stay distinguishable from the colour
65
+ maps beneath them.
66
+ - `fit_raster` reads http(s) and s3 URLs.
67
+ - Swat valley sample data in `docs/data/swat/` (not in the package) with
68
+ `DATA_LICENSES.md`; gallery entries for the Swat study area map and a house style.
69
+ - `eofigs.palettes`: Okabe-Ito, muted, slate and terracotta-slate palettes and neutral
70
+ colours; colour maps `"eofigs.slate"` and `"eofigs.terra_slate"` (and `_r`).
71
+ - `cvd_preview`: one image showing a figure in normal vision, protan, deutan and tritan
72
+ simulation and greyscale.
73
+ - `tidy_axes`: four or five ticks at round values on axes and colour bars.
74
+ `set_style(max_ticks=5)` sets a house tick limit, which `check_figure` then checks.
75
+ - `set_style(panel_titles=False)`: recipes leave out panel titles and name the panels in
76
+ their caption sentence instead.
77
+ - `check_figure` accepts metric-compatible free fonts (Liberation Sans, Arimo, TeX Gyre
78
+ Heros, Liberation Serif, Tinos, TeX Gyre Termes) in place of the journal's fonts, with a
79
+ note.
80
+ - `save_figure` rasterises dense layers (mesh plots, collections with more than 2 000
81
+ elements) inside vector files; `rasterize_dense=False` keeps them vector.
82
+ - Styles use a true minus sign.
83
+ - Example gallery built from `examples/*.py` when the documentation is built, with the
84
+ check report and downloads for each figure.
85
+
86
+ - `set_style` and the `style` context manager: journal presets for Elsevier, Springer,
87
+ MDPI, Wiley, Frontiers and Taylor & Francis (plus `custom`), font fallback to
88
+ metric-compatible free fonts with a warning, mathtext matched to the text font,
89
+ Okabe-Ito colour cycle, TrueType font embedding.
90
+ - `new_figure`: figures sized in millimetres from named column widths.
91
+ - `label_panels`: bold (a), (b), ... panel labels in several formats.
92
+ - `save_figure`: one call writes the journal's formats (vector PDF plus TIFF/PNG/EPS) at
93
+ 600 dpi or an exact pixel width, without trimming, with reproducible PDFs.
94
+ - `check_figure`: size, resolution, smallest font, fonts in use or embedded, colour-blind
95
+ safety of categorical colours (CIEDE2000 with simulated colour-vision deficiency) and
96
+ colour-map lightness, for live figures and exported files.
97
+ - Journal presets in `journals.json` with source links and check dates; documentation pages
98
+ for style and export, and for the presets.
99
+ - `art=` option ("combination", "line", "halftone") for `save_figure` and `check_figure`:
100
+ line art is written and checked at the publisher's line-art resolution (for example
101
+ 1000 dpi for Elsevier, 1200 dpi for Springer).
102
+ - Variable library (`variable`, `register_variable`, `Variable`): 22 Earth observation
103
+ variables in `variables.json` with long names, symbols, mathtext units, cmcrameri colour
104
+ maps, default ranges and zero-centred anomaly and trend maps (terracotta–slate for all
105
+ vegetation variables: indices, productivity and structure; `vik` with the physically
106
+ sensible direction for water, temperature, terrain and burn severity); recognises xarray variables
107
+ from CF attributes and writes CF units in mathtext.
108
+ - `fit_raster`: reduces GeoTIFFs, COGs and xarray rasters to the printed resolution (mean,
109
+ mode or mask fraction), ignores nodata, sets sparse pixels to NaN (`min_valid`), keeps the
110
+ CRS, stays lazy with dask, and reads files at the output size (integer files are averaged
111
+ exactly by eofigs).
112
+ - `trend`: Theil–Sen slope and Mann–Kendall test (tie- and continuity-corrected) per pixel,
113
+ against real dates, with `min_valid`, a memory budget for any series length, and dask
114
+ support; compared with `scipy.stats.theilslopes` in the tests. The slope is labelled as a
115
+ trend of the input variable, and the intercept records its `reference_time`.
116
+ - `figure_set` and `FigureSet`: manuscript figures saved as `Fig01_<name>` / `FigS01_<name>`
117
+ in the journal's formats, reordering with file renaming, and `figures_manifest.csv` with
118
+ sizes, resolution, check results and captions; resumes from the manifest.
119
+ - `check_figure` treats single-colour contour lines as lines, not as colour maps.
120
+ - Project structure, packaging, test and documentation workflows, with a check of the
121
+ built wheel and source distribution and an install test on Linux, Windows and macOS.
122
+ - Container image workflow for GitHub Container Registry (development `dev` tag); release tags build
123
+ a multi-architecture image (amd64 and arm64).
124
+ - Code of conduct (Contributor Covenant 2.1), issue templates, pull request template.
125
+ - Citation file validation and coverage total in continuous integration.
126
+
127
+ [Unreleased]: https://github.com/kmkamilkhel/eofigs/compare/v0.1.0...HEAD
128
+ [0.1.0]: https://github.com/kmkamilkhel/eofigs/releases/tag/v0.1.0
@@ -0,0 +1,29 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it using these metadata."
3
+ title: "eofigs: analysis-aware, publication-ready figures for Earth observation research"
4
+ type: software
5
+ version: 0.1.0
6
+ date-released: "2026-11-08"
7
+ abstract: >-
8
+ eofigs turns Earth observation analysis outputs (rasters, time series and validation
9
+ pairs) into journal-ready figures that know the analysis, the variable and the printed
10
+ size. It provides journal presets with one-call export to vector PDF and 600 dpi raster
11
+ files, a figure check (size, resolution, smallest font, font embedding, colour-blind
12
+ safety), a variable library with fixed colour maps and units, print-size raster handling,
13
+ Theil-Sen and Mann-Kendall trend statistics, and recipe figures for study area maps,
14
+ trend maps with significance, event composites and accuracy scatters.
15
+ authors:
16
+ - family-names: Mehmood
17
+ given-names: Kaleem
18
+ orcid: "https://orcid.org/0000-0002-7996-8684"
19
+ affiliation: "Institute of Forest Sciences, University of Swat, Khyber Pakhtunkhwa, Pakistan"
20
+ repository-code: "https://github.com/kmkamilkhel/eofigs"
21
+ url: "https://kmkamilkhel.github.io/eofigs/"
22
+ license: MIT
23
+ keywords:
24
+ - remote sensing
25
+ - earth observation
26
+ - geospatial
27
+ - cartography
28
+ - scientific figures
29
+ - python
eofigs-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kaleem Mehmood
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
eofigs-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,202 @@
1
+ Metadata-Version: 2.5
2
+ Name: eofigs
3
+ Version: 0.1.0
4
+ Summary: Analysis-aware, publication-ready figures for Earth observation research.
5
+ Project-URL: Homepage, https://kmkamilkhel.github.io/eofigs/
6
+ Project-URL: Documentation, https://kmkamilkhel.github.io/eofigs/
7
+ Project-URL: Source, https://github.com/kmkamilkhel/eofigs
8
+ Project-URL: Issues, https://github.com/kmkamilkhel/eofigs/issues
9
+ Project-URL: Changelog, https://github.com/kmkamilkhel/eofigs/blob/main/CHANGELOG.md
10
+ Author-email: Kaleem Mehmood <kaleemmehmood73@gmail.com>
11
+ Maintainer-email: Kaleem Mehmood <kaleemmehmood73@gmail.com>
12
+ License-Expression: MIT
13
+ License-File: LICENSE
14
+ Keywords: cartography,earth observation,geospatial,maps,matplotlib,remote sensing,scientific figures
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Scientific/Engineering :: GIS
25
+ Classifier: Topic :: Scientific/Engineering :: Visualization
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.11
28
+ Requires-Dist: cartopy>=0.23
29
+ Requires-Dist: cmcrameri>=1.9
30
+ Requires-Dist: geopandas>=1.0
31
+ Requires-Dist: matplotlib-scalebar>=0.8
32
+ Requires-Dist: matplotlib>=3.9
33
+ Requires-Dist: numpy>=1.26
34
+ Requires-Dist: pandas>=2.1
35
+ Requires-Dist: pyproj>=3.6
36
+ Requires-Dist: rioxarray>=0.15
37
+ Requires-Dist: scipy>=1.11
38
+ Requires-Dist: shapely>=2.0
39
+ Requires-Dist: xarray>=2024.6
40
+ Provides-Extra: dask
41
+ Requires-Dist: dask[array]>=2024.6; extra == 'dask'
42
+ Requires-Dist: tqdm>=4.66; extra == 'dask'
43
+ Provides-Extra: dev
44
+ Requires-Dist: build>=1.2; extra == 'dev'
45
+ Requires-Dist: dask[array]>=2024.6; extra == 'dev'
46
+ Requires-Dist: mkdocs-material>=9.5; extra == 'dev'
47
+ Requires-Dist: mkdocstrings[python]>=0.26; extra == 'dev'
48
+ Requires-Dist: pre-commit>=4; extra == 'dev'
49
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
50
+ Requires-Dist: pytest-mpl>=0.17; extra == 'dev'
51
+ Requires-Dist: pytest>=8; extra == 'dev'
52
+ Requires-Dist: ruff>=0.17; extra == 'dev'
53
+ Requires-Dist: tqdm>=4.66; extra == 'dev'
54
+ Provides-Extra: docs
55
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
56
+ Requires-Dist: mkdocstrings[python]>=0.26; extra == 'docs'
57
+ Provides-Extra: test
58
+ Requires-Dist: dask[array]>=2024.6; extra == 'test'
59
+ Requires-Dist: pytest-cov>=5; extra == 'test'
60
+ Requires-Dist: pytest-mpl>=0.17; extra == 'test'
61
+ Requires-Dist: pytest>=8; extra == 'test'
62
+ Provides-Extra: xee
63
+ Requires-Dist: earthengine-api>=1.0; extra == 'xee'
64
+ Requires-Dist: xee>=0.1; extra == 'xee'
65
+ Description-Content-Type: text/markdown
66
+
67
+ # eofigs
68
+
69
+ [![Tests](https://github.com/kmkamilkhel/eofigs/actions/workflows/tests.yml/badge.svg)](https://github.com/kmkamilkhel/eofigs/actions/workflows/tests.yml)
70
+ [![Docs](https://github.com/kmkamilkhel/eofigs/actions/workflows/docs.yml/badge.svg)](https://kmkamilkhel.github.io/eofigs/)
71
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
72
+
73
+ Analysis-aware, publication-ready figures for Earth observation research.
74
+
75
+ eofigs turns Earth observation analysis outputs (rasters, time series, validation pairs) into
76
+ journal-ready figures that know the analysis, the variable and the printed size:
77
+
78
+ - **Recipe figures** for common analyses: trend with significance, event composites, and later
79
+ recovery, burn severity, disturbance and divergence.
80
+ - **A variable library** with fixed colour maps, symbols and units, so NDVI, LST or GPP look the
81
+ same in every figure, and their anomalies and trends get zero-centred diverging colours.
82
+ - **Print-size rendering**: rasters are read and reduced to the pixels the printed figure needs,
83
+ from its width in mm and its dpi, keeping memory use and PDF size small.
84
+ - **Journal presets and one-call export** to vector PDF plus 600 dpi PNG or TIFF, with a check
85
+ of size, resolution, smallest font, font embedding and colour-blind safety.
86
+
87
+ ## Gallery
88
+
89
+ <table>
90
+ <tr>
91
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/study_area_swat/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/study_area_swat.png" alt="Study area map: Swat valley"></a><br><b>Study area map: Swat valley</b></td>
92
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/study_area_single_column/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/study_area_single_column.png" alt="Study area map: single column"></a><br><b>Study area map: single column</b></td>
93
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/house_style/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/house_style.png" alt="House style"></a><br><b>House style</b></td>
94
+ </tr>
95
+ <tr>
96
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/style_export/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/style_export.png" alt="Journal style and export"></a><br><b>Journal style and export</b></td>
97
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/large_raster/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/large_raster.png" alt="Large raster at print size"></a><br><b>Large raster at print size</b></td>
98
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/trend_significance/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/trend_significance.png" alt="Trend and significance"></a><br><b>Trend and significance</b></td>
99
+ </tr>
100
+ <tr>
101
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/trend_map_swat/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/trend_map_swat.png" alt="Trend map: Swat valley NDVI 2001–2024"></a><br><b>Trend map: Swat valley NDVI 2001–2024</b></td>
102
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/trend_profile_swat/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/trend_profile_swat.png" alt="Trend map with latitude profile"></a><br><b>Trend map with latitude profile</b></td>
103
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/palettes/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/palettes.png" alt="Built-in palettes"></a><br><b>Built-in palettes</b></td>
104
+ </tr>
105
+ <tr>
106
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/event_composite_swat/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/event_composite_swat.png" alt="Event composite: Swat hot-dry months"></a><br><b>Event composite: Swat hot-dry months</b></td>
107
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/event_composite_synthetic/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/event_composite_synthetic.png" alt="Event composite with significance"></a><br><b>Event composite with significance</b></td>
108
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/accuracy_scatter_icesat2/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/accuracy_scatter_icesat2.png" alt="Accuracy scatter: ICESat-2 against a DEM"></a><br><b>Accuracy scatter: ICESat-2 against a DEM</b></td>
109
+ </tr>
110
+ <tr>
111
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/accuracy_scatter_synthetic/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/accuracy_scatter_synthetic.png" alt="Accuracy scatter: calibration and validation"></a><br><b>Accuracy scatter: calibration and validation</b></td>
112
+ <td width="33%"></td>
113
+ <td width="33%"></td>
114
+ </tr>
115
+ </table>
116
+
117
+ More in the [gallery](https://kmkamilkhel.github.io/eofigs/gallery/), with the code for
118
+ each figure.
119
+
120
+ ## Installation
121
+
122
+ ```bash
123
+ pip install eofigs
124
+ ```
125
+
126
+ eofigs needs Python 3.11 or newer. On Windows and macOS, conda-forge is the simplest source
127
+ of its geospatial libraries; see the
128
+ [installation guide](https://kmkamilkhel.github.io/eofigs/installation/).
129
+
130
+ ## Quick start
131
+
132
+ ```python
133
+ import numpy as np
134
+ import eofigs
135
+
136
+ eofigs.set_style("elsevier") # fonts, sizes and widths of the journal
137
+ rng = np.random.default_rng(1)
138
+ field = rng.gamma(5, 30, 300) # observed aboveground biomass (Mg ha⁻¹)
139
+ model = 0.9 * field + rng.normal(10, 20, 300) # predicted
140
+ fig = eofigs.accuracy_scatter(field, model, variable="agb")
141
+ print(fig.eofigs_layout["caption"]) # a ready caption sentence
142
+ print(eofigs.check_figure(fig)) # size, dpi, smallest font, fonts, colour-blind safety
143
+ eofigs.save_figure(fig, "fig_agb") # vector PDF and a 600 dpi raster
144
+ ```
145
+
146
+ More in the [quickstart](https://kmkamilkhel.github.io/eofigs/quickstart/) and the
147
+ [gallery](https://kmkamilkhel.github.io/eofigs/gallery/).
148
+
149
+ ## Run with Docker
150
+
151
+ A container image with eofigs and its geospatial stack (cartopy, rioxarray, geopandas, fonts)
152
+ is published on GitHub Container Registry for each release (`0.1.0`, `latest`; `dev` follows
153
+ the main branch):
154
+
155
+ ```bash
156
+ docker run --rm -v "$PWD":/work ghcr.io/kmkamilkhel/eofigs:0.1.0 python script.py
157
+ ```
158
+
159
+ ## Roadmap
160
+
161
+ Available in v0.1: `set_style`, `style`, `new_figure`, `label_panels`,
162
+ `save_figure`, `check_figure`, `cvd_preview`, `tidy_axes`, `palettes`, `variable`,
163
+ `register_variable`, `fit_raster`, `trend`, `figure_set`, `study_area_map`,
164
+ `add_north_arrow`, `add_scale_bar`, `add_inset`, `trend_map`, `event_composite` and
165
+ `accuracy_scatter`.
166
+
167
+
168
+ **v0.1**
169
+
170
+ | Function | Purpose |
171
+ |---|---|
172
+ | `set_style`, `new_figure`, `save_figure` | Journal presets (Elsevier, Springer, MDPI, Wiley, Frontiers, Taylor & Francis), widths in mm, one-call export |
173
+ | `check_figure`, `cvd_preview` | Size, dpi, smallest font, embedded fonts, colour-blind safety; preview as seen with colour-vision deficiencies |
174
+ | `palettes`, `tidy_axes` | Built-in palettes and colour maps; a few ticks at round values |
175
+ | `figure_set` | Manuscript figure set with automatic Fig/FigS numbering and a manifest |
176
+ | `variable`, `register_variable` | Variable library: colour map, symbol, unit, range |
177
+ | `fit_raster` | Reduce large rasters to the pixels the printed figure needs |
178
+ | `trend` | Theil–Sen slope with Mann–Kendall test on a time-series cube |
179
+ | `study_area_map` | DEM hillshade, overlay, labelled points, locator inset, graticule, north arrow to true north, scale bar, legend; automatic layout |
180
+ | `trend_map` | Trend map with zero-centred colours, significance dots, optional latitude profile |
181
+ | `event_composite` | Before/during/after anomaly maps with a composite time series |
182
+ | `accuracy_scatter` | Observed against predicted values with the 1:1 line, a fitted line (Piñeiro et al. 2008), R², RMSE, NMAD and bias, density colours or groups |
183
+
184
+ **v0.2**: burn severity, recovery and disturbance recipes, SHAP and partial dependence styling,
185
+ confusion matrix, Google Earth Engine input through Xee at print scale.
186
+
187
+ **v0.3**: R package with matching function names.
188
+
189
+ ## Contributing
190
+
191
+ Questions and ideas are welcome in [Discussions](https://github.com/kmkamilkhel/eofigs/discussions);
192
+ bugs and feature requests in [Issues](https://github.com/kmkamilkhel/eofigs/issues).
193
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md).
194
+
195
+ ## Citation
196
+
197
+ If you use eofigs, please cite it using the metadata in [CITATION.cff](CITATION.cff).
198
+
199
+ ## License
200
+
201
+ MIT. See [LICENSE](LICENSE). Data files have their own licences, listed in
202
+ [DATA_LICENSES.md](DATA_LICENSES.md).
eofigs-0.1.0/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # eofigs
2
+
3
+ [![Tests](https://github.com/kmkamilkhel/eofigs/actions/workflows/tests.yml/badge.svg)](https://github.com/kmkamilkhel/eofigs/actions/workflows/tests.yml)
4
+ [![Docs](https://github.com/kmkamilkhel/eofigs/actions/workflows/docs.yml/badge.svg)](https://kmkamilkhel.github.io/eofigs/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+
7
+ Analysis-aware, publication-ready figures for Earth observation research.
8
+
9
+ eofigs turns Earth observation analysis outputs (rasters, time series, validation pairs) into
10
+ journal-ready figures that know the analysis, the variable and the printed size:
11
+
12
+ - **Recipe figures** for common analyses: trend with significance, event composites, and later
13
+ recovery, burn severity, disturbance and divergence.
14
+ - **A variable library** with fixed colour maps, symbols and units, so NDVI, LST or GPP look the
15
+ same in every figure, and their anomalies and trends get zero-centred diverging colours.
16
+ - **Print-size rendering**: rasters are read and reduced to the pixels the printed figure needs,
17
+ from its width in mm and its dpi, keeping memory use and PDF size small.
18
+ - **Journal presets and one-call export** to vector PDF plus 600 dpi PNG or TIFF, with a check
19
+ of size, resolution, smallest font, font embedding and colour-blind safety.
20
+
21
+ ## Gallery
22
+
23
+ <table>
24
+ <tr>
25
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/study_area_swat/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/study_area_swat.png" alt="Study area map: Swat valley"></a><br><b>Study area map: Swat valley</b></td>
26
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/study_area_single_column/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/study_area_single_column.png" alt="Study area map: single column"></a><br><b>Study area map: single column</b></td>
27
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/house_style/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/house_style.png" alt="House style"></a><br><b>House style</b></td>
28
+ </tr>
29
+ <tr>
30
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/style_export/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/style_export.png" alt="Journal style and export"></a><br><b>Journal style and export</b></td>
31
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/large_raster/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/large_raster.png" alt="Large raster at print size"></a><br><b>Large raster at print size</b></td>
32
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/trend_significance/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/trend_significance.png" alt="Trend and significance"></a><br><b>Trend and significance</b></td>
33
+ </tr>
34
+ <tr>
35
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/trend_map_swat/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/trend_map_swat.png" alt="Trend map: Swat valley NDVI 2001–2024"></a><br><b>Trend map: Swat valley NDVI 2001–2024</b></td>
36
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/trend_profile_swat/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/trend_profile_swat.png" alt="Trend map with latitude profile"></a><br><b>Trend map with latitude profile</b></td>
37
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/palettes/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/palettes.png" alt="Built-in palettes"></a><br><b>Built-in palettes</b></td>
38
+ </tr>
39
+ <tr>
40
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/event_composite_swat/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/event_composite_swat.png" alt="Event composite: Swat hot-dry months"></a><br><b>Event composite: Swat hot-dry months</b></td>
41
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/event_composite_synthetic/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/event_composite_synthetic.png" alt="Event composite with significance"></a><br><b>Event composite with significance</b></td>
42
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/accuracy_scatter_icesat2/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/accuracy_scatter_icesat2.png" alt="Accuracy scatter: ICESat-2 against a DEM"></a><br><b>Accuracy scatter: ICESat-2 against a DEM</b></td>
43
+ </tr>
44
+ <tr>
45
+ <td width="33%"><a href="https://kmkamilkhel.github.io/eofigs/gallery/accuracy_scatter_synthetic/"><img src="https://kmkamilkhel.github.io/eofigs/gallery/thumbs/accuracy_scatter_synthetic.png" alt="Accuracy scatter: calibration and validation"></a><br><b>Accuracy scatter: calibration and validation</b></td>
46
+ <td width="33%"></td>
47
+ <td width="33%"></td>
48
+ </tr>
49
+ </table>
50
+
51
+ More in the [gallery](https://kmkamilkhel.github.io/eofigs/gallery/), with the code for
52
+ each figure.
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install eofigs
58
+ ```
59
+
60
+ eofigs needs Python 3.11 or newer. On Windows and macOS, conda-forge is the simplest source
61
+ of its geospatial libraries; see the
62
+ [installation guide](https://kmkamilkhel.github.io/eofigs/installation/).
63
+
64
+ ## Quick start
65
+
66
+ ```python
67
+ import numpy as np
68
+ import eofigs
69
+
70
+ eofigs.set_style("elsevier") # fonts, sizes and widths of the journal
71
+ rng = np.random.default_rng(1)
72
+ field = rng.gamma(5, 30, 300) # observed aboveground biomass (Mg ha⁻¹)
73
+ model = 0.9 * field + rng.normal(10, 20, 300) # predicted
74
+ fig = eofigs.accuracy_scatter(field, model, variable="agb")
75
+ print(fig.eofigs_layout["caption"]) # a ready caption sentence
76
+ print(eofigs.check_figure(fig)) # size, dpi, smallest font, fonts, colour-blind safety
77
+ eofigs.save_figure(fig, "fig_agb") # vector PDF and a 600 dpi raster
78
+ ```
79
+
80
+ More in the [quickstart](https://kmkamilkhel.github.io/eofigs/quickstart/) and the
81
+ [gallery](https://kmkamilkhel.github.io/eofigs/gallery/).
82
+
83
+ ## Run with Docker
84
+
85
+ A container image with eofigs and its geospatial stack (cartopy, rioxarray, geopandas, fonts)
86
+ is published on GitHub Container Registry for each release (`0.1.0`, `latest`; `dev` follows
87
+ the main branch):
88
+
89
+ ```bash
90
+ docker run --rm -v "$PWD":/work ghcr.io/kmkamilkhel/eofigs:0.1.0 python script.py
91
+ ```
92
+
93
+ ## Roadmap
94
+
95
+ Available in v0.1: `set_style`, `style`, `new_figure`, `label_panels`,
96
+ `save_figure`, `check_figure`, `cvd_preview`, `tidy_axes`, `palettes`, `variable`,
97
+ `register_variable`, `fit_raster`, `trend`, `figure_set`, `study_area_map`,
98
+ `add_north_arrow`, `add_scale_bar`, `add_inset`, `trend_map`, `event_composite` and
99
+ `accuracy_scatter`.
100
+
101
+
102
+ **v0.1**
103
+
104
+ | Function | Purpose |
105
+ |---|---|
106
+ | `set_style`, `new_figure`, `save_figure` | Journal presets (Elsevier, Springer, MDPI, Wiley, Frontiers, Taylor & Francis), widths in mm, one-call export |
107
+ | `check_figure`, `cvd_preview` | Size, dpi, smallest font, embedded fonts, colour-blind safety; preview as seen with colour-vision deficiencies |
108
+ | `palettes`, `tidy_axes` | Built-in palettes and colour maps; a few ticks at round values |
109
+ | `figure_set` | Manuscript figure set with automatic Fig/FigS numbering and a manifest |
110
+ | `variable`, `register_variable` | Variable library: colour map, symbol, unit, range |
111
+ | `fit_raster` | Reduce large rasters to the pixels the printed figure needs |
112
+ | `trend` | Theil–Sen slope with Mann–Kendall test on a time-series cube |
113
+ | `study_area_map` | DEM hillshade, overlay, labelled points, locator inset, graticule, north arrow to true north, scale bar, legend; automatic layout |
114
+ | `trend_map` | Trend map with zero-centred colours, significance dots, optional latitude profile |
115
+ | `event_composite` | Before/during/after anomaly maps with a composite time series |
116
+ | `accuracy_scatter` | Observed against predicted values with the 1:1 line, a fitted line (Piñeiro et al. 2008), R², RMSE, NMAD and bias, density colours or groups |
117
+
118
+ **v0.2**: burn severity, recovery and disturbance recipes, SHAP and partial dependence styling,
119
+ confusion matrix, Google Earth Engine input through Xee at print scale.
120
+
121
+ **v0.3**: R package with matching function names.
122
+
123
+ ## Contributing
124
+
125
+ Questions and ideas are welcome in [Discussions](https://github.com/kmkamilkhel/eofigs/discussions);
126
+ bugs and feature requests in [Issues](https://github.com/kmkamilkhel/eofigs/issues).
127
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md).
128
+
129
+ ## Citation
130
+
131
+ If you use eofigs, please cite it using the metadata in [CITATION.cff](CITATION.cff).
132
+
133
+ ## License
134
+
135
+ MIT. See [LICENSE](LICENSE). Data files have their own licences, listed in
136
+ [DATA_LICENSES.md](DATA_LICENSES.md).
@@ -0,0 +1,24 @@
1
+ """Test set-up shared by the test suite and the docstring examples."""
2
+
3
+ import matplotlib
4
+
5
+ matplotlib.use("Agg")
6
+
7
+ import matplotlib.pyplot as plt # noqa: E402
8
+ import pytest # noqa: E402
9
+
10
+ from eofigs import styling, variables # noqa: E402
11
+
12
+
13
+ @pytest.fixture(autouse=True)
14
+ def _clean_state():
15
+ """Run every test and example with fresh matplotlib settings, eofigs defaults and library."""
16
+ saved_style = dict(styling._STATE)
17
+ saved_registry = dict(variables._REGISTERED)
18
+ with matplotlib.rc_context():
19
+ yield
20
+ plt.close("all")
21
+ styling._STATE.clear()
22
+ styling._STATE.update(saved_style)
23
+ variables._REGISTERED.clear()
24
+ variables._REGISTERED.update(saved_registry)