Polar Data Lands in the Wrong Place
On this page
Problem statement
You load a polar grid β sea-ice concentration, an ice-sheet DEM, a snow product β and it does not sit where it should. The ice edge is rotated a quarter turn around the pole, or appears over Antarctica, or sits a few tens of kilometres too far from the pole all round. Polar stereographic grids come in several near-identical versions that differ in central meridian, latitude of true scale, ellipsoid and hemisphere, and a file whose CRS was lost or overwritten can be assigned the wrong one without any error.
This page takes NSIDC's September 2025 Arctic sea-ice grid, deliberately assigns it the wrong polar CRSs that are most often confused, measures where known places end up, and shows how to tell which mistake you are looking at.
Quick answer
Push a few known places through the right CRS and back through the suspect one, and measure the error. The pattern names the mistake:
for label, wrong in WRONG.items():
to_wrong = Transformer.from_crs(wrong, 4326, always_xy=True)
errs = []
for name, (lon, lat) in PLACES.items():
x, y = to_right.transform(lon, lat) # where the grid really puts this place
lon2, lat2 = to_wrong.transform(x, y) # where a mislabelled grid says it is
errs.append(f"{name} {geod.inv(lon, lat, lon2, lat2)[2] / 1000:,.0f} km")
print(f"{label:30} " + " | ".join(errs))
EPSG:3413 (WGS 84 twin) Utqiagvik 0 km | Longyearbyen 0 km | Tiksi 0 km | Nuuk 0 km
EPSG:3995 (meridian 0) Utqiagvik 1,572 km | Longyearbyen 999 km | Tiksi 1,544 km | Nuuk 2,139 km
true scale at the pole Utqiagvik 62 km | Longyearbyen 39 km | Tiksi 61 km | Nuuk 84 km
EPSG:3031 (Antarctic) Utqiagvik 17,046 km | Longyearbyen 18,390 km | Tiksi 18,071 km | Nuuk 17,272 km
| error pattern | likely mistake |
|---|---|
| none | the right CRS, or EPSG:3413 for EPSG:3411 |
| hundreds to thousands of km, rotated about the pole | wrong central meridian (e.g. EPSG:3995 for EPSG:3411) |
| tens of km, all towards or away from the pole | wrong latitude of true scale |
| the other hemisphere | north grid labelled with a south CRS |
Read the CRS, compare candidates, spot rotation or scale
1. Read the CRS the file actually has
The NSIDC GeoTIFF carries its CRS. Look at it before assigning anything:
with rasterio.open("data/N_202509_concentration_v4.0.tif") as src:
print(src.crs.to_epsg(), src.crs.to_proj4())
3411 +proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +x_0=0 +y_0=0 +a=6378273 +rf=298.279411123064 +units=m +no_defs=True
Polar stereographic north, origin at the pole, true scale at 70Β° N, central meridian 45Β° W, on the Hughes 1980 ellipsoid. Four parameters, each of which differs between common polar CRSs.
2. Compare the candidates
for code in (3411, 3413, 3995, 3031):
print(code, CRS.from_epsg(code).name, "|", CRS.from_epsg(code).to_proj4().replace("+no_defs +type=crs", ""))
3411 NSIDC Sea Ice Polar Stereographic North | +proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +x_0=0 +y_0=0 +a=6378273 +b=6356889.449 +units=m
3413 WGS 84 / NSIDC Sea Ice Polar Stereographic North | +proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +x_0=0 +y_0=0 +datum=WGS84 +units=m
3995 WGS 84 / Arctic Polar Stereographic | +proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m
3031 WGS 84 / Antarctic Polar Stereographic | +proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m
EPSG:3413 is EPSG:3411 on WGS 84; EPSG:3995 has its central meridian at 0Β° and true scale at 71Β° N; EPSG:3031 is the Antarctic grid. Only the first pair is interchangeable at the scale of a 25 km cell.
3. Recognise a rotation
A different central meridian rotates the whole grid about the pole by the difference β 45Β° between EPSG:3411 and EPSG:3995. Places keep their latitude and lose their longitude:
x, y = to_right.transform(*PLACES["Utqiagvik"])
print("Utqiagvik read as EPSG:3995:", [round(v, 1) for v in Transformer.from_crs(3995, 4326, always_xy=True).transform(x, y)])
Utqiagvik read as EPSG:3995: [-111.8, 71.3]
4. Recognise a scale error
A different latitude of true scale shrinks or stretches the grid radially. Assuming true scale at the pole instead of at 70Β° N puts every point slightly too far south β tens of kilometres at the ice edge β without rotating anything. It is the hardest of the mistakes to see on a map and the easiest to measure with a known place.
5. Fix it by assigning, not reprojecting
If the CRS label is wrong, the coordinates are right and only the label must change. Reprojecting from the wrong label would bake the error into the data:
with rasterio.open("data/N_202509_concentration_v4.0.tif") as src:
profile = src.profile | {"crs": CRS.from_epsg(3411)}
with rasterio.open("data/fixed.tif", "w", **profile) as dst:
dst.write(src.read())
print(rasterio.open("data/fixed.tif").crs.to_epsg())
3411
Diagnosing an unknown label from the data
The data used on this page
NSIDC Sea Ice Index, version 4 (G02135), September 2025 monthly concentration GeoTIFF, Northern Hemisphere, from NSIDC / NOAA.
import warnings
from pathlib import Path
import numpy as np
import rasterio
import requests
from pyproj import CRS, Geod, Transformer
Path("data").mkdir(exist_ok=True)
UA = {"User-Agent": "spatialworkflow.io guide (https://www.spatialworkflow.io)"}
f = Path("data/N_202509_concentration_v4.0.tif")
if not f.exists():
f.write_bytes(requests.get("https://noaadata.apps.nsidc.org/NOAA/G02135/north/monthly/geotiff/09_Sep/" + f.name,
headers=UA, timeout=120).content)
PLACES = {"Utqiagvik": (-156.79, 71.29), "Longyearbyen": (15.63, 78.22), "Tiksi": (128.87, 71.64), "Nuuk": (-51.72, 64.18)}
WRONG = {"EPSG:3413 (WGS 84 twin)": "EPSG:3413", "EPSG:3995 (meridian 0)": "EPSG:3995",
"true scale at the pole": "+proj=stere +lat_0=90 +lat_ts=90 +lon_0=-45 +a=6378273 +rf=298.279411123064 +units=m",
"EPSG:3031 (Antarctic)": "EPSG:3031"}
to_right = Transformer.from_crs(4326, 3411, always_xy=True)
geod = Geod(ellps="WGS84")
warnings.filterwarnings("ignore", message="You will likely lose") # PROJ-string export is for display only
print(f.stat().st_size, "bytes")
666553 bytes
Example 1: diagnose an unknown label from the data itself
If you do not know which places should be where, the grid's own land mask is a check. NSIDC marks land as 2540; those cells should fall on land in any coastline dataset:
import geopandas as gpd
from shapely.geometry import Point
if not Path("data/ne_110m_land.zip").exists():
Path("data/ne_110m_land.zip").write_bytes(requests.get("https://naciscdn.org/naturalearth/110m/physical/ne_110m_land.zip", headers=UA, timeout=120).content)
land = gpd.read_file("/vsizip/data/ne_110m_land.zip").union_all()
with rasterio.open(f) as src:
a, tr = src.read(1), src.transform
r, c = np.nonzero(a == 2540)
sel = np.random.default_rng(0).choice(len(r), 400, replace=False)
xs, ys = rasterio.transform.xy(tr, r[sel], c[sel])
for label, code in (("EPSG:3411", "EPSG:3411"), ("EPSG:3995", "EPSG:3995")):
lon, lat = Transformer.from_crs(code, 4326, always_xy=True).transform(np.array(xs), np.array(ys))
on_land = np.mean([land.contains(Point(x, y)) for x, y in zip(lon, lat)])
print(f"{label}: {on_land:.0%} of the grid's land cells fall on Natural Earth land")
EPSG:3411: 100% of the grid's land cells fall on Natural Earth land
EPSG:3995: 46% of the grid's land cells fall on Natural Earth land
Example 2: the southern grid
The Antarctic files use EPSG:3412 β polar stereographic south, true scale at 70Β° S, central meridian 0Β°. Assign it to a northern file and everything moves to the other end of the Earth, which is at least easy to spot; assign EPSG:3411 to a southern file and the error is just as large but the map can look plausible over the Arctic Ocean.
What defines a polar stereographic grid
A polar stereographic projection is defined by the pole it is centred on, the latitude at which its scale is true, the meridian that points down the page, and the ellipsoid. Data producers choose these differently: NSIDC's sea-ice grids use 70Β° and 45Β° W on the Hughes ellipsoid, the European Arctic grid EPSG:3995 uses 71Β° and 0Β° on WGS 84, Antarctic products use their own. The coordinates in a file are meaningless without the right set.
Each parameter, if wrong, moves the data in a characteristic way. A wrong meridian rotates; a wrong latitude of true scale changes the radius; a wrong ellipsoid shifts by metres to hundreds of metres; a wrong hemisphere moves everything to the other pole. Measuring known places β or the data's own land mask β against those patterns identifies the mistake without guessing, and the fix is always to correct the label rather than to reproject.
EPSG 3411 versus 3413, and assign not reproject
- EPSG:3411 and EPSG:3413 differ by ellipsoid only; interchangeable for 25 km grids, not for metre-scale data.
- Rotation about the pole means a wrong central meridian.
- Radial error means a wrong latitude of true scale.
- Assign, do not reproject, when the label is the problem.
- Old NSIDC binary files have no georeferencing at all; supply EPSG:3411 and the grid's corner coordinates.
- Check with the data's own land mask when you have no reference points.
Internal links
- Polar stereographic projections explained β the parameters in detail
- How to map sea-ice concentration β drawing the grid correctly
- Georeferenced map lands in the wrong place β the same diagnosis for scanned maps
- MODIS sinusoidal tiles do not line up β another unusual projection
- Sea-ice extent versus area explained β the totals the grid gives
FAQ
Why is my polar data rotated?
The CRS has the wrong central meridian. NSIDC grids use 45Β° W; EPSG:3995 uses 0Β°, so a mix-up rotates the data 45Β° about the pole.
What is the difference between EPSG:3411 and EPSG:3413?
The ellipsoid: Hughes 1980 for 3411, WGS 84 for 3413. For 25 km sea-ice cells the difference is negligible.
My data is slightly too far from the pole everywhere β why?
Probably a wrong latitude of true scale, which stretches or shrinks the grid radially by tens of kilometres at the ice edge.
How do I fix a wrong CRS on a GeoTIFF?
Rewrite the file with the correct CRS in its profile (or use gdal_edit.py -a_srs). Do not reproject from the wrong CRS.