Skip to content

Clip instead of squeeze out-of-range latitudes in mercator_transform - #2305

Open
ybai08 wants to merge 1 commit into
python-visualization:mainfrom
ybai08:mercator-transform-clip-bounds
Open

ybai08 wants to merge 1 commit into
python-visualization:mainfrom
ybai08:mercator-transform-clip-bounds

Conversation

@ybai08

@ybai08 ybai08 commented Oct 18, 2026

Copy link
Copy Markdown

Problem

The mercator_transform docstring (and ImageOverlay(mercator_project=True)) says the image is clipped beyond latitude ±85.05. In practice, when lat_bounds goes past that limit, the input rows are laid out between the clipped bounds. The data from the full range is squeezed into ±85.05 instead of being cropped. For a global (-90, 90) grid, every row away from the equator is drawn too far toward it, by up to about 5 degrees. For example, the bottom output row (centred at about -84.96°) gets the -89.5° row's value. The global "Good" example in docs/advanced_guide/geodedetic_image_overlay.md uses these bounds.

import numpy as np
from folium.utilities import mercator_transform

lats = np.linspace(-90, 90, 181)[:-1] + 0.5          # each row = its own latitude
data = np.repeat(lats[:, None], 2, axis=1)
out = mercator_transform(data, (-90, 90), origin="lower")
out[0, 0, 0]   # -89.5 before, about -84.94 after (row centre is -84.96)

Changes

Compute the input row latitudes from the original lat_bounds, and keep the clipped bounds only for the output grid. Bounds inside ±85.05 give the same result as before.

The new test checks that each output row of a latitude-valued global image holds its own centre latitude (within 0.05°, well inside a 1° input pixel). The expected PNG in test_image_overlay changes, because that test uses bounds [0, 90]. Its south row is now interpolated from rows centred at 22.5° and 67.5° rather than 21.3° and 63.8°.

Validation

  • Without the fix (folium/utilities.py reverted), the new test fails ([0]: -89.5 (ACTUAL), -84.964 (DESIRED), max abs difference 4.90) and test_image_overlay fails on the old URL. With the fix both pass.
  • python -m pytest tests --ignore=tests/selenium --ignore=tests/snapshots: 396 passed, 3 failed. The 3 failures are in tests/test_repr.py (cannot import name 'webdriver' from 'selenium', since selenium isn't installed) and fail the same way on main.
  • ruff check folium tests (0.16.10), black --check (26.10.0), codespell on the changed files, and mypy folium pass.
  • The selenium, snapshot, and notebook suites were not run, and the rendered docs page was not checked visually.

When lat_bounds went beyond the Web Mercator limit (+-85.0511), the input
rows were placed between the clipped bounds, so data from the full range was
squeezed into it. For a global (-90, 90) image the rows were shifted towards
the equator by up to ~5 degrees. Lay the input rows out over the original
bounds and only clip the output, as the docstring describes.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant