Choropleth Maps in F#

How to make choropleth maps in F# with Plotly.


Plotly Studio: Transform any dataset into an interactive data application in minutes with AI. Try Plotly Studio now.

Note: We are retiring documentation for R, MATLAB, Julia, and F# in November 2025. Learn more about this change here.

In [1]:
#r "nuget: Plotly.NET, 2.0.0-preview.8" #r "nuget: Plotly.NET.Interactive, 2.0.0-preview.8" 
Installed Packages
  • Plotly.NET, 2.0.0-preview.8
  • Plotly.NET.Interactive, 2.0.0-preview.8

Loading extensions from Plotly.NET.Interactive.dll

Added Kernel Extension including formatters for Plotly.NET charts.

A Choropleth Map is a map composed of colored polygons. It is used to represent spatial variations of a quantity. This page documents how to build outline choropleth maps, but you can also build choropleth tile maps using our Mapbox trace types.

Base Map Configuration

Introduction: main parameters for choropleth outline maps

Making choropleth maps requires two main types of input:

Geometry information: This can either be a supplied GeoJSON file where each feature has either an id field or some identifying value in properties; or one of the built-in geometries within plot_ly: US states and world countries (see below) A list of values indexed by feature identifier. The GeoJSON data is passed to the geojson argument, and the data is passed into the z argument of choropleth traces.

Note the geojson attribute can also be the URL to a GeoJSON file, which can speed up map rendering in certain cases.

Choropleth Map Using GeoJSON

In [2]:
#r "nuget: FSharp.Data" #r "nuget: Newtonsoft.Json" open FSharp.Data open Newtonsoft.Json open Plotly.NET.LayoutObjects open Plotly.NET.TraceObjects #r "nuget: Deedle" open Deedle open System.IO open System.Text open Plotly.NET let data = Http.RequestString "https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv" |> fun csv -> Frame.ReadCsvString(csv,true,separators=",",schema="fips=string,unemp=float") let geoJson = Http.RequestString "https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json" |> JsonConvert.DeserializeObject let locationsGeoJSON: string [] = data |> Frame.getCol "fips" |> Series.values |> Array.ofSeq let zGeoJSON: int [] = data |> Frame.getCol "unemp" |> Series.values |> Array.ofSeq Chart.ChoroplethMap( locations = locationsGeoJSON, z = zGeoJSON, Locationmode=StyleParam.LocationFormat.GeoJson_Id, GeoJson = geoJson, FeatureIdKey="id" ) |> Chart.withGeo( Geo.init( Scope=StyleParam.GeoScope.NorthAmerica, Projection=GeoProjection.init(StyleParam.GeoProjectionType.AzimuthalEqualArea), ShowLand=true, LandColor = Color.fromString "lightgrey" ) ) |> Chart.withSize (800.,800.) 
Installed Packages
  • Deedle, 2.4.3
  • FSharp.Data, 4.2.4
  • newtonsoft.json, 12.0.3
Out[2]:

Indexing by GeoJSON Properties

If the GeoJSON you are using either does not have an id field or you wish you use one of the keys in the properties field, you may use the featureidkey parameter to specify where to match the values of locations.

In the following GeoJSON object/data-file pairing, the values of properties.district match the values of the district column:

In [3]:
#r "nuget: FSharp.Data" open FSharp.Data open Newtonsoft.Json let data = Http.RequestString "https://raw.githubusercontent.com/plotly/datasets/master/election.csv" |> fun csv -> Frame.ReadCsvString(csv,true,separators=",") let geoJson = Http.RequestString "https://raw.githubusercontent.com/plotly/datasets/master/election.geojson" |> JsonConvert.DeserializeObject let locationsGeoJSON: string [] = data |> Frame.getCol "district" |> Series.values |> Array.ofSeq let zGeoJSON: int [] = data |> Frame.getCol "Bergeron" |> Series.values |> Array.ofSeq Chart.ChoroplethMap(locations = locationsGeoJSON, z = zGeoJSON, GeoJson = geoJson, Colorscale= StyleParam.Colorscale.Viridis, FeatureIdKey="properties.district") |> Chart.withGeoStyle(FitBounds=StyleParam.GeoFitBounds.Locations,Visible=false) |> Chart.withColorBarStyle(Title.init("Bergeron Votes")) |> Chart.withTitle(title="2013 Montreal Election") |> Chart.withSize (800.,800.) 
Installed Packages
  • FSharp.Data, 4.2.4
Out[3]:

Using Built-in Country and State Geometries

Plotly comes with two built-in geometries which do not require an external GeoJSON file:

USA States Countries as defined in the Natural Earth dataset. Note and disclaimer: cultural (as opposed to physical) features are by definition subject to change, debate and dispute. Plotly includes data from Natural Earth "as-is" and defers to the Natural Earth policy regarding disputed borders which read:

Natural Earth Vector draws boundaries of countries according to defacto status. We show who actually controls the situation on the ground.

To use the built-in countries geometry, provide locations as three-letter ISO country codes.

In [4]:
let data = Http.RequestString "https://raw.githubusercontent.com/plotly/datasets/master/2014_world_gdp_with_codes.csv" |> fun csv -> Frame.ReadCsvString(csv,true,separators=",") data.Print() 
 COUNTRY GDP (BILLIONS) CODE 0 -> Afghanistan 21.71 AFG 1 -> Albania 13.40 ALB 2 -> Algeria 227.80 DZA 3 -> American Samoa 0.75 ASM 4 -> Andorra 4.80 AND 5 -> Angola 131.40 AGO 6 -> Anguilla 0.18 AIA 7 -> Antigua and Barbuda 1.24 ATG 8 -> Argentina 536.20 ARG 9 -> Armenia 10.88 ARM 10 -> Aruba 2.52 ABW 11 -> Australia 1483.00 AUS 12 -> Austria 436.10 AUT 13 -> Azerbaijan 77.91 AZE 14 -> Bahamas, The 8.65 BHM : ... ... ... 207 -> Uganda 26.09 UGA 208 -> Ukraine 134.90 UKR 209 -> United Arab Emirates 416.40 ARE 210 -> United Kingdom 2848.00 GBR 211 -> United States 17420.00 USA 212 -> Uruguay 55.60 URY 213 -> Uzbekistan 63.08 UZB 214 -> Vanuatu 0.82 VUT 215 -> Venezuela 209.20 VEN 216 -> Vietnam 187.80 VNM 217 -> Virgin Islands 5.08 VGB 218 -> West Bank 6.64 WBG 219 -> Yemen 45.45 YEM 220 -> Zambia 25.61 ZMB 221 -> Zimbabwe 13.74 ZWE 
In [5]:
let getColumnData column= data |> Frame.getCol column |> Series.values |> Array.ofSeq Chart.ChoroplethMap(locations=(getColumnData "CODE"),z=getColumnData "GDP (BILLIONS)",Text=getColumnData "COUNTRY",Colorscale=StyleParam.Colorscale.Bluered) 
Out[5]:

To use the USA States geometry, set locationmode='USA-states' and provide locations as two-letter state abbreviations

In [6]:
let data = Http.RequestString "https://raw.githubusercontent.com/plotly/datasets/master/2011_us_ag_exports.csv" |> fun csv -> Frame.ReadCsvString(csv,true,separators=",") let getColumnData column= data |> Frame.getCol column |> Series.values |> Array.ofSeq data?hover <- [ for k in data.RowKeys -> let dataRow = (data.GetRowAt(k)) let state = string (dataRow |> Series.get "state") let beef = string (dataRow |> Series.get "beef") let dairy = string (dataRow |> Series.get "dairy") let fruits = string (dataRow |> Series.get "total fruits") let veggies = string (dataRow |> Series.get "total veggies") let wheat = string (dataRow |> Series.get "wheat") let corn = string (dataRow |> Series.get "corn") String.Format(" {0} <br> Beef {1} Dairy {2} <br> Fruits {3} Veggies {4} <br> Wheat {5} Corn {6}",state, beef,dairy,fruits,veggies,wheat,corn) ] Chart.ChoroplethMap(locations=(getColumnData "code"),z=getColumnData "total exports",Locationmode=StyleParam.LocationFormat.USA_states,Text=getColumnData "hover", Colorscale=StyleParam.Colorscale.Bluered) 
Out[6]:

Customize choropleth chart

Note In this example we set layout.geo.scope to usa to automatically configure the map to display USA-centric data in an appropriate projection.

In [7]:
Chart.ChoroplethMap(locations=(getColumnData "code"),z=getColumnData "total exports",Locationmode=StyleParam.LocationFormat.USA_states,Text=getColumnData "hover", Colorscale=StyleParam.Colorscale.Bluered) |> Chart.withGeo( Geo.init( Scope=StyleParam.GeoScope.Usa, Projection=GeoProjection.init(StyleParam.GeoProjectionType.AlbersUSA), ShowLakes=true, LakeColor = Color.fromString "white" ) ) 
Out[7]:

World Choropleth Map

In [8]:
let data = Http.RequestString "https://raw.githubusercontent.com/plotly/datasets/master/2014_world_gdp_with_codes.csv" |> fun csv -> Frame.ReadCsvString(csv,true,separators=",") let getColumnData column= data |> Frame.getCol column |> Series.values |> Array.ofSeq Chart.ChoroplethMap(locations=(getColumnData "CODE"),z=getColumnData "GDP (BILLIONS)",Text=getColumnData "COUNTRY",Colorscale=StyleParam.Colorscale.Greens,Marker=Marker.init(Line=Line.init(Color= Color.fromString "grey",Width=0.5))) |> Chart.withColorBarStyle(title=Title.init("GDP Billions US$")) |> Chart.withTitle(title="2014 Global GDP<br>Source:<a href=\"https://www.cia.gov/library/publications/the-world-factbook/fields/2195.html\">CIA World Factbook</a>") |> Chart.withGeo( Geo.init( Projection=GeoProjection.init(StyleParam.GeoProjectionType.Mercator), ShowCoastLines=false, ShowFrame=false ) ) 
Out[8]: