forcingkit 0.9.0__tar.gz → 0.10.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 (111) hide show
  1. {forcingkit-0.9.0 → forcingkit-0.10.0}/PKG-INFO +1 -1
  2. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/conf.py +1 -1
  3. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/mesh_frames.rst +11 -5
  4. {forcingkit-0.9.0 → forcingkit-0.10.0}/pyproject.toml +1 -1
  5. forcingkit-0.10.0/src/forcingkit/ramps/currents_lis_deep.csv +71 -0
  6. forcingkit-0.10.0/src/forcingkit/ramps/currents_lis_haline.csv +70 -0
  7. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/render.py +4 -0
  8. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_mesh_frames.py +23 -1
  9. {forcingkit-0.9.0 → forcingkit-0.10.0}/uv.lock +1 -1
  10. {forcingkit-0.9.0 → forcingkit-0.10.0}/.agents/forcingkit.md +0 -0
  11. {forcingkit-0.9.0 → forcingkit-0.10.0}/.claude/CLAUDE.md +0 -0
  12. {forcingkit-0.9.0 → forcingkit-0.10.0}/.env.template +0 -0
  13. {forcingkit-0.9.0 → forcingkit-0.10.0}/.github/copilot-instructions.md +0 -0
  14. {forcingkit-0.9.0 → forcingkit-0.10.0}/.github/workflows/docs.yml +0 -0
  15. {forcingkit-0.9.0 → forcingkit-0.10.0}/.github/workflows/publish.yml +0 -0
  16. {forcingkit-0.9.0 → forcingkit-0.10.0}/.github/workflows/tests.yml +0 -0
  17. {forcingkit-0.9.0 → forcingkit-0.10.0}/.gitignore +0 -0
  18. {forcingkit-0.9.0 → forcingkit-0.10.0}/.markdownlint.yaml +0 -0
  19. {forcingkit-0.9.0 → forcingkit-0.10.0}/.pre-commit-config.yaml +0 -0
  20. {forcingkit-0.9.0 → forcingkit-0.10.0}/.python-version +0 -0
  21. {forcingkit-0.9.0 → forcingkit-0.10.0}/AGENTS.md +0 -0
  22. {forcingkit-0.9.0 → forcingkit-0.10.0}/CONTRIBUTING.md +0 -0
  23. {forcingkit-0.9.0 → forcingkit-0.10.0}/Dockerfile +0 -0
  24. {forcingkit-0.9.0 → forcingkit-0.10.0}/LICENSE +0 -0
  25. {forcingkit-0.9.0 → forcingkit-0.10.0}/README.md +0 -0
  26. {forcingkit-0.9.0 → forcingkit-0.10.0}/docker-compose.yml +0 -0
  27. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/Makefile +0 -0
  28. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/make.bat +0 -0
  29. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/requirements-docs.txt +0 -0
  30. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/_extra/CNAME +0 -0
  31. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/_static/custom.css +0 -0
  32. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/_static/forcingkit-noreaster-wind.gif +0 -0
  33. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/atmospheric_forcing.rst +0 -0
  34. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/fetchers.rst +0 -0
  35. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/hycom.rst +0 -0
  36. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/index.rst +0 -0
  37. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/necofs.rst +0 -0
  38. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/nyofs.rst +0 -0
  39. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/rivers.rst +0 -0
  40. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/roadmap.rst +0 -0
  41. {forcingkit-0.9.0 → forcingkit-0.10.0}/docs/source/sources.rst +0 -0
  42. {forcingkit-0.9.0 → forcingkit-0.10.0}/main.py +0 -0
  43. {forcingkit-0.9.0 → forcingkit-0.10.0}/service/__init__.py +0 -0
  44. {forcingkit-0.9.0 → forcingkit-0.10.0}/service/forcingkit_serve/__init__.py +0 -0
  45. {forcingkit-0.9.0 → forcingkit-0.10.0}/service/forcingkit_serve/main.py +0 -0
  46. {forcingkit-0.9.0 → forcingkit-0.10.0}/service/forcingkit_serve/routers/bathymetry.py +0 -0
  47. {forcingkit-0.9.0 → forcingkit-0.10.0}/service/forcingkit_serve/routers/plotly_api.py +0 -0
  48. {forcingkit-0.9.0 → forcingkit-0.10.0}/service/forcingkit_serve/routers/removed.py +0 -0
  49. {forcingkit-0.9.0 → forcingkit-0.10.0}/service/forcingkit_serve/routers/viewer.py +0 -0
  50. {forcingkit-0.9.0 → forcingkit-0.10.0}/service/run_server.py +0 -0
  51. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/__init__.py +0 -0
  52. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/data/rivers/northeast_us.json +0 -0
  53. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/dispatcher.py +0 -0
  54. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/coastwatch.py +0 -0
  55. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/dbofs.py +0 -0
  56. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/erddap.py +0 -0
  57. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/hrrr.py +0 -0
  58. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/hrrr_atmosphere.py +0 -0
  59. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/hrrr_points.py +0 -0
  60. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/hycom.py +0 -0
  61. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/hydrography.py +0 -0
  62. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/ndbc.py +0 -0
  63. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/necofs.py +0 -0
  64. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/noaa.py +0 -0
  65. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/nyofs.py +0 -0
  66. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/usgs.py +0 -0
  67. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/fetchers/usgs_rivers.py +0 -0
  68. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/mesh_frames.py +0 -0
  69. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/ramps/currents_lis.csv +0 -0
  70. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/ramps/currents_lis_dark.csv +0 -0
  71. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/settings.py +0 -0
  72. {forcingkit-0.9.0 → forcingkit-0.10.0}/src/forcingkit/zarr_stream.py +0 -0
  73. {forcingkit-0.9.0 → forcingkit-0.10.0}/static/app.js +0 -0
  74. {forcingkit-0.9.0 → forcingkit-0.10.0}/static/favicon.ico +0 -0
  75. {forcingkit-0.9.0 → forcingkit-0.10.0}/static/favicon.svg +0 -0
  76. {forcingkit-0.9.0 → forcingkit-0.10.0}/static/index.html +0 -0
  77. {forcingkit-0.9.0 → forcingkit-0.10.0}/static/logo.svg +0 -0
  78. {forcingkit-0.9.0 → forcingkit-0.10.0}/static/preview3d.js +0 -0
  79. {forcingkit-0.9.0 → forcingkit-0.10.0}/static/styles.css +0 -0
  80. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/__init__.py +0 -0
  81. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/integration/test_auth.py +0 -0
  82. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/integration/test_erddap_fetch.py +0 -0
  83. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/integration/test_mesh_frames_necofs.py +0 -0
  84. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/integration/test_nyofs_obc_fetch.py +0 -0
  85. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/integration/test_obc_offshore_nj.py +0 -0
  86. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/integration/test_ofs_archive_paths.py +0 -0
  87. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/integration/test_s3_roms_fetchers.py +0 -0
  88. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/scripts/inspect_dem.py +0 -0
  89. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/scripts/inspect_grib.py +0 -0
  90. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/scripts/inspect_zarr.py +0 -0
  91. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_coastwatch.py +0 -0
  92. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_dbofs.py +0 -0
  93. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_dispatcher.py +0 -0
  94. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_erddap.py +0 -0
  95. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_hrrr_atm.py +0 -0
  96. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_hrrr_idx.py +0 -0
  97. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_hrrr_points.py +0 -0
  98. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_hycom.py +0 -0
  99. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_main.py +0 -0
  100. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_ndbc.py +0 -0
  101. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_necofs_parent.py +0 -0
  102. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_noaa_currents.py +0 -0
  103. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_noaa_datum.py +0 -0
  104. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_nyofs.py +0 -0
  105. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_obc_donor_report.py +0 -0
  106. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_obc_pipeline.py +0 -0
  107. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_removed_routes.py +0 -0
  108. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_settings.py +0 -0
  109. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_usgs.py +0 -0
  110. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_usgs_rivers.py +0 -0
  111. {forcingkit-0.9.0 → forcingkit-0.10.0}/tests/unit/test_zarr_stream.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: forcingkit
3
- Version: 0.9.0
3
+ Version: 0.10.0
4
4
  Summary: Spatiotemporal forcing for computational Earth-system models: selects, regrids and serves model-ready time series with provenance.
5
5
  Project-URL: Documentation, https://forcingkit.docs.lhzn.io
6
6
  Project-URL: Issues, https://github.com/lhzn-io/forcingkit/issues
@@ -9,7 +9,7 @@ sys.path.insert(0, os.path.abspath("../../src"))
9
9
  project = "forcingkit"
10
10
  copyright = "2026, Long Horizon Observatory"
11
11
  author = "Daniel Fry"
12
- release = "0.9.0"
12
+ release = "0.10.0"
13
13
 
14
14
  extensions = [
15
15
  "sphinx.ext.autodoc",
@@ -45,12 +45,18 @@ Colour
45
45
  last row take the last colour; NaN is transparent. ``load_lut_csv(path)`` reads such a table
46
46
  from a ``value,r,g,b[,a]`` CSV;
47
47
  - ``packaged_color("currents_lis")``: the surface-current table shipped with the package
48
- (``forcingkit/ramps/currents_lis.csv``), 0.02 to 3.1 m/s on a log axis, pale blue through
49
- yellow to dark green with CIELAB lightness falling monotonically. Its CSV header records the
48
+ (``forcingkit/ramps/currents_lis.csv``), 0.02 to 3.1 m/s on a log axis, pale aqua through
49
+ teal to deep blue-green with CIELAB lightness falling monotonically. Its CSV header records the
50
50
  knots and their source;
51
51
  - ``packaged_color("currents_lis_dark")``: its twin for a dark basemap, on the same speeds, from
52
- midnight blue through steel blue to pale seafoam with lightness rising monotonically, so the
53
- two swap by theme alone.
52
+ deep blue-teal through teal to pale seafoam with lightness rising monotonically, so the two
53
+ swap by theme alone;
54
+ - ``packaged_color("currents_lis_deep")`` and ``packaged_color("currents_lis_haline")``: multi-hue
55
+ alternatives on the same speeds, after cmocean "deep" (light backgrounds: pale green through
56
+ teal and navy to deep purple) and "haline" (dark backgrounds: indigo through blue and green to
57
+ pale yellow). They separate speeds more strongly than the single-hue pair, but they are not
58
+ mirror images: purple is fast in one and slow in the other. Use them for a field shown alone
59
+ with its legend, not beside other colour-mapped layers.
54
60
 
55
61
  Python
56
62
  ------
@@ -83,7 +89,7 @@ Command line
83
89
  --size 1200x800 --ramp viridis --vmax 1.5 \
84
90
  --edges 0,0,0,40 --background 242,243,240 --out frames/
85
91
 
86
- ``--ramp`` takes a built-in name, a packaged table (``currents_lis``, ``currents_lis_dark``) or a path to a
92
+ ``--ramp`` takes a built-in name, a packaged table (``currents_lis``, ``currents_lis_dark``, ``currents_lis_deep``, ``currents_lis_haline``) or a path to a
87
93
  ``value,r,g,b[,a]`` CSV (with ``--log`` and ``--floor``). The output directory receives
88
94
  ``frame_0000.png``, ``frame_0001.png``, ... and ``frames.json``, which lists the frame times, the box
89
95
  and the size.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "forcingkit"
7
- version = "0.9.0"
7
+ version = "0.10.0"
8
8
  description = "Spatiotemporal forcing for computational Earth-system models: selects, regrids and serves model-ready time series with provenance."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1,71 @@
1
+ # Currents speed ramp after cmocean "deep" (Thyng et al. 2016; cmocean is MIT licensed):
2
+ # speed_m_s,r,g,b (sRGB), on the same speeds as currents_lis. Interpolate in log(speed); speeds below the
3
+ # first row take its colour (floor 0.02 m/s) and speeds above the last row (3.1 m/s) clamp to it.
4
+ # Multi-hue for light backgrounds, for a field shown alone with its legend (exports, animations): pale
5
+ # green at slack through teal and navy to deep purple, lightness falling with speed. Colormap position
6
+ # is piecewise linear in log(speed): 0.02 -> 0.12 (past deep's pale-yellow start, so slack never reads
7
+ # as sand), 0.494 -> 0.38, 2.418 -> 0.80, 3.097 -> 1.0.
8
+ # Knots from 2026 NOAA CO-OPS current predictions (MAX_SLACK), Long Island Sound and Block Island
9
+ # Sound: regional median daily maximum 0.494 m/s; ACT2611 Little Gull Island median daily maximum
10
+ # 2.418 m/s, 95th percentile 2.964 m/s, annual maximum 3.097 m/s.
11
+ speed_m_s,r,g,b
12
+ 0.0200,191,231,174
13
+ 0.0221,187,230,172
14
+ 0.0244,183,229,171
15
+ 0.0270,178,227,170
16
+ 0.0299,172,225,168
17
+ 0.0330,167,224,167
18
+ 0.0365,163,222,166
19
+ 0.0403,159,221,165
20
+ 0.0446,154,219,165
21
+ 0.0493,150,218,164
22
+ 0.0545,146,216,164
23
+ 0.0602,141,215,163
24
+ 0.0666,137,213,163
25
+ 0.0736,133,211,163
26
+ 0.0813,129,210,163
27
+ 0.0899,125,208,163
28
+ 0.0994,120,206,163
29
+ 0.1099,117,204,163
30
+ 0.1215,113,202,163
31
+ 0.1343,110,200,163
32
+ 0.1484,107,198,163
33
+ 0.1641,105,196,164
34
+ 0.1813,102,194,164
35
+ 0.2005,100,193,164
36
+ 0.2216,98,191,164
37
+ 0.2449,96,189,164
38
+ 0.2708,94,187,164
39
+ 0.2993,92,185,164
40
+ 0.3309,90,183,164
41
+ 0.3657,88,179,164
42
+ 0.4043,87,177,164
43
+ 0.4469,86,175,164
44
+ 0.4940,85,173,163
45
+ 0.5348,82,168,163
46
+ 0.5790,79,162,162
47
+ 0.6269,77,157,161
48
+ 0.6787,75,152,160
49
+ 0.7348,73,146,159
50
+ 0.7955,72,141,157
51
+ 0.8613,70,136,156
52
+ 0.9324,68,130,155
53
+ 1.0095,67,125,154
54
+ 1.0929,65,119,153
55
+ 1.1833,64,114,152
56
+ 1.2810,63,109,151
57
+ 1.3869,62,103,149
58
+ 1.5015,62,98,148
59
+ 1.6256,62,92,147
60
+ 1.7600,62,86,145
61
+ 1.9054,63,80,142
62
+ 2.0629,65,74,137
63
+ 2.2334,65,69,131
64
+ 2.4180,65,64,123
65
+ 2.5198,63,57,108
66
+ 2.6259,60,51,95
67
+ 2.7365,56,45,81
68
+ 2.8518,51,39,68
69
+ 2.9719,45,32,55
70
+ 3.0970,40,26,44
71
+ 3.1000,40,26,44
@@ -0,0 +1,70 @@
1
+ # Currents speed ramp after cmocean "haline" (Thyng et al. 2016; cmocean is MIT licensed):
2
+ # speed_m_s,r,g,b (sRGB), on the same speeds as currents_lis. Interpolate in log(speed); speeds below the
3
+ # first row take its colour (floor 0.02 m/s) and speeds above the last row (3.1 m/s) clamp to it.
4
+ # Multi-hue for dark backgrounds, for a field shown alone with its legend (exports, animations): indigo
5
+ # at slack through blue and green to pale yellow, lightness rising with speed. Colormap position is
6
+ # piecewise linear in log(speed): 0.02 -> 0, 0.494 -> 0.29, 2.418 -> 0.80, 3.097 -> 1.0.
7
+ # Knots from 2026 NOAA CO-OPS current predictions (MAX_SLACK), Long Island Sound and Block Island
8
+ # Sound: regional median daily maximum 0.494 m/s; ACT2611 Little Gull Island median daily maximum
9
+ # 2.418 m/s, 95th percentile 2.964 m/s, annual maximum 3.097 m/s.
10
+ speed_m_s,r,g,b
11
+ 0.0200,42,24,108
12
+ 0.0221,42,25,113
13
+ 0.0244,43,25,117
14
+ 0.0270,44,26,122
15
+ 0.0299,45,27,130
16
+ 0.0330,46,27,135
17
+ 0.0365,46,28,140
18
+ 0.0403,46,29,147
19
+ 0.0446,46,30,152
20
+ 0.0493,45,32,156
21
+ 0.0545,43,36,160
22
+ 0.0602,41,39,162
23
+ 0.0666,38,43,163
24
+ 0.0736,34,48,163
25
+ 0.0813,32,52,162
26
+ 0.0899,29,55,161
27
+ 0.0994,25,60,159
28
+ 0.1099,23,63,158
29
+ 0.1215,21,65,156
30
+ 0.1343,18,69,155
31
+ 0.1484,16,72,153
32
+ 0.1641,15,74,152
33
+ 0.1813,13,78,150
34
+ 0.2005,12,80,149
35
+ 0.2216,12,82,148
36
+ 0.2449,12,84,147
37
+ 0.2708,13,87,146
38
+ 0.2993,14,89,145
39
+ 0.3309,15,91,144
40
+ 0.3657,17,94,143
41
+ 0.4043,19,96,142
42
+ 0.4469,20,98,142
43
+ 0.4940,23,100,141
44
+ 0.5348,28,106,140
45
+ 0.5790,34,112,138
46
+ 0.6269,38,117,138
47
+ 0.6787,43,123,137
48
+ 0.7348,47,128,137
49
+ 0.7955,52,134,136
50
+ 0.8613,55,139,136
51
+ 0.9324,59,145,135
52
+ 1.0095,62,151,135
53
+ 1.0929,66,157,133
54
+ 1.1833,70,164,131
55
+ 1.2810,74,169,129
56
+ 1.3869,79,175,126
57
+ 1.5015,84,181,123
58
+ 1.6256,92,187,119
59
+ 1.7600,99,192,114
60
+ 1.9054,110,198,109
61
+ 2.0629,120,203,104
62
+ 2.2334,134,208,98
63
+ 2.4180,148,211,93
64
+ 2.5198,170,216,92
65
+ 2.6259,189,220,98
66
+ 2.7365,208,224,109
67
+ 2.8518,224,229,122
68
+ 2.9719,240,234,138
69
+ 3.0970,253,239,154
70
+ 3.1000,253,239,154
@@ -146,6 +146,10 @@ PACKAGED_RAMPS: dict[str, dict] = {
146
146
  "currents_lis": {"log": True, "floor": 0.02},
147
147
  # Its twin for a dark basemap: the same speeds, lightness rising monotonically.
148
148
  "currents_lis_dark": {"log": True, "floor": 0.02},
149
+ # Multi-hue alternatives on the same speeds, after cmocean "deep" (light backgrounds; lightness
150
+ # falling) and "haline" (dark; rising), for a field shown alone with its legend.
151
+ "currents_lis_deep": {"log": True, "floor": 0.02},
152
+ "currents_lis_haline": {"log": True, "floor": 0.02},
149
153
  }
150
154
 
151
155
 
@@ -367,7 +367,29 @@ def test_dark_currents_ramp_matches_axis_and_rises_in_lightness():
367
367
  _assert_cool_hues(dark[:, 1:])
368
368
 
369
369
 
370
- @pytest.mark.parametrize("name", ["currents_lis", "currents_lis_dark"])
370
+ @pytest.mark.parametrize(
371
+ ("name", "falling"), [("currents_lis_deep", True), ("currents_lis_haline", False)]
372
+ )
373
+ def test_multi_hue_currents_ramps_share_the_axis(name, falling):
374
+ light = np.array(render.packaged_ramp_rows("currents_lis"))
375
+ rows = np.array(render.packaged_ramp_rows(name))
376
+ np.testing.assert_array_equal(rows[:, 0], light[:, 0])
377
+ L = _lightness(rows[:, 1:])
378
+ steps = np.diff(L)
379
+ assert np.all(steps <= 0) if falling else np.all(steps >= 0), (
380
+ "lightness must be monotone"
381
+ )
382
+ # No warning hues: nothing between red and orange-yellow among the coloured rows.
383
+ lab = _lab(rows[:, 1:])
384
+ hue = np.degrees(np.arctan2(lab[:, 2], lab[:, 1])) % 360
385
+ chroma = np.hypot(lab[:, 1], lab[:, 2])
386
+ assert not np.any((chroma > 10) & ((hue < 80) | (hue > 340))), hue
387
+
388
+
389
+ @pytest.mark.parametrize(
390
+ "name",
391
+ ["currents_lis", "currents_lis_dark", "currents_lis_deep", "currents_lis_haline"],
392
+ )
371
393
  def test_currents_ramp_floor_log_axis_and_clamp(name):
372
394
  rows = render.packaged_ramp_rows(name)
373
395
  color = render.packaged_color(name)
@@ -873,7 +873,7 @@ wheels = [
873
873
 
874
874
  [[package]]
875
875
  name = "forcingkit"
876
- version = "0.9.0"
876
+ version = "0.10.0"
877
877
  source = { editable = "." }
878
878
  dependencies = [
879
879
  { name = "bottleneck" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes