Skip to content

Commit 8913842

Browse files
joa-quimclaude
andauthored
Add standalone mapscale() function for map scale bars (#1918)
Convenience wrapper around basemap that draws map scale bars (-L). Extracts scale-specific options (anchor, scale_at_lat, length, fancy, label, align, units, etc.) as top-level kwargs. Uses Dict-based dispatch pattern to avoid recompilation. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5be0b89 commit 8913842

3 files changed

Lines changed: 74 additions & 1 deletion

File tree

src/GMT.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export
129129
grdcut, grdedit, grdfft, grdfill, grdfilter, grdgradient, grdhisteq, grdimage, grdimage!, grdinfo, grdinterpolate,
130130
grdlandmask, grdmath, grdmask, grdpaste, grdproject, grdsample, grdtrack, grdtrend, grdvector, grdvector!,
131131
grdview, grdview!, grdvolume, greenspline, histogram, histogram!, image, image!, image_alpha!, image_cpt!,
132-
imshow, ind2rgb, isnodata, kml2gmt, logo, logo!, makecpt, mask, mask!, mapproject, movie, nearneighbor, plot, plot!,
132+
imshow, ind2rgb, isnodata, kml2gmt, logo, logo!, makecpt, mapscale, mapscale!, mask, mask!, mapproject, movie, nearneighbor, plot, plot!,
133133
plot3, plot3!, plot3d, plot3d!, plotyy, project, pscontour, pscontour!, psconvert, psbasemap, psbasemap!,
134134
psclip, psclip!, pscoast, pscoast!, psevents, pshistogram, pshistogram!,
135135
psimage, psimage!, pslegend, pslegend!, psmask, psmask!, psrose, psrose!, psscale, psscale!, pssolar, pssolar!,
@@ -285,6 +285,7 @@ include("plot.jl")
285285
include("project.jl")
286286
include("psbasemap.jl")
287287
include("compass.jl")
288+
include("mapscale.jl")
288289
include("psclip.jl")
289290
include("pscoast.jl")
290291
include("pscontour.jl")

src/mapscale.jl

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
mapscale(; kwargs...)
3+
4+
Draw a map scale bar on the map.
5+
6+
Can be called as an overlay (`mapscale!`) on an existing plot, or standalone with explicit
7+
`region` and `proj`.
8+
9+
### Map scale options
10+
11+
- **anchor** :: [Type => Tuple | Str] — Reference point on the map for the scale bar.
12+
- **scale_at_lat** :: [Type => Number] — Latitude at which the scale is computed.
13+
- **length** or **width** :: [Type => Str | Number] — Length of the scale bar (append unit, e.g., `"1000k"`).
14+
- **fancy** :: [Type => Bool] — Draw a fancy scale bar instead of a plain one.
15+
- **label** :: [Type => Str | Bool] — Label for the scale bar. Use `true` for the default unit label.
16+
- **align** :: [Type => Symbol | Str] — Label alignment (`:left`, `:right`, `:top`, `:bottom`).
17+
- **justify** :: [Type => Str] — Justification of the scale relative to anchor.
18+
- **offset** :: [Type => Tuple | Str] — Offset from the anchor point.
19+
- **units** :: [Type => Bool | Str] — Append the unit to all distance annotations.
20+
- **vertical** :: [Type => Bool] — Plot a vertical instead of horizontal Cartesian scale.
21+
- **map** | **inside** | **outside** | **norm** | **paper** :: [Type => Str] — Coordinate system for the anchor.
22+
23+
All other keyword arguments (e.g., `region`, `proj`, `frame`, `par`, `show`, `savefig`, `Vd`,
24+
`box`, etc.) are passed through to `basemap`.
25+
26+
### Examples
27+
28+
```julia
29+
coast(region=(0,40,50,56), proj=:Mercator, frame=:auto, land=:lightgray)
30+
mapscale!(inside=:ML, scale_at_lat=53, length="1000k", fancy=true, label=true, show=true)
31+
```
32+
"""
33+
mapscale!(; kw...) = mapscale(; first=false, kw...)
34+
function mapscale(; first=true, kw...)
35+
d = init_module(false, kw...)[1] # Also checks if the user wants ONLY the HELP mode
36+
mapscale(first, d)
37+
end
38+
function mapscale(first::Bool, d::Dict{Symbol, Any})
39+
40+
scale_keys = (:anchor, :scale_at_lat, :length, :width, :fancy, :label, :align,
41+
:justify, :offset, :units, :vertical,
42+
:map, :inside, :outside, :norm, :paper)
43+
44+
nt_pairs = Pair{Symbol,Any}[]
45+
for k in scale_keys
46+
haskey(d, k) && push!(nt_pairs, k => pop!(d, k))
47+
end
48+
49+
d[:map_scale] = (; nt_pairs...)
50+
51+
haskey(d, :frame) || haskey(d, :B) || (d[:frame] = :none)
52+
helper_basemap(!first, true, d)
53+
end

test/test_PSs.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,25 @@ r = compass!(width=2.5, anchor=(0,0), justify=:CM, fancy=true, labels=",,,N", Vd
6464
r = compass(width=3, fancy=true, Vd=dbg2);
6565
@test !contains(r, "-B")
6666

67+
println(" MAPSCALE")
68+
# Standalone with explicit R/J
69+
r = mapscale(region=(0,40,50,56), proj=:Mercator, figsize=13, inside=:ML, scale_at_lat=53, length="1000k", fancy=true, label=true, Vd=dbg2);
70+
@test startswith(r, "psbasemap -R0/40/50/56 -JM13") && contains(r, "-LjML+c53+w1000k+f+l")
71+
# With anchor and box
72+
r = mapscale(region=(0,40,50,56), proj=:Mercator, figsize=13, anchor=:BR, scale_at_lat=53, length="1000k", fancy=true, Vd=dbg2);
73+
@test contains(r, "-LjBR+c53+w1000k+f")
74+
# Overlay mode
75+
basemap(region=(0,40,50,56), proj=:Mercator, figsize=13, frame=:auto, Vd=dbg2)
76+
r = mapscale!(inside=:ML, scale_at_lat=53, length="500k", label="Test", Vd=dbg2);
77+
@test contains(r, " -R -J") || contains(r, "-R0/40/50/56 -J ")
78+
@test contains(r, "-LjML+c53+w500k+lTest")
79+
# frame=:none is default
80+
r = mapscale(region=(0,40,50,56), proj=:merc, inside=:ML, scale_at_lat=53, length="500k", Vd=dbg2);
81+
@test !contains(r, "-B")
82+
# With units and align options
83+
r = mapscale(region=(0,40,50,56), proj=:merc, inside=:BR, scale_at_lat=53, length="500k", units=true, align=:top, Vd=dbg2);
84+
@test contains(r, "+at") && contains(r, "+u")
85+
6786
println(" PSCLIP")
6887
d = [0.2 0.2; 0.2 0.8; 0.8 0.8; 0.8 0.2; 0.2 0.2];
6988
psclip(d, J="X3i", R="0/1/0/1", N=true, V=:q);

0 commit comments

Comments
 (0)