paint-brush
Python Web Development with Reflex: Creating Dynamic Graphs Easilyby@tomg
1,892 reads
1,892 reads

Python Web Development with Reflex: Creating Dynamic Graphs Easily

by Tom GNovember 22nd, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Create beautiful interactive graphs for web apps in pure Python

People Mentioned

Mention Thumbnail
featured image - Python Web Development with Reflex: Creating Dynamic Graphs Easily
Tom G HackerNoon profile picture

Almost any web app that contains data needs a way to represent it succinctly and clearly to the user. However, most Python web development solutions do not provide an easy way to do this purely in Python.


Thanks to the plethora of existing React components for creating graphs, an implementation for Python can be created to easily solve this problem.


In this post, we’ll walk through how to build a web app purely in Python, which contains graphs that strike a balance between flexibility and ease of use. The graphs are easy to build but also easy to customize to your needs.

For this project, we are going to use a new open-source dev tool called Reflex.


1. Getting started with your Python Web App

If you face any problems here with installation check out more docs here: https://reflex.dev/docs/getting-started/installation/


  1. $ pip install reflex


  2. $ reflex init


2. Creating an Interactive Graph

In this example, we will create a live-streaming graph that updates every second with random data.


We start by defining some initial data for our chart to use, as well as some imports we will use for the project:


from typing import Any, Dict, List
import reflex as rx
import random
import asyncio

data = [
    {"name": "A", "uv": 10, "pv": 110, "amt": 210},
    {"name": "B", "uv": 20, "pv": 120, "amt": 230},
    {"name": "C", "uv": 30, "pv": 120, "amt": 240},
    {"name": "D", "uv": 30, "pv": 130, "amt": 210},
    {"name": "E", "uv": 20, "pv": 140, "amt": 230},
    {"name": "F", "uv": 40, "pv": 170, "amt": 250},
    {"name": "G", "uv": 50, "pv": 190, "amt": 260},
]


Here uv stands for unique visitors, pv stands for page views and amt stands for amount.

They are arbitrary values that we will use to populate our graph.


Next, we define a StreamingState class that will be used to store the data and update it with an event handler:


class StreamingState(rx.State):
    data: List[Dict[str, Any]] = data
    stream: bool = False

    def stop_stream(self):
        self.stream = False

    @rx.background
    async def start_stream(self):
        async with self:
            self.stream = True
        while self.stream:
            async with self:
                for i in range(len(self.data)):
                    self.data[i]["uv"] = random.randint(0, 100)
                    self.data[i]["pv"] = random.randint(100, 200)
                    self.data[i]["amt"] = random.randint(200, 300)
            await asyncio.sleep(3)


Here, we define a stop_stream method that will stop the stream when called. We also define a start_stream method that will start the stream. We use the @rx.background decorator to run the method in the background. This allows us to update the data without blocking the UI.


Remember to use async with self: when updating the state in a background task.


Finally, we will define our UI using Reflex's new graphing components. We pass the data from our StreamingState class to the area_chart component and reference the data key we want to use in area component. We also add a button to start and stop the stream.


The result is a live updating graph that looks like this:



An Interactive Graph


The code for this graph is below:

def index():
   return rx.vstack(
     rx.recharts.area_chart(
        rx.recharts.area(
            data_key="pv",
            stroke="#82ca9d",
            fill="#82ca9d",
            type_="natural",
        ),
        rx.recharts.x_axis(
            data_key="name",
        ),
        rx.recharts.y_axis(),
        rx.recharts.legend(),
        data=StreamingState.data,
        width="100%",
        height=400,
    ),
    rx.hstack(
        rx.button(
            "Start Stream",
            on_click=StreamingState.start_stream,
            disabled=StreamingState.stream,
        ),
        rx.button(
            "Stop Stream",
            on_click=StreamingState.stop_stream,
        ),
        width="100%",
    ),
    width="100%",
)

# Add state and page to the app.
app = rx.App()
app.add_page(index)
app.compile()


The last three lines define our app, add the graph component to the base route, and then compile our app. Now, we can run it with the $ reflex run terminal command.

3. Multiple Graphs

We can add extra area components to our chart to show the uv and amt data as well. We can also add a graphing_tooltip an cartesian_grid component to show the data when we hover over the chart.


Keep in mind the child coming first will be displayed in the back, so the order of the area components matter.



An interactive graph with several plots


The code for this graph is below:

def index():
  return rx.vstack(
    rx.recharts.area_chart(
        rx.recharts.area(
            data_key="pv",
            fill="#48BB78",
            stroke="#48BB78",
            type_="natural",
        ),
        rx.recharts.area(
            data_key="uv",
            fill="#F56565",
            stroke="#F56565",
            type_="natural",
        ),
        rx.recharts.area(
            data_key="amt",
            fill="#4299E1",
            stroke="#4299E1",
            type_="natural",
        ),
        rx.recharts.x_axis(
            data_key="name",
        ),
        rx.recharts.y_axis(),
        data=StreamingState.data,
        width="90%",
        height=400,
    ),
    rx.hstack(
        rx.button(
            "Start Stream",
            on_click=StreamingState.start_stream,
            is_disabled=StreamingState.stream,
            width="100%",
            color_scheme="green",
        ),
        rx.button(
            "Stop Stream",
            on_click=StreamingState.stop_stream,
            is_disabled=StreamingState.stream == False,
            width="100%",
            color_scheme="red",

        ),
        width="100%",
    )
)

# Add state and page to the app.
app = rx.App()
app.add_page(index)
app.compile()


4. Conclusion

So that’s it; in just a few lines of simple code, you’ve created your live streaming graphing web app in pure Python.


If you want to learn more about this and how to build graphs with Python check out this documentation.



If you have questions, please comment them below or message me on Twitter at @tgotsman12 or on LinkedIn. Share your app creations on social media and tag me, and I’ll be happy to provide feedback or help retweet!


Disclaimer: I work as a Founding Engineer at Reflex, where I build the open-source framework.