Module:ChoroplethMap
| This module is rated as beta. It is considered ready for widespread use, but as it is still relatively new, it should be applied with some caution to ensure results are as expected. |
This module is invoked by Template:Choropleth map to generate choropleth maps.
- See Template:Choropleth map for parameter documentation and usage examples
- See Commons:Data:ChoroplethMap.map for geographical data used for countries and continents
- See Open Street Map for geographical data used for subnational entities
-- Module:ChoroplethMap generates colored maps of countries and other entities
-- Documentation and master version: https://en.wikipedia.org/wiki/Module:ChoroplethMap
-- Authors: User:Sophivorus
-- License: CC-BY-SA-4.0
local ChoroplethMap = {}
local lang = mw.getContentLanguage()
-- Helper function to get an argument
-- Arguments from Lua calls have priority over parent arguments from templates
local function getArg( key, default )
local frame = mw.getCurrentFrame()
local parent = frame:getParent()
for k, value in pairs( parent.args ) do
if k == key and mw.text.trim( value ) ~= '' then
return value
end
end
for k, value in pairs( frame.args ) do
if k == key and mw.text.trim( value ) ~= '' then
return value
end
end
return default
end
-- Get geographical data from Commons
-- and make an index to optimize search
local source = getArg( 'source', 'ChoroplethMap.map' )
local sourceFeatures = mw.ext.data.get( source ).data.features
local sourceIndex = {}
for i = 0, #sourceFeatures do -- don't use ipairs because it starts at 1
local feature = sourceFeatures[ i ]
if feature.properties.wikidata then
sourceIndex[ feature.properties.wikidata ] = i
end
if feature.properties.iso_a2 then
sourceIndex[ feature.properties.iso_a2 ] = i
end
if feature.properties.name then
sourceIndex[ feature.properties.name ] = i
end
end
-- Helper function to get the Wikidata id of an entity
local function getID( entity )
if not entity then
return
end
entity = mw.text.trim( entity )
if entity == '' then
return
end
if string.match( entity, '^Q%d+$' ) then
return entity
end
local index = sourceIndex[ entity ]
if index then
local feature = sourceFeatures[ index ]
return feature.properties.wikidata
end
return mw.wikibase.getEntityIdForTitle( entity )
end
function ChoroplethMap.main( frame )
-- Get the arguments
local entities = getArg( 'entities' )
local color = getArg( 'color', '#f00' )
local view = getArg( 'view', 'Q2' ) -- Q2 is the Wikidata item for the Earth
local latitude = getArg( 'latitude' )
local longitude = getArg( 'longitude' )
local zoom = getArg( 'zoom' )
local width = getArg( 'width', '250' )
local height = getArg( 'height', '200' )
local align = getArg( 'align' )
local frameless = getArg( 'frameless' )
local mapstyle = getArg( 'mapstyle' )
local alt = getArg( 'alt' )
local caption = getArg( 'caption' )
local legends = getArg( 'legends' )
local logarithmicScale = getArg( 'logarithmic-scale' )
local minOpacity = getArg( 'min-opacity', '0' )
-- Parse the entities into a clean data table
local data = {}
if entities then
-- If any color directive is an absolute value
-- we need to figure out what the top value is
-- before we can color any of them
local topValue
for entity in mw.text.gsplit( entities, '[;\n]' ) do
entity = mw.text.trim( entity )
local value = entity:match( '^([0-9.,]-) *: *.+$' )
if value then
value = lang:parseFormattedNumber( value )
if not topValue or value > topValue then
topValue = value
end
end
end
local opacity = .7
local value
local min = lang:parseFormattedNumber( minOpacity )
for entity in mw.text.gsplit( entities, '[;\n]' ) do
entity = mw.text.trim( entity )
if entity ~= '' then
local colorPart, entityPart = entity:match( '^([#0-9A-Za-z .,%%]-) *: *(.+)$' )
if colorPart and entityPart then
if colorPart:match( '^([0-9.,]+) ?%%$' ) then
value = colorPart
local plainValue = lang:parseFormattedNumber( mw.text.trim( value, '%%' ) )
if logarithmicScale then
opacity = min + ( math.log( math.max( plainValue, 1 ) ) / math.log( 100 ) ) * ( 1 - min )
else
opacity = min + ( plainValue / 100 ) * ( 1 - min )
end
elseif colorPart:match( '^[0-9.,]+$' ) then
value = colorPart
local plainValue = lang:parseFormattedNumber( value )
if logarithmicScale then
opacity = min + ( math.log( math.max( plainValue, 1 ) ) / math.log( topValue ) ) * ( 1 - min )
else
opacity = min + ( plainValue / topValue ) * ( 1 - min )
end
else
color = colorPart
value = nil
opacity = .7
end
entity = entityPart
end
local id = getID( entity )
if id then
local title = mw.wikibase.getSitelink( id )
local label = mw.wikibase.getLabel( id )
table.insert( data, { id = id, title = title, label = label, value = value, color = color, opacity = opacity } )
end
end
end
end
-- Make the features
local features = {}
local done = {}
-- Make the view feature
if view ~= 'auto' then
local viewID = getID( view )
local viewIndex = sourceIndex[ viewID ]
local viewFeature
if viewIndex then
viewFeature = sourceFeatures[ viewIndex ]
viewFeature.properties[ 'fill-opacity' ] = 0
viewFeature.properties[ 'stroke-opacity' ] = 0
else
viewFeature = {
[ 'type' ] = 'ExternalData',
[ 'service' ] = 'geoshape',
[ 'ids' ] = viewID,
[ 'properties' ] = {
[ 'fill-opacity' ] = 0,
[ 'stroke-opacity' ] = 0
}
}
end
table.insert( features, viewFeature )
done[ viewID ] = true
end
-- Make the entity features
for _, entity in ipairs( data ) do
if not done[ entity.id ] then
local entityFeature
local entityWikitext = '[[' .. entity.title .. '|' .. entity.label .. ']]' .. ( entity.value and ( '<br>' .. entity.value ) or '' )
local entityIndex = sourceIndex[ entity.id ]
if entityIndex then
entityFeature = sourceFeatures[ entityIndex ]
entityFeature.properties[ 'title' ] = entityWikitext
entityFeature.properties[ 'fill' ] = entity.color
entityFeature.properties[ 'fill-opacity' ] = entity.opacity
entityFeature.properties[ 'stroke-width' ] = 0.1
else
entityFeature = {
[ 'type' ] = 'ExternalData',
[ 'service' ] = 'geoshape',
[ 'ids' ] = entity.id,
[ 'properties' ] = {
[ 'title' ] = entityWikitext,
[ 'fill' ] = entity.color,
[ 'fill-opacity' ] = entity.opacity,
[ 'stroke-width' ] = 0.1
}
}
end
table.insert( features, entityFeature )
done[ entity.id ] = true
end
end
local json = mw.text.jsonEncode( features )
-- Build the automatic legends
if legends then
-- First look for repeated colors
local legendsData = {}
for _, entity in ipairs( data ) do
local repeated
for _, legendData in ipairs( legendsData ) do
if legendData.color == entity.color and legendData.opacity == entity.opacity then
repeated = legendData
break
end
end
if repeated then
repeated.wikitext = repeated.wikitext .. ', [[' .. entity.title .. '|' .. entity.label .. ']]'
else
local legendData = {
[ 'wikitext' ] = '[[' .. entity.title .. '|' .. entity.label .. ']]',
[ 'value' ] = entity.value,
[ 'color' ] = entity.color,
[ 'opacity' ] = entity.opacity
}
table.insert( legendsData, legendData )
end
end
legends = mw.html.create( 'div' )
legends:css( 'column-width', '250px' )
for _, legendData in ipairs( legendsData ) do
local colorBox = mw.html.create( 'span' )
colorBox:css( 'background', legendData.color )
colorBox:css( 'display', 'inline-block' )
colorBox:css( 'margin-right', '.5em' )
colorBox:css( 'opacity', legendData.opacity )
colorBox:css( 'vertical-align', 'middle' )
colorBox:css( 'width', '1em' )
colorBox:css( 'height', '1em' )
local wikitext = legendData.wikitext
if legendData.value then
local message = '$1: $2'
if lang:getCode() == 'fr' then
message = '$1 : $2'
end
wikitext = mw.message.newRawMessage( message, legendData.value, wikitext ):plain()
end
local legend = mw.html.create( 'div' )
legend:node( colorBox )
legend:wikitext( wikitext )
legends:node( legend )
end
legends = tostring( legends )
if caption then
caption = caption .. legends
else
caption = legends
end
end
local attributes = {
[ 'latitude' ] = latitude,
[ 'longitude' ] = longitude,
[ 'zoom' ] = zoom,
[ 'width' ] = width,
[ 'height' ] = height,
[ 'align' ] = align,
[ 'text' ] = caption,
[ 'alt' ] = alt,
[ 'frameless' ] = frameless,
[ 'mapstyle' ] = mapstyle
}
return frame:extensionTag( 'mapframe', json, attributes )
end
return ChoroplethMap
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.