Jump to content
Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

This is a documentation subpage for Boundaries. It contains usage information, categories, and other content that is not part of the original template.

This module stores boundary polygons for geographic entities on the wiki. Growing regions, growing areas, appellations and admin subdivisions all read their polygon from a single keyed entry, replacing the inline boundary= parameters that previously lived on each page.

The entries themselves are kept on data subpages, one per tier and longitude band (see below). This page holds only the code that finds a key on them, so every call below works whichever subpage holds the entry.

Schema

Each entry is a Lua table with five fields:

Field Type Description
polygon string Vertex string in lat,lng;lat,lng format. See format below.
style string Provenance signal: editorial, admin, or derived.
source string Human-readable note on origin, e.g. "Freehand trace, geojson.io" or "OSM relation 18547452".
vertices number Vertex count.
area_km2 number Computed area in square kilometres.

Functions

All functions are called via {{#invoke:Boundaries|function}}. Each looks up an entry using the lookup priority described below.

Function Returns
get Polygon string. Empty if no entry.
getStyle Style value (editorial, admin, or derived). Empty if no entry.
getSource Provenance string.
getMeta Formatted summary: Source: X · N vertices · ~Y km². Useful on talk pages.
has "yes" if entry exists, empty otherwise.
listKeys Bulleted list of all registered keys, sorted alphabetically.

Lua modules can also call it directly: require('Module:Boundaries').get(frame), with the key as the frame's first argument.

Lookup priority

The key used to look up an entry is resolved in this order:

  1. Explicit positional argument: {{#invoke:Boundaries|get|Some Name}} (pass it as 1= when the value might contain an equals sign)
  2. Parent template's boundary_key parameter, when invoked from inside a template that exposes one
  3. {{PAGENAME}} as fallback

Most page-level usage works without arguments. An infobox calls {{#invoke:Boundaries|get}} and the page name resolves the lookup automatically.

Data subpages

The entries are split by tier and by longitude band so that no page comes near the wiki's page-size limit. Each subpage returns a plain table of entries and is read with mw.loadData, which loads it once per page render however many calls the page makes. A key is on one subpage only.

Tier Americas West Central Central-East East East-95 East-100
Appellations Americas West Central Central-East East (in East) East-100
Growing areas Americas West Central Central-East East (in East) East-100
Growing regions Americas West Central Central-East East East-95 East-100
Admin subdivisions Module:Boundaries/Admin

The band of a new entry is the mean longitude of all its vertices:

Band Mean longitude Covers
Americas west of 25°W the Americas and the eastern Pacific
West 25°W to 60°E Europe, Africa and West Asia
Central 60°E to 77°E Central Asia, Afghanistan, Pakistan, Kashmir and western India
Central-East 77°E to 90°E the Himalaya from Kullu east, eastern Kyrgyzstan, Xinjiang east of Kashgar, the rest of India, Nepal and Sri Lanka
East 90°E to 100°E (growing regions: 90°E to 95°E) Tibet, Bhutan, Myanmar and Thailand; for growing regions, Bhutan, Northeast India, Bangladesh and southern Siberia
East-95 95°E to 100°E, growing regions only eastern Tibet, Myanmar, Thailand and northern Sumatra
East-100 100°E and east Yunnan, Laos, Vietnam, Cambodia, the rest of China, Japan, Southeast Asia and Oceania

An entry stays on its subpage when its polygon is redrawn, even if the redraw moves its mean longitude across a band edge. An entry moved to another tier goes to its new tier's subpage for its band. Each subpage is kept under 450,000 bytes; a band that outgrows that is split in two, and the new subpage is added to the DATA list in this module in the same edit.

Polygon string format

Polygons are stored as flat strings rather than nested tables for compatibility with SMW Text properties and direct embedding in HTML data- attributes:

  • lat,lng per vertex, comma-separated
  • ; separates vertices within one polygon
  • : separates polygons in a multipolygon
  • No closing repeat: the rendering layer closes the ring implicitly

Single polygon:

32.07413,77.27155;32.07296,77.27128;...;32.07156,77.27403

Multipolygon (used for entities with disconnected lobes, e.g. The Dooars):

26.57477,89.14644;...;26.56641,89.15261:26.33025,88.72855;...;26.29716,88.73344

Style values

The style field signals provenance and is read by the JS renderer to apply visual styling.

Style Meaning
editorial Hand-traced polygon, typically via geojson.io. Default rendering: slate-blue fill, palette-by-neighbour on the multi-polygon home map view.
admin Fetched from OSM administrative relations. Solid grey, thin stroke, minimal fill.
derived Computed by derive_boundaries.py as the morphological union of child entries (e.g. a growing region derived from its growing areas, or a valley derived from its appellations). Rendered identically to editorial.

Adding or modifying entries

Add or change an entry on the data subpage that holds it (or, for a new entry, the subpage of its tier and band); this page needs no edit. Entries use the same block format on every subpage:

  ["Some Name"] = {
    polygon     = "lat,lng;lat,lng;...",
    style       = "editorial",
    source      = "...",
    vertices    = 123,
    area_km2    = 456.78,
  },

Derived entries (regions, valleys) regenerate via the local derive_boundaries.py pipeline, which reads all the subpages together and writes the whole table as one file; the changed entries are then copied to their subpages. After a change, null-edit the affected pages so SMW reindexes the new boundary.

Used by

Semantic properties

Each infobox that reads from this module also writes the polygon to Has boundary (type Text), enabling tier-specific queries from the home map and other contexts:

[[Category:Growing Areas]][[Has boundary::+]]|?Has boundary|?Has area name

See also


-- Module:Boundaries
-- Border polygons of growing regions, growing areas, appellations and admin subdivisions.
-- The entries are kept on data subpages, one per tier and longitude band (listed in DATA below), so that no page
-- nears the wiki's page-size limit. This module finds a key on them; its functions and arguments are unchanged.
-- Schema, the band rule and the subpages: Module:Boundaries/doc.

local p = {}

-- Searched in this order. A key is on one subpage only.
local DATA = {
  "Module:Boundaries/Appellations/Americas",
  "Module:Boundaries/Appellations/West",
  "Module:Boundaries/Appellations/Central",
  "Module:Boundaries/Appellations/Central-East",
  "Module:Boundaries/Appellations/East",
  "Module:Boundaries/Appellations/East-100",
  "Module:Boundaries/Areas/Americas",
  "Module:Boundaries/Areas/West",
  "Module:Boundaries/Areas/Central",
  "Module:Boundaries/Areas/Central-East",
  "Module:Boundaries/Areas/East",
  "Module:Boundaries/Areas/East-100",
  "Module:Boundaries/Regions/Americas",
  "Module:Boundaries/Regions/West",
  "Module:Boundaries/Regions/Central",
  "Module:Boundaries/Regions/Central-East",
  "Module:Boundaries/Regions/East",
  "Module:Boundaries/Regions/East-95",
  "Module:Boundaries/Regions/East-100",
  "Module:Boundaries/Admin",
}

-- mw.loadData reads each subpage once per page render, however many times it is called.
local function findEntry(key)
  for _, page in ipairs(DATA) do
    local e = mw.loadData(page)[key]
    if e then return e end
  end
  return nil
end

local function getKey(frame)
  local args = frame.args
  if args[1] and args[1] ~= "" then return args[1] end
  local pframe = frame:getParent()
  if pframe and pframe.args and pframe.args.boundary_key and pframe.args.boundary_key ~= "" then
    return pframe.args.boundary_key
  end
  return mw.title.getCurrentTitle().text
end

local function getEntry(frame)
  return findEntry(getKey(frame))
end

function p.get(frame)
  local e = getEntry(frame); return e and e.polygon or ""
end

function p.getStyle(frame)
  local e = getEntry(frame); return e and e.style or ""
end

function p.getSource(frame)
  local e = getEntry(frame); return e and e.source or ""
end

function p.getMeta(frame)
  local e = getEntry(frame)
  if not e then return "" end
  return string.format("Source: %s · %d vertices · ~%.1f km²", e.source, e.vertices, e.area_km2)
end

function p.has(frame)
  return getEntry(frame) and "yes" or ""
end

function p.listKeys(frame)
  local keys, seen = {}, {}
  for _, page in ipairs(DATA) do
    for k in pairs(mw.loadData(page)) do
      if not seen[k] then seen[k] = true; table.insert(keys, k) end
    end
  end
  table.sort(keys)
  local out = {}
  for _, k in ipairs(keys) do table.insert(out, "* [[" .. k .. "]]") end
  return table.concat(out, "\n")
end

return p