Build an interactive dashboard from a CSV dataset

In this tutorial, we’re going to build an interactive dashboard to display insights from a CSV dataset. We’re going to be using a dataset of Uber pickups in New York City. We’ll use Anvil’s Data Files service to upload and store our CSV file, so that it is easily accessible from our app’s code. We will also be using pandas to read our data and Plotly to turn our data into interactive plots.

The final app will look something like this:

Screenshot of the finished dashboard app

You can test it out here: uber-pickups-example.anvil.app

We’ll build the app in 7 quick steps:

  1. We’ll first import the dataset and Python packages we need.
  2. Second, we’ll create the app’s UI with Anvil’s drag-and-drop designer.
  3. Next, we’ll examine our data to better understand how to use it.
  4. We’ll then use numpy and Plotly to create and plot a histogram of all pickups per hour.
  5. We’ll next plot the location data onto an interactive map using Mapbox and Plotly.
  6. To finish the app, we’ll allow users to filter the data displayed on the map.
  7. Finally, we’ll publish our app and share it with the world!

You can download the source code for the finished app here:


Step 1: Import the dataset and packages

1.1 Download the dataset

The first thing we need to do is download our dataset, which you can find here: https://www.kaggle.com/datasets/fivethirtyeight/uber-pickups-in-new-york-city. In this tutorial, I’m using the uber-raw-data-sep14.csv dataset, which includes time and location data of Uber pickups in New York City during September 2014.

1.2 Create an app and add the data

Once we have the dataset downloaded, we can create a new Anvil app. Go to Anvil, create a new blank app and choose the Rally theme. In the top left, you’ll see the name of your app. Click on this and change it to “Uber Pickups in NYC”.

The Anvil build screen then creating a new app with the Rally theme

Next, add the Data Files service by choosing the blue plus button in the Sidebar Menu then selecting Data Files.

The 'Add a Feature' modal with Data Files highlighted.

Now we can upload our dataset to our Anvil app. Click the Upload button and select the dataset we just downloaded. You can also drag and drop the file in order to add it to the app. When the upload is complete, you will see the file listed.

The uploaded file shown in the Data Files dialog

1.3 Configure the Python environment

We’ll be using pandas and numpy to build our app, so we’ll need to modify the Python environment that is running our app. Choose Settings from the Sidebar Menu, then Python Versions. Switch the app to Python 3.10, then choose the Data Science base package. This will have the libraries we need pre-installed.

Step 2: Build the User Interface

Now that we have our data added to our app and the Python environment is configured, we can actually start building our app.

2.1 Add a title

Navigate to ‘App’ in the sidebar menu, then choose Form1. Here we can see the Design view of our app. Drag and drop a Label from the Toolbox and add it to the top of the app. In the Properties Panel, change the label’s text to “Uber Pickups in NYC” and its role to ‘headline’.

Dragging and dropping a Label from the Toolbox then changing its text and role properties

2.2 Add the plots

Our dashboard is going to have two plots: a histogram of the number of pickups per hour and a map of the pickup locations. Drag and drop two plot components to the Form and two Labels to act as titles for the plots. Change the name property of one plot to be bar_chart and the other to be mapbox_map.

Change the Label above the bar_chart to be “Number of pickups per hour” and change its role to ’title’. We’ll set the other Label’s text property in code, so we can leave that blank. Change its name to mapbox_title and its role to ’title’.

We’re going to want users to be able to filter the map data based on the hour of pickup. Add a DropDown component above the mapbox_map and rename it to hour_dropdown. We’ll populate the dropdown later in code. (You can add a Spacer component over the bar_chart title to make the UI look more even)

Our Form should now look something like this:

Screenshot of the Form Editor showing the finished UI

Step 3: Examine the Data

We now have a UI built for our dashboard, but before we actually create our plots, let’s explore our dataset. Our dataset is stored in our app’s Data Files, which we can only access from server code.

In the App Browser, add a new server module.

Add the following import statements to the module:

import pandas as pd
import numpy as np
import plotly.graph_objects as go

Let’s add a function to read our CSV file and print out the first few rows using pandas. We can access our CSV file with data_files['uber-raw-data-sep14.csv']:

@anvil.server.callable
def get_uber_data():
    #read in 10000 rows of data 
    df = pd.read_csv(data_files['uber-raw-data-sep14.csv'], nrows=10000)
    #print the first 5 rows of the dataframe
    print(df.head())

Decorating the function with @anvil.server.callable means we can call the function from our client Form.

Switch back to Form1 then switch to Code view. Call the server function we just wrote in Form1’s __init__ method:

class Form1(Form1Template):

  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    #call the server function
    anvil.server.call("get_uber_data")

You should see output that looks like this in the App Console:

          Date/Time      Lat      Lon    Base
0  9/1/2014 0:01:00  40.2201 -74.0021  B02512
1  9/1/2014 0:01:00  40.7500 -74.0027  B02512
2  9/1/2014 0:03:00  40.7559 -73.9864  B02512
3  9/1/2014 0:06:00  40.7450 -73.9889  B02512
4  9/1/2014 0:11:00  40.8145 -73.9444  B02512

We can see that we have Date/Time, Lat, Lon and Base columns. We won’t need the Base column but we’ll use the Lat and Lon columns when plotting our map data and the Date/Time column for both the histogram and map plots.

Step 4: Create a histogram

Let’s now write a function that creates a histogram of the hours in the Date/Time column that we can then plot on our self.bar_chart.

4.1 Return the dataframe from get_uber_data

First, we need to modify the get_uber_data function to return the dataframe instead of just the head. We also need to convert the values in the Date/Time column to be datetime objects. We can also remove @anvil.server.callable from the function since we won’t need to call it from the client. The function should now look like this:

def get_uber_data():
  #read in 10000 rows of data 
  df = pd.read_csv(data_files['uber-raw-data-sep14.csv'], nrows=10000)
  df['Date/Time'] = pd.to_datetime(df['Date/Time'])
  return df

Next, we need to call the function from the server module:

DATA = get_uber_data()

4.2 Create a numpy histogram

Let’s now add a function to create a histogram of the values in the Date/Time column. We’ll make this function callable from our client Form. We can use numpy’s histogram method to count the number of entries in our dataset per hour. This method returns two arrays, but we only care about the first, which is an array of the histogram values.

@anvil.server.callable
def create_histogram():
  histogram = np.histogram(DATA['Date/Time'].dt.hour, bins=24)[0]
  return histogram

4.3 Add data to self.bar_chart

Finally, we need to switch back to our Form code and in the Form’s __init__ method, set the data of the bar_chart plot to be a Plotly go.Bar object where the y-axis values are the histogram values. Remove anvil.server.call("get_uber_data") and replace it with:

self.bar_chart.data = go.Bar(y=anvil.server.call('create_histogram'))

Click the green Run button at the top of the Anvil Editor to run the app. If we’ve done everything correctly, the app should look like this:

Screenshot of the app running. The bar chart is populate but doesn't match the app theme.

The plot is right, but it looks…wrong. Go back to the Form code and add Plot.templates.default = 'rally' to the __init__ function. This will give all Plots in our app the Rally theme (the same theme as our app). Run the app again, and it should look much better:

Screenshot of the app running. The bar chart now has the same theme as the app.

Step 5: Plot the map data

Now let’s use the Lat and Lon columns of our CSV file to plot the location data on a map. We’ll use the Scattermapbox Plotly plot to do this, but we’ll first need a Mapbox access token.

5.1 Get a Mapbox access token

If you don’t already have a Mapbox account, go to mapbox.com to sign up for free and generate a public access token. Add this token to the __init__ method of Form1:

token = '<your-access-token>'

5.2 Return the map data

Back in our Anvil app, we’ll add another function to the Server Module which will generate the map data. Create a client-callable function called get_map_data that takes one argument called hour. Let’s set it so that it defaults to 0 if no argument is given. We’ll filter the dataframe based on the hour passed into the function and plot the data onto a map.

@anvil.server.callable
def get_map_data(hour=0):
  filtered_data = DATA[DATA['Date/Time'].dt.hour == hour]
  map_data = go.Scattermapbox(lat=filtered_data['Lat'], lon=filtered_data['Lon'], mode='markers')
  return map_data

5.3 Add data to self.mapbox_map

We can now switch back to Form1 and add the map data to the self.mapbox_map plot we added in Step 2. We’ll also need to add our access token and modify the map’s layout slightly. The __init__ method of the Form should look something like this:

class Form1(Form1Template):

  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    Plot.templates.default = "rally"

    #create the histogram of uber pickups per hour
    self.bar_chart.data = go.Bar(y=anvil.server.call('create_histogram'))

    #create the map of pickup locations
    token = "<your-token-here>"
    self.mapbox_map.data = anvil.server.call('get_map_data')
    #add the access token and center the map on NYC
    self.mapbox_map.layout.mapbox = dict(accesstoken=token, center=dict(lat=40.7128, lon=-74.0060), zoom=10)
    #remove padding from map
    self.mapbox_map.layout.margin = dict(t=0, b=0, l=0, r=0)

Run the app and both plots should now be populated with data

Screenshot of the running app with both the bar chart and map plots populated with data

Step 6: Respond to user input

The last thing we need to do is make our dashboard respond to user input. We’ll modify our app so that users can choose an hour from the dropdown menu to filter and reload the map data.

6.1 Populate the dropdown menu

First, we need to set the items property of the dropdown menu to be a list of all the hours in a day. We can actually set it to be a list of tuples where the first value of the tuple is what is displayed in the dropdown and the second value is the return value when that item is selected:

self.hour_dropdown.items = [(f'{n}:00',n) for n in range(0,24)]

6.2 Set up an event handler

Switch to the Design view of the Form and select the dropdown. Scroll to the bottom of the Properties Panel and click the arrows next to change under Events. This will open the Code view and create a function that will run when the selected_value of self.hour_dropdown changes. When this function is called, we want to reload the map data and set the text property of the self.mapbox_title Label to reflect the data we’re viewing:

def hour_dropdown_change(self, **event_args):
  """This method is called when an item is selected"""
  time = self.hour_dropdown.selected_value
  self.mapbox_title.text = f'Number of pickups at {time}:00'
  self.mapbox_map.data = anvil.server.call('get_map_data', time)

6.3 Initialise the dropdown and map

We can actually set the selected_value of the dropdown and run the above function when the app loads. In the Form’s __init__, set the dropdown’s value and replace self.mapbox_map.data = anvil.server.call('get_map_data') with a call to the function we just wrote. The __init__ function should now look something like this:

class Form1(Form1Template):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    Plot.templates.default = 'rally'
    
    #create the histogram of uber pickups per hour
    self.bar_chart.data = go.Bar(y=anvil.server.call('create_histogram'))
    
    #initialise the dropdown and map
    self.hour_dropdown.items = [(f'{n}:00',n) for n in range(0,24)]
    self.hour_dropdown.selected_value = 0
    #call the function we just wrote
    self.hour_dropdown_change()

    #add the access token and center the map on NYC
    token = "<your-token-here>"
    self.mapbox_map.layout.mapbox = dict(accesstoken=token, center=dict(lat=40.7128, lon=-74.0060), zoom=10)
    self.mapbox_map.layout.margin = dict(t=0, b=0, l=0, r=0)

We can now test out our app. Run the app and choose a different value in the dropdown menu. Make sure the map changes as well.

Running the app and changing the value in the dropdown menu. The map reloads showing updated data.

Step 7: Publish your app

That’s it! You’ve just built an interactive dashboard with Anvil. We’ve seen how to store a CSV dataset in our app’s Data Files, create a UI with the drag-and-drop designer and create interactive plots using pandas and Plotly.

The only thing left to do is to publish your app. Anvil takes care of deployment and hosting for you. All you need to do is click the Publish button at the top of the Anvil Editor, then select ‘Publish this app’. You can use the public URL provided or enter your own, or, if you want to share your app privately, you can switch to a private URL

Location of the Publish button at the top of the Anvil Editor

Want to dig into how this app works? Our tutorials show you all the pieces these apps are made from and more.


New to Anvil?

If you’re new here, welcome! Anvil is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just build it all in Python.

Yes – Python that runs in the browser. Python that runs on the server. Python that builds your UI. A drag-and-drop UI editor. We even have a built-in Python database, in case you don’t have your own.

Why not have a play with the app builder? It’s free! Click here to get started:

Would you like to see some examples of dashboards built with Anvil? Check out our dashboard gallery: