Skip to content

Customization reference

Every decoration in AcadGIS follows the same pattern, so you can dial in as much or as little as you want:

You pass Meaning
True / False on with defaults / off
"rose" (a string) a style shortcut, e.g. north_arrow="rose"
{...} (a dict) full control — every option below
[a, b, c] (a list) per‑panel in study_area — one value per map

So in study_area, graticule=False turns the grid off everywhere, graticule={'grid': False} configures all panels, and graticule=[True, True, {'grid': False}] sets each panel independently.

Everything here is reachable through a single import acadgis as agis — no matplotlib imports.


Grid & ticks (graticule)

Independent control of the grid lines and the degree ticks/labels. Pass as graticule={...} in plot() / study_area() (or a per‑panel list).

Option Values Default Notes
grid True / False True draw grid lines. False keeps ticks, drops lines
grid_color colour #9aa0a6 grid line colour
grid_lw number 0.5 grid line width
grid_alpha 0–1 0.55 grid line opacity
grid_style '-','--',':','-.', dash tuple '-' grid line dash
square True / False True equal interval on both axes (square cells)
interval degrees auto spacing for both axes
x_interval / y_interval degrees auto per‑axis spacing (overrides interval)
n int 5 target number of divisions when auto
ticks True / False True draw tick marks + labels
tick_dir 'in','out','inout' 'out' tick direction (like QGIS/Excel)
tick_len / tick_width number 3.5 / 0.8 tick mark size
tick_color colour #333 tick mark colour
minor True / False False minor ticks between majors
minor_n int 2 minor subdivisions
sides subset of 'lrtb' or 'all' 'lb' which sides get labels
tick_sides subset of 'lrtb' or 'all' = sides which sides get tick marks
fontsize number 8 label size
label_color colour #333 label colour
bold / italic True / False False label weight/style
font font family default label font
rotate_x / rotate_y degrees 0 label rotation (rotate_y=90 = vertical latitude)
# grid OFF, keep ticks, on all four sides, vertical latitude labels
agis.study_area(..., graticule={'grid': False, 'sides': 'all', 'rotate_y': 90})

# dashed teal square grid, 1° spacing, ticks pointing inward, with minor ticks
agis.plot(gdf, graticule={'grid_color': '#1b9aaa', 'grid_style': '--', 'grid_lw': 0.8,
                          'interval': 1.0, 'tick_dir': 'in', 'minor': True})

# bold labels, custom font, coarser ticks on just the focus map (per-panel list)
agis.study_area(..., graticule=[True, True, {'interval': 0.3, 'bold': True}])

# fully off
agis.study_area(..., graticule=False)

North arrow (north_arrow)

Option Values Default Notes
style classic,minimal,pointer,rose classic arrow design
size number 0.12 height as a fraction of the axes
color colour theme fill colour
edge colour none outline colour for the arrow shapes
label text "N" the label
label_color colour = color label colour
label_size number auto label font size
rotation degrees 0 rotate the whole arrow (e.g. declination)
coords 'axes' / 'data' 'axes' placement system
loc (x,y) (0.92, 0.88) position: axes fraction 0–1, or (lon,lat) if coords='data'
agis.plot(gdf, north_arrow="rose")                              # style shortcut
agis.plot(gdf, north_arrow={'style': 'rose', 'size': 0.16, 'color': '#1b9aaa',
                            'edge': '#06222b', 'label_color': '#e63946', 'rotation': 12})
agis.plot(gdf, north_arrow={'style': 'pointer', 'coords': 'data', 'loc': (92.3, 25.0)})
agis.study_area(..., north_arrow=[True, False, {'style': 'minimal'}])   # per panel
agis.plot(gdf, north_arrow=False)                              # off

Scale bar (scale_bar)

Option Values Default Notes
style bar,simple,stepped,double,ticks bar QGIS‑style bars
length_km number auto real length; auto‑rounded if omitted
units km,mi km label units
size number 1.0 scales bar + label
color colour theme fill / line
edge colour = color outline
text_color colour = color label colour
divisions int 4 segments for stepped/double/ticks
coords 'axes' / 'data' 'axes' placement system
loc (x,y) (0.07, 0.07) bar's left end: axes fraction or (lon,lat)
fontsize number auto label size
agis.plot(gdf, scale_bar="stepped")
agis.plot(gdf, scale_bar={'style': 'double', 'divisions': 5, 'color': '#0b3b34',
                          'text_color': '#e63946', 'length_km': 100})
agis.plot(gdf, scale_bar={'style': 'ticks', 'coords': 'data', 'loc': (88.2, 21.4)})
agis.plot(gdf, scale_bar=False)

Region highlight (highlight_*)

The marked region on each parent panel. By default a single indicator (no more double box).

Option Values Default Notes
highlight_style overlay,rect,circle overlay fill+border / rectangle / circle
highlight_color colour red fill colour
highlight_edge colour / 'none' = colour border colour
highlight_alpha 0–1 0.30 fill opacity (0 = no fill)
highlight_width number 2.0 border thickness (0 = no border)
agis.study_area(..., highlight_style='overlay', highlight_color='#2d6a4f',
                highlight_edge='#3ad29f', highlight_width=3)      # glowing border
agis.study_area(..., highlight_style='circle', highlight_color='#2b6cb0')
agis.study_area(..., highlight_style='overlay', highlight_alpha=0, highlight_width=0)  # hide it

Connectors

Built‑in linking between panels, plus a wrapped agis.connect() for hand‑placed lines.

Built‑in (in study_area):

Option Values Default Notes
links True/False True draw connector lines
link_color colour = highlight line colour
link_width number 1.6 line width
link_style '-','--',':','-.', dash tuple '-' line dash
box True/False False draw a focus box on the parent (opt‑in)

Customagis.connect(fig, a, xy_a, b, xy_b, ...):

Arg Values Notes
a, b panels e.g. fig.panels[0], fig.panels[1]
xy_a, xy_b (x,y) endpoints
a_coords,b_coords 'data','axes','figure' data=lon/lat · axes=panel 0–1 corner · figure=whole fig
color,width,style,alpha line styling
arrow True/False arrowhead at the b end
fig = agis.study_area(..., links=False, box=False)
p1, p2, p3 = fig.panels[:3]

# a wedge: two lines from a panel's corners to a map point
for corner in [(1, 1), (1, 0)]:
    agis.connect(fig, p2, corner, p1, (-4.0, 57.0),
                 a_coords='axes', b_coords='data', style=(0, (6, 3)))

# an arrowed connector between two map points
agis.connect(fig, p3, (0, 0.5), p2, (-4.2, 56.1),
             a_coords='axes', b_coords='data', arrow=True, color='#e63946')

Zoom (zoom, agis.zoom_axes)

Zoom each map independently. > 1 zooms in, < 1 zooms out (use 0.1 steps as you like).

agis.study_area(..., zoom=[1.0, 1.3, 1.6])         # per-panel factor
agis.zoom_axes(ax, 1.5)                              # zoom one map in 1.5x
agis.zoom_axes(ax, 0.8, center=(90.4, 23.6))        # zoom out about a lon/lat

Oversized‑country callouts (agis.callout)

The Alaska/Hawaii pattern — show a far‑flung part in its own framed box, placed anywhere.

Option Values Default Notes
loc (x0,y0,w,h) (0.02,0.02,0.28,0.28) box position+size (axes fraction)
color / palette / terrain fill: single colour, AcadGIS palette, or relief
cmap colormap terrain terrain colormap
edge / lw / facecolor #333/1.0/white the callout frame
zoom number 1.0 extra zoom inside the box
title / title_size callout label
usa = agis.load_boundaries("USA", "state")
ax  = agis.plot(usa, palette="vibrant", scale_bar=False, north_arrow=False)
ax.set_xlim(-125, -66); ax.set_ylim(24, 50)                    # CONUS only
agis.callout(ax, usa[usa.NAME_1=="Alaska"], loc=(0.005,0.02,0.26,0.26),
             palette="vibrant", title="Alaska")
agis.callout(ax, usa[usa.NAME_1=="Hawaii"], loc=(0.28,0.02,0.15,0.18),
             palette="vibrant", title="Hawaii")

Layout & panel sizes

Keep the template defaults, then tweak any panel.

Option Values Default Notes
template single,two,cascade,series,grid cascade preset layout
uniform_panels True/False True equal panel boxes
panel_scale {index_or_role: factor} resize specific panels
gap number or (w,h) easy spacing between maps
width_ratios / height_ratios list template manual column/row sizes
wspace / hspace number template manual gaps
figsize (w,h) template whole‑figure size

panel_scale keys accept an index (0,1,2,…, negatives ok) or a role: country/first · region/state/second · detail/focus/last/terrain.

agis.study_area(..., panel_scale={'detail': 1.5})       # focus map 1.5x bigger
agis.study_area(..., panel_scale={2: 0.7}, gap=0.30)     # panel 2 smaller, wider gaps
agis.study_area(..., width_ratios=[1, 2.4], height_ratios=[1, 1.3])   # manual

Titles inside or outside (title_inside)

Option Values Default Notes
title_inside True/False or per‑panel list False move the map title inside the panel
title_loc (x,y) (0.03, 0.96) inside position (axes fraction)
title_box True/False True white background behind the title
suptitle text the figure title (always outside, on top)
agis.study_area(..., title_inside=True)                              # all inside
agis.study_area(..., title_inside=[False, False, True],              # only the focus
                title_loc=(0.5, 0.97), title_box=False)

Colorbar (terrain panel) — colorbar

Key Values Default Notes
loc right,bottom,inside right position (doesn't shrink the map)
length 0–1 0.72 bar length (fraction of the side)
size 0–1 0.03 bar thickness
pad number 0.02 gap from the map
label text "Elevation (m)" colorbar label
show True/False True show/hide
agis.study_area(..., terrain=True,
                colorbar={'loc': 'bottom', 'length': 0.6, 'pad': 0.05, 'label': 'Elevation (m)'})

Standalone relief() exposes the same via legend_loc / legend_length / legend_size / legend_pad / legend_label.


Sea / ocean (sea, agis.add_sea)

Show the ocean around a coastal country with one argument — no extra imports (geopandas/shapely are wrapped inside). The country's own detailed coast bounds the sea, so there are no coastline slivers; landlocked countries draw nothing.

agis.plot(gdf, sea=True)                         # bundled 110 m, offline
agis.plot(gdf, sea="#9ecae9")                    # just the colour
agis.plot(gdf, sea={"source": "ne10m", "pad": 0.35,
                    "labels": {"Bay of Bengal": (91.2, 21.2)}})   # crisp coast
agis.study_area(..., sea=[{"source": "ne10m"}, None, None])       # per panel

agis.add_sea(ax, country=…, …) options:

Option Values Default Notes
source auto · ne10m · ocean auto 110 m bundled · 10 m land (crisp) · 10 m ocean polygon
color colour #9ecae9 ocean fill
extent / pad (minx,miny,maxx,maxy) / number view frame; pad reveals more ocean
background colour white land/neighbour background
neighbours True/False False fill neighbour land vs. leave white
coastline True/False False draw the country coastline
labels {"Bay of Bengal": (lon,lat), …} sea labels

Data

source="ne10m"/"ocean" download Natural Earth 10 m (~3 MB) once and cache it in ~/.acadgis/cache; source="auto" is fully offline.

Per‑panel pattern (recap)

Anywhere study_area takes a decoration, a list sets it per map (country → … → focus):

agis.study_area("Bangladesh",
    steps=[("division","Dhaka"), ("district","Madaripur")],
    template="cascade", terrain=True,
    graticule=[True, True, {'grid': False, 'sides': 'all'}],
    north_arrow=[True, False, {'style': 'rose'}],
    scale_bar=[False, True, {'style': 'double'}],
    title_inside=[False, False, True],
    zoom=[1.0, 1.2, 1.4],
)

Layers — raster · vector · basemap · topography

Every layer is an add_*(ax, …) overlay, so it composes with plot() and any study_area panel. Rasters are reprojected to lon/lat automatically.

Z‑order ladder (defaults, so layers stack predictably): sea 0 · basemap/raster 1 · land polygons 5 · rivers/roads 6 · points/labels 8.

add_raster — any GeoTIFF

Three modes — continuous, categorical, RGB. area clips to a geometry. (needs acadgis[terrain])

# continuous (NDVI / climate / elevation)
agis.add_raster(ax, "ndvi.tif", area=gdf, cmap="YlGn", vmin=0, vmax=1,
                colorbar=True, colorbar_label="NDVI", opacity=1.0)

# categorical (land cover) — classes = {value: (colour, label)}
agis.add_raster(ax, "landcover.tif", area=gdf, categorical=True,
                classes={1: ("#4a90d9", "Water"), 2: ("#2a9d4a", "Forest")},
                legend=True, legend_loc="lower left", legend_title="Land cover")

# true-colour
agis.add_raster(ax, "scene_rgb.tif", rgb=True)

add_layer — any vector, with label control

Auto‑detects polygon / line / point. labels=: None/False hide · "one"/1 single · an int top‑N · True/"all" every feature.

agis.add_layer(ax, "roads.geojson", color="#555", linewidth=0.6)          # lines
agis.add_layer(ax, sites_gdf, color="#c0392b", marker="^", markersize=55,  # points
               labels="all", label_field="name", label_size=8,
               label="Field sites", legend=True)
agis.add_layer(ax, regions, facecolor="none", edgecolor="#333")            # polygons

add_basemap / add_satellite — XYZ tiles

Styles: satellite · osm · light · dark · terrain · toner. Set the map extent first, then call it. (needs acadgis[basemap])

agis.add_basemap(ax, style="satellite", alpha=1.0, zoom="auto")
agis.add_satellite(ax)        # shortcut

add_topography — DEM hillshade

agis.add_topography(ax, area=(91.7, 21.9, 92.5, 23.2),   # name / bbox / GeoDataFrame
                    cmap="terrain", hillshade=True,
                    colorbar=True, colorbar_label="Elevation (m)", max_size=900)

add_cities / add_roads — curated context

agis.add_cities(ax, area=gdf, top=8, labels=5)            # Natural Earth places, ranked
agis.add_roads(ax, area=gdf, classes=("motorway", "trunk", "primary"))   # OpenStreetMap

add_landcover / add_ndvi — curated raster data (no GeoTIFF needed)

Fetch a real global dataset for an area automatically and render it.

# ESA WorldCover 10 m land cover (public COGs, windowed remote read) + class legend
agis.add_landcover(ax, area, year=2021)

# Sentinel-2 NDVI — least-cloudy scene in a date window, computed (NIR-Red)/(NIR+Red)
agis.add_ndvi(ax, area, start="2023-11-01", end="2024-03-01", max_cloud=10,
              cmap="RdYlGn")
# the chosen scene date is on ax._acadgis_ndvi_date

Area & extras

area may be a country/region name, a (minx, miny, maxx, maxy) bbox, or a GeoDataFrame (clips to the polygon). Both need pip install "acadgis[terrain]" and network access.

Thematic map types

The full standard catalogue (0.2.0). Choropleth (choropleth()) and graduated symbols (points(size_by=)) shipped earlier; these complete it.

Interpolated fields — isopleth & isolines

# sparse stations -> smooth grid (numpy Gaussian kernel; clip= masks the ocean)
Z, ext = agis.interpolate_field(lon, lat, temp, bbox=(-125, 24, -66, 50),
                                clip=usa, bw=6)      # bw in degrees: bigger = smoother

agis.add_isopleth(ax, (Z, ext), cmap="RdYlBu_r", levels=14,
                  colorbar=True, colorbar_label="Temperature (°C)")   # filled
agis.add_contours(ax, (Z, ext), levels=12, colors="#c1121f",
                  labels=True, fmt="%d°", fontsize=6)                  # isolines
# both also accept a bare 2-D array (+ extent=), a DEM, or a GeoTIFF path
agis.add_contours(ax, agis.load_dem(area), levels=15, fmt="%d m")

Heat map (density)

agis.add_heatmap(ax, lon, lat, kind="kde", weights=pop, colorbar=True)  # smooth
agis.add_heatmap(ax, lon, lat, kind="hexbin", gridsize=120, bins="log") # dense events
# kind="auto" picks KDE for sparse data, hexbin for large point sets

Dot-density

agis.dot_density(ax, states, "population", per=100000,   # 1 dot = 100 000
                 color="#1d3557", size=1.6, seed=0)

Bivariate choropleth

agis.bivariate(gdf, "income", "education",               # terciles × terciles
               xlabel="Income", ylabel="Education")      # 3×3 palette + 2-D legend
# custom palette: a 3×3 list of colours via palette=

Cartograms

agis.cartogram(gdf, "population", kind="dorling",        # circles ∝ value
               labels="NAME_1", cmap="viridis")
agis.cartogram(gdf, "population", kind="noncontig",      # regions scaled in place
               cmap="YlOrRd", colorbar=True)             # ghost outlines underneath

One engine, three maps

interpolate_field is shared: the same (Z, extent) grid renders as a filled isopleth, labelled isolines, or an imshow heat surface.

links= accepts True/False or a dict for full connector control:

agis.study_area("Bangladesh", [("division", "Dhaka"), ("district", "Gazipur")],
    template="series",
    links={
        "single": True,            # one line per hop (default: two corner lines)
        "shrink": (10, -18),       # trim/stretch each end, in points
                                   #   positive = shrink · negative = stretch past the end
        "arrow": True,             # arrowhead at the destination (deeper) end
        "arrow_size": 16,          #   or arrow="->" / "wedge" / any matplotlib arrowstyle
        "dots": True,              # endpoint markers …
        "dot_size": 10,            # … enlarged
        "dot_color": "#b30000",
        "alpha": 0.9,
        "pad": 0.25,               # padding of the (invisible) locator box the
                                   # corner anchors sit on — bigger = wider spread
        "anchors": [("r", (0.0, 0.5))],
        # where each line attaches:
        #   source  = a corner/edge name  tl · tr · bl · br · t · b · l · r · c
        #             or an explicit (lon, lat) point on the source panel
        #   target  = (x, y) axes fraction on the destination panel
        # a list applies to every hop; use {hop_index: [...]} per hop
        "color": "#ff0000", "width": 2.2, "style": "-", "box": False,
    })

For arbitrary extra lines (arrows, panel-to-panel annotations) use agis.connect(fig, axA, (lon, lat), axB, (x, y), b_coords="axes", arrow=True).

Per-panel layers — sea, rivers, labels

sea, rivers and labels are scalar (all panels) or a per-panel list [country, …, focus] — turn each on/off exactly where you want it:

agis.study_area("Bangladesh", [("division", "Dhaka"), ("district", "Gazipur")],
    template="series",
    sea=[True, False, False],                         # ocean only on the country panel
    #   sea=True · a colour · {"source": "ne10m", "color": "#a9d3e8"} · False
    rivers=[{"color": "#2b7bba", "scale": "10m"},     # NE rivers on the first two panels
            {"color": "#2b7bba", "scale": "10m"}, False],
    #   rivers=True · a colour · {"source": "osm"} (dense OpenStreetMap) · False
    labels=[False, True, False],                      # region names only on the division
    scale_bar=[False, True, True],                    # decorations are per-panel too
    north_arrow=[False, {"style": "rose"}, {"style": "minimal"}],
    graticule={"grid": True, "sides": "lb", "tick_dir": "in", "fontsize": 6})

Extras

add_raster/add_topography need pip install "acadgis[terrain]"; add_basemap/add_satellite need pip install "acadgis[basemap]". add_cities/add_roads download from Natural Earth / OpenStreetMap and cache in ~/.acadgis/cache.