Repository navigation
[Feature]: Publication layout in one command: a finished map sheet or figure sized to the page (layout.publication) #682
Description
Before you start
- I searched the existing issues and the roadmap and did not find a duplicate request.
What problem does this solve?
RustGIS has the building blocks of a finished map sheet:
- map frames with a labelled graticule (
grid, withformat,hemisphereand labellededges, [Feature]: Finer layout cartographic controls: border grid ticks, coordinate label formatting, and surround properties panes #327); - a legend that leaves layers out (Layout: a legend can leave layers out though the map draws them (#517, point 1) #518);
- a raster colorbar ([Feature]: Dedicated Raster Colorbar layout element with customizable ticks, units, and orientation #326);
- scale bar, north arrow, extent indicator, text and dynamic text, rectangles;
- the
maptemplate oflayout.new: a frame, title, legend, north arrow, scale bar and credits.
Turning those into a sheet that meets cartographic conventions is still manual work, and it has to be redone for every page size:
- The page size doesn't carry the composition.
layout.pagechanges the sheet but leaves every element where it was. An A4 composition doesn't become an A3 one, nor a 90 mm journal figure, whose texts must stay at 6–7 pt at the final size while the graphics shrink. - The locator is several steps. A second map in
globe, its scale set so the globe has the right diameter, a frame, the area highlighted. - The footer is placed by hand. Data sources, the cartographic reference (projection, datum, graticule), notes and authorship are text elements positioned one by one, with no wrapping. Long lines run past the frame unless shortened by hand.
- Elements land on the theme. Nothing keeps the legend, the scale bar or the locator off the area being mapped, or warns when they overlap.
- Numbers follow one convention. Colorbar and scale labels use a decimal point, while maps in Portuguese, Spanish, French or German expect a comma.
The example attached is a teaching map (NDVI trend in Piauí, Brazil, 2001–2025, from #579's Trend Analysis). It took about 1,100 lines of Python (an 830-line layout generator and a 270-line wrapper for this map) driving rustgis-cli. The script:
- computes the scale for the frame;
- places every element by lon/lat;
- draws the footer columns and their boxes;
- sizes the globe;
- warns about overlaps.
The same configuration produces A4, A3, A2, a journal figure of one, one and a half or two columns, and a thesis figure. This is the part I'd like RustGIS to do itself.
Proposed solution
A command, layout.publication, that builds a complete layout from the active map and a few texts. It is also offered in Publish › Layout as New Publication Layout…, a dialog with the same fields.
layout.publication {
"profile": "A4-portrait", // A4/A3/A2 portrait|landscape, figure-1col|-1.5col|-2col, thesis-full|-half
"extent": [-46.8, -11.6, -38.5, -2.2], // lon/lat that must fit; default: the map view
"title": "PIAUÍ",
"subtitle": "Greening and browning of vegetation: NDVI trend, 2001–2025",
"sources": ["NDVI: MOD13Q1 v6.1 (NASA LP DAAC), via the Brazil Data Cube (INPE)", "Boundaries: IBGE 2022"],
"reference": ["Projection: {projection}", "Datum: {datum} · Graticule {grid}"],
"note": "Only cells with a significant trend (p < 0.05) are coloured.",
"author": "Made with RustGIS · {date}",
"locator": "globe", // "globe" | "inset" | "none"
"decimal": "," // number labels in the layout: "." (default) or ","
}
What it builds:
- Sheet profiles (
A4/A3/A2, portrait or landscape): a frame and margin, then title and subtitle, the map, and a footer in two boxed columns (sources | cartographic reference) with the note and authorship below. Text sizes scale with the sheet by the short side ÷ 210 mm. - Figure profiles (journal 90/140/190 mm, thesis 160 × 225 / 160 × 110 mm): no frame, title or footer, which belong to the figure caption. The map runs edge to edge, with a one-line projection and datum note under it. Texts stay at 7 pt (never below 6) at the final size, and graphics follow the width.
- The map frame: the extent fitted at a round scale (two significant figures), the graticule labelled on its edges, the step chosen from the extent (10°, 5°, 1°, 0.5°, minutes).
- Legend: the visible layers' symbology.
- Only classes drawn in the frame, as the
legendelement already does. - A raster on a ramp becomes a colorbar inside the legend box.
- Titles come from the layers' names.
- Only classes drawn in the frame, as the
- Scale bar with a round length (1, 2, 2.5 or 5 × 10ⁿ), with the numeric scale under it. It reads "approximate" below 1:1,000,000, and the note says the scale holds at the centre.
- North arrow at the top right.
- Locator:
globe: a second map inglobe, centred on the area, with the area highlighted and the globe's diameter set for the profile;inset: a rectangle of the surrounding region.
- Placement: legend, scale bar and locator each go to the frame corner that covers the least of the mapped data. The visible layers' features and raster cells are rasterised at low resolution to find it. Anything placed over data, or overlapping another element, is reported in the command's result (
"warnings": [...]), and every element can be moved afterwards as usual. - Text that fits: footer lines and the legend are measured with the layout's font and wrapped to their box, so nothing runs past the frame.
Behaviour:
- One layout: the result is an ordinary layout, every element editable and saved with the project. Running it again with another
profilemakes a second layout from the same map, without touching the first. - Tokens:
{projection},{datum}and{grid}in the texts are filled from the map, and{date}as dynamic text is today. - Docs: a section in
layouts.md, with the profiles and an example sheet and figure. - Tests:
- every profile builds, with no element outside the page or the frame;
- the scale and grid steps for a few extents;
- a long footer line wraps;
decimal: ","gives0,05on a colorbar;- the corner choice avoids a raster that fills one corner.
Choices in this proposal
- One command over a fixed set of profiles, not a template file format. The profiles are the sizes people publish at, and adding one later is a table row. A user-defined template format can come after, if wanted.
- Corners, not free placement, in this first version. Choosing among the four corners by data coverage is predictable and testable. A free search for empty space, such as the ocean, can follow.
- No new element kinds. The command composes existing ones (frame, grid, legend, colorbar, scale bar, north arrow, text, rectangle, a second map for the locator). Everything it makes is editable with the tools users already know.
decimalas an option on number labels (colorbar ticks, scale bar), defaulting to., rather than tied to the interface language. A map's language is not always the app's.- The footer texts are the user's. RustGIS fills tokens but doesn't guess sources or credits.
Estimated scope
Medium: a broader feature that is feasible in a reasonable timeframe. I would split it into three PRs:
- profiles, sizing and the footer (with wrapping);
- the locator;
- corner placement, the warnings and
decimal.
Alternatives considered
layout.newwith themaptemplate, thenlayout.page: this is today's path. The template doesn't adapt to the page, and the page doesn't move the elements.- An external script (the one behind the attached map, Python driving
rustgis-cli): it works, but it lives outside RustGIS, so the app and the assistant can't use it. Its positions are computed against RustGIS's internals (the scale definition, the globe's size), which a change in RustGIS silently breaks. - A plugin wrapping the script: it puts it in the menus, but the coupling to internals remains, and it can't measure text with the layout's own font.
Related
#326 (colorbar), #327 (grid labels and surrounds), #517/#518 (legend layers), #213 (the earlier round of layout work), #205/#210/#211 (earlier layout issues the script had to work around), #579 (the analysis behind the example map).
Activity
Layouts: a publication layout in one command, a sheet or a figure siz…
Layouts: a publication layout's locator, a globe or an inset with the…
Layouts: a publication layout's surrounds keep off the data; a decima…
Layouts: a publication sheet's style, accent and orientation; graticu…
elpidioassinaturas commentedon Oct 24, 2026
The three PRs this issue planned have all landed, plus two more, so I'm closing it. Thanks for the quick reviews.
layout.publicationin one command:"decimal": ",", a colour bar for raster themes, and UTM/SIRGAS names.styles (classic, banner, panel, editorial, modular, poster) with anaccentcolour, and rounded rectangles;"profile": "a4"picks portrait or landscape from the area;Two follow-ups were offered in #742, if they're wanted: splitting
publication's styles into functions of their own, and aradiuscontrol in the properties pane. I'm happy to do either on request.