Distance Type Provider
Tags: fsharp, dotnet
Published: 2022-12-23 22:50:34


I'm presenting my Distance Type Provider: a little bit different, literacy-close type provider, created for interactive, notebook-driven geospatial explorations. 

If you threaten the geospatial domain as far from your interest, I encourage you to read the post even more, as I'm using tangible, life inspired examples.

Distance Type Provider plays a crucial role in my other, not yet released endeavor Florence, but can be used alone.

In short, DTP helps to find distances and travel times for different movement profiles just by typing: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j85jl36knzpebhulaxjf.png)

You can find some of the examples I present [here](https://github.com/PawelStadnicki/Distance-Type-Provider/tree/main/notebooks).

## Type Providers

Type Providers have many applications and are a fabulous concept on their own. Almost any F# developer had intrinsic desire to create one at some point!  

They are especially useful in data explorations: you get a local or remote data source and query it.

Most of the existing type providers have a generic purpose to traverse through well established schemas: [json](https://fsprojects.github.io/FSharp.Data/library/JsonProvider.html), [swagger](https://fsprojects.github.io/SwaggerProvider/#/). Other serve DSL purpose like [Regex](http://fsprojects.github.io/FSharp.Text.RegexProvider/). [World Bank](https://fsprojects.github.io/FSharp.Data/library/WorldBank.html) type provider is instead one that is very close to the literate programming. It collects development indicators and other data about countries in the world:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/go06oc5cj3lbjygiqh5k.png)


Literate programming is about writing code, that is meant to be clear to a human being, not a developer itself. In data explorations, any burden distracts and we should document what we already know. **Literate code communicates data as information**. It is very useful.

## Distance Type Provider

If you follow me on Twitter, you know that I'm interested in smart city and open data domains. They in turn are strictly connected with geospatial, and geospatial is all about distances.

You may ask:
> Wait! Distance is something you measure, it is a value or variable but not a type! Ok, it can be int or float (or unit of measure) but it already exists...

It is all about data literacy. The goal is to not only provide a distance itself, but **ask about it in plain English**.

Let's start with an example, which describes our life without such a provider. 

## Ordinary code

Assuming we have a set of places (with names and positions):
how can we calculate distances between some wanted places ?


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gwowehxbhuwr9wgluxd4.png)

Every developer wrote similar code hundreds of times and it is very easy to follow, even for newbies and people outside IT.
However, we need to filter out wanted entities first. If we want to compare many of them, the code will consist mostly of middle steps everyone has to read (and potentially, likely be distracted from the program goal). Also, with more and more data, data discoverability shrinks.

So how we could write code with data literacy?
In other words, how we would transform the previous code to a question in English ?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kuil43mwhgbuyhncnpbm.png)

With Distance Type Provider you can write code exactly like above. 

## Geojson everywhere

To make the provider as generic as possible, it expects a geosjon as an input.
If we look at F1 dataset, that contains F1 tracks, we can find some properties that determine these tracks:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kko84a7i0junpwvqpkxa.png)

The default geojson property that provider expects is "name", so if we run provider without additional parameters, we can check distances based on track names:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wgrqq2f4f37kh96dq4nq.png)

If we want to use other attribute name, we should pass it as a static parameter:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3j9qu5tf2gkkx2i07tj5.png)

What about two different data sources ?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g5ptir8py2qrpdo2dvqk.png)

**MyLife** geojson is very interesting, as you can define it once and use it in many municipal  analyses.

Florence even comes with special editor based on Mapbox autofill that you can use directly from the notebooks:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mdqkvkd8sxyhjxafw96q.png)
 and/or continue data analyses in the very next cell:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2o9yfbqhzr04qdcvqsf.png)

With such a life space data ready for our disposal, we can rank city places with life-inspired function:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5ntgkcnptkka3el89ni.png)


## Spatial distance vs actual distance

The easiest way to measure the distance between 2 points is to provide spatial distance, a straight line length. It can be calculated with this [formula](http://www.fssnip.net/7P8/title/Calculate-distance-between-two-GPS-latitudelongitude-points). Although it is not 100% accurate for larger distances (
due to possible differences in height above sea level and the fact that the Earth is not perfectly round ) it is fair enough for most analysis.

So spatial distance is the default one.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wyjxced4d4nakpbsv9h9.png)

But there are situations when we need a distance between 2 or more points, that is measured through the exact road or path. Moreover, the road will be different depending on the means of transport used: car, bike, bus. We can always decide to just walk.

And all of these can return different values on different hours due to the current traffic level.

Fortunately, there are data providers that do that for almost any area in the World. 

Distance Type Provider leverages Mapbox for this purpose.
Despite the fact Mapbox offers generous free plans, the provider user must use his own token.

In return you get 3 new profiles: driving, cycling and walking:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8iplpw92819l7box51e.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xvtmxcx3p6fhzskvqw0g.png)

That is nice! What about checking more data at once? Not a problem at all, you can use any place from the geojson combined with any other, even at hoc location:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0sgkg857lso7clc8lfz3.png)

Just in case you haven't noticed it:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/po64sbtxuwe5og6rsb85.png)

Mapbox direction-matrix API return also expected duration of the travel. That is a nice bonus!

## What next

To be honest, I added the Mapbox support just 2 days ago so it is all very fresh. The provider itself is still experimental but will evolve ratehr rapidly, / I definately want to add many more capabilities of the Mapbox API.

I hope it will serve some purpose outside of my own experiments!
Stay tuned for more geospatial stuff related to F#.