Snippet Wednesday! - Add maps to your Automatic Reports 🗺️

Nice post, @ThomasN !

To add to this, if you want to make an image of your MapView, you can extract the geojson from the MapResult. Here is a snippet of how you can set up your map view (taking the example provided in the documentation):

    def _get_map_view(self, params):
        # Create some points using coordinates
        markers = [
            MapPoint(25.7617, -80.1918, description='Miami'),
            MapPoint(18.4655, -66.1057, description='Puerto Rico'),
            MapPoint(32.3078, -64.7505, description='Bermudas')
        ]
        # Create a polygon
        polygon = MapPolygon(markers)

        # Visualize map
        features = markers + [polygon]
        return MapResult(features)

    @MapView('Map view', duration_guess=1)
    def get_map_view(self, params, **kwargs):
        return self._get_map_view(params)

Then, using the geojson property on the MapResult object, you can extract the geojson. Here is the snippet combining the code presented above:

    def make_plotly_map(self, params, **kwargs):
        geojson = self._get_map_view(params).geojson
        geo_df = gpd.GeoDataFrame.from_features(geojson["features"])
        # get average of bounds
        fig = px.choropleth_mapbox(geo_df,
                                   geojson=geo_df.geometry,
                                   locations=geo_df.index,
                                   color=geo_df.fill,
                                   opacity=0.3,
                                   mapbox_style="open-street-map",
                                   title="VIKTOR developers around the world",
                                   zoom=self._get_map_zoom(geo_df),
                                   center=self._get_map_center(geo_df),
                                   )
        fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})

        return fig

Notice that I’ve added methods to the zoom and center arguments. Here is the map center method:

    @staticmethod
    def _get_map_center(geo_dataframe):
        lat_min = geo_dataframe.bounds['miny'].min()
        lat_max = geo_dataframe.bounds['maxy'].max()
        lon_min = geo_dataframe.bounds['minx'].min()
        lon_max = geo_dataframe.bounds['maxx'].max()
        lat = (lat_min + lat_max) / 2
        lon = (lon_min + lon_max) / 2
        return {'lat': lat, 'lon': lon}

Basically, I’m taking the bounds of the geodataframe, and averaging them to get the center.

For the zoom, it was a bit more difficult, and definitely not accurate. For this I’ve applied my own crude algorithm (I recommend adjusting the constants if they do not fit the cases that you would apply it to):

    @staticmethod
    def _get_map_zoom(geo_dataframe):
        lat_min = geo_dataframe.bounds['miny'].min()
        lat_max = geo_dataframe.bounds['maxy'].max()
        lon_min = geo_dataframe.bounds['minx'].min()
        lon_max = geo_dataframe.bounds['maxx'].max()
        lat_diff = lat_max - lat_min
        lon_diff = lon_max - lon_min
        alpha = 20
        beta = 0.55
        # set up a simple algorithm based on two constants
        zoom = alpha / (max(lat_diff, lon_diff)) ** beta
        return zoom

I’ve only hacked this together quickly, and noticed that many things can be improved to making the maps similar. Hopefully we can get more developers onboard to get this snippet improved.

Here is my test case comparison:

MapView

Plotly image

1 Like