Skip to main content

pumpwood-streamlit-pkg

Python Package to deploy Streamlit Dashboards at Pumpwood Systems.


Pumpwood is a native brasilian tree which has a symbiotic relation with ants (Murabei)

This packages help to deploy Streamlit Dashboard associated with Pumpwood based Systems registering routes at Kong for single end-point for all microservice.

It implements an abstract class that should be inherited. When rendering the dashboard, it uses cookie PumpwoodAuthorization to get authentication token and validates if user is logged at Pumpwood Auth microservice. If authentication token is not valid, authentication_error_page is called to render unauthorized page.

Documentation Page

You can check the doc page here.

Example

Example using dashboard example made avaiable by Streamlit oficial website.

import os
import streamlit as st
import pandas as pd
import altair as alt
import plotly.express as px
from pumpwood_streamlit.dashboard import PumpwoodStreamlitDashboard


class Dashboard(PumpwoodStreamlitDashboard):
    def set_page_config(self):
        #######################
        # Page configuration
        st.set_page_config(
            page_title="US Population Dashboard",
            page_icon="🏂",
            layout="wide",
            initial_sidebar_state="expanded")

    def main_view(self):
        alt.themes.enable("dark")

        #######################
        # Load data
        file_path = os.path.join(
            os.path.dirname(__file__),
            'data/us-population-2010-2019-reshaped.csv')
        df_reshaped = pd.read_csv(file_path)


        #######################
        # Sidebar
        with st.sidebar:
            st.title('🏂 US Population Dashboard')

            year_list = list(df_reshaped.year.unique())[::-1]

            selected_year = st.selectbox('Select a year', year_list)
            df_selected_year = df_reshaped[df_reshaped.year == selected_year]
            df_selected_year_sorted = df_selected_year.sort_values(by="population", ascending=False)

            color_theme_list = ['blues', 'cividis', 'greens', 'inferno', 'magma', 'plasma', 'reds', 'rainbow', 'turbo', 'viridis']
            selected_color_theme = st.selectbox('Select a color theme', color_theme_list)


        #######################
        # Plots

        # Heatmap
        def make_heatmap(input_df, input_y, input_x, input_color, input_color_theme):
            heatmap = alt.Chart(input_df).mark_rect().encode(
                    y=alt.Y(f'{input_y}:O', axis=alt.Axis(title="Year", titleFontSize=18, titlePadding=15, titleFontWeight=900, labelAngle=0)),
                    x=alt.X(f'{input_x}:O', axis=alt.Axis(title="", titleFontSize=18, titlePadding=15, titleFontWeight=900)),
                    color=alt.Color(f'max({input_color}):Q',
                                     legend=None,
                                     scale=alt.Scale(scheme=input_color_theme)),
                    stroke=alt.value('black'),
                    strokeWidth=alt.value(0.25),
                ).properties(width=900
                ).configure_axis(
                labelFontSize=12,
                titleFontSize=12
                )
            # height=300
            return heatmap

        # Choropleth map
        def make_choropleth(input_df, input_id, input_column, input_color_theme):
            choropleth = px.choropleth(input_df, locations=input_id, color=input_column, locationmode="USA-states",
                                       color_continuous_scale=input_color_theme,
                                       range_color=(0, max(df_selected_year.population)),
                                       scope="usa",
                                       labels={'population':'Population'}
                                      )
            choropleth.update_layout(
                template='plotly_dark',
                plot_bgcolor='rgba(0, 0, 0, 0)',
                paper_bgcolor='rgba(0, 0, 0, 0)',
                margin=dict(l=0, r=0, t=0, b=0),
                height=350
            )
            return choropleth


        # Donut chart
        def make_donut(input_response, input_text, input_color):
          if input_color == 'blue':
              chart_color = ['#29b5e8', '#155F7A']
          if input_color == 'green':
              chart_color = ['#27AE60', '#12783D']
          if input_color == 'orange':
              chart_color = ['#F39C12', '#875A12']
          if input_color == 'red':
              chart_color = ['#E74C3C', '#781F16']

          source = pd.DataFrame({
              "Topic": ['', input_text],
              "% value": [100-input_response, input_response]
          })
          source_bg = pd.DataFrame({
              "Topic": ['', input_text],
              "% value": [100, 0]
          })

          plot = alt.Chart(source).mark_arc(innerRadius=45, cornerRadius=25).encode(
              theta="% value",
              color= alt.Color("Topic:N",
                              scale=alt.Scale(
                                  #domain=['A', 'B'],
                                  domain=[input_text, ''],
                                  # range=['#29b5e8', '#155F7A']),  # 31333F
                                  range=chart_color),
                              legend=None),
          ).properties(width=130, height=130)

          text = plot.mark_text(align='center', color="#29b5e8", font="Lato", fontSize=32, fontWeight=700, fontStyle="italic").encode(text=alt.value(f'{input_response} %'))
          plot_bg = alt.Chart(source_bg).mark_arc(innerRadius=45, cornerRadius=20).encode(
              theta="% value",
              color= alt.Color("Topic:N",
                              scale=alt.Scale(
                                  # domain=['A', 'B'],
                                  domain=[input_text, ''],
                                  range=chart_color),  # 31333F
                              legend=None),
          ).properties(width=130, height=130)
          return plot_bg + plot + text

        # Convert population to text
        def format_number(num):
            if num > 1000000:
                if not num % 1000000:
                    return f'{num // 1000000} M'
                return f'{round(num / 1000000, 1)} M'
            return f'{num // 1000} K'

        # Calculation year-over-year population migrations
        def calculate_population_difference(input_df, input_year):
          selected_year_data = input_df[input_df['year'] == input_year].reset_index()
          previous_year_data = input_df[input_df['year'] == input_year - 1].reset_index()
          selected_year_data['population_difference'] = selected_year_data.population.sub(previous_year_data.population, fill_value=0)
          return pd.concat([selected_year_data.states, selected_year_data.id, selected_year_data.population, selected_year_data.population_difference], axis=1).sort_values(by="population_difference", ascending=False)


        #######################
        # Dashboard Main Panel
        col = st.columns((1.5, 4.5, 2), gap='medium')

        with col[0]:
            st.markdown('#### Gains/Losses')

            df_population_difference_sorted = calculate_population_difference(df_reshaped, selected_year)

            if selected_year > 2010:
                first_state_name = df_population_difference_sorted.states.iloc[0]
                first_state_population = format_number(df_population_difference_sorted.population.iloc[0])
                first_state_delta = format_number(df_population_difference_sorted.population_difference.iloc[0])
            else:
                first_state_name = '-'
                first_state_population = '-'
                first_state_delta = ''
            st.metric(label=first_state_name, value=first_state_population, delta=first_state_delta)

            if selected_year > 2010:
                last_state_name = df_population_difference_sorted.states.iloc[-1]
                last_state_population = format_number(df_population_difference_sorted.population.iloc[-1])
                last_state_delta = format_number(df_population_difference_sorted.population_difference.iloc[-1])
            else:
                last_state_name = '-'
                last_state_population = '-'
                last_state_delta = ''
            st.metric(label=last_state_name, value=last_state_population, delta=last_state_delta)


            st.markdown('#### States Migration')

            if selected_year > 2010:
                # Filter states with population difference > 50000
                # df_greater_50000 = df_population_difference_sorted[df_population_difference_sorted.population_difference_absolute > 50000]
                df_greater_50000 = df_population_difference_sorted[df_population_difference_sorted.population_difference > 50000]
                df_less_50000 = df_population_difference_sorted[df_population_difference_sorted.population_difference < -50000]

                # % of States with population difference > 50000
                states_migration_greater = round((len(df_greater_50000)/df_population_difference_sorted.states.nunique())*100)
                states_migration_less = round((len(df_less_50000)/df_population_difference_sorted.states.nunique())*100)
                donut_chart_greater = make_donut(states_migration_greater, 'Inbound Migration', 'green')
                donut_chart_less = make_donut(states_migration_less, 'Outbound Migration', 'red')
            else:
                states_migration_greater = 0
                states_migration_less = 0
                donut_chart_greater = make_donut(states_migration_greater, 'Inbound Migration', 'green')
                donut_chart_less = make_donut(states_migration_less, 'Outbound Migration', 'red')

            migrations_col = st.columns((0.2, 1, 0.2))
            with migrations_col[1]:
                st.write('Inbound')
                st.altair_chart(donut_chart_greater)
                st.write('Outbound')
                st.altair_chart(donut_chart_less)

        with col[1]:
            st.markdown('#### Total Population')

            choropleth = make_choropleth(df_selected_year, 'states_code', 'population', selected_color_theme)
            st.plotly_chart(choropleth, use_container_width=True)

            heatmap = make_heatmap(df_reshaped, 'year', 'states', 'population', selected_color_theme)
            st.altair_chart(heatmap, use_container_width=True)

        with col[2]:
            st.markdown('#### Top States')

            st.dataframe(df_selected_year_sorted,
                         column_order=("states", "population"),
                         hide_index=True,
                         width=None,
                         column_config={
                            "states": st.column_config.TextColumn(
                                "States",
                            ),
                            "population": st.column_config.ProgressColumn(
                                "Population",
                                format="%f",
                                min_value=0,
                                max_value=max(df_selected_year_sorted.population),
                             )}
                         )

            with st.expander('About', expanded=True):
                st.write('''
                    - Data: [U.S. Census Bureau](https://www.census.gov/data/datasets/time-series/demo/popest/2010s-state-total.html).
                    - :orange[**Gains/Losses**]: states with high inbound/ outbound migration for selected year
                    - :orange[**States Migration**]: percentage of states with annual inbound/ outbound migration > 50,000
                    ''')

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pumpwood_streamlit-0.18.12.tar.gz (18.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pumpwood_streamlit-0.18.12-py3-none-any.whl (21.4 kB view details)

Uploaded Python 3

File details

Details for the file pumpwood_streamlit-0.18.12.tar.gz.

File metadata

  • Download URL: pumpwood_streamlit-0.18.12.tar.gz
  • Upload date:
  • Size: 18.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.12.13 Linux/6.17.0-1022-azure

File hashes

Hashes for pumpwood_streamlit-0.18.12.tar.gz
Algorithm Hash digest
SHA256 71126a70248ba9ec5d97d8f8ceb5eff7821055c413d683457bf91859a6c14e1f
MD5 3811cdb43e0e789ed71a9df8c5b5b674
BLAKE2b-256 d02b240f28e2761c2188eaff4d46485738d41b259a169bbdeca233a1e30ba01b

See more details on using hashes here.

File details

Details for the file pumpwood_streamlit-0.18.12-py3-none-any.whl.

File metadata

  • Download URL: pumpwood_streamlit-0.18.12-py3-none-any.whl
  • Upload date:
  • Size: 21.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.12.13 Linux/6.17.0-1022-azure

File hashes

Hashes for pumpwood_streamlit-0.18.12-py3-none-any.whl
Algorithm Hash digest
SHA256 a6c271845f4e514a738ed4f3b4f124f673802622e67e4217bdc82de8f4cedb22
MD5 d02c8220496ff2bc260a752d700bcafc
BLAKE2b-256 67383cf5444ff0636de01b67317a4c7ed11faaf3206061cf27cf3df91cef8019

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page