Создание интерактивных аналитических панелей с помощью Python Streamlit

В этой статье приводится руководство по построению интерактивной аналитической панели с помощью Streamlit на языке Python.

Введение

Представьте, что вы специалист по изучению данных, аналитик, инженер машинного обучения или веб-разработчик, и вам нужно превратить сценарий обработки данных на языке Python в быструю практическую идею. Streamlit – это ваш ответ.
Streamlit – это фреймворк Python с открытым исходным кодом, позволяющий без особых усилий создавать веб-приложения. С помощью Streamlit вы можете превратить сценарии данных в веб-приложения, доступные для совместного использования, за считанные минуты, а не недели, и он абсолютно бесплатен.

В этой статье вы узнаете, как создать аналитическую панель с помощью пакета Streamlit Python. Мы проведем вас через весь процесс шаг за шагом, начиная с установки необходимых пакетов и заканчивая созданием интерактивных визуализаций.

Пакеты Python

Прежде чем приступить к работе, необходимо установить следующие пакеты с помощью pip:

pip install streamlit numpy pandas streamlit_extras millify altair plotly

После установки необходимых пакетов импортируйте их в свой python-скрипт.

import streamlit as st # streamlit package
import numpy as np
import pandas as pd
from millify import millify # shortens values (10_000 ---> 10k)
from streamlit_extras.metric_cards import style_metric_cards # beautify metric card with css
import plotly.graph_objects as go
import altair as alt 

Загрузка набора данных

В данном учебном пособии мы будем использовать набор данных Superstore Sales, доступный на сайте Superstore Sales 2023 – dataset by ehughes | data.world.

Создание интерактивных аналитических панелей с помощью Python Streamlit
предварительный просмотр набора данных “Продажи в супермаркетах”.

Прежде чем создавать приборную панель на основе своих данных, необходимо определить ключевые показатели эффективности (KPI), которые вы хотите визуализировать на приборной панели.

Вот некоторые KPI, которые следует рассмотреть:

  • Какова общая сумма продаж?
  • Сколько прибыли было получено?
  • Сколько отдельных заказов получил магазин?
  • Каковы 10 лучших товаров по объему продаж?
  • Каковы 10 лучших товаров по прибыли?
  • Сколько дней в среднем уходит на доставку заказа?
  • Какова динамика продаж различных категорий товаров за год?

Эти вопросы подскажут вам, что следует изобразить на панели.

Теперь давайте загрузим набор данных и подготовим его для нашей приборной панели:

# this function get the % change for any column by year and the specified aggregate
def get_per_year_change(col,df,metric):
    # Group by years and calculate the specified metric
    grp_years = df.groupby('year')[col].agg([metric])[metric]
    # Calculate the % change
    grp_years = grp_years.pct_change() * 100
    grp_years.fillna(0, inplace=True)
    grp_years = grp_years.apply(lambda x: f"{x:.1f}%" if pd.notnull(x) else 'NaN')

    return grp_years
# Cache the dataset for better performance
@st.cache_data(ttl=3600)
def load_data():
    df = pd.read_excel('Sample - Superstore.xls',sheet_name=0)
    # Extract the year and store it as a new column
    df['year'] = df['Order Date'].dt.year
    # Calculate the difference between Shipped date and order date
    df['days to ship'] = abs(df['Ship Date']- df['Order Date']).dt.days

    # Calculate the % change of sales, profit and orders over the years
    grp_years_sales = get_per_year_change('Sales',df,'sum')
    grp_year_profit = get_per_year_change('Profit',df,'sum')
    grp_year_orders = get_per_year_change('Order ID',df,'count')

    return df, grp_years_sales, grp_year_profit,grp_year_orders

# load cached data
df_original ,grp_years_sales, grp_year_profit,grp_year_orders = load_data()

Функция load_data(), получая набор данных супермаркета, извлекает год, количество дней на доставку товара и создает DataFrames для процентного изменения по сравнению с предыдущим годом для продаж, прибыли и количества заказов.

Контейнер для метрических карт

Создадим карточку метрики для отображения показателей KPI по общему объему продаж, общей прибыли и количеству отдельных заказов. Мы также покажем их процентное изменение по сравнению с предыдущим годом.

Streamlit’s st.metric отображает метрику с необязательным индикатором ее изменения.

# creates the container for page title
dash_1 = st.container()

with dash_1:
    st.markdown("<h2 style='text-align: center;'>Superstore Sales Dashboard</h2>", unsafe_allow_html=True)
    st.write("")


# creates the container for metric card
dash_2 = st.container()

with dash_2:
    # get kpi metrics
    total_sales = df['Sales'].sum()
    total_profit = df['Profit'].sum()
    total_orders = df['Order ID'].nunique()

    col1, col2, col3 = st.columns(3)
    # create column span
    col1.metric(label="Sales", value= "$"+millify(total_sales, precision=2) , delta=sales_per_change)
    
    col2.metric(label="Profit", value= "$"+millify(total_profit, precision=2), delta=profit_per_change)
    
    col3.metric(label="Orders", value=total_orders, delta=order_count_per_change)
    
    # this is used to style the metric card
    style_metric_cards(border_left_color="#DBF227")
Создание интерактивных аналитических панелей с помощью Python Streamlit
Контейнер для метрических карт, показывающий KPI продаж, прибыли и заказов.

Контейнер для диаграмм

Теперь создадим горизонтальные гистограммы для отображения метрик 10 лучших продуктов по сумме продаж и по сумме прибыли.

В приведенном ниже коде мы сначала запросим кадр данных, сгруппировав его по сумме продаж и сумме прибыли, а затем получим 10 лучших продуктов.

Для отображения диаграммы с помощью библиотеки Altair используется st.altair_chart из Streamlit.

# container for top 10 best selling and most profitable products
with dash_3:
    
    # create columna for both graph
    col1,col2 = st.columns(2)
    # get the top 10 best selling products
    top_product_sales = df.groupby('Product Name')['Sales'].sum()
    top_product_sales = top_product_sales.nlargest(10)
    top_product_sales = pd.DataFrame(top_product_sales).reset_index()

    # get the top 10 most profitable products
    top_product_profit = df.groupby('Product Name')['Profit'].sum()
    top_product_profit = top_product_profit.nlargest(10)
    top_product_profit = pd.DataFrame(top_product_profit).reset_index()
   
    
    # create the altair chart
    with col1:
        chart = alt.Chart(top_product_sales).mark_bar(opacity=0.9,color="#9FC131").encode(
                x='sum(Sales):Q',
                y=alt.Y('Product Name:N', sort='-x')   
            )
        chart = chart.properties(title="Top 10 Selling Products" )

        
        st.altair_chart(chart,use_container_width=True)

    # create the altair chart
    with col2:
        chart = alt.Chart(top_product_profit).mark_bar(opacity=0.9,color="#9FC131").encode(
                x='sum(Profit):Q',
                y=alt.Y('Product Name:N', sort='-x')
                
            )
        chart = chart.properties(title="Top 10 Most Profitable Products" )

        st.altair_chart(chart,use_container_width=True)
Создание интерактивных аналитических панелей с помощью Python Streamlit
10 самых продаваемых и прибыльных продуктов Диаграмма.

Теперь, чтобы завершить работу над приборной панелью, мы создадим графики для отображения метрик: среднего количества дней, необходимых для доставки заказа, и динамики продаж для различных категорий товаров за несколько лет.

Мы используем график plotly для отображения среднего количества дней доставки, а также минимального и максимального количества дней. Затем мы создадим гистограмму для отображения общего объема продаж для различных категорий товаров за несколько лет.

# container for avg shipping days and sales of different products categories over the years
with dash_4:

    col1,col2 = st.columns([1,2])

    with col1:
        value =int(np.round(df['days to ship'].mean()))  # Example value

        fig = go.Figure(go.Indicator(
            mode="gauge+number",
            value=value,
            title={'text': "Average Shipping Days"},
            gauge={'axis': {'range': [df['days to ship'].min() , df['days to ship'].max()]},
                'bar': {'color': "#005C53"},
                }
        ))

        fig.update_layout(height=350) 

        st.plotly_chart(fig, use_container_width=True)
  
    
    with col2:
        custom_colors = {'Furniture': '#005C53', 'Office Supplies': '#9FC131', 'Technology': '#042940'}


        bars = alt.Chart(df).mark_bar().encode(
            y=alt.Y('sum(Sales):Q', stack='zero', axis=alt.Axis(format='~s') ),
            x=alt.X('year:N'),
            #color=alt.Color('Category')
            color=alt.Color('Category:N', scale=alt.Scale(domain=list(custom_colors.keys()), range=list(custom_colors.values())))

        )

        text = alt.Chart(df).mark_text(dx=-15, dy=30, color='white').encode(
             y=alt.Y('sum(Sales):Q', stack='zero', axis=alt.Axis(format='~s') ),
            x=alt.X('year:N'),
            detail='Category:N',
            text=alt.Text('sum(Sales):Q', format='~s')
          )

        chart = bars + text

        chart = chart.properties(title="Sales trends for Product Categories over the years" )

        st.altair_chart(chart,use_container_width=True)
Создание интерактивных аналитических панелей с помощью Python Streamlit
График продаж по категориям товаров и средним дням отгрузки.

Полная приборная панель

В результате объединения всех элементов получается современная интерактивная приборная панель, позволяющая с первого взгляда получить ценные сведения.

Создание интерактивных аналитических панелей с помощью Python Streamlit
Приборная панель продаж супермаркета в Streamlit (superstore-sales-app.streamlit.app)

Заключение и призыв к действию

Спасибо за чтение! В этой статье вы узнали, как создать динамическую аналитическую панель с помощью Streamlit на языке Python. Благодаря простоте и гибкости Streamlit вы можете быстро превратить ваши данные в полезные сведения.

Теперь настала ваша очередь. Приступайте к созданию своих панелей в реальном времени с помощью Streamlit. Код этого проекта можно найти на GitHub.

Счастливых дашбордов! 😊

+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *