How to build an interactive data visualization with gen AI
Using Vizro-AI to create Plotly charts and Vizro to assemble a dashboard
In this tutorial, you’ll learn how to make a low-code data dashboard, written in Python using Vizro, which is an open-source framework built on top of Dash, Plotly, and Pydantic. You’ll learn how to iterate gen AI prompts to build three Plotly charts, then add the prompts to a Vizro dashboard on PyCafe, before adding some interactive controls.
Here’s a preview of the dashboard, which you can try out here:
Note on use of gen AI
Parts of this tutorial use OpenAI models. To run through those steps yourself, you must have an OpenAI account with paid-for credits available. None of the free accounts will suffice. Check the OpenAI models and pricing on their website. The latter parts of the tutorial take the generated code and work with that, and you don’t need a key for those.
Before using a generative AI model, you should review OpenAI’s guidelines on risk mitigation to understand potential model limitations and best practices. See the OpenAI site for more details on responsible usage.
What is PyCafe?
The project is hosted on PyCafe, which is a free platform to create, run, edit, and share Python web applications in a browser. It’s available for building Vizro dashboards, as well as Streamlit, and Dash applications. Sharing a link to a PyCafe project enables anyone to access the code and visualization locally without installing any Python packages.
The data
To create this dashboard, I used a dataset of all my connections on LinkedIn. I went to the Data privacy section of Settings on the LinkedIn website, chose Get a copy of your data, and then selected Connections. I received a link to the data by email a few minutes later. The CSV contained columns of strings for rows of connections: their first name, last name, the URL of their profile, their email address (where they’ve made it public), current company, current position, and the date we on which we connected. Before I used the data, I removed the first three rows that warned about potential missing emails and I renamed the file as connections.csv
.
I used my real data to make the example, but to keep my connections’ privacy safe, I made a new set of fake data before writing up and publishing this article. The fake data fields match the layout of a genuine LinkedIn data dump, so if you download your own LinkedIn data, you can substitute it for my made-up set and it will work perfectly in the PyCafe project (as long as you remove those first three rows).
Chart generation with Vizro-AI
In the first step, we’ll prototype building a set of Plotly charts using a hosted version of Vizro-AI, found at py.cafe/app/vizro-official/vizro-ai-charts. Navigate to the site, which will open with a settings pane where you can set the API key for your chosen vendor. At the time of writing, you can use OpenAI, Anthropic, Mistral, or xAI:
Prototyping a set of Plotly charts
Once the API key is set, return to the main screen and upload the fake data for the project, which is stored on my repo on GitHub. Now we can build some charts by iterating text to form effective prompts using natural language to describe what we want to see.
Common job titles
The first chart should show the most common current job titles of my connections. Use gpt-4o with the following prompt:
Create a horizontal bar chart that shows the most common 20 Positions, with the highest frequency bar at the top of the chart.
Here’s the generated code that Vizro-AI spits out, which makes the chart:
import vizro.plotly.express as px
from vizro.models.types import capture
@capture("graph")
def custom_chart(data_frame):
# Count the frequency of each position
position_counts = data_frame["Position"].value_counts().head(20)
# Create a horizontal bar chart
fig = px.bar(
position_counts,
x=position_counts.values,
y=position_counts.index,
orientation="h",
title="Top 20 Most Common Positions",
)
# Update layout for better readability
fig.update_layout(
yaxis_title="Position",
xaxis_title="Frequency",
yaxis=dict(categoryorder="total ascending"),
)
return fig
Common employers
The second chart charts the most common current employer companies for my connections.
Create a doughnut chart using the Company data to show the most common 5.
Here’s the generated code that Vizro-AI spits out, which makes the chart:
import vizro.plotly.express as px
from vizro.models.types import capture
@capture("graph")
def custom_chart(data_frame):
# Count the occurrences of each company
company_counts = data_frame["Company"].value_counts().nlargest(5)
# Create a DataFrame for the top 5 companies
top_companies = company_counts.reset_index()
top_companies.columns = ["Company", "Count"]
# Create a doughnut chart
fig = px.pie(
top_companies,
values="Count",
names="Company",
hole=0.4,
title="Top 5 Most Common Companies",
)
return fig
Cumulative connection total
The third chart shows the cumulative count of my connections over the years. It took a few iterations to get this prompt correct.
Create a new column in the dataframe called Year, and for each row add a value by calculating the Year from the Connected On data. Then calculate the cumulative sum of connections for each year and plot a bar chart showing the total number of connections per year. Plot year on the x axis and connection count on the y axis.
Superimpose a scatter graph that shows the cumulative total of connections by year, using a different scale on the right hand side y axis.
Here’s the generated code that Vizro-AI spits out, which makes the chart:
import pandas as pd
import plotly.graph_objects as go
from vizro.models.types import capture
@capture("graph")
def custom_chart(data_frame):
# Convert 'Connected On' to datetime and extract the year
data_frame["Year"] = pd.to_datetime(data_frame["Connected On"]).dt.year
# Count connections per year
yearly_counts = data_frame["Year"].value_counts().sort_index()
# Calculate cumulative sum of connections
cumulative_counts = yearly_counts.cumsum()
# Create figure with secondary y-axis
fig = go.Figure()
# Add bar chart for yearly connections
fig.add_trace(go.Bar(x=yearly_counts.index, y=yearly_counts, name="Connections per Year"))
# Add scatter plot for cumulative connections
fig.add_trace(
go.Scatter(
x=cumulative_counts.index,
y=cumulative_counts,
name="Cumulative Connections",
yaxis="y2",
)
)
# Set up the layout for secondary y-axis
fig.update_layout(yaxis2=dict(title="Cumulative Total", overlaying="y", side="right"))
return fig
Adding the charts to a Vizro dashboard
At this point, we have the code for the Plotly charts that will sit in the interactive dashboard, and we don’t need to use gen AI for anything further. We’ll continue to use Vizro on PyCafe to work on the dashboard.
Navigate to py.cafe and create a new Vizro project, which comes prepopulated with a boilerplate tutorial project. Upload the data file connections.csv
to add the data to the project.
If you want to explore this boilerplate code, the Vizro documentation walks through the code to explain common features and ways of building a dashboard.
However, for this tutorial, simply replace the existing template code in the boilerplate project with this skeleton, which we’ll flesh out with our prototype charts:
import vizro.plotly.express as px
from vizro import Vizro
import vizro.models as vm
page = vm.Page(
title="My LinkedIn connections",
layout=vm.Layout(grid=[[0, 1], [0, 2]]),
components=[
],
)
dashboard = vm.Dashboard(pages=[page], theme="vizro_light")
Vizro().build(dashboard).run()
Now we’ll add the data handling code and the three chunks of code that were output by Vizro-AI. We’ll also add components
code as arguments to vm.Page
to call those chunks of gen AI code.
components=[
vm.Graph(id="role_bar_chart_id", figure=common_jobs(data_frame=df)),
vm.Graph(id="company_pie_chart_id", figure=common_companies(data_frame=df)),
vm.Graph(id="growth_cumulative_chart_id", figure=cumulative_totals(data_frame=df)),
],
That’s it! I’ve made a PyCafe project that stops at this point (you can find it here) for easy review and extension. The rest of the article continues in a separate project to add interactivity by including some simple controls.
Adding interactivity
Let’s extend the dashboard to add controls to illustrate how to interact and change the presentation. The Vizro documentation has a set of how-to guides and as an example, we’ll add a two sliders to enable a user to vary the number of common job titles and companies displayed in their respective charts. Code for the controls is as follows (the relevant charting functions also need to be updated to take an extra parameter to reflect the user-selected value):
controls=[
vm.Parameter(
targets=["role_bar_chart_id.top_n"],
selector=vm.Slider(min=0, max=30, step=5, value=20, title="Show top n positions:"),
),
vm.Parameter(
targets=["company_pie_chart_id.top_n"],
selector=vm.Slider(min=0, max=30, step=5, value=5, title="Show top n companies:"),
)
]
You can see the complete code for the interactive dashboard in this project: py.cafe/stichbury/linkedin-connections-project-v1.
Summary
This tutorial used just over 100 lines of code and comments to make a basic dashboard with some interactive features. We used Vizro-AI to generate code for a set of Plotly charts using natural language prompts, and then slotted them into a skeleton Vizro dashboard on PyCafe.
The project could be further extended and improved since Vizro is opinionated about design for the layout, navigation, and chart templates. If you have design skills and want to modify the look of the dashboard, you can overwrite the defaults in CSS. Want more customization? You can extend the default code to incorporate Dash or React.js customizations, or just to plug in customized Plotly charts, tables, dashboard components, actions, or reactive HTML components.
What do you reckon? If you don’t want to make any changes to the code, you can use it explore your LinkedIn data by opening the project and uploading your data locally to make a personal dashboard. If you try out the tutorial, use the dashboard, or extend the project, please let me know your thoughts in the comments!
Resources
Ideas for future dashboard blog posts? Add them below in the comments and I’ll (try to) make them!