Greppo: All you need is 4 minutes to build an Interactive Geospatial Webapp
Tags: geospatial, webdev, python, tutorial
Published: 2021-11-30 00:27:22

# Introduction
Looking to build a Geospatial dashboard for your python script? This blog post is for you! Read along for 3 easy steps to get started with Greppo, a python prototyping tool to quickly build interactive Geo-spatial web apps.

For this tutorial we will be building an app that will visualize some Geospatial data from San Francisco. The data lists the public amenities available in the city. We will plot this data and summarize the count of amenities within an area selected by the user using a Bar Chart.

The code used in this tutorial can be found [here](https://github.com/greppo-io/greppo-demo/tree/main/Basic-amenities-in-SFO).

If you’re like me and like to quickly jump to the end of a tutorial and play around with the web app simply,
- Clone this [repo](https://github.com/greppo-io/greppo-demo).
- Navigate to `Basic-amenities-in-SFO`.
- Install greppo via pip `pip install greppo`.
- On a console run, `greppo serve app.py`.

Alternatively, [here’s](https://greppoapps.page.link/sf-amenities) a link to a deployed app instance that is currently running if you want to play around hands-free.

# 3 Easy Steps

### Setup Dir
```
mkdir greppo-quickstart
cd greppo-quickstart
```

### Install Greppo

It is recommended that you install `greppo` inside a Python virtual environment. For this tutorial we are going to use virtualenv (see [here](https://docs.greppo.io/installation.html#python-environment-management) for other environment managers)
```
virtualenv ENV
source ENV/bin/activate
pip install greppo
```

### Setup the Python Script

#### Create an empty python script
```
touch app.py
```

#### Import Greppo
```python
from greppo import app
import geopandas as gpd
```
First let's import greppo and geopandas. For greppo, `app` is the entry point for adding interactive and visual components to your application. With `app` we can instruct greppo to add a map layer, or a bar chart, or set up APIs to variables. Geopandas is imported as `gpd` by convention to read vector data.

#### Read in the data using Geopandas
```python
sfo_amenities = gpd.read_file("./SFO_Amenities.geojson")
amenities = list(sfo_amenities['amenity'].unique())
```
For this tutorial go ahead and download the data from [here](https://github.com/greppo-io/greppo-demo/blob/main/Basic-amenities-in-SFO/SFO_Amenities.geojson) and [here](https://github.com/greppo-io/greppo-demo/blob/main/Basic-amenities-in-SFO/SFO_Selection.geojson) in the Greppo demos github repo (you can download with wget or curl, or simply copy the raw contents via github).

In the snippet above we read the geojson file and get a list of the amenities available using `.unique()`.

#### Setup Base Layer for Map
```python
app.base_layer(
    name="CartoDB Light",
    visible=True,
    url="https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}@2x.png",
    subdomains=None,
    attribution='&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors | Carto Tile',
)
```

The base layer is the map interface onto which we will project our (computed) data. Here we are using a basic CartoDB Light variant.

#### Setup the Data as an Overlay Layer
```python
app.overlay_layer(
    sfo_amenities,
    title="SFO Amenities",
    description="Location of some basic amenities in San Francisco",
    style={"fillColor": "#F87979"},
    visible=True,
)
```

With the base layer setup from the previous snippet, we now set up the data that will be visualized on the map. This is done with the `overlay_layer` API, and the first argument is the geojson file that we read in step 1.

#### Setup Draw Feature
```python
default_area_selection = gpd.read_file("./SFO_Selection.geojson")
area_selection = app.draw_feature(
    name="Draw area selection", features=default_area_selection, geometry=["Polygon"]
)
```
For this tutorial, to demonstrate the flexibility and power of Greppo, we set up a draw feature that the user can interact with. In this example we read a set of default draw features as a geojson. The default features can be omitted (ie. don’t pass in `default_area_selection`).

Here `area_selection` is a list of polygons. For interactivity Greppo binds the state of the user interaction to this variable `area_selection`. That is, whenever app.py runs or is updated, `area_selection` will contain all the polygons as seen on the screen. To be clear, app.py can always assume area_selection will have the *data* it cares about and can perform computations on that (see next step).

#### Perform computation on the data
With the variable binding setup in the snippet above, we can now use the polygons from the draw feature to perform some computation,

```python
selected_amenities = sfo_amenities.loc[sfo_amenities.within(
    area_selection.at[0, 'geometry'])]
selected_amenities_count_df = selected_amenities['amenity'].value_counts()
```
In this code snippet we take the first polygon from `area_selection` and filter out the counts of amenities within the `selected_amenities` data frame, and create a new data frame `selected_amenities_count_df`.

Next we get the counts by values from the created data frame as an example of some python processing that is performed in a usual business setting,
```python
selected_amenities_count = []

for amenity in amenities:
    if(amenity in selected_amenities_count_df.index):
        selected_amenities_count.append(
            selected_amenities_count_df[amenity].item())
    else:
        selected_amenities_count.append(0)
```

#### Plotting the Data as a Chart
We are almost done with our app now! With the main parts in the previous snippets out of the way, let’s plot a bar chart of the counts. This is a common scenario where we have some data that we manipulate on the map layer and we want to summarize the data and visualize it.

Let's do that with a bar chart,
```python
app.bar_chart(
    name="amenities-sfo-select",
    title="Amenities in SFO",
    description="The count of the basic amenities within the selected area in SFO.",
    x=amenities,
    y=selected_amenities_count,
    backgroundColor="rgb(200, 50, 150)",
)
```

#### Serve the Grepp App :)

With `app.py` ready, let’s serve the app with Greppo and look at our output!

Simply run the serve command on the console,
```
greppo serve app.py
```

(Note: It will take a few seconds to run if this is the first time you’re prototyping with Greppo because Python is generating cached `.pyc` for fast execution)

You should get the following output,
```
INFO:     Started server process [76886]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
```

Now, head on over to `http://0.0.0.0:8080` in your favorite browser and viola!

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

On the right you should see,
- The base layer.
- The data as an overlay layer.
- A default draw feature on the right.

On the left you should see,
- Some options to change the base layer. 
- An on/off toggle for the overlay layer.
- lat/long details of the draw feature as seen on the right.
- A bar chart.

Now go ahead and interact with the map! Edit the existing polygon by hitting the edit button on the toolbar,

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1qhdl3h58264jo1p4ml9.png)

which should change to,

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8dtaq6mly7okalba6wxz.png)

When you hit edit the existing polygon will show up with it’s edges, 

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

Go ahead and drag the points around the red dots on the map and hit `Save`.

Hit the update button which should now turn red, and note the numbers on the bar chart refresh!

As an exercise, modify the code from step 6 to account for multiple polygons on the draw feature and try combining the values (hint: simply loop through the list of polygons, extract the geojson data and add them up!)

# Conclusion
It took us about 4 mins to get started with this simple example and that’s the flexibility of Greppo. [Here’s](https://docs.greppo.io/index.html) a link to the docs if you’d like to learn more!

Feel free to reach out with questions or feedback!

Happy hacking!