Config
The configuration file for an election must be stored in a folder inside the data
folder of the af-election-api repo.
data/
│── 2014-presidential/
│ │── trends/
│ └── index.yml
└── 2018-wolesi-jirga/
│── trends/
└── index.yml
The election folder must be named according to the election id and the configuration file must be index.yml
.
The electionId
is defined in the config.js file located at the root of the af-election-api repo.
Properties
name<String>
- Human readable name of the electionyear<Number>
- Year the election takes placetype<String>
- Either "parliamentary" or "presidential"cardImage<String>
- Image to display on the election card of the election listapi<Object>
- Election specific api endpoints. If the election has rounds, the api is specified on a round basisadmin-areas.geo<String>
- Url to the geojson file with the admin area boundariesadmin-areas.meta<String>
- Url to the json file with the admin area information (name, ids, etc)
rounds<Array[Object]>
- Round definition, ornull
if there are no roundsid<Number>
- Id of the roundname<String>
- Human readable name of the roundapi<Object>
- Election round specific api endpoints.admin-areas.geo<String>
- Url to the geojson file with the admin area boundariesadmin-areas.meta<String>
- Url to the json file with the admin area information (name, ids, etc)
dataBrowser<Object>
- Configuration for the data browser page of the election. The data browser may require specific configuration for different elections, for example the data tables may need to show additional columns depending on the election.tables<Array[Object]>
- Optional. Configuration for the tablesid<String>
- Id of the table to target. Must be the same as defined on the frontent applicationextraColumns<Array[Object]>
- Configuration for the extra columns a table should have, besides the ones common to all electionsid<String>
- Id of the columnlabel<String>
- Human readable name of the column. Will be displayed on the table headersortable<Boolean>
- Whether or not the column should be sortableaccessor<String>
- Path to the value on the election results rowinclude<Boolean>
- Whether or not to include a core column. This property is only used to customize core columns and has no effect on additional columns. See Customize core data table columns section
overview<Object>
- Configuration for the overview page of the electiontitle<String>
- Title for the card of the overview pagecontent<String>
- Content for the card. Should be a paragraph with the highlights of the election. Markdown is supportedlongTitle<String>
- Optional. Longer title for the bottom part of the overview page. Can be though of as a calloutlongContent<String>
- Optional. Body of the overview page. Markdown is supportedmapConfig<Object>
- Configuration for the map on the overview pagestyle<String>
- Mapbox stylelayers<Array[Object]>
- Optional. List of layers that are toggable by the userid<String>
- The id for this entry. Can be anythinglabel<String>
- The label to show on the layer panellayer<String>
- The layer id from mapbox. Must be present on the map styleenabled<Boolean>
- Whether or not this layer should be enabled by defaultlegend<Object>
- The legend definition for this layertype<String>
- The legend type. Can berange
orcategorical
. A range legend will be displayed as a gradient bar using the first and last values of thevalues
list. Defaults tocategorical
label<String>
- Optional. The legend title, if not specified the layer label will be displayedvalues<Array[Object]>
- The color:label pairs for the legendcolor<String>
- The color of the legend itemlabel<String>
- The label of the legend item
displayData<Array[Object]>
- Data from this layer to display on the popover. See belowlabel<String>
- Label for this property. Mutually exclusive withlabelProp
labelProp<String>
- Syntax expression to compute the label. Mutually exclusive withlabel
value<String>
- Value for this property. Mutually exclusive withvalueProp
valueProp<String>
- Syntax expression to compute a the value. Mutually exclusive withvalue
Data to display on popovers
It is possible to extract data from the features of each map layer and display it on a popover.
For each layer you can specify a label:value
pair using a syntax expression.
Note that data will be shown for every feature that the mouse intersects, even if they overlap, as the following gif demonstrates:
There are 2 properties to get a label
and a value
.
- When using
label
the value is assumed static and will be displayed as is. - When using
labelProp
the value will be extracted from the feature data and computed.
The same is true for value
and valueProp
.
To allow some processing of labels and values it is possible to use a simple inline piping syntax to define functions (and respective arguments) to apply to a value.
The property name is always the first element to appear and subsequent functions are separated using pipes |
and arguments are separated using colons :
Example:
candidate1_percentage|round:2|suffix:%
In this example the system would get the value of candidate1_percentage
from the feature of the corresponding layer, round
it to 2
decimal digits, and then add a suffix
of %
.
The functions available are:
sum : value
subtract : value
multiply : value
divide : value
prefix : value
suffix : value
capitalize
formatThousands : decimal_digits : separator
round : decimal_digits
Customize core data table columns
The data table has some core columns that are included by default in all elections. However, it may be needed to hide them because they don't make sense in a given context.
To disable a core column, simply use it's id
and set the include
property to false
. Adding this property to a non core column has no effect.
Example:
extraColumns: [
{
id: 'presidential',
extraColumns: [
{
id: 'ballotDist',
include: false
}
]
}
]
It is also possible to change the label of a core column. To modify any core column and keep it include
must be set to true.
extraColumns: [
{
id: 'presidential',
extraColumns: [
{
id: 'ballotDist',
label: 'Distribution of ballots'
include: true
}
]
}
]
Example without rounds
name: Wolesi Jirga
year: 2018
type: parliamentary
cardImage: http://example.com/2018image.png
api:
admin-areas.geo: /aa/2009-aa.geojson
admin-areas.meta: /elections/2018-wolesi-jirga/admin-areas
rounds: null
dataBrowser:
tables:
-
id: candidates
extraColumns:
-
id: preliminary
label: Preliminary votes
sortable: true
accessor: votes.preliminary
overview:
title: 2018 Wolesi Jirga
content: AfghanistanElectionData.org is designed
longTitle: 2018 Polling data suggests higher citizen engagement
longContent: |
This is the content. **Markdown supported**
mapConfig:
style: mapbox://styles/ndi/cjux5wqyp0hqg1fqhcds5hxky
layers:
-
id: ds-first-round-voter-turnout
label: Voter Turnout
layer: ds-first-round-voter-turnout
enabled: true
legend:
type: categorical
label: The legend title
values:
-
color: '#b268b3'
label: High
-
color: '#c58bc5'
label: Medium
-
color: '#e6cde6'
label: Low
displayData:
-
labelProp: 'candidate1_name'
valueProp: 'candidate1_percentage|round:2|suffix:%'
-
label: 'Admin Type',
valueProp: 'admin_type'
Example with rounds
name: Presidential
year: 2014
type: parliamentary
cardImage: http://example.com/2018image.png
api: null
rounds:
-
id: first
name: First Round
api:
admin-areas.meta: /elections/2014-presidential/first/admin-areas
admin-areas.geo: /aa/2009-aa.geojson
-
id: runoff
name: Final Round
api:
admin-areas.meta: /elections/2014-presidential/runoff/admin-areas
admin-areas.geo: /aa/2009-aa.geojson
dataBrowser: null
overview:
title: 2014 Presidential
content: AfghanistanElectionData.org is designed
mapConfig:
style: mapbox://styles/ndi/cjux5wqyp0hqg1fqhcds5hxky
layers:
-
id: ds-first-round-voter-turnout
label: Voter Turnout
layer: ds-first-round-voter-turnout
enabled: true
legend: null
Api
The election endpoint is generated using the CLI command:
$ yarn api config <electionId>
Individual election
/elections/[election-id]/config.json
Each election has a separate configuration file.
{
"name": "Wolesi Jirga",
"year": 2018,
"type": "parliamentary",
"cardImage": "http://example.com/2018image.png",
"api": {
"admin-areas.geo": "/aa/2009-aa.geojson",
"admin-areas.meta": "/elections/2018-wolesi-jirga/admin-areas"
},
"rounds": null,
"#comment": "The hasTrends is a computed property stating whether the election has trends or not",
"hasTrends": true,
"dataBrowser": {
"tables": [
{
"id": "candidates",
"extraColumns": [
{
"id": "preliminary",
"label": "Preliminary votes",
"sortable": true,
"accessor": "votes.preliminary"
}
]
}
]
},
"overview": {
"title": "2018 Wolesi Jirga",
"content": "AfghanistanElectionData.org is designed...",
"longTitle": "2018 Polling data suggests higher citizen engagement",
"longContent": "This is the content. **Markdown supported**",
"mapConfig": {
"style": "mapbox://styles/devseed/cjnawi07v06cq2rmtof8u8hie",
"layers": [
{
"id": "regions",
"label": "Choroplet",
"layer": "peruRegions",
"enabled": true,
"legend": {
"type": "categorical",
"label": "Legend Title",
"values": [
{
"color": "#ff0000",
"label": "High"
},
"..."
]
}
},
"..."
]
}
}
}
If a given election has rounds, the rounds
property will be an array of objects where each object has the following properties:
{
"...": "...",
"api": null,
"rounds": [
{
"id": "first",
"name": "First Round",
"api": {
"admin-areas.meta": "/elections/2014-presidential/first/admin-areas",
"admin-areas.geo": "/aa/2009-aa.geojson"
}
},
{
"id": "final",
"name": "Final Round",
"api": {
"admin-areas.meta": "/elections/2014-presidential/runoff/admin-areas",
"admin-areas.geo": "/aa/2009-aa.geojson"
}
}
]
}