diff --git a/src/GMT.jl b/src/GMT.jl index e3a12ca21..f5e4ba2a8 100644 --- a/src/GMT.jl +++ b/src/GMT.jl @@ -129,7 +129,7 @@ export grdcut, grdedit, grdfft, grdfill, grdfilter, grdgradient, grdhisteq, grdimage, grdimage!, grdinfo, grdinterpolate, grdlandmask, grdmath, grdmask, grdpaste, grdproject, grdsample, grdtrack, grdtrend, grdvector, grdvector!, grdview, grdview!, grdvolume, greenspline, histogram, histogram!, image, image!, image_alpha!, image_cpt!, - imshow, ind2rgb, isnodata, kml2gmt, logo, logo!, makecpt, mask, mask!, mapproject, movie, nearneighbor, plot, plot!, + imshow, ind2rgb, isnodata, kml2gmt, logo, logo!, makecpt, mapscale, mapscale!, mask, mask!, mapproject, movie, nearneighbor, plot, plot!, plot3, plot3!, plot3d, plot3d!, plotyy, project, pscontour, pscontour!, psconvert, psbasemap, psbasemap!, psclip, psclip!, pscoast, pscoast!, psevents, pshistogram, pshistogram!, psimage, psimage!, pslegend, pslegend!, psmask, psmask!, psrose, psrose!, psscale, psscale!, pssolar, pssolar!, @@ -285,6 +285,7 @@ include("plot.jl") include("project.jl") include("psbasemap.jl") include("compass.jl") +include("mapscale.jl") include("psclip.jl") include("pscoast.jl") include("pscontour.jl") diff --git a/src/mapscale.jl b/src/mapscale.jl new file mode 100644 index 000000000..e543ca753 --- /dev/null +++ b/src/mapscale.jl @@ -0,0 +1,53 @@ +""" + mapscale(; kwargs...) + +Draw a map scale bar on the map. + +Can be called as an overlay (`mapscale!`) on an existing plot, or standalone with explicit +`region` and `proj`. + +### Map scale options + +- **anchor** :: [Type => Tuple | Str] — Reference point on the map for the scale bar. +- **scale_at_lat** :: [Type => Number] — Latitude at which the scale is computed. +- **length** or **width** :: [Type => Str | Number] — Length of the scale bar (append unit, e.g., `"1000k"`). +- **fancy** :: [Type => Bool] — Draw a fancy scale bar instead of a plain one. +- **label** :: [Type => Str | Bool] — Label for the scale bar. Use `true` for the default unit label. +- **align** :: [Type => Symbol | Str] — Label alignment (`:left`, `:right`, `:top`, `:bottom`). +- **justify** :: [Type => Str] — Justification of the scale relative to anchor. +- **offset** :: [Type => Tuple | Str] — Offset from the anchor point. +- **units** :: [Type => Bool | Str] — Append the unit to all distance annotations. +- **vertical** :: [Type => Bool] — Plot a vertical instead of horizontal Cartesian scale. +- **map** | **inside** | **outside** | **norm** | **paper** :: [Type => Str] — Coordinate system for the anchor. + +All other keyword arguments (e.g., `region`, `proj`, `frame`, `par`, `show`, `savefig`, `Vd`, +`box`, etc.) are passed through to `basemap`. + +### Examples + +```julia +coast(region=(0,40,50,56), proj=:Mercator, frame=:auto, land=:lightgray) +mapscale!(inside=:ML, scale_at_lat=53, length="1000k", fancy=true, label=true, show=true) +``` +""" +mapscale!(; kw...) = mapscale(; first=false, kw...) +function mapscale(; first=true, kw...) + d = init_module(false, kw...)[1] # Also checks if the user wants ONLY the HELP mode + mapscale(first, d) +end +function mapscale(first::Bool, d::Dict{Symbol, Any}) + + scale_keys = (:anchor, :scale_at_lat, :length, :width, :fancy, :label, :align, + :justify, :offset, :units, :vertical, + :map, :inside, :outside, :norm, :paper) + + nt_pairs = Pair{Symbol,Any}[] + for k in scale_keys + haskey(d, k) && push!(nt_pairs, k => pop!(d, k)) + end + + d[:map_scale] = (; nt_pairs...) + + haskey(d, :frame) || haskey(d, :B) || (d[:frame] = :none) + helper_basemap(!first, true, d) +end diff --git a/test/test_PSs.jl b/test/test_PSs.jl index 988360303..6b6daffda 100644 --- a/test/test_PSs.jl +++ b/test/test_PSs.jl @@ -64,6 +64,25 @@ r = compass!(width=2.5, anchor=(0,0), justify=:CM, fancy=true, labels=",,,N", Vd r = compass(width=3, fancy=true, Vd=dbg2); @test !contains(r, "-B") +println(" MAPSCALE") +# Standalone with explicit R/J +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); +@test startswith(r, "psbasemap -R0/40/50/56 -JM13") && contains(r, "-LjML+c53+w1000k+f+l") +# With anchor and box +r = mapscale(region=(0,40,50,56), proj=:Mercator, figsize=13, anchor=:BR, scale_at_lat=53, length="1000k", fancy=true, Vd=dbg2); +@test contains(r, "-LjBR+c53+w1000k+f") +# Overlay mode +basemap(region=(0,40,50,56), proj=:Mercator, figsize=13, frame=:auto, Vd=dbg2) +r = mapscale!(inside=:ML, scale_at_lat=53, length="500k", label="Test", Vd=dbg2); +@test contains(r, " -R -J") || contains(r, "-R0/40/50/56 -J ") +@test contains(r, "-LjML+c53+w500k+lTest") +# frame=:none is default +r = mapscale(region=(0,40,50,56), proj=:merc, inside=:ML, scale_at_lat=53, length="500k", Vd=dbg2); +@test !contains(r, "-B") +# With units and align options +r = mapscale(region=(0,40,50,56), proj=:merc, inside=:BR, scale_at_lat=53, length="500k", units=true, align=:top, Vd=dbg2); +@test contains(r, "+at") && contains(r, "+u") + println(" PSCLIP") d = [0.2 0.2; 0.2 0.8; 0.8 0.8; 0.8 0.2; 0.2 0.2]; psclip(d, J="X3i", R="0/1/0/1", N=true, V=:q);