Skip to content

Instantly share code, notes, and snippets.

@robatwilliams
Last active December 27, 2018 12:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robatwilliams/e698db75fbbe9d92de655a9906b71ba1 to your computer and use it in GitHub Desktop.
Save robatwilliams/e698db75fbbe9d92de655a9906b71ba1 to your computer and use it in GitHub Desktop.
Currencies, then and now

Companion gist for blog post: Mapping currency strength changes with D3

Displays currency strengthening or weakening against other world currencies, between a reference date in the past and today.

Try it out - click to change the base country, use the picker to change the reference date. Data is available from the start of 2000.

Uses ES6 features, so you need a modern browser.

Data sources

World map: https://github.com/topojson/world-atlas

Country codes (ISO 3611-1): https://github.com/srcagency/iso-3166-1-codes

Country (ISO 3611) -> currency (ISO 4217) mapping: https://github.com/srcagency/country-currencies

Currency exchange rates: http://fixer.io/

[
{"numeric":"004","alpha2":"AF","alpha3":"AFG","name":"Afghanistan"},
{"numeric":"248","alpha2":"AX","alpha3":"ALA","name":"Åland Islands"},
{"numeric":"008","alpha2":"AL","alpha3":"ALB","name":"Albania"},
{"numeric":"012","alpha2":"DZ","alpha3":"DZA","name":"Algeria"},
{"numeric":"016","alpha2":"AS","alpha3":"ASM","name":"American Samoa"},
{"numeric":"020","alpha2":"AD","alpha3":"AND","name":"Andorra"},
{"numeric":"024","alpha2":"AO","alpha3":"AGO","name":"Angola"},
{"numeric":"660","alpha2":"AI","alpha3":"AIA","name":"Anguilla"},
{"numeric":"010","alpha2":"AQ","alpha3":"ATA","name":"Antarctica"},
{"numeric":"028","alpha2":"AG","alpha3":"ATG","name":"Antigua and Barbuda"},
{"numeric":"032","alpha2":"AR","alpha3":"ARG","name":"Argentina"},
{"numeric":"051","alpha2":"AM","alpha3":"ARM","name":"Armenia"},
{"numeric":"533","alpha2":"AW","alpha3":"ABW","name":"Aruba"},
{"numeric":"036","alpha2":"AU","alpha3":"AUS","name":"Australia"},
{"numeric":"040","alpha2":"AT","alpha3":"AUT","name":"Austria"},
{"numeric":"031","alpha2":"AZ","alpha3":"AZE","name":"Azerbaijan"},
{"numeric":"044","alpha2":"BS","alpha3":"BHS","name":"Bahamas"},
{"numeric":"048","alpha2":"BH","alpha3":"BHR","name":"Bahrain"},
{"numeric":"050","alpha2":"BD","alpha3":"BGD","name":"Bangladesh"},
{"numeric":"052","alpha2":"BB","alpha3":"BRB","name":"Barbados"},
{"numeric":"112","alpha2":"BY","alpha3":"BLR","name":"Belarus"},
{"numeric":"056","alpha2":"BE","alpha3":"BEL","name":"Belgium"},
{"numeric":"084","alpha2":"BZ","alpha3":"BLZ","name":"Belize"},
{"numeric":"204","alpha2":"BJ","alpha3":"BEN","name":"Benin"},
{"numeric":"060","alpha2":"BM","alpha3":"BMU","name":"Bermuda"},
{"numeric":"064","alpha2":"BT","alpha3":"BTN","name":"Bhutan"},
{"numeric":"068","alpha2":"BO","alpha3":"BOL","name":"Bolivia (Plurinational State of)"},
{"numeric":"535","alpha2":"BQ","alpha3":"BES","name":"Bonaire, Sint Eustatius and Saba"},
{"numeric":"070","alpha2":"BA","alpha3":"BIH","name":"Bosnia and Herzegovina"},
{"numeric":"072","alpha2":"BW","alpha3":"BWA","name":"Botswana"},
{"numeric":"074","alpha2":"BV","alpha3":"BVT","name":"Bouvet Island"},
{"numeric":"076","alpha2":"BR","alpha3":"BRA","name":"Brazil"},
{"numeric":"086","alpha2":"IO","alpha3":"IOT","name":"British Indian Ocean Territory"},
{"numeric":"096","alpha2":"BN","alpha3":"BRN","name":"Brunei Darussalam"},
{"numeric":"100","alpha2":"BG","alpha3":"BGR","name":"Bulgaria"},
{"numeric":"854","alpha2":"BF","alpha3":"BFA","name":"Burkina Faso"},
{"numeric":"108","alpha2":"BI","alpha3":"BDI","name":"Burundi"},
{"numeric":"132","alpha2":"CV","alpha3":"CPV","name":"Cabo Verde"},
{"numeric":"116","alpha2":"KH","alpha3":"KHM","name":"Cambodia"},
{"numeric":"120","alpha2":"CM","alpha3":"CMR","name":"Cameroon"},
{"numeric":"124","alpha2":"CA","alpha3":"CAN","name":"Canada"},
{"numeric":"136","alpha2":"KY","alpha3":"CYM","name":"Cayman Islands"},
{"numeric":"140","alpha2":"CF","alpha3":"CAF","name":"Central African Republic"},
{"numeric":"148","alpha2":"TD","alpha3":"TCD","name":"Chad"},
{"numeric":"152","alpha2":"CL","alpha3":"CHL","name":"Chile"},
{"numeric":"156","alpha2":"CN","alpha3":"CHN","name":"China"},
{"numeric":"162","alpha2":"CX","alpha3":"CXR","name":"Christmas Island"},
{"numeric":"166","alpha2":"CC","alpha3":"CCK","name":"Cocos (Keeling) Islands"},
{"numeric":"170","alpha2":"CO","alpha3":"COL","name":"Colombia"},
{"numeric":"174","alpha2":"KM","alpha3":"COM","name":"Comoros"},
{"numeric":"178","alpha2":"CG","alpha3":"COG","name":"Congo"},
{"numeric":"180","alpha2":"CD","alpha3":"COD","name":"Congo (Democratic Republic of the)"},
{"numeric":"184","alpha2":"CK","alpha3":"COK","name":"Cook Islands"},
{"numeric":"188","alpha2":"CR","alpha3":"CRI","name":"Costa Rica"},
{"numeric":"384","alpha2":"CI","alpha3":"CIV","name":"Côte d'Ivoire"},
{"numeric":"191","alpha2":"HR","alpha3":"HRV","name":"Croatia"},
{"numeric":"192","alpha2":"CU","alpha3":"CUB","name":"Cuba"},
{"numeric":"531","alpha2":"CW","alpha3":"CUW","name":"Curaçao"},
{"numeric":"196","alpha2":"CY","alpha3":"CYP","name":"Cyprus"},
{"numeric":"203","alpha2":"CZ","alpha3":"CZE","name":"Czechia"},
{"numeric":"208","alpha2":"DK","alpha3":"DNK","name":"Denmark"},
{"numeric":"262","alpha2":"DJ","alpha3":"DJI","name":"Djibouti"},
{"numeric":"212","alpha2":"DM","alpha3":"DMA","name":"Dominica"},
{"numeric":"214","alpha2":"DO","alpha3":"DOM","name":"Dominican Republic"},
{"numeric":"218","alpha2":"EC","alpha3":"ECU","name":"Ecuador"},
{"numeric":"818","alpha2":"EG","alpha3":"EGY","name":"Egypt"},
{"numeric":"222","alpha2":"SV","alpha3":"SLV","name":"El Salvador"},
{"numeric":"226","alpha2":"GQ","alpha3":"GNQ","name":"Equatorial Guinea"},
{"numeric":"232","alpha2":"ER","alpha3":"ERI","name":"Eritrea"},
{"numeric":"233","alpha2":"EE","alpha3":"EST","name":"Estonia"},
{"numeric":"231","alpha2":"ET","alpha3":"ETH","name":"Ethiopia"},
{"numeric":"238","alpha2":"FK","alpha3":"FLK","name":"Falkland Islands (Malvinas)"},
{"numeric":"234","alpha2":"FO","alpha3":"FRO","name":"Faroe Islands"},
{"numeric":"242","alpha2":"FJ","alpha3":"FJI","name":"Fiji"},
{"numeric":"246","alpha2":"FI","alpha3":"FIN","name":"Finland"},
{"numeric":"250","alpha2":"FR","alpha3":"FRA","name":"France"},
{"numeric":"254","alpha2":"GF","alpha3":"GUF","name":"French Guiana"},
{"numeric":"258","alpha2":"PF","alpha3":"PYF","name":"French Polynesia"},
{"numeric":"260","alpha2":"TF","alpha3":"ATF","name":"French Southern Territories"},
{"numeric":"266","alpha2":"GA","alpha3":"GAB","name":"Gabon"},
{"numeric":"270","alpha2":"GM","alpha3":"GMB","name":"Gambia"},
{"numeric":"268","alpha2":"GE","alpha3":"GEO","name":"Georgia"},
{"numeric":"276","alpha2":"DE","alpha3":"DEU","name":"Germany"},
{"numeric":"288","alpha2":"GH","alpha3":"GHA","name":"Ghana"},
{"numeric":"292","alpha2":"GI","alpha3":"GIB","name":"Gibraltar"},
{"numeric":"300","alpha2":"GR","alpha3":"GRC","name":"Greece"},
{"numeric":"304","alpha2":"GL","alpha3":"GRL","name":"Greenland"},
{"numeric":"308","alpha2":"GD","alpha3":"GRD","name":"Grenada"},
{"numeric":"312","alpha2":"GP","alpha3":"GLP","name":"Guadeloupe"},
{"numeric":"316","alpha2":"GU","alpha3":"GUM","name":"Guam"},
{"numeric":"320","alpha2":"GT","alpha3":"GTM","name":"Guatemala"},
{"numeric":"831","alpha2":"GG","alpha3":"GGY","name":"Guernsey"},
{"numeric":"324","alpha2":"GN","alpha3":"GIN","name":"Guinea"},
{"numeric":"624","alpha2":"GW","alpha3":"GNB","name":"Guinea-Bissau"},
{"numeric":"328","alpha2":"GY","alpha3":"GUY","name":"Guyana"},
{"numeric":"332","alpha2":"HT","alpha3":"HTI","name":"Haiti"},
{"numeric":"334","alpha2":"HM","alpha3":"HMD","name":"Heard Island and McDonald Islands"},
{"numeric":"336","alpha2":"VA","alpha3":"VAT","name":"Holy See"},
{"numeric":"340","alpha2":"HN","alpha3":"HND","name":"Honduras"},
{"numeric":"344","alpha2":"HK","alpha3":"HKG","name":"Hong Kong"},
{"numeric":"348","alpha2":"HU","alpha3":"HUN","name":"Hungary"},
{"numeric":"352","alpha2":"IS","alpha3":"ISL","name":"Iceland"},
{"numeric":"356","alpha2":"IN","alpha3":"IND","name":"India"},
{"numeric":"360","alpha2":"ID","alpha3":"IDN","name":"Indonesia"},
{"numeric":"364","alpha2":"IR","alpha3":"IRN","name":"Iran (Islamic Republic of)"},
{"numeric":"368","alpha2":"IQ","alpha3":"IRQ","name":"Iraq"},
{"numeric":"372","alpha2":"IE","alpha3":"IRL","name":"Ireland"},
{"numeric":"833","alpha2":"IM","alpha3":"IMN","name":"Isle of Man"},
{"numeric":"376","alpha2":"IL","alpha3":"ISR","name":"Israel"},
{"numeric":"380","alpha2":"IT","alpha3":"ITA","name":"Italy"},
{"numeric":"388","alpha2":"JM","alpha3":"JAM","name":"Jamaica"},
{"numeric":"392","alpha2":"JP","alpha3":"JPN","name":"Japan"},
{"numeric":"832","alpha2":"JE","alpha3":"JEY","name":"Jersey"},
{"numeric":"400","alpha2":"JO","alpha3":"JOR","name":"Jordan"},
{"numeric":"398","alpha2":"KZ","alpha3":"KAZ","name":"Kazakhstan"},
{"numeric":"404","alpha2":"KE","alpha3":"KEN","name":"Kenya"},
{"numeric":"296","alpha2":"KI","alpha3":"KIR","name":"Kiribati"},
{"numeric":"408","alpha2":"KP","alpha3":"PRK","name":"Korea (Democratic People's Republic of)"},
{"numeric":"410","alpha2":"KR","alpha3":"KOR","name":"Korea (Republic of)"},
{"numeric":"414","alpha2":"KW","alpha3":"KWT","name":"Kuwait"},
{"numeric":"417","alpha2":"KG","alpha3":"KGZ","name":"Kyrgyzstan"},
{"numeric":"418","alpha2":"LA","alpha3":"LAO","name":"Lao People's Democratic Republic"},
{"numeric":"428","alpha2":"LV","alpha3":"LVA","name":"Latvia"},
{"numeric":"422","alpha2":"LB","alpha3":"LBN","name":"Lebanon"},
{"numeric":"426","alpha2":"LS","alpha3":"LSO","name":"Lesotho"},
{"numeric":"430","alpha2":"LR","alpha3":"LBR","name":"Liberia"},
{"numeric":"434","alpha2":"LY","alpha3":"LBY","name":"Libya"},
{"numeric":"438","alpha2":"LI","alpha3":"LIE","name":"Liechtenstein"},
{"numeric":"440","alpha2":"LT","alpha3":"LTU","name":"Lithuania"},
{"numeric":"442","alpha2":"LU","alpha3":"LUX","name":"Luxembourg"},
{"numeric":"446","alpha2":"MO","alpha3":"MAC","name":"Macao"},
{"numeric":"807","alpha2":"MK","alpha3":"MKD","name":"Macedonia (the former Yugoslav Republic of)"},
{"numeric":"450","alpha2":"MG","alpha3":"MDG","name":"Madagascar"},
{"numeric":"454","alpha2":"MW","alpha3":"MWI","name":"Malawi"},
{"numeric":"458","alpha2":"MY","alpha3":"MYS","name":"Malaysia"},
{"numeric":"462","alpha2":"MV","alpha3":"MDV","name":"Maldives"},
{"numeric":"466","alpha2":"ML","alpha3":"MLI","name":"Mali"},
{"numeric":"470","alpha2":"MT","alpha3":"MLT","name":"Malta"},
{"numeric":"584","alpha2":"MH","alpha3":"MHL","name":"Marshall Islands"},
{"numeric":"474","alpha2":"MQ","alpha3":"MTQ","name":"Martinique"},
{"numeric":"478","alpha2":"MR","alpha3":"MRT","name":"Mauritania"},
{"numeric":"480","alpha2":"MU","alpha3":"MUS","name":"Mauritius"},
{"numeric":"175","alpha2":"YT","alpha3":"MYT","name":"Mayotte"},
{"numeric":"484","alpha2":"MX","alpha3":"MEX","name":"Mexico"},
{"numeric":"583","alpha2":"FM","alpha3":"FSM","name":"Micronesia (Federated States of)"},
{"numeric":"498","alpha2":"MD","alpha3":"MDA","name":"Moldova (Republic of)"},
{"numeric":"492","alpha2":"MC","alpha3":"MCO","name":"Monaco"},
{"numeric":"496","alpha2":"MN","alpha3":"MNG","name":"Mongolia"},
{"numeric":"499","alpha2":"ME","alpha3":"MNE","name":"Montenegro"},
{"numeric":"500","alpha2":"MS","alpha3":"MSR","name":"Montserrat"},
{"numeric":"504","alpha2":"MA","alpha3":"MAR","name":"Morocco"},
{"numeric":"508","alpha2":"MZ","alpha3":"MOZ","name":"Mozambique"},
{"numeric":"104","alpha2":"MM","alpha3":"MMR","name":"Myanmar"},
{"numeric":"516","alpha2":"NA","alpha3":"NAM","name":"Namibia"},
{"numeric":"520","alpha2":"NR","alpha3":"NRU","name":"Nauru"},
{"numeric":"524","alpha2":"NP","alpha3":"NPL","name":"Nepal"},
{"numeric":"528","alpha2":"NL","alpha3":"NLD","name":"Netherlands"},
{"numeric":"540","alpha2":"NC","alpha3":"NCL","name":"New Caledonia"},
{"numeric":"554","alpha2":"NZ","alpha3":"NZL","name":"New Zealand"},
{"numeric":"558","alpha2":"NI","alpha3":"NIC","name":"Nicaragua"},
{"numeric":"562","alpha2":"NE","alpha3":"NER","name":"Niger"},
{"numeric":"566","alpha2":"NG","alpha3":"NGA","name":"Nigeria"},
{"numeric":"570","alpha2":"NU","alpha3":"NIU","name":"Niue"},
{"numeric":"574","alpha2":"NF","alpha3":"NFK","name":"Norfolk Island"},
{"numeric":"580","alpha2":"MP","alpha3":"MNP","name":"Northern Mariana Islands"},
{"numeric":"578","alpha2":"NO","alpha3":"NOR","name":"Norway"},
{"numeric":"512","alpha2":"OM","alpha3":"OMN","name":"Oman"},
{"numeric":"586","alpha2":"PK","alpha3":"PAK","name":"Pakistan"},
{"numeric":"585","alpha2":"PW","alpha3":"PLW","name":"Palau"},
{"numeric":"275","alpha2":"PS","alpha3":"PSE","name":"Palestine, State of"},
{"numeric":"591","alpha2":"PA","alpha3":"PAN","name":"Panama"},
{"numeric":"598","alpha2":"PG","alpha3":"PNG","name":"Papua New Guinea"},
{"numeric":"600","alpha2":"PY","alpha3":"PRY","name":"Paraguay"},
{"numeric":"604","alpha2":"PE","alpha3":"PER","name":"Peru"},
{"numeric":"608","alpha2":"PH","alpha3":"PHL","name":"Philippines"},
{"numeric":"612","alpha2":"PN","alpha3":"PCN","name":"Pitcairn"},
{"numeric":"616","alpha2":"PL","alpha3":"POL","name":"Poland"},
{"numeric":"620","alpha2":"PT","alpha3":"PRT","name":"Portugal"},
{"numeric":"630","alpha2":"PR","alpha3":"PRI","name":"Puerto Rico"},
{"numeric":"634","alpha2":"QA","alpha3":"QAT","name":"Qatar"},
{"numeric":"638","alpha2":"RE","alpha3":"REU","name":"Réunion"},
{"numeric":"642","alpha2":"RO","alpha3":"ROU","name":"Romania"},
{"numeric":"643","alpha2":"RU","alpha3":"RUS","name":"Russian Federation"},
{"numeric":"646","alpha2":"RW","alpha3":"RWA","name":"Rwanda"},
{"numeric":"652","alpha2":"BL","alpha3":"BLM","name":"Saint Barthélemy"},
{"numeric":"654","alpha2":"SH","alpha3":"SHN","name":"Saint Helena, Ascension and Tristan da Cunha"},
{"numeric":"659","alpha2":"KN","alpha3":"KNA","name":"Saint Kitts and Nevis"},
{"numeric":"662","alpha2":"LC","alpha3":"LCA","name":"Saint Lucia"},
{"numeric":"663","alpha2":"MF","alpha3":"MAF","name":"Saint Martin (French part)"},
{"numeric":"666","alpha2":"PM","alpha3":"SPM","name":"Saint Pierre and Miquelon"},
{"numeric":"670","alpha2":"VC","alpha3":"VCT","name":"Saint Vincent and the Grenadines"},
{"numeric":"882","alpha2":"WS","alpha3":"WSM","name":"Samoa"},
{"numeric":"674","alpha2":"SM","alpha3":"SMR","name":"San Marino"},
{"numeric":"678","alpha2":"ST","alpha3":"STP","name":"Sao Tome and Principe"},
{"numeric":"682","alpha2":"SA","alpha3":"SAU","name":"Saudi Arabia"},
{"numeric":"686","alpha2":"SN","alpha3":"SEN","name":"Senegal"},
{"numeric":"688","alpha2":"RS","alpha3":"SRB","name":"Serbia"},
{"numeric":"690","alpha2":"SC","alpha3":"SYC","name":"Seychelles"},
{"numeric":"694","alpha2":"SL","alpha3":"SLE","name":"Sierra Leone"},
{"numeric":"702","alpha2":"SG","alpha3":"SGP","name":"Singapore"},
{"numeric":"534","alpha2":"SX","alpha3":"SXM","name":"Sint Maarten (Dutch part)"},
{"numeric":"703","alpha2":"SK","alpha3":"SVK","name":"Slovakia"},
{"numeric":"705","alpha2":"SI","alpha3":"SVN","name":"Slovenia"},
{"numeric":"090","alpha2":"SB","alpha3":"SLB","name":"Solomon Islands"},
{"numeric":"706","alpha2":"SO","alpha3":"SOM","name":"Somalia"},
{"numeric":"710","alpha2":"ZA","alpha3":"ZAF","name":"South Africa"},
{"numeric":"239","alpha2":"GS","alpha3":"SGS","name":"South Georgia and the South Sandwich Islands"},
{"numeric":"728","alpha2":"SS","alpha3":"SSD","name":"South Sudan"},
{"numeric":"724","alpha2":"ES","alpha3":"ESP","name":"Spain"},
{"numeric":"144","alpha2":"LK","alpha3":"LKA","name":"Sri Lanka"},
{"numeric":"729","alpha2":"SD","alpha3":"SDN","name":"Sudan"},
{"numeric":"740","alpha2":"SR","alpha3":"SUR","name":"Suriname"},
{"numeric":"744","alpha2":"SJ","alpha3":"SJM","name":"Svalbard and Jan Mayen"},
{"numeric":"748","alpha2":"SZ","alpha3":"SWZ","name":"Swaziland"},
{"numeric":"752","alpha2":"SE","alpha3":"SWE","name":"Sweden"},
{"numeric":"756","alpha2":"CH","alpha3":"CHE","name":"Switzerland"},
{"numeric":"760","alpha2":"SY","alpha3":"SYR","name":"Syrian Arab Republic"},
{"numeric":"158","alpha2":"TW","alpha3":"TWN","name":"Taiwan, Province of China[a]"},
{"numeric":"762","alpha2":"TJ","alpha3":"TJK","name":"Tajikistan"},
{"numeric":"834","alpha2":"TZ","alpha3":"TZA","name":"Tanzania, United Republic of"},
{"numeric":"764","alpha2":"TH","alpha3":"THA","name":"Thailand"},
{"numeric":"626","alpha2":"TL","alpha3":"TLS","name":"Timor-Leste"},
{"numeric":"768","alpha2":"TG","alpha3":"TGO","name":"Togo"},
{"numeric":"772","alpha2":"TK","alpha3":"TKL","name":"Tokelau"},
{"numeric":"776","alpha2":"TO","alpha3":"TON","name":"Tonga"},
{"numeric":"780","alpha2":"TT","alpha3":"TTO","name":"Trinidad and Tobago"},
{"numeric":"788","alpha2":"TN","alpha3":"TUN","name":"Tunisia"},
{"numeric":"792","alpha2":"TR","alpha3":"TUR","name":"Turkey"},
{"numeric":"795","alpha2":"TM","alpha3":"TKM","name":"Turkmenistan"},
{"numeric":"796","alpha2":"TC","alpha3":"TCA","name":"Turks and Caicos Islands"},
{"numeric":"798","alpha2":"TV","alpha3":"TUV","name":"Tuvalu"},
{"numeric":"800","alpha2":"UG","alpha3":"UGA","name":"Uganda"},
{"numeric":"804","alpha2":"UA","alpha3":"UKR","name":"Ukraine"},
{"numeric":"784","alpha2":"AE","alpha3":"ARE","name":"United Arab Emirates"},
{"numeric":"826","alpha2":"GB","alpha3":"GBR","name":"United Kingdom of Great Britain and Northern Ireland"},
{"numeric":"840","alpha2":"US","alpha3":"USA","name":"United States of America"},
{"numeric":"581","alpha2":"UM","alpha3":"UMI","name":"United States Minor Outlying Islands"},
{"numeric":"858","alpha2":"UY","alpha3":"URY","name":"Uruguay"},
{"numeric":"860","alpha2":"UZ","alpha3":"UZB","name":"Uzbekistan"},
{"numeric":"548","alpha2":"VU","alpha3":"VUT","name":"Vanuatu"},
{"numeric":"862","alpha2":"VE","alpha3":"VEN","name":"Venezuela (Bolivarian Republic of)"},
{"numeric":"704","alpha2":"VN","alpha3":"VNM","name":"Viet Nam"},
{"numeric":"092","alpha2":"VG","alpha3":"VGB","name":"Virgin Islands (British)"},
{"numeric":"850","alpha2":"VI","alpha3":"VIR","name":"Virgin Islands (U.S.)"},
{"numeric":"876","alpha2":"WF","alpha3":"WLF","name":"Wallis and Futuna"},
{"numeric":"732","alpha2":"EH","alpha3":"ESH","name":"Western Sahara"},
{"numeric":"887","alpha2":"YE","alpha3":"YEM","name":"Yemen"},
{"numeric":"894","alpha2":"ZM","alpha3":"ZMB","name":"Zambia"},
{"numeric":"716","alpha2":"ZW","alpha3":"ZWE","name":"Zimbabwe"}
]
[
{ "country": "AD", "currency": "EUR" },
{ "country": "AE", "currency": "AED" },
{ "country": "AF", "currency": "AFN" },
{ "country": "AG", "currency": "XCD" },
{ "country": "AI", "currency": "XCD" },
{ "country": "AL", "currency": "ALL" },
{ "country": "AM", "currency": "AMD" },
{ "country": "AO", "currency": "AOA" },
{ "country": "AQ", "currency": null },
{ "country": "AR", "currency": "ARS" },
{ "country": "AS", "currency": "USD" },
{ "country": "AT", "currency": "EUR" },
{ "country": "AU", "currency": "AUD" },
{ "country": "AW", "currency": "AWG" },
{ "country": "AX", "currency": "EUR" },
{ "country": "AZ", "currency": "AZN" },
{ "country": "BA", "currency": "BAM" },
{ "country": "BB", "currency": "BBD" },
{ "country": "BD", "currency": "BDT" },
{ "country": "BE", "currency": "EUR" },
{ "country": "BF", "currency": "XOF" },
{ "country": "BG", "currency": "BGN" },
{ "country": "BH", "currency": "BHD" },
{ "country": "BI", "currency": "BIF" },
{ "country": "BJ", "currency": "XOF" },
{ "country": "BL", "currency": "EUR" },
{ "country": "BM", "currency": "BMD" },
{ "country": "BN", "currency": "BND" },
{ "country": "BO", "currency": "BOB" },
{ "country": "BQ", "currency": "USD" },
{ "country": "BR", "currency": "BRL" },
{ "country": "BS", "currency": "BSD" },
{ "country": "BT", "currency": "INR" },
{ "country": "BV", "currency": "NOK" },
{ "country": "BW", "currency": "BWP" },
{ "country": "BY", "currency": "BYR" },
{ "country": "BZ", "currency": "BZD" },
{ "country": "CA", "currency": "CAD" },
{ "country": "CC", "currency": "AUD" },
{ "country": "CD", "currency": "CDF" },
{ "country": "CF", "currency": "XAF" },
{ "country": "CG", "currency": "XAF" },
{ "country": "CH", "currency": "CHF" },
{ "country": "CI", "currency": "XOF" },
{ "country": "CK", "currency": "NZD" },
{ "country": "CL", "currency": "CLP" },
{ "country": "CM", "currency": "XAF" },
{ "country": "CN", "currency": "CNY" },
{ "country": "CO", "currency": "COP" },
{ "country": "CR", "currency": "CRC" },
{ "country": "CU", "currency": "CUP" },
{ "country": "CV", "currency": "CVE" },
{ "country": "CW", "currency": "ANG" },
{ "country": "CX", "currency": "AUD" },
{ "country": "CY", "currency": "EUR" },
{ "country": "CZ", "currency": "CZK" },
{ "country": "DE", "currency": "EUR" },
{ "country": "DJ", "currency": "DJF" },
{ "country": "DK", "currency": "DKK" },
{ "country": "DM", "currency": "XCD" },
{ "country": "DO", "currency": "DOP" },
{ "country": "DZ", "currency": "DZD" },
{ "country": "EC", "currency": "USD" },
{ "country": "EE", "currency": "EUR" },
{ "country": "EG", "currency": "EGP" },
{ "country": "EH", "currency": "MAD" },
{ "country": "ER", "currency": "ERN" },
{ "country": "ES", "currency": "EUR" },
{ "country": "ET", "currency": "ETB" },
{ "country": "FI", "currency": "EUR" },
{ "country": "FJ", "currency": "FJD" },
{ "country": "FK", "currency": "FKP" },
{ "country": "FM", "currency": "USD" },
{ "country": "FO", "currency": "DKK" },
{ "country": "FR", "currency": "EUR" },
{ "country": "GA", "currency": "XAF" },
{ "country": "GB", "currency": "GBP" },
{ "country": "GD", "currency": "XCD" },
{ "country": "GE", "currency": "GEL" },
{ "country": "GF", "currency": "EUR" },
{ "country": "GG", "currency": "GGP" },
{ "country": "GH", "currency": "GHS" },
{ "country": "GI", "currency": "GIP" },
{ "country": "GL", "currency": "DKK" },
{ "country": "GM", "currency": "GMD" },
{ "country": "GN", "currency": "GNF" },
{ "country": "GP", "currency": "EUR" },
{ "country": "GQ", "currency": "XAF" },
{ "country": "GR", "currency": "EUR" },
{ "country": "GS", "currency": "GBP" },
{ "country": "GT", "currency": "GTQ" },
{ "country": "GU", "currency": "USD" },
{ "country": "GW", "currency": "XOF" },
{ "country": "GY", "currency": "GYD" },
{ "country": "HK", "currency": "HKD" },
{ "country": "HM", "currency": "AUD" },
{ "country": "HN", "currency": "HNL" },
{ "country": "HR", "currency": "HRK" },
{ "country": "HT", "currency": "HTG" },
{ "country": "HU", "currency": "HUF" },
{ "country": "ID", "currency": "IDR" },
{ "country": "IE", "currency": "EUR" },
{ "country": "IL", "currency": "ILS" },
{ "country": "IM", "currency": "GBP" },
{ "country": "IN", "currency": "INR" },
{ "country": "IO", "currency": "USD" },
{ "country": "IQ", "currency": "IQD" },
{ "country": "IR", "currency": "IRR" },
{ "country": "IS", "currency": "ISK" },
{ "country": "IT", "currency": "EUR" },
{ "country": "JE", "currency": "GBP" },
{ "country": "JM", "currency": "JMD" },
{ "country": "JO", "currency": "JOD" },
{ "country": "JP", "currency": "JPY" },
{ "country": "KE", "currency": "KES" },
{ "country": "KG", "currency": "KGS" },
{ "country": "KH", "currency": "KHR" },
{ "country": "KI", "currency": "AUD" },
{ "country": "KM", "currency": "KMF" },
{ "country": "KN", "currency": "XCD" },
{ "country": "KP", "currency": "KPW" },
{ "country": "KR", "currency": "KRW" },
{ "country": "KW", "currency": "KWD" },
{ "country": "KY", "currency": "KYD" },
{ "country": "KZ", "currency": "KZT" },
{ "country": "LA", "currency": "LAK" },
{ "country": "LB", "currency": "LBP" },
{ "country": "LC", "currency": "XCD" },
{ "country": "LI", "currency": "CHF" },
{ "country": "LK", "currency": "LKR" },
{ "country": "LR", "currency": "LRD" },
{ "country": "LS", "currency": "LSL" },
{ "country": "LT", "currency": "EUR" },
{ "country": "LU", "currency": "EUR" },
{ "country": "LV", "currency": "EUR" },
{ "country": "LY", "currency": "LYD" },
{ "country": "MA", "currency": "MAD" },
{ "country": "MC", "currency": "EUR" },
{ "country": "MD", "currency": "MDL" },
{ "country": "ME", "currency": "EUR" },
{ "country": "MF", "currency": "EUR" },
{ "country": "MG", "currency": "MGA" },
{ "country": "MH", "currency": "USD" },
{ "country": "MK", "currency": "MKD" },
{ "country": "ML", "currency": "XOF" },
{ "country": "MM", "currency": "MMK" },
{ "country": "MN", "currency": "MNT" },
{ "country": "MO", "currency": "MOP" },
{ "country": "MP", "currency": "USD" },
{ "country": "MQ", "currency": "EUR" },
{ "country": "MR", "currency": "MRO" },
{ "country": "MS", "currency": "XCD" },
{ "country": "MT", "currency": "EUR" },
{ "country": "MU", "currency": "MUR" },
{ "country": "MV", "currency": "MVR" },
{ "country": "MW", "currency": "MWK" },
{ "country": "MX", "currency": "MXN" },
{ "country": "MY", "currency": "MYR" },
{ "country": "MZ", "currency": "MZN" },
{ "country": "NA", "currency": "NAD" },
{ "country": "NC", "currency": "XPF" },
{ "country": "NE", "currency": "XOF" },
{ "country": "NF", "currency": "AUD" },
{ "country": "NG", "currency": "NGN" },
{ "country": "NI", "currency": "NIO" },
{ "country": "NL", "currency": "EUR" },
{ "country": "NO", "currency": "NOK" },
{ "country": "NP", "currency": "NPR" },
{ "country": "NR", "currency": "AUD" },
{ "country": "NU", "currency": "NZD" },
{ "country": "NZ", "currency": "NZD" },
{ "country": "OM", "currency": "OMR" },
{ "country": "PA", "currency": "PAB" },
{ "country": "PE", "currency": "PEN" },
{ "country": "PF", "currency": "XPF" },
{ "country": "PG", "currency": "PGK" },
{ "country": "PH", "currency": "PHP" },
{ "country": "PK", "currency": "PKR" },
{ "country": "PL", "currency": "PLN" },
{ "country": "PM", "currency": "EUR" },
{ "country": "PN", "currency": "NZD" },
{ "country": "PR", "currency": "USD" },
{ "country": "PS", "currency": "JOD" },
{ "country": "PT", "currency": "EUR" },
{ "country": "PW", "currency": "USD" },
{ "country": "PY", "currency": "PYG" },
{ "country": "QA", "currency": "QAR" },
{ "country": "RE", "currency": "EUR" },
{ "country": "RO", "currency": "RON" },
{ "country": "RS", "currency": "RSD" },
{ "country": "RU", "currency": "RUB" },
{ "country": "RW", "currency": "RWF" },
{ "country": "SA", "currency": "SAR" },
{ "country": "SB", "currency": "SBD" },
{ "country": "SC", "currency": "SCR" },
{ "country": "SD", "currency": "SDG" },
{ "country": "SE", "currency": "SEK" },
{ "country": "SG", "currency": "SGD" },
{ "country": "SH", "currency": "SHP" },
{ "country": "SI", "currency": "EUR" },
{ "country": "SJ", "currency": "NOK" },
{ "country": "SK", "currency": "EUR" },
{ "country": "SL", "currency": "SLL" },
{ "country": "SM", "currency": "EUR" },
{ "country": "SN", "currency": "XOF" },
{ "country": "SO", "currency": "SOS" },
{ "country": "SR", "currency": "SRD" },
{ "country": "SS", "currency": "SSP" },
{ "country": "ST", "currency": "STD" },
{ "country": "SV", "currency": "USD" },
{ "country": "SX", "currency": "ANG" },
{ "country": "SY", "currency": "SYP" },
{ "country": "SZ", "currency": "SZL" },
{ "country": "TC", "currency": "USD" },
{ "country": "TD", "currency": "XAF" },
{ "country": "TF", "currency": "EUR" },
{ "country": "TG", "currency": "XOF" },
{ "country": "TH", "currency": "THB" },
{ "country": "TJ", "currency": "TJS" },
{ "country": "TK", "currency": "NZD" },
{ "country": "TL", "currency": "USD" },
{ "country": "TM", "currency": "TMT" },
{ "country": "TN", "currency": "TND" },
{ "country": "TO", "currency": "TOP" },
{ "country": "TR", "currency": "TRY" },
{ "country": "TT", "currency": "TTD" },
{ "country": "TV", "currency": "AUD" },
{ "country": "TW", "currency": "TWD" },
{ "country": "TZ", "currency": "TZS" },
{ "country": "UA", "currency": "UAH" },
{ "country": "UG", "currency": "UGX" },
{ "country": "UM", "currency": "USD" },
{ "country": "US", "currency": "USD" },
{ "country": "UY", "currency": "UYU" },
{ "country": "UZ", "currency": "UZS" },
{ "country": "VA", "currency": "EUR" },
{ "country": "VC", "currency": "XCD" },
{ "country": "VE", "currency": "VEF" },
{ "country": "VG", "currency": "USD" },
{ "country": "VI", "currency": "USD" },
{ "country": "VN", "currency": "VND" },
{ "country": "VU", "currency": "VUV" },
{ "country": "WF", "currency": "XPF" },
{ "country": "WS", "currency": "EUR" },
{ "country": "YE", "currency": "YER" },
{ "country": "YT", "currency": "EUR" },
{ "country": "ZA", "currency": "ZAR" },
{ "country": "ZM", "currency": "ZMW" },
{ "country": "ZW", "currency": "USD" }
]
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Currencies, then and now</title>
<link rel="stylesheet" href="style.css" />
<script defer src="https://unpkg.com/d3@4.12.2/build/d3.js"></script>
<script defer src="https://unpkg.com/d3fc@13.1.1/build/d3fc.js"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.4/d3-legend.js"></script>
<script defer src="https://unpkg.com/topojson-client@3.0.0"></script>
</head>
<body>
<d3fc-group id="container" class="container" auto-resize>
<d3fc-svg id="map" class="map"></d3fc-svg>
<label class="datepicker-group">
Reference date
<input id="datepicker" class="datepicker" type="date" required />
</label>
</d3fc-group>
<script defer src="index.js"></script>
</body>
</html>
(function () {
const apiBase = 'https://api.fixer.io';
const apiMinDate = '2000-01-01';
const containerFc = d3.select('#container');
const svgFc = containerFc.select('#map');
const svg = svgFc.select('svg');
let countries;
let baseCountryCode = 'GB';
let referenceDate = oneYearAgo();
const projection = d3.geoMercator();
const pathGenerator = d3.geoPath(projection);
const percentFormatTitle = d3.format('+.1%');
const percentFormatLegend = d3.format('+.0%');
const rateFormat = d3.format('.2f');
const colorScale = d3.scaleLinear()
.range(['red', 'white', 'green']);
const legend = d3.legendColor()
.scale(colorScale)
.cells(7) // odd, so the 0 pivot is included
.cellFilter(d => { d; return true; })
.labelFormat(percentFormatLegend)
.title('Change')
.titleWidth(100);
svgFc.on('measure', () => {
const { width, height } = d3.event.detail;
projection
// scale to fit width (Mercator-specific equation)
.scale((width - 5) / (2 * Math.PI))
// clip to fit height
.clipExtent([[0, 0], [width, height]])
// center the projection center in the element
.translate([width / 2, height / 2])
// shift projection center down to match Mercator's original map which was truncated at 80deg N and 66deg S
.center([0, 10]);
});
// called on requestRedraw, auto-resize of d3fc-group will make subsequent calls
svgFc.on('draw', draw);
d3.select('#datepicker')
.attr('min', apiMinDate)
.on('change', onDatepickerChange)
.node().value = referenceDate;
Promise.all([
loadJson('https://unpkg.com/world-atlas@1/world/110m.json'),
loadJson('country-codes.json'),
loadJson('country-currency.json'),
]).then(([world, countryCodes, countryCurrency]) => {
const data = prepareGeoData(world);
countries = data.countries;
countries.forEach(country => addCountryData(country, countryCodes, countryCurrency));
svg.datum(data);
update();
});
function update() {
const baseCountry = countries.find(country => country.properties.code === baseCountryCode);
const baseCurrency = baseCountry.properties.currency;
svg.datum().baseCountry = baseCountry;
return Promise.all([
getFxRates(baseCurrency, 'latest'),
getFxRates(baseCurrency, referenceDate)
]).then(rates => {
countries.forEach(country => updateCountryFx(country, rates[0], rates[1]));
// A fixed scale would make for easier comparisons of different periods, but extents vary wildly, so make it dynamic.
const [min, max] = d3.extent(countries, d => d.properties.rates && d.properties.rates.change);
const largestExtent = Math.max(Math.abs(min), Math.abs(max));
colorScale.domain([-largestExtent, 0, largestExtent]); // symmetric with pivot at zero, to match the range
containerFc.node().requestRedraw();
});
}
function draw() {
// fc.dataJoin simplifies pattern of enter().append() & all.attr()
// Since it's projected, sphere will be rendered as a rectangle.
fc.dataJoin('path', 'sphere-background')(svg, d => [d.land])
.datum({ type: 'Sphere' }) // shape the path generator should render
.attr('d', pathGenerator);
// The selectAll() underneath pushes data down from context (svg in this case) to the selectees
fc.dataJoin('path', 'land')(svg, d => [d.land])
.attr('d', pathGenerator);
const countries = fc.dataJoin('path', 'country')(svg, d => d.countries)
.attr('d', pathGenerator)
.attr('fill', countryColor);
countries.enter()
.filter(d => d.properties.currency)
.classed('interactive', true)
.on('click', d => selectBaseCountry(d.properties.code));
fc.dataJoin('title')(countries, d => [d])
.text(countryTitle);
fc.dataJoin('path', 'country-borders')(svg, d => [d.borders])
.attr('d', pathGenerator);
fc.dataJoin('g', 'legend')(svg, d => [d])
.attr('transform', `translate(${projection([-150, 0])})`) // put it out of the way, in the Pacific Ocean
.call(legend);
}
function countryColor(country) {
return countryCharacteristic(country, {
base: () => 'hsl(240, 100%, 50%)',
sameCurrencyAsBase: () => 'hsl(240, 100%, 70%)',
ratesPresent: rates => colorScale(rates.change),
ratesMissing: () => 'gray'
});
}
function countryTitle(country) {
const { properties: props } = country;
const { name, currency } = props;
return countryCharacteristic(country, {
base: () => `${name} (base country) (${currency})`,
sameCurrencyAsBase: () => `${name} (same currency as base) (${currency})`,
ratesPresent: rates =>
`${name} (${currency}, then ${rateFormat(rates.reference)}, now ${rateFormat(rates.current)}, change ${percentFormatTitle(rates.change)})`,
ratesMissing: () => `${name} (${currency ? currency + ', no data for current context' : 'no currency'})`
});
}
function countryCharacteristic(country, characteristics) {
const baseCountry = svg.datum().baseCountry;
if (country === baseCountry) {
return characteristics.base();
} else if (country.properties.currency === baseCountry.properties.currency) {
return characteristics.sameCurrencyAsBase();
} else if (country.properties.rates) {
return characteristics.ratesPresent(country.properties.rates);
} else {
return characteristics.ratesMissing();
}
}
function selectBaseCountry(code) {
baseCountryCode = code;
update();
}
function selectReferenceDate(date) {
referenceDate = date;
update();
}
function onDatepickerChange() {
const picker = d3.event.target;
const date = picker.value;
if (picker.validity.valid && date && /^\d{4}-\d{2}-\d{2}/.test(date)) {
selectReferenceDate(date);
}
}
function prepareGeoData(world) {
const land = topojson.feature(world, world.objects.land);
const countries = topojson.feature(world, world.objects.countries).features;
// Mesh excludes sea borders. Filter further to include shared borders only once
const borders = topojson.mesh(world, world.objects.countries, (a, b) => a !== b);
return { land, countries, borders };
}
function addCountryData(country, countryCodes, countryCurrency) {
const codes = countryCodes.find(candidate => candidate.numeric === country.id);
if (codes) {
Object.assign(country.properties, {
code: codes.alpha2,
name: codes.name,
currency: countryCurrency.find(candidate => candidate.country === codes.alpha2).currency
});
}
}
function updateCountryFx(country, currentRates, referenceRates) {
const currency = country.properties.currency;
let rates;
if (currency) {
const reference = referenceRates[currency];
const current = currentRates[currency];
if (reference != null && current != null) {
const change = (current - reference) / reference;
rates = { current, reference, change };
}
}
country.properties.rates = rates;
}
function getFxRates(base, date) {
// API returns previous weekday for weekend dates
return loadJson(`${apiBase}/${date}?base=${base}`)
.catch(reason => {
alert(`Error loading FX data: ${reason.status} ${reason.responseText}`);
throw reason;
})
.then(data => data.rates);
}
function loadJson(url) {
return new Promise((resolve, reject) => {
d3.json(url, (error, data) => error ? reject(error.target) : resolve(data));
});
}
function oneYearAgo() {
const date = new Date();
date.setFullYear(date.getFullYear() - 1);
return date.toISOString().slice(0, 10);
}
})();
// Make the data function simply copy data down, by wrapping it to counter the unwrapping that data().does
// const dataKey = d => [d];
body {
margin: 0;
font-family: sans-serif;
}
d3fc-group.container {
display: block;
width: 100vw;
height: calc(100vw / 1.65); /* Mercator's original aspect ratio */
}
@media (min-aspect-ratio: 165/100) {
d3fc-group.container {
width: calc(100vh * 1.65);
height: 100vh;
}
}
d3fc-svg.map {
display: block;
height: 100%;
}
.sphere-background {
fill: rgb(170, 218, 255);
}
.country {
cursor: not-allowed;
}
.country.interactive {
cursor: pointer;
}
.country-borders {
fill: none;
stroke: black;
stroke-width: 0.5px;
}
.datepicker-group {
position: absolute;
left: 20px;
bottom: 20px;
}
.datepicker {
display: block;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment