Module:Infobox mapframe: Difference between revisions

From escforumwiki
Jump to navigation Jump to search
m (1 revision imported)
No edit summary
 
Line 1: Line 1:
local mf = require('Module:Mapframe')
local mf = require('Module:Mapframe')
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local infoboxImage = require('Module:InfoboxImage').InfoboxImage


-- Defaults
function setCleanArgs(argsTable)
local DEFAULT_FRAME_WIDTH = "270"
local DEFAULT_FRAME_HEIGHT = "200"
local DEFAULT_ZOOM = 10
local DEFAULT_GEOMASK_STROKE_WIDTH = "1"
local DEFAULT_GEOMASK_STROKE_COLOR = "#777777"
local DEFAULT_GEOMASK_FILL = "#888888"
local DEFAULT_GEOMASK_FILL_OPACITY = "0.5"
local DEFAULT_SHAPE_STROKE_WIDTH = "3"
local DEFAULT_SHAPE_STROKE_COLOR = "#FF0000"
local DEFAULT_SHAPE_FILL = "#606060"
local DEFAULT_SHAPE_FILL_OPACITY = "0.5"
local DEFAULT_LINE_STROKE_WIDTH = "5"
local DEFAULT_LINE_STROKE_COLOR = "#FF0000"
local DEFAULT_MARKER_COLOR = "#5E74F3"
 
 
-- Trim whitespace from args, and remove empty args
function trimArgs(argsTable)
local cleanArgs = {}
local cleanArgs = {}
for key, val in pairs(argsTable) do
for key, val in pairs(argsTable) do
Line 37: Line 16:
end
end


function getBestStatement(item_id, property_id)
function hasWikidataProperty(item_id, property_id)
if not(item_id) or not(mw.wikibase.isValidEntityId(item_id)) or not(mw.wikibase.entityExists(item_id)) then
if not(item_id) or not(mw.wikibase.isValidEntityId(item_id)) or not(mw.wikibase.entityExists(item_id)) then
return false
return false
Line 49: Line 28:
return false
return false
end
end
return statements[1]
return true
end
 
function hasWikidataProperty(item_id, property_id)
return getBestStatement(item_id, property_id) and true or false
end
 
function getStatementValue(statement)
return statement and statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value or nil
end
end


function relatedEntity(item_id, property_id)
local value = getStatementValue( getBestStatement(item_id, property_id) )
return value and value.id or false
end


function idType(id)
function getZoom(length_km)
if not id then
return nil
elseif mw.ustring.match(id, "[Pp]%d+") then
return "property"
elseif mw.ustring.match(id, "[Qq]%d+") then
return "item"
else
return nil
end
end
 
function getZoom(value, unit)
local length_km
if unit == 'km' then
length_km = tonumber(value)
elseif unit == 'mi' then
length_km = tonumber(value)*1.609344
elseif unit == 'km2' then
length_km = math.sqrt(tonumber(value))
elseif unit == 'mi2' then
length_km = math.sqrt(tonumber(value))*1.609344
end
-- max for zoom 2 is 6400km, for zoom 3 is 3200km, for zoom 4 is 1600km, etc
-- max for zoom 2 is 6400km, for zoom 3 is 3200km, for zoom 4 is 1600km, etc
local zoom = math.floor(8 - (math.log10(length_km) - 2)/(math.log10(2)))
local zoom = math.floor(8 - (math.log10(length_km) - 2)/(math.log10(2)))
-- limit to values below 17
-- limit to values between 1 and 17
zoom = math.min(17, zoom)
return math.max(1, math.min(17, zoom))
-- take off 1 when calculated from area, to account for unusual shapes
if unit == 'km2' or unit == 'mi2' then
zoom = zoom - 1
end
-- minimum value is 1
return math.max(1, zoom)
end
 
function shouldAutoRun(frame)
-- Check if should be running
local explicitlyOn = yesno(mw.text.trim(frame.getParent(frame).args.mapframe or "")) -- true of false or nil
local onByDefault = (explicitlyOn == nil) and yesno(mw.text.trim(frame.args.onByDefault or ""), false) -- true or false
return explicitlyOn or onByDefault
end
 
function argsFromAuto(frame)
-- Get args from the frame (invoke call) and the parent (template call).
-- Frame arguments are default values which are overridden by parent values
-- when both are present
local args = getArgs(frame, {parentFirst = true})
-- Discard args not prefixed with "mapframe-", remove that prefix from those that remain
local fixedArgs = {}
for name, val in pairs(args) do
local fixedName = string.match(name, "^mapframe%-(.+)$" )
if fixedName then
fixedArgs[fixedName] = val
-- allow coord, coordinates, etc to be unprefixed
elseif name == "coordinates" or name == "coord" or name == "coordinate" and not fixedArgs.coord then
fixedArgs.coord = val
-- allow id, qid to be unprefixed, map to id (if not already present)
elseif name == "id" or name == "qid" and not fixedArgs.id then
fixedArgs.id = val
end
end
return fixedArgs
end
end


local p = {}
local p = {}
p.autocaption = function(frame)
if not shouldAutoRun(frame) then return "" end
local args = argsFromAuto(frame)
if args.caption then
return args.caption
elseif args.switcher then
return ""
end
local maskItem
local maskType = idType(args.geomask)
if maskType == 'item' then
maskItem = args.geomask
elseif maskType == "property" then
maskItem = relatedEntity(args.id or mw.wikibase.getEntityIdForCurrentPage(), args.geomask)
end
local maskItemLabel = maskItem and mw.wikibase.getLabel( maskItem )
return maskItemLabel and "Location in "..maskItemLabel or ""
end
function parseCustomWikitext(customWikitext)
-- infoboxImage will format an image if given wikitext containing an
-- image, or else pass through the wikitext unmodified
return infoboxImage({
args = {
image = customWikitext
}
})
end
p.auto = function(frame)
if not shouldAutoRun(frame) then return "" end
local args = argsFromAuto(frame)
if args.custom then
return frame:preprocess(parseCustomWikitext(args.custom))
end
local mapframe = p._main(args)
return frame:preprocess(mapframe)
end


p.main = function(frame)
p.main = function(frame)
Line 179: Line 49:


p._main = function(_config)
p._main = function(_config)
-- `config` is the args passed to this module
local config = setCleanArgs(_config)
local config = trimArgs(_config)
-- Require wikidata item, or specified coords
local wikidataId = config.id or mw.wikibase.getEntityIdForCurrentPage()
local wikidataId = config.id or mw.wikibase.getEntityIdForCurrentPage()
if not(wikidataId) and not(config.coord) then
if not wikidataId then
return ''
return ''
end
end


-- Require coords (specified or from wikidata), so that map will be centred somewhere
-- Require wikidata item with coords, so something will be centred somewhere
-- (P625 = coordinate location)
local hasCoordinates = hasWikidataProperty(wikidataId, 'P625') -- P625 = coordinate location
local hasCoordinates = hasWikidataProperty(wikidataId, 'P625') or config.coordinates or config.coord
if not hasCoordinates then   
if not hasCoordinates then   
return ''
return ''
end
end


-- `args` is the arguments which will be passed to the mapframe module
-- arguments for mapframe module
local args = {}
local args = {}


Line 202: Line 68:
args.frame = "yes"
args.frame = "yes"
args.plain = "yes"
args.plain = "yes"
args["frame-width"]  = config["frame-width"] or config.width or DEFAULT_FRAME_WIDTH
args["frame-width"]  = config["frame-width"] or "270"
args["frame-height"] = config["frame-height"] or config.height or DEFAULT_FRAME_HEIGHT
args["frame-height"] = config["frame-height"] or "200"
args["frame-align"]  = "center"
args["frame-align"]  = "center"
 
args["frame-coord"] = config["frame-coordinates"] or config["frame-coord"] or config["coordinates"] or config["coord"] or ""
args["frame-coord"] = config["frame-coordinates"] or config["frame-coord"] or ""
  -- deprecated lat and long parameters
-- Note: config["coordinates"] or config["coord"] should not be used for the alignment of the frame;
-- see talk page ( https://en.wikipedia.org/wiki/Special:Diff/876492931 )
 
-- deprecated lat and long parameters
args["frame-lat"]    = config["frame-lat"] or config["frame-latitude"] or ""
args["frame-lat"]    = config["frame-lat"] or config["frame-latitude"] or ""
args["frame-long"]  = config["frame-long"] or config["frame-longitude"] or ""
args["frame-long"]  = config["frame-long"] or config["frame-longitude"] or ""
Line 216: Line 78:
-- Calculate zoom from length or area (converted to km or km2)
-- Calculate zoom from length or area (converted to km or km2)
if config.length_km then
if config.length_km then
args.zoom = getZoom(config.length_km, 'km')
args.zoom = getZoom(tonumber(config.length_km))
elseif config.length_mi then
elseif config.length_mi then
args.zoom = getZoom(config.length_mi, 'mi')
args.zoom = getZoom(tonumber(config.length_mi)*1.609344)
elseif config.area_km2 then
elseif config.area_km2 then
args.zoom = getZoom(config.area_km2, 'km2')
args.zoom = getZoom(math.sqrt(tonumber(config.area_km2)))
elseif config.area_mi2 then
elseif config.area_mi2 then
args.zoom = getZoom(config.area_mi2, 'mi2')
args.zoom = getZoom(math.sqrt(tonumber(config.area_mi2))*1.609344)
else
else
args.zoom = config.zoom or DEFAULT_ZOOM
args.zoom = config.zoom or 10
end
end


-- Conditionals: whether point, geomask should be shown
-- Shape
local hasOsmRelationId = hasWikidataProperty(wikidataId, 'P402') -- P402 is OSM relation ID
args.type = "shape"
local shouldShowPointMarker;
if config.id then args.id = config.id end
if config.point == "on" then
args["stroke-width"] = config["shape-stroke-width"] or config["stroke-width"] or "3"
shouldShowPointMarker = true
args["stroke-color"] = config["shape-stroke-color"] or config["shape-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or "#FF0000"
elseif config.point == "none" then
 
shouldShowPointMarker = false
else
shouldShowPointMarker = not(hasOsmRelationId) or (config.marker and config.marker ~= 'none') or (config.coordinates or config.coord)
end
local shouldShowShape = config.shape ~= 'none'
local shapeType = config.shape == 'inverse' and 'shape-inverse' or 'shape'
local shouldShowLine = config.line ~= 'none'
local maskItem
local useWikidata = wikidataId and true or false -- Use shapes/lines based on wikidata id, if there is one
-- But do not use wikidata when local coords are specified (and not turned off), unless explicitly set
if useWikidata and config.coord and shouldShowPointMarker then
useWikidata = config.wikidata and true or false
end
-- Switcher
if config.switcher == "zooms" then
-- switching between zoom levels
local maxZoom = math.max(tonumber(args.zoom), 3) -- what zoom would have otherwise been (if 3 or more, otherwise 3)
local minZoom = 1 -- completely zoomed out
local midZoom = math.floor((maxZoom + minZoom)/2) -- midway between maxn and min
args.switch = "zoomed in, zoomed midway, zoomed out"
args.zoom = string.format("SWITCH:%d,%d,%d", maxZoom, midZoom, minZoom)
elseif config.switcher == "auto" then
-- switching between P276 and P131 areas with recursive lookup, e.g. item's city,
-- that city's state, and that state's country
args.zoom = nil -- let kartographer determine the zoom
local maskLabels = {}
local maskItems = {}
local maskItemId = relatedEntity(wikidataId, "P276") or  relatedEntity(wikidataId, "P131")
local maskLabel = mw.wikibase.getLabel(maskItemId)
while maskItemId and maskLabel and mw.text.trim(maskLabel) ~= "" do
table.insert(maskLabels, maskLabel)
table.insert(maskItems, maskItemId)
maskItemId = maskItemId and relatedEntity(maskItemId, "P131")
maskLabel = maskItemId and mw.wikibase.getLabel(maskItemId)
end
if #maskLabels > 1 then
args.switch = table.concat(maskLabels, "###")
maskItem = "SWITCH:" .. table.concat(maskItems, ",")
elseif #maskLabels == 1 then
maskItem = maskItemId[1]
end
elseif config.switcher == "geomasks" and config.geomask then
-- switching between items in geomask parameter
args.zoom = nil -- let kartographer determine the zoom
local separator = (mw.ustring.find(config.geomask, "###", 0, true ) and "###") or
(mw.ustring.find(config.geomask, ";", 0, true ) and ";") or ","
local pattern = "%s*"..separator.."%s*"
local maskItems = mw.text.split(mw.ustring.gsub(config.geomask, "SWITCH:", ""), pattern)
local maskLabels = {}
if #maskItems > 1 then
for i, item in ipairs(maskItems) do
table.insert(maskLabels, mw.wikibase.getLabel(item))
end
args.switch = table.concat(maskLabels, "###")
maskItem = "SWITCH:" .. table.concat(maskItems, ",")
end
end
-- resolve geomask item id (if not using geomask switcher)
if not maskItem then -- 
local maskType = idType(config.geomask)
if maskType == 'item' then
maskItem = config.geomask
elseif maskType == "property" then
maskItem = relatedEntity(wikidataId, config.geomask)
end
end
-- Keep track of arg numbering
local argNumber = ''
local function incrementArgNumber()
if argNumber == '' then
argNumber = 2
else
argNumber = argNumber + 1
end
end
-- Geomask
if maskItem then
args["type"..argNumber] = "shape-inverse"
args["id"..argNumber] = maskItem
args["stroke-width"..argNumber] = config["geomask-stroke-width"] or DEFAULT_GEOMASK_STROKE_WIDTH
args["stroke-color"..argNumber] = config["geomask-stroke-color"] or config["geomask-stroke-colour"] or DEFAULT_GEOMASK_STROKE_COLOR
args["fill"..argNumber] = config["geomask-fill"] or DEFAULT_GEOMASK_FILL
args["fill-opacity"..argNumber] = config["geomask-fill-opacity"] or DEFAULT_SHAPE_FILL_OPACITY
-- Let kartographer determine zoom and position, unless it is explicitly set in config
if not config.zoom and not config.switcher then
args.zoom = nil
args["frame-coord"] = nil
args["frame-lat"] = nil
args["frame-long"] = nil
local maskArea = getStatementValue( getBestStatement(maskItem, 'P2046') )
end
incrementArgNumber()
-- Hack to fix phab:T255932
if not args.zoom then
args["type"..argNumber] = "line"
args["id"..argNumber] = maskItem
args["stroke-width"..argNumber] = 0
incrementArgNumber()
end
end
-- Shape (or shape-inverse)
if useWikidata and shouldShowShape then
args["type"..argNumber] = shapeType
if config.id then args["id"..argNumber] = config.id end
args["stroke-width"..argNumber] = config["shape-stroke-width"] or config["stroke-width"] or DEFAULT_SHAPE_STROKE_WIDTH
args["stroke-color"..argNumber] = config["shape-stroke-color"] or config["shape-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or DEFAULT_SHAPE_STROKE_COLOR
args["fill"..argNumber] = config["shape-fill"] or DEFAULT_SHAPE_FILL
args["fill-opacity"..argNumber] = config["shape-fill-opacity"] or DEFAULT_SHAPE_FILL_OPACITY
incrementArgNumber()
end
-- Line
-- Line
if useWikidata and shouldShowLine then
args.type2 = "line"
args["type"..argNumber] = "line"
if config.id then args.id2 = config.id end
if config.id then args["id"..argNumber] = config.id end
args["stroke-width2"] = config["line-stroke-width"] or config["stroke-width"] or "5"
args["stroke-width"..argNumber] = config["line-stroke-width"] or config["stroke-width"] or DEFAULT_LINE_STROKE_WIDTH
args["stroke-color2"] = config["line-stroke-color"] or config["line-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or "#FF0000"
args["stroke-color"..argNumber] = config["line-stroke-color"] or config["line-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or DEFAULT_LINE_STROKE_COLOR
incrementArgNumber()
end


-- Point
-- Point
local hasOsmRelationId = hasWikidataProperty(wikidataId, 'P402') -- P402 is OSM relation ID
local shouldShowPointMarker = not(hasOsmRelationId) or (config.marker and config.marker ~= 'none')
if shouldShowPointMarker then
if shouldShowPointMarker then
args["type"..argNumber] = "point"
args.type3 = "point"
if config.id then args["id"..argNumber] = config.id end
if config.id then args.id3 = config.id end
if config.coord then args["coord"..argNumber] = config.coord end
if config.marker then args.marker3 = config.marker end
if config.marker then args["marker"..argNumber] = config.marker end
args["marker-color3"] = config["marker-color"] or config["marker-colour"] or "#5E74F3"
args["marker-color"..argNumber] = config["marker-color"] or config["marker-colour"] or DEFAULT_MARKER_COLOR
incrementArgNumber()
end
end
 
local mapframe = mf._main(args)
local mapframe = args.switch and mf.multi(args) or mf._main(args)
local tracking = hasOsmRelationId and '' or '[[Category:Infobox mapframe without OSM relation ID on Wikidata]]'
local tracking = hasOsmRelationId and '' or '[[Category:Infobox mapframe without OSM relation ID on Wikidata]]'
return mapframe .. tracking
return mapframe .. tracking

Latest revision as of 20:48, 17 April 2024

Usage

Module that automatically makes a mapframe suitable for an infobox automatically, with minimal user input.

Generic usage

Just use the template {{Infobox mapframe}}, following the documentation there. This module may also be imported to another Lua module.

Automatic maps in infoboxes

Example edits: Template:Infobox prison, Template:Infobox prison/doc

Edit the infobox template (or its sandbox). Add lines like the following examples to the infobox. Replace numbers (4, or 97 to 99), with the appropriate number based on how many other image or data parameters are already present.

If placing near the top of infobox If placing at/near the bottom of the infobox
| image4     = {{#invoke:Infobox mapframe|auto}}
| caption4   = {{#invoke:Infobox mapframe|autocaption}}
| header97   = {{#if:{{{mapframe|}}}|Location}}
| data98     = {{#invoke:Infobox mapframe|auto}}
| data99     = {{#invoke:Infobox mapframe|autocaption}}

If the template has a {{#invoke:Check for unknown parameters}}, add the following parameters:

| mapframe | mapframe-area_km2 | mapframe-area_mi2 | mapframe-caption | mapframe-coord | mapframe-coordinates | mapframe-custom | mapframe-frame-coord | mapframe-frame-coordinates | mapframe-frame-height | mapframe-frame-width | mapframe-geomask | mapframe-geomask-fill | mapframe-geomask-fill-opacity | mapframe-geomask-stroke-color | mapframe-geomask-stroke-colour | mapframe-geomask-stroke-width | mapframe-height | mapframe-id | mapframe-length_km | mapframe-length_mi | mapframe-marker | mapframe-marker-color | mapframe-marker-colour | mapframe-point | mapframe-shape | mapframe-shape-fill | mapframe-shape-fill-opacity | mapframe-stroke-color | mapframe-stroke-colour | mapframe-stroke-width | mapframe-switcher | mapframe-width | mapframe-wikidata | mapframe-zoom 

Once this is done, the above parameters will be available to users of the template.

  • Defaults values for these parameters can also be specified in the #invoke calls above, e.g. {{#invoke:Infobox mapframe|auto|mapframe-marker=library}} means that the library marker will be used, unless a different value is passed in to the template.
  • The maps are off by default, which means maps will not be displayed unless |mapframe=yes is present in the template call. To turn maps on by default, in the #invoke calls above add |onByDefault=yes – which means maps will be displayed unless |mapframe=no is present in the template call. onByDefault can also be set to a conditional, such as if another parameters is present, e.g. |onByDefault={{#if:{{{pushpin_map|}}}|no|yes}}
  • Add the new parameters to the document. You can use {{Infobox mapframe/doc/parameters}}. Specify default values (if any are used in the #invoke calls) using by adding parameters in the form Template:Ttparameter-nameTemplate:Ttvalue. The default output is shown here collapsed:
Extended content

view · talk · edit

  • Basic parameters:
    • mapframe – Specify yes or no to show or hide the map, overriding the default. Default: no
    • mapframe-caption – Caption for the map. Default: blank (or if |mapframe-geomask= is set, "Location in geomask's label")
    • mapframe-custom – Use a custom map instead of the automatic mapframe. Specify either a {{maplink}} template, or another template that generates a mapframe map, or an image name. If used, the subsequent mapframe parameters will be ignored. Default: not specified
    • mapframe-id or id or qid – Id (Q-number) of Wikidata item to use. Default: item for current page
    • mapframe-coordinates or mapframe-coord or coordinates or coord – Coordinates to use, instead of any on Wikidata. Use the {{Coord}} template, e.g. |coord={{Coord|12.34|N|56.78|E}}. Default: coordinates from Wikidata
    • mapframe-wikidata – Set to yes to show shape/line features from the wikidata item, if any, when |coord= is set. Default: not specified
  • Customise which features are displayed:
  • Other optional parameters:
    • mapframe-frame-width or mapframe-width – Frame width. Default: 270
    • mapframe-frame-height or mapframe-height – Frame height. Default: 200
    • mapframe-shape-fill – Color used to fill shape features. Default: #606060
    • mapframe-shape-fill-opacity – Opacity level of shape fill, a number between 0 and 1. Default: 0.5
    • mapframe-stroke-color or mapframe-stroke-colour – Color of line features, and outlines of shape features. Default: #ff0000
    • mapframe-stroke-width – Width of line features, and outlines of shape features; default is "5". Default: 5
    • mapframe-marker – Marker symbol to use for coordinates; see mw:Help:Extension:Kartographer/Icons for options. Default: not specified (i.e. blank)
      • Can also be set to blank to override any default marker symbol
    • mapframe-marker-color or mapframe-marker-colour – Background color for the marker. Default: #5E74F3
    • mapframe-geomask-stroke-color or mapframe-geomask-stroke-colour – Color of outline of geomask shape. Default: #555555
    • mapframe-geomask-stroke-width – Width of outline of geomask shape. Default: 2
    • mapframe-geomask-fill – Color used to fill outside geomask features. Default: #606060
    • mapframe-geomask-fill-opacity – Opacity level of fill outside geomask features, a number between 0 and 1. Default: 0.5
    • mapframe-zoom – Set the zoom level, from "1" (map of earth) to "18" (maximum zoom in), to be used if the zoom level cannot be determined automatically from object length or area. Default: 10
    • mapframe-length_km or mapframe-length_mi or mapframe-area_km2 or mapframe-area_mi2 – Determine zoom level by passing in object's length (in kilometres or miles) or area (in square kilometres or square miles). Default: not specified
    • mapframe-frame-coordinates or mapframe-frame-coord – Alternate latitude and longitude coordinates for initial placement of map, using {{coord}}. Default: derived from item coordinates

See also



local mf = require('Module:Mapframe')

function setCleanArgs(argsTable)
	local cleanArgs = {}
	for key, val in pairs(argsTable) do
		if type(val) == 'string' then
			val = val:match('^%s*(.-)%s*$')
			if val ~= '' then
				cleanArgs[key] = val
			end
		else
			cleanArgs[key] = val
		end
	end
	return cleanArgs
end

function hasWikidataProperty(item_id, property_id)
	if not(item_id) or not(mw.wikibase.isValidEntityId(item_id)) or not(mw.wikibase.entityExists(item_id)) then
		return false
	end
	local statements = mw.wikibase.getBestStatements(item_id, property_id)
	if not statements or #statements == 0 then
		return false
	end
	local hasNoValue = ( statements[1].mainsnak and statements[1].mainsnak.snaktype == 'novalue' )
	if hasNoValue then
		return false
	end
	return true
end


function getZoom(length_km)
	-- max for zoom 2 is 6400km, for zoom 3 is 3200km, for zoom 4 is 1600km, etc
	local zoom = math.floor(8 - (math.log10(length_km) - 2)/(math.log10(2)))
	-- limit to values between 1 and 17
	return math.max(1, math.min(17, zoom))
end

local p = {}

p.main = function(frame)
	local parent = frame.getParent(frame)
	local parentArgs = parent.args
	local mapframe = p._main(parentArgs)
	return frame:preprocess(mapframe)
end

p._main = function(_config)
	local config = setCleanArgs(_config)
	local wikidataId = config.id or mw.wikibase.getEntityIdForCurrentPage()
	if not wikidataId then
		return ''
	end

	-- Require wikidata item with coords, so something will be centred somewhere
	local hasCoordinates = hasWikidataProperty(wikidataId, 'P625') -- P625 = coordinate location
	if not hasCoordinates then  
		return ''
	end

	-- arguments for mapframe module
	local args = {}

	-- Some defaults/overrides for infobox presentation
	args.display = "inline"
	args.frame = "yes"
	args.plain = "yes"
	args["frame-width"]  = config["frame-width"] or "270"
	args["frame-height"] = config["frame-height"] or "200"
	args["frame-align"]  = "center"
	args["frame-coord"] = config["frame-coordinates"] or config["frame-coord"] or config["coordinates"] or config["coord"] or ""
	  -- deprecated lat and long parameters
	args["frame-lat"]    = config["frame-lat"] or config["frame-latitude"] or ""
	args["frame-long"]   = config["frame-long"] or config["frame-longitude"] or ""

	-- Calculate zoom from length or area (converted to km or km2)
	if config.length_km then
		args.zoom = getZoom(tonumber(config.length_km))
	elseif config.length_mi then
		args.zoom = getZoom(tonumber(config.length_mi)*1.609344)
	elseif config.area_km2 then
		args.zoom = getZoom(math.sqrt(tonumber(config.area_km2)))
	elseif config.area_mi2 then
		args.zoom = getZoom(math.sqrt(tonumber(config.area_mi2))*1.609344)
	else
		args.zoom = config.zoom or 10
	end

	-- Shape
	args.type = "shape"
	if config.id then args.id = config.id end
	args["stroke-width"] = config["shape-stroke-width"] or config["stroke-width"] or "3"
	args["stroke-color"] = config["shape-stroke-color"] or config["shape-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or "#FF0000"

	-- Line
	args.type2 = "line"
	if config.id then args.id2 = config.id end
	args["stroke-width2"] = config["line-stroke-width"] or config["stroke-width"] or "5"
	args["stroke-color2"] = config["line-stroke-color"] or config["line-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or "#FF0000"

	-- Point
	local hasOsmRelationId = hasWikidataProperty(wikidataId, 'P402') -- P402 is OSM relation ID
	local shouldShowPointMarker = not(hasOsmRelationId) or (config.marker and config.marker ~= 'none')
	if shouldShowPointMarker then
		args.type3 = "point"
		if config.id then args.id3 = config.id end
		if config.marker then args.marker3 = config.marker end
		args["marker-color3"] = config["marker-color"] or config["marker-colour"] or "#5E74F3"
	end
	local mapframe = mf._main(args)
	local tracking = hasOsmRelationId and '' or '[[Category:Infobox mapframe without OSM relation ID on Wikidata]]'
	return mapframe .. tracking
end

return p