TLDR; I'm presenting Florence, a library that lets you evaluate and compare any city area using a single F# function.

You can download the presented notebook here. Open it with VS Code (Polyglot Notebooks extension is required)

Data-driven cities need data-driven community leaders.

I use Polyglot Notebooks to promote civic programming and F# as the municipal language.

I'm publishing my work under the Florence umbrella of libraries:

  • Florence.GeojsonCloud to use open city data right away

  • Florence.DistanceProvider to provide spatial, walking, cycling, and driving measures in the form of DSL (integrated with Mapbox Directions API)

  • Florence.Notebooks to evaluate any place by writing a single F# function

  • frontend applications that can be used directly from notebooks:

FSQStudio formatter that displays calculated rankings on map

- Mapbox autofill UI to gather city locations and converts to DSL types

This post covers how these parts can work together. Details about each of them will be presented in separate posts.

Florence: Open Data Renaissance

Florence library lets you evaluate and compare any city area using a single F# function.

It supports defining such a function with words that describe aspects of your city life or specific municipal challenges.

An example that uses distances :

Such a function can be executed against all addresses within a city or against relevant blocks of places. There are many more ways to write evaluation functions, and except for distances, we can use facility properties.

But let's first see how this function fits into the broader picture and how we can grab city data and visualize ranker results.


Florence aims to be accessible to any potential community leader and make F# the default language for municipal endeavors. To achieve this goal, access to data must be made as straightforward as possible so that users can quickly write the ranker function and view the results.

Example: simple but complete notebook of city analysis.

There are two supported ways to obtain the city data:

  1. Download from Open Data Portal or any other public/commercial source. Florence expects data to be in GEOJSON format, downloaded or copied to VS Code workspace.

  2. Load NuGet package (dedicated to a particular city) that knows where the data are and enable preview, display, download, or load data directly to Florence.

GeojsonCloud is my crafted collection of interesting, useful datasets publicly available online.

It will grow and evolve, and you can give your city priority by buying me a coffee.

Before loading data, we can check the count of the files and the number of geometry features it contains for the particular file. Often, when sharing notebooks, we should also take care of attribution about the source and license:

Geojson Cloud is an F# Type Provider for some storage in the cloud. It was inspired by and is very similar to the Azure Storage Type Provider, with a few differences, which I will highlight in a dedicated post.

Include yourself in the city analysis.

In the beginning, I mentioned that the ranker function could be based on our life in the city:

What is the source of this "MyFirenze" type? First of all, it can be named as you wish. The name should reflect the fields it has and how they are relevant to the challenge the ranker function addresses.

This type, no matter its name, has a constructor that takes the position of any place (as longitude and latitude) and returns spatial distances between this place and other named locations.

You can see all distances at once:

How it works

Life-inspired type is created by ... a special Type Provider.

To trigger it, you have two options:

  1. Create type from random locations: useful for quick explorations ( especially for cities we don't live in )

  2. Create type from UI

Creating type from UI lets you create your data once and save it for future endeavors.

It is a Feliz application that communicates with Mapbox.

I will provide details on how to use it in the next post.

As most of us don't live in Florence, the first option is good to continue.

To rand locations, we need to provide a data source we will rand location from and descriptive names of the places that state your life in the city (or any municipal challenge).

Also, provide a type name you want to operate with.

Alternative function definitions

Having a way to define our city-related type, we can include it in a ranking function.

Specifying the ranker function like we did at the beginning looks intimidating but is usable only for simple problems and small areas. We typically don't want to include places in calculations that are too far away, and point per meter may also not be the best measure.

Alternatively, we can give a small number of points for each place with a maximum distance considered.

Pts function allows converting distance to points. In the example above, we give 0 to 9 points. Anything further than 3km does not count:

And sample evaluation function:

Visualizations with FSQ Studio

Florence comes with a formatter that display result into the map.

When you hover over a particular area, you will notice the same evaluation details:

1. place: how good is that area according to the ranker function from 1 to n

2. score: the result of the evaluation function. Most often, the cumulative distances or their inversion (best on your ranking function)

3. rank: number between 0.00..00 to 1.000...0. It tells how far the actual score is from the best value (quantile rank), which is good for using linear color palettes

4. ratio: similar to rank but is not linear, hence better reflects differences between sequenced places

The nice thing is that our city type doesn't only allow us to specify distances to a particular place in a DSL fashion. You can see all of them at once, also on a map

Saving and continuation of explorations

Just ranked data can be an input to yet another ranking. We can save our analyses and use them later in yet another analysis

We can load it anytime and do new data processing or ranking.