How to add plotly charts in reactpy application

reactpy plotly chart
Updated: August 20, 2023

A. Plotly in Python

ReactPy is a python library used to create user interfaces for web application. Plotly is a library for data visualization. It can generate bar, line charts and many others.

Let us create a practical example of data visualization using Plotly in an application developed from reactpy. Our data is from a csv file with expenses records. You may download the sample expenses.csv from my google drive. Place this file in the same folder where your module or chart.py is located.

Contents of expenses.csv

          Date  Amount        Category
0   2023-08-01    80.0       Utilities
1   2023-08-01    20.0            Food
2   2023-08-01     6.0  Transportation
3   2023-08-01     5.0       Personals
4   2023-08-01    15.0        Supplies
5   2023-08-02    12.0            Food
6   2023-08-02     8.0  Transportation
7   2023-08-03    18.0            Food
8   2023-08-03     8.0  Transportation
9   2023-08-04    15.0            Food
10  2023-08-04     8.0  Transportation
11  2023-08-04    25.0      Recreation
12  2023-08-04    10.0         Housing
13  2023-08-05    50.0        Supplies
14  2023-08-05    30.0            Food
15  2023-08-05    12.0  Transportation
16  2023-08-05   130.0        Clothing

Our dataframe has 3 columns, Date, Amount and Category. We will create a bar chart showing the sum in each category.

Here is the code to sum the Category using pandas' groupby.

DATA_FILENAME = 'expenses.csv'

df = pd.read_csv(DATA_FILENAME)

# Group the Category and sum it.
df_grp = df.groupby(['Category'])['Amount'].sum().reset_index()
print(df_grp)

This is the grouped dataframe output.

         Category  Amount
0        Clothing   130.0
1            Food    95.0
2         Housing    10.0
3       Personals     5.0
4      Recreation    25.0
5        Supplies    65.0
6  Transportation    42.0
7       Utilities    80.0

B. Bar chart in Plotly Python

This is the bar chart written in Python.

# Create a figure using the grouped dataframe.
fig = px.bar(df_grp, x='Amount', y='Category', orientation='h',
             width=600, height=400, text_auto=True,
             title='Bar Chart')
fig.show()

Now the question is how can we show the chart in a web application created by ReactPy?

C. Expenses Bar Chart in ReactPy

Plotly has a method to convert the figure into an html, while ReactPy has a way to convert an html to its VDOM (Virtual Document Object Model) representation. We can combine those to generate an applicaton in ReactPy that shows a chart.

Step 1: Convert the plotly figure to html

No, we don't output an html file, instead we hold the figure in memory as an html object.

# Create an html object in memory from fig.
buffer = StringIO()
fig.write_html(buffer, include_plotlyjs='cdn')
fig_html = buffer.getvalue()

Step 2: Convert the figure html to ReactPy VDOM

utils.html_to_vdom(fig_html)

D. BarChart component

@component
def BarChart():
    """Creates a plotly bar chart."""
    # Read csv file and convert to dataframe.
    df = pd.read_csv(DATA_FILENAME)

    # Group similar category and sum it.
    df_grp = df.groupby(['Category'])['Amount'].sum().reset_index()

    # Create a figure using the grouped dataframe.
    fig = px.bar(
        df_grp, x='Amount', y='Category', orientation='h',
        width=600, height=400, text_auto=True, title='Bar Chart'
    )

    # Create an html object in memory from fig.
    buffer = StringIO()
    fig.write_html(buffer, include_plotlyjs='cdn')
    fig_html = buffer.getvalue()

    return html.div(
        html.h2('Plotly Bar Chart in ReactPy'),
        utils.html_to_vdom(fig_html)
    )

E. Full code

chart.py
"""Renders plotly chart in ReactPy"""


from io import StringIO
from reactpy import component, html, utils
from reactpy.backend.fastapi import configure, Options
from fastapi import FastAPI
import plotly.express as px
import pandas as pd


DATA_FILENAME = 'expenses.csv'

PAGE_TITLE = 'ReactPy-PlotlyChart'

PLOTLY_JS = {
    'src': 'https://cdn.plot.ly/plotly-latest.min.js',
    'charset': 'utf-8'
}


@component
def BarChart():
    """Creates a plotly bar chart."""
    # Read csv file and convert to dataframe.
    df = pd.read_csv(DATA_FILENAME)

    # Group similar category and sum it.
    df_grp = df.groupby(['Category'])['Amount'].sum().reset_index()

    # Create a figure using the grouped dataframe.
    fig = px.bar(
        df_grp, x='Amount', y='Category', orientation='h',
        width=600, height=400, text_auto=True, title='Bar Chart'
    )

    # Create an html object in memory from fig.
    buffer = StringIO()
    fig.write_html(buffer, include_plotlyjs='cdn')
    fig_html = buffer.getvalue()

    return html.div(
        html.h2('Plotly Chart in ReactPy'),
        utils.html_to_vdom(fig_html)
    )


app = FastAPI()
configure(
    app,
    BarChart,
    Options(
        head=html.head(
            html.script(PLOTLY_JS),
            html.title(PAGE_TITLE)
        )
    )
)

This is the page output.

F. Required modules

requirements.txt
reactpy[fastapi]
plotly
pandas
uvicorn[standard]

Have a look on how to install reactpy.

G. Command line to run the chart.py

uvicorn chart:app

H. Line Chart Component

This component is similar to BarChart but our x-axis is Date and y-axis is Amount. Also we will group the amount by Date so that we can see the daily trend of the expenses.

# Group similar category and sum it.
df_grp = df.groupby(['Date'])['Amount'].sum().reset_index()

This is the full line chart component code.

@component
def LineChart():
    """Creates a plotly line chart."""
    # Read csv file and convert to dataframe.
    df = pd.read_csv(DATA_FILENAME)

    # Group similar category and sum it.
    df_grp = df.groupby(['Date'])['Amount'].sum().reset_index()

    # Create a figure using the grouped dataframe.
    fig = px.line(
        df_grp, x='Date', y='Amount', orientation='h',
        width=600, height=400, title='Line Chart'
    )

    # Create an html object in memory from fig.
    buffer = StringIO()
    fig.write_html(buffer, include_plotlyjs='cdn')
    fig_html = buffer.getvalue()

    return html.div(
        html.h2('Plotly Line Chart in ReactPy'),
        utils.html_to_vdom(fig_html)
    )

If you use this component, it would look like this.

The change is this.

app = FastAPI()
configure(
    app,
    LineChart,  # this one
    Options(
        head=html.head(
            html.script(PLOTLY_JS),
            html.title(PAGE_TITLE)
        )
    )
)

I. Combine the two components

Instead of a single chart, we can place the two charts in the page.

This is our root component

@component
def ChartCombo():
    return html.div(
        BarChart(),
        LineChart()
    )

This is the full code.

mychart.py
"""Renders plotly chart in ReactPy"""


from io import StringIO
from reactpy import component, html, utils
from reactpy.backend.fastapi import configure, Options
from fastapi import FastAPI
import plotly.express as px
import pandas as pd


DATA_FILENAME = 'expenses.csv'

PAGE_TITLE = 'ReactPy-PlotlyChart'

PLOTLY_JS = {
    'src': 'https://cdn.plot.ly/plotly-latest.min.js',
    'charset': 'utf-8'
}


@component
def BarChart():
    """Creates a plotly bar chart."""
    # Read csv file and convert to dataframe.
    df = pd.read_csv(DATA_FILENAME)

    # Group similar category and sum it.
    df_grp = df.groupby(['Category'])['Amount'].sum().reset_index()

    # Create a figure using the grouped dataframe.
    fig = px.bar(
        df_grp, x='Amount', y='Category', orientation='h',
        width=600, height=400, text_auto=True, title='Bar Chart'
    )

    # Create an html object in memory from fig.
    buffer = StringIO()
    fig.write_html(buffer, include_plotlyjs='cdn')
    fig_html = buffer.getvalue()

    return html.div(
        html.h2('Plotly Bar Chart in ReactPy'),
        utils.html_to_vdom(fig_html)
    )


@component
def LineChart():
    """Creates a plotly line chart."""
    # Read csv file and convert to dataframe.
    df = pd.read_csv(DATA_FILENAME)

    # Group similar category and sum it.
    df_grp = df.groupby(['Date'])['Amount'].sum().reset_index()

    # Create a figure using the grouped dataframe.
    fig = px.line(
        df_grp, x='Date', y='Amount', orientation='h',
        width=600, height=400, title='Line Chart'
    )

    # Create an html object in memory from fig.
    buffer = StringIO()
    fig.write_html(buffer, include_plotlyjs='cdn')
    fig_html = buffer.getvalue()

    return html.div(
        html.h2('Plotly Line Chart in ReactPy'),
        utils.html_to_vdom(fig_html)
    )


@component
def ChartCombo():
    return html.div(
        BarChart(),
        LineChart()
    )


app = FastAPI()
configure(
    app,
    ChartCombo,
    Options(
        head=html.head(
            html.script(PLOTLY_JS),
            html.title(PAGE_TITLE)
        )
    )
)

Run the app with the following command line.

uvicorn mychart:app

The rendered page.

J. Pie chart component

The pie chart shows figures in percentages. Useful to see how the categories differ by percent.

@component
def PieChart():
    """Creates a plotly pie chart."""
    # Read csv file and convert to dataframe.
    df = pd.read_csv(DATA_FILENAME)

    # Group similar category and sum it.
    df_grp = df.groupby(['Category'])['Amount'].sum().reset_index()

    # Create a figure using the grouped dataframe.
    fig = px.pie(df_grp, values='Amount', names='Category',
             width=500, height=500, title='Pie Chart')

    # Create an html object in memory from fig.
    buffer = StringIO()
    fig.write_html(buffer, include_plotlyjs='cdn')
    fig_html = buffer.getvalue()

    return html.div(
        html.h2('Plotly Pie Chart in ReactPy'),
        utils.html_to_vdom(fig_html)
    )

K. Scatter chart component

Scatter chart tells us the relationship between two variables. We will create a scatter chart showing the relationships between 'Food' and 'Transportation' costs. Do some data preprocessing such as collecting all the daily food and transportation costs and build a dataframe with 'Food' and 'Transportation' columns.

DATA_FILENAME = 'expenses.csv'

# Read csv file and convert to dataframe.
df = pd.read_csv(DATA_FILENAME)

# Create a new dataframe showing Food and Transportation column.
food = df.loc[df.Category == 'Food']
transportation = df.loc[df.Category == 'Transportation']
new_df = pd.DataFrame(
    {'Food': food['Amount'].to_list(),
     'Transportation': transportation['Amount'].to_list()}
)
print(new_df)

Output

   Food  Transportation
0  20.0             6.0
1  12.0             8.0
2  18.0             8.0
3  15.0             8.0
4  30.0            12.0

So we have a dataframe with two columns. Each row has column values, this is enough to visualize what those figures are. Do the food costs increases with transportation or the otherway around or no relationships at all.

This is our scatter plot.

Full scatter component code

@component
def Scatter():
    """Creates a plotly scatter chart."""
    # Read csv file and convert to dataframe.
    df = pd.read_csv(DATA_FILENAME)

    # Create a new dataframe showing Food and Transportation column.
    food = df.loc[df.Category == 'Food']
    transportation = df.loc[df.Category == 'Transportation']
    new_df = pd.DataFrame(
        {'Food': food['Amount'].to_list(),
         'Transportation': transportation['Amount'].to_list()}
    )

    # Create figure.
    fig = px.scatter(
        new_df, x='Food', y='Transportation', width=600,
        height=400, title='Scatter Chart'
    )

    # Create an html object in memory from fig.
    buffer = StringIO()
    fig.write_html(buffer, include_plotlyjs='cdn')
    fig_html = buffer.getvalue()

    return html.div(
        html.h2('Plotly Chart in ReactPy'),
        utils.html_to_vdom(fig_html)
    )

L. Summary

Charts built from ploty can be shown in reactpy app. Plotly-created figure is converted to html text and shown in ReactPy app by transforming the html to ReactPy VDOM.