Chapter 7: The CEO strikes back: Supercharging the dashboard
This chapter introduces an iterative upgrade of the Note n’ Nib metrics dashboard in response to user feedback, using advanced Streamlit features to improve flexibility and usability.
After this chapter you will be able to
- Feedback-driven dashboard iteration. Explain how chapter 7 evaluates the dashboard created for Note n’ Nib in chapter 6, reviews user feedback, and makes targeted incremental improvements to address concerns and improve quality and satisfaction.
- CEO feedback enhancement agenda. Describe how executive adoption of the dashboard led to consolidated CEO feedback requesting additional features, and state that the chapter addresses the items on that wishlist.
- Time-series granularity problem. Explain why plotting one daily marker for every date works for short ranges but overwhelms a chart covering long periods, and describe user-selected granularity as the proposed solution.
- Period-based date grain columns. Describe how prep_data adds Week, Month, and Year columns from the existing Day column using pandas period and timestamp conversions. Explain that each resulting value represents the start of its corresponding week, month, or year.
- Configurable grain in backend. Explain how the backend generalizes daily time-series processing by passing a grain parameter and using it in place of the hardcoded Day column name. Describe that the same aggregation logic can then operate at daily, weekly, monthly, or yearly grain.
- Ordered text selection. Explain when to use st.select_slider: for text choices that have a meaningful order, combining aspects of a selectbox and a slider. Relate the ordered Day, Week, Month, and Year choices to units from smallest to largest.
- Time grain selector wiring. Describe how the time_series_chart function creates grain_options, passes that ordered list and a label to st.select_slider, stores its returned selection in grain, and passes grain to get_time_series_chart. State that selecting a coarser grain such as Month can make a chart spanning multiple years more readable.
- Interdependent filter behavior. Explain why independent dropdown options create invalid or irrelevant filter combinations, and how interdependent filters avoid this problem. Describe why this becomes especially valuable when a dashboard has many products or values.
- Sequential dataframe filtering. Describe the sequential filtering approach: obtain unique values for a filter from the current effective_df, apply that filter’s selected values to recompute the dataframe, and repeat for the next filter. State that filter order matters because a filter can only constrain dropdowns whose options are computed after it.
- Metric comparison context. Explain why a standalone metric, such as RoyalQuill sales of $1.32M in July, does not by itself show whether performance is good or bad. Describe how comparing it with a past comparable period makes the metric actionable.
- Dashboard comparison requirement. Describe the dashboard requirement introduced here: when a user views a metric for a selected time period, the dashboard should also show how that metric changed relative to the past. State that the current dashboard does not yet provide an easy way to make this comparison.
- Common comparison date ranges. Describe the MoM, QoQ, YoY, and Previous period comparison ranges derived from a selected main date range. Explain that MoM shifts the range back one month, QoQ back three months, YoY back one year, and Previous period selects the immediately preceding equal-length range.
- Comparison range calculation. Explain how get_compare_range computes comparison start and end dates from the main start date, end date, and comparison type. Describe the offsets dictionary using comparison names as keys and pandas DateOffset values, with the same offset subtracted from both dates.
- Comparison selector integration. Describe how date_range_panel adds an st.selectbox for discrete comparison choices, calls get_compare_range, displays the resulting dates in an st.info box, and returns start, end, compare_start, and compare_end. State that dashboard.py must unpack all four returned values when calling the function.
- Comparison-period metric calculation. Explain how the dashboard creates a comparison dataframe for the selected comparison dates using the same non-date filters as the main dataframe, then calculates each metric separately for that dataframe.
- Percentage delta computation. Describe how get_delta calculates a metric’s percentage change from the main value and the comparison-period value, and state when it returns None instead of a delta.
- Drilldown view purpose. Explain why the dashboard needs a drilldown view that exposes individual rows from the source data alongside its existing aggregate metrics and visualizations.
- Power-user dashboard needs. Describe the tension between keeping a dashboard simple for most users and supporting a power user who wants to explore data in more advanced detail.
- Modal dialog behavior. Explain what a modal dialog is and why it suits the dashboard drilldown: it overlays the main dashboard, blocks interaction with it until dismissal, and keeps advanced functionality available without cluttering the primary view.
- Dialog-decorated drilldown function. Describe how st.dialog decorates a function rather than acting as a layout container, so calling the decorated drilldown function renders its contents in a popup. Explain that the drilldown function receives main_df and compare_df, uses Main and Compare tabs, and displays each pandas dataframe with st.dataframe.
- Container placeholder ordering. Trace how st.container separates screen placement from computation order: create dd_button_container above the sidebar date-range panel, then later call dd_button_container.button after main_df and compare_df have been computed so the Drilldown button appears in the earlier placeholder and can call drilldown.
- Flexible drilldown table requirements. Explain why displaying the raw main_df and compare_df dataframes is inadequate for a drilldown, and describe the requirements for the replacement table. State that it must support any combination of dimensions, let users hide irrelevant fields, and show aggregates for the full selected breakdown.
- Pivot-style drilldown interface. Describe the proposed drilldown UI as a pivot-table-like table with a Drilldown Fields multiselect, rows for every combination of selected dimensions, aggregated metrics, and a total row. Explain that it retains Main and Comparison tabs so users can inspect present and past metrics.
- Dimension-based metric aggregation. Describe how the drilldown lets a user select dimensions with st.multiselect and produces metrics aggregated at the selected level of detail. Explain the different result shape when dimensions are selected versus when none are selected.
- Summary total row. Explain how add_total_row constructs a total for the complete raw dataframe rather than summing the already aggregated drilldown table. Describe how the row differs when dimensions are present versus absent.
- Dialog-local reruns. Explain why interacting with widgets inside the st.dialog-decorated drilldown does not close the dialog even though a normal button click lasts for only one app rerun. State that only the decorated dialog function reruns and connect this behavior to st.fragment.
- Deeplinking collaboration problem. Explain why sharing a dashboard view through screenshots or manual recreation instructions creates a collaboration problem, and how deeplinks address it by letting another user open the same view.
- URL-encoded dashboard inputs. Describe the basic deeplinking model: a URL can embed information about a user's inputs, which an application uses to take another user to the corresponding view or state.
- Deeplink implementation requirements. State the two required capabilities for dashboard deeplinks: embedding user inputs in the app URL and automatically repopulating those inputs from a URL.
- st.query_params synchronization. Explain that st.query_params is a dictionary-like object containing the current URL query parameters, and describe reading from it and assigning to it to respectively access parameter values and update the browser URL.
- URL-driven widget state. Trace the deeplinking flow: when the app opens, use any supplied query parameters to set corresponding widget values; when a widget changes, update the matching query parameter so the URL reflects the current app state. State that missing parameters leave widgets at their normal defaults.
- Widget defaults through session state. Explain how assigning a key to a Streamlit input widget makes its value available through st.session_state and allows code to set the widget's initial displayed value. State that the session-state value must be assigned before the widget's code runs, not after it has rendered.
- Widget-query parameter synchronization. Explain how the query_params.py helpers synchronize deeplink-enabled widget values between st.session_state and st.query_params. Describe how get_param reads a parameter, set_widget_defaults restores URL values into widget state, and set_params writes current widget state back to the URL.
- Deeplink widget key convention. Describe why only widget keys prefixed with w: are included in deeplinks and why a widget value is restored only when its key is not already in st.session_state. Explain that every widget intended for the URL needs a defined w:-prefixed key.
- Widget initialization and update order. Trace the required placement of deeplink calls and widget changes in the dashboard. State that set_widget_defaults runs at the top of dashboard.py after st.set_page_config and before widgets, while set_params runs at the end after widgets; for date inputs, defaults must be assigned through st.session_state before the widgets rather than also through value.
- Typed query parameter encoding. Explain why raw URL query parameter strings cannot directly restore date inputs and multiselects, and describe the L# and D# encoding scheme. State that set_params serializes lists and dates with type prefixes, while get_param recognizes those prefixes and converts them back into lists or date objects.
- CSV source limitations. Explain why a static CSV file is an easy initial data source for the dashboard but becomes impractical for large datasets.
- Data warehouse motivation. Describe how a data warehouse differs from the CSV approach: it is a specialized system for large volumes of structured data and can support querying data at the source rather than loading all of it into application memory first.
- BigQuery warehouse role. Explain what Google BigQuery is and what it provides: a cloud-based GCP data warehouse for storing and analyzing massive datasets with SQL without managing infrastructure or scaling.
- CSV table upload workflow. Trace the workflow for loading sales_data.csv into BigQuery: create a dataset under the project, create a table within that dataset, select Upload and CSV, choose the local file and table name, enable Auto Detect for the schema, and create the table.
- Service account authentication. Describe how to create a GCP service account for the application and grant it the Viewer role. Explain that this is an application-owned account, rather than an individual user's account, which lets the app authenticate to and interact with Google Cloud services such as BigQuery.
- Service account credential secret. Trace how to create a JSON service account key and turn it into a Streamlit secrets.toml file under the "bigquery" key. State that the downloaded key contains credentials and details such as the project ID, so it must be kept secret because anyone holding it can read the BigQuery data.
- BigQuery data-loading flow. Describe how load_data reads service-account information from st.secrets, creates BigQuery and BigQuery Storage clients with those credentials, builds a fully qualified table reference, runs a SELECT * query, and returns the results as a pandas dataframe using the Storage client.
- Modular replacement and cache refresh. Explain that separation of concerns confines the source change to load_data in data_loader.py so the rest of the app can continue working, and state that after changing this cached function the app must be restarted with streamlit run dashboard.py rather than merely rerun in the browser.
- Dashboard data deployment choices. Distinguish the deployment requirements for a dashboard that reads a static CSV from one that reads data from BigQuery. State that a static CSV must be committed to Git and stored in the GitHub repository, whereas a BigQuery-backed dashboard does not need the CSV in the repository.
- BigQuery credential configuration. Describe the extra Community Cloud setup needed for a BigQuery-backed dashboard: configure the GCP credentials in Streamlit Community Cloud using the same credentials process introduced in chapter 5.
What it builds on
- A metrics dashboard (chapter 6) · The original concept and requirements for the Note n’ Nib metrics dashboard.
- Summary (chapter 6) · The completed initial dashboard that is being assessed and enhanced.
- Constructing visualizations (chapter 6) · The initial time-series and pie-chart visualizations that the chapter extends.
- Creating a date range selector (chapter 6) · The dashboard's selectable date range, which determines whether the chart covers a short or long time horizon.
- Creating a time series chart (chapter 6) · The existing line chart that displays the selected metric over time.
- Reading and displaying a dataframe (chapter 6) · Loading and displaying the dashboard dataframe.
- Calculating the metrics (chapter 6) · The dashboard's metric-calculation logic.
- Creating a filter panel (chapter 6) · the dashboard’s filter panel and its category, segment, and product-name filtering
Section by section
Introduction
This chapter introduces an iterative upgrade of the Note n’ Nib metrics dashboard in response to user feedback, using advanced Streamlit features to improve flexibility and usability.
- Feedback-driven dashboard iteration: Explain how chapter 7 evaluates the dashboard created for Note n’ Nib in chapter 6, reviews user feedback, and makes targeted incremental improvements to address concerns and improve quality and satisfaction.
Why it matters: Real applications improve after launch by responding to how users experience them. - Advanced dashboard enhancement roadmap: Describe the advanced dashboard capabilities introduced in this chapter: more flexible visualizations, easier access to frequently used features, modal dialogs, and query parameters for deeplinks.
Why it matters: These capabilities are the chapter’s toolkit for turning an initial dashboard into a more flexible and usable one. - Chapter code repository: State that the book’s GitHub repository contains a chapter_07 folder with this chapter’s code and a requirements.txt file listing the exact required Python library versions.
Why it matters: Using the chapter-specific code and dependency versions helps readers reproduce the examples consistently.
Key terms: user feedback, targeted improvements, iterating on the app, quality and satisfaction, advanced Streamlit visualizations, modal dialogs, query parameters, deeplinks, usability, GitHub repository
7.1 Feedback on the dashboard
This section sets up the CEO’s consolidated feedback as the motivation for enhancing the previously built sales dashboard and recommends using the complete GitHub code as a reference.
- CEO feedback enhancement agenda: Describe how executive adoption of the dashboard led to consolidated CEO feedback requesting additional features, and state that the chapter addresses the items on that wishlist.
Why it matters: The feedback provides the practical reason for each dashboard enhancement introduced in the rest of the chapter. - Previous dashboard code baseline: State that the chapter builds on the final state of the dashboard from the previous chapter and explain why the author recommends keeping the GitHub repository open while following the substantial code additions.
Why it matters: Using the finished prior dashboard and the complete repository helps readers follow changes without losing the working baseline.
Key terms: consolidated feedback, wishlist, dashboard, final state, GitHub repo, complete code
7.2 Granularity in the time series chart
This section identifies why day-level time-series charts become unreadable over long date ranges and proposes letting users choose an appropriate time granularity.
- Time-series granularity problem: Explain why plotting one daily marker for every date works for short ranges but overwhelms a chart covering long periods, and describe user-selected granularity as the proposed solution.
Why it matters: Choosing an appropriate aggregation level makes long-term trends interpretable instead of visually overwhelming.
Key terms: daily granularity, time series chart, markers, date range, granularity
7.2.1 Enabling different time granularities
This subsection prepares dashboard data for weekly, monthly, and yearly aggregation and replaces hardcoded daily logic with a configurable time-grain parameter.
- Period-based date grain columns: Describe how prep_data adds Week, Month, and Year columns from the existing Day column using pandas period and timestamp conversions. Explain that each resulting value represents the start of its corresponding week, month, or year.
Why it matters: These normalized date columns give the dashboard a field on which it can group metrics at each requested time scale. - Configurable grain in backend: Explain how the backend generalizes daily time-series processing by passing a grain parameter and using it in place of the hardcoded Day column name. Describe that the same aggregation logic can then operate at daily, weekly, monthly, or yearly grain.
Why it matters: Parameterizing the grain avoids separate implementations for every time scale and enables the eventual user-controlled chart granularity.
Key terms: prep_data, pandas dataframe, Day, Week, Month, Year, get_metric_time_series, data_wrangling.py, time_series_chart.py, grain
7.2.2 Creating a time grain selector
This section adds an ordered time-grain selector to the dashboard’s time series chart so users can choose Day, Week, Month, or Year.
- Ordered text selection: Explain when to use st.select_slider: for text choices that have a meaningful order, combining aspects of a selectbox and a slider. Relate the ordered Day, Week, Month, and Year choices to units from smallest to largest.
Why it matters: Choosing the right widget makes the available chart resolutions clear and easy to navigate. - Time grain selector wiring: Describe how the time_series_chart function creates grain_options, passes that ordered list and a label to st.select_slider, stores its returned selection in grain, and passes grain to get_time_series_chart. State that selecting a coarser grain such as Month can make a chart spanning multiple years more readable.
Why it matters: The selected UI value must flow into chart generation for the control to change the visualization.
Key terms: st.select_slider, st.selectbox, st.slider, time grain, time_series_chart, grain_options, grain, get_time_series_chart, Day
7.3 Interdependent filters
This section makes dashboard filters interdependent by deriving each filter’s options from data already narrowed by earlier selections.
- Interdependent filter behavior: Explain why independent dropdown options create invalid or irrelevant filter combinations, and how interdependent filters avoid this problem. Describe why this becomes especially valuable when a dashboard has many products or values.
Why it matters: Interdependent filters keep users from navigating irrelevant choices and make large dashboards practical to use. - Sequential dataframe filtering: Describe the sequential filtering approach: obtain unique values for a filter from the current effective_df, apply that filter’s selected values to recompute the dataframe, and repeat for the next filter. State that filter order matters because a filter can only constrain dropdowns whose options are computed after it.
Why it matters: Filtering step by step provides dependent options without having to define and maintain a separate dependency map.
Key terms: interdependent filters, filter bar, Category, Segment, Product name, effective_df, get_unique_values, apply_filters, filter fields, unique values
7.4 Date range comparisons
This section establishes that dashboard metrics need comparison to past periods for meaningful context and introduces adding date-range comparisons to the dashboard.
- Metric comparison context: Explain why a standalone metric, such as RoyalQuill sales of $1.32M in July, does not by itself show whether performance is good or bad. Describe how comparing it with a past comparable period makes the metric actionable.
Why it matters: A number gains business meaning when users can see it relative to an appropriate earlier result. - Dashboard comparison requirement: Describe the dashboard requirement introduced here: when a user views a metric for a selected time period, the dashboard should also show how that metric changed relative to the past. State that the current dashboard does not yet provide an easy way to make this comparison.
Why it matters: This requirement drives the dashboard enhancements that let users evaluate performance rather than merely read current values.
Key terms: metric, contextualizing data, comparable period, date range comparison, date range comparisons, metric bar, date range selector
7.4.1 Adding another date range selector
This section adds a selectable comparison date range to the dashboard and calculates comparison dates for common reporting periods.
- Common comparison date ranges: Describe the MoM, QoQ, YoY, and Previous period comparison ranges derived from a selected main date range. Explain that MoM shifts the range back one month, QoQ back three months, YoY back one year, and Previous period selects the immediately preceding equal-length range.
Why it matters: These options let dashboard users interpret a metric against a meaningful earlier period. - Comparison range calculation: Explain how get_compare_range computes comparison start and end dates from the main start date, end date, and comparison type. Describe the offsets dictionary using comparison names as keys and pandas DateOffset values, with the same offset subtracted from both dates.
Why it matters: A single offset-based function makes each comparison option produce a consistent, correctly aligned date range. - Comparison selector integration: Describe how date_range_panel adds an st.selectbox for discrete comparison choices, calls get_compare_range, displays the resulting dates in an st.info box, and returns start, end, compare_start, and compare_end. State that dashboard.py must unpack all four returned values when calling the function.
Why it matters: The selector and updated return values connect the user’s choice in the sidebar to comparison data that later dashboard code can use. - Date type consistency: Explain why get_compare_range calls .date() on the results of subtracting pandas DateOffset objects. State that the input dates are datetime.date objects, subtraction produces pandas timestamp objects, and .date() converts the results back to datetime.date for consistency.
Why it matters: Keeping one date type throughout the dashboard avoids inconsistent values in later filtering and comparison code.
Key terms: MoM, QoQ, YoY, Previous period, main date range, comparison date range, get_compare_range, offsets, pandas DateOffset, compare_start
7.4.2 Showing the comparison in the metric bar
This subsection adds comparison-period percentage changes to the dashboard’s metric bar while preserving the user’s other filters.
- Comparison-period metric calculation: Explain how the dashboard creates a comparison dataframe for the selected comparison dates using the same non-date filters as the main dataframe, then calculates each metric separately for that dataframe.
Why it matters: A comparison is meaningful only when the date range changes while the category, gender, and other selected filters remain consistent. - Percentage delta computation: Describe how get_delta calculates a metric’s percentage change from the main value and the comparison-period value, and state when it returns None instead of a delta.
Why it matters: The percentage delta gives readers context about whether the current-period metric improved or declined relative to the selected comparison period. - Metric delta display settings: Explain how the metric bar passes a formatted percentage delta and a delta_color setting to st.metric, including why this dashboard uses the normal color scheme.
Why it matters: Using Streamlit’s delta display makes changes immediately visible and colors them according to whether an increase is desirable.
Key terms: compare_df, main_df, get_filtered_data_within_date_range, get_metric, comparison date range, get_delta, get_formatted_delta, format_metric, percentage delta, st.metric
7.5 A drilldown view
This section motivates adding a detailed drilldown view for power users who need to investigate the individual data behind dashboard aggregates.
- Drilldown view purpose: Explain why the dashboard needs a drilldown view that exposes individual rows from the source data alongside its existing aggregate metrics and visualizations.
Why it matters: A drilldown lets users investigate the data behind a dashboard number instead of relying only on summaries. - Power-user dashboard needs: Describe the tension between keeping a dashboard simple for most users and supporting a power user who wants to explore data in more advanced detail.
Why it matters: Recognizing this tension helps you add advanced exploration without losing the clarity that makes a dashboard useful. - Drilldown implementation scope: State that adding the drilldown is expected to be the chapter's most complex task because it requires a completely new view rather than an incremental improvement to an existing feature.
Why it matters: This sets appropriate expectations for the design and implementation effort required by an advanced dashboard feature.
Key terms: drilldown view, source data, metrics bar, aggregate numbers, power user, visualizations, drill down, new view, existing features
7.5.1 Inserting a modal dialog
This section adds an unobtrusive drilldown trigger that opens main and comparison data in a Streamlit modal dialog while using a container placeholder to control sidebar display order.
- Modal dialog behavior: Explain what a modal dialog is and why it suits the dashboard drilldown: it overlays the main dashboard, blocks interaction with it until dismissal, and keeps advanced functionality available without cluttering the primary view.
Why it matters: A modal lets power users access detailed data while casual users can continue to focus on the main dashboard. - Dialog-decorated drilldown function: Describe how st.dialog decorates a function rather than acting as a layout container, so calling the decorated drilldown function renders its contents in a popup. Explain that the drilldown function receives main_df and compare_df, uses Main and Compare tabs, and displays each pandas dataframe with st.dataframe.
Why it matters: Understanding the decorator-based dialog model lets you put a focused view behind a user action without building a separate page. - Container placeholder ordering: Trace how st.container separates screen placement from computation order: create dd_button_container above the sidebar date-range panel, then later call dd_button_container.button after main_df and compare_df have been computed so the Drilldown button appears in the earlier placeholder and can call drilldown.
Why it matters: This pattern solves cases where a UI control must appear early on the page but needs values computed later in top-to-bottom Streamlit code.
Key terms: modal dialog, drilldown view, overlay, st.dialog, decorator, drilldown, main_df, compare_df, st.dataframe, st.container
7.5.2 Designing the content of the drilldown
This section derives a flexible pivot-table-like drilldown design from CEO feedback so users can inspect aggregated metrics across any chosen combination of dimensions.
- Flexible drilldown table requirements: Explain why displaying the raw main_df and compare_df dataframes is inadequate for a drilldown, and describe the requirements for the replacement table. State that it must support any combination of dimensions, let users hide irrelevant fields, and show aggregates for the full selected breakdown.
Why it matters: A drilldown is useful only when users can focus on the specific slices of data that answer their question. - Pivot-style drilldown interface: Describe the proposed drilldown UI as a pivot-table-like table with a Drilldown Fields multiselect, rows for every combination of selected dimensions, aggregated metrics, and a total row. Explain that it retains Main and Comparison tabs so users can inspect present and past metrics.
Why it matters: This interface gives users a repeatable way to investigate detailed metric breakdowns without creating a new chart for each question.
Key terms: drilldown view, main_df, compare_df, dimensions, aggregate numbers, pivot table, Drilldown Fields, multi-select, Main tab, Comparison tab
7.5.3 Implementing the drilldown view
This section implements a configurable drilldown dialog that aggregates dashboard metrics by chosen dimensions, adds and styles a total row, and explains why dialog interactions rerun independently of the main app.
- Dimension-based metric aggregation: Describe how the drilldown lets a user select dimensions with st.multiselect and produces metrics aggregated at the selected level of detail. Explain the different result shape when dimensions are selected versus when none are selected.
Why it matters: This is what lets a dashboard user move from overall metrics to a breakdown that answers a specific business question. - Drilldown table workflow: Trace the flow that obtains selected dimensions, builds main and comparison drilldown tables, and displays each table in separate tabs. State how an empty result is handled and why the dataframe index is hidden.
Why it matters: Separating selection, transformation, and display keeps the drilldown feature understandable and easier to extend. - Summary total row: Explain how add_total_row constructs a total for the complete raw dataframe rather than summing the already aggregated drilldown table. Describe how the row differs when dimensions are present versus absent.
Why it matters: A clearly calculated total gives users context for the groups they are inspecting and avoids relying on an inappropriate aggregated input. - Metric table formatting: Describe how the drilldown applies existing metric formatting rules to every relevant dataframe column and conditionally shades the total row. Explain how the style function identifies a total row.
Why it matters: Consistent number formatting and a visible total row make a dense drilldown table easier to read correctly. - Dialog-local reruns: Explain why interacting with widgets inside the st.dialog-decorated drilldown does not close the dialog even though a normal button click lasts for only one app rerun. State that only the decorated dialog function reruns and connect this behavior to st.fragment.
Why it matters: Understanding dialog-local reruns helps you build interactive modal content without unnecessarily managing button state in session state.
Key terms: st.multiselect, drilldown dimensions, get_metric_cols, get_aggregate_metrics, grouped.apply, pandas Series, drilldown, get_drilldown_table, main_data, compare_data
7.6 Enabling deeplinks
This section motivates dashboard deeplinks as shareable URLs that preserve a user's selected dashboard state for collaborative viewing.
- Deeplinking collaboration problem: Explain why sharing a dashboard view through screenshots or manual recreation instructions creates a collaboration problem, and how deeplinks address it by letting another user open the same view.
Why it matters: Deeplinks let collaborators discuss an interactive dashboard state instead of trying to reconstruct it by trial and error. - URL-encoded dashboard inputs: Describe the basic deeplinking model: a URL can embed information about a user's inputs, which an application uses to take another user to the corresponding view or state.
Why it matters: Encoding state in a URL makes a dashboard view portable, so a copied link can communicate more than the app's location. - Deeplink implementation requirements: State the two required capabilities for dashboard deeplinks: embedding user inputs in the app URL and automatically repopulating those inputs from a URL.
Why it matters: Both directions are necessary: the app must create a meaningful shareable link and restore its state when someone opens it.
Key terms: deeplinking, dashboard state, collaboration tax, URL, embedded information, inputs, q=streamlit, user inputs, app's URL, repopulate inputs
7.6.1 Using st.query_params
This section explains how to use URL query parameters through st.query_params so a dashboard URL reflects and can restore a user’s widget selections.
- Query string structure: Describe a URL query string as the portion after a question mark containing ampersand-separated key-value query parameters, and relate those parameters to user selections that can be captured in an app URL.
Why it matters: Understanding the URL format makes it clear how an app can carry its current selections in a shareable link. - st.query_params synchronization: Explain that st.query_params is a dictionary-like object containing the current URL query parameters, and describe reading from it and assigning to it to respectively access parameter values and update the browser URL.
Why it matters: This object is the link between dashboard state in Python and a URL that users can revisit or share. - URL-driven widget state: Trace the deeplinking flow: when the app opens, use any supplied query parameters to set corresponding widget values; when a widget changes, update the matching query parameter so the URL reflects the current app state. State that missing parameters leave widgets at their normal defaults.
Why it matters: This two-way flow makes a dashboard’s current configuration reproducible from its link without overriding defaults when no link value exists.
Key terms: query string, query parameters, key-value pairs, st.query_params, st.session_state, pie_chart_dimension, deeplinks, widget values, default behavior, start_date
7.6.2 Setting widget defaults through st.session_state
This subsection explains how a keyed Streamlit widget can receive a programmatically set default through st.session_state, provided the value is assigned before the widget renders.
- Widget defaults through session state: Explain how assigning a key to a Streamlit input widget makes its value available through st.session_state and allows code to set the widget's initial displayed value. State that the session-state value must be assigned before the widget's code runs, not after it has rendered.
Why it matters: This lets an app initialize widgets programmatically, which is necessary for features such as deeplinks that restore UI selections.
Key terms: key, st.session_state, widget, select_dim
7.6.3 Implementing deeplinks
This section implements shareable dashboard deeplinks by synchronizing selected widget state with URL query parameters and restoring correctly typed values from those URLs.
- Widget-query parameter synchronization: Explain how the query_params.py helpers synchronize deeplink-enabled widget values between st.session_state and st.query_params. Describe how get_param reads a parameter, set_widget_defaults restores URL values into widget state, and set_params writes current widget state back to the URL.
Why it matters: This two-way synchronization makes a dashboard URL capture and recreate the selections a user is viewing. - Deeplink widget key convention: Describe why only widget keys prefixed with w: are included in deeplinks and why a widget value is restored only when its key is not already in st.session_state. Explain that every widget intended for the URL needs a defined w:-prefixed key.
Why it matters: The convention prevents unrelated session data from leaking into the URL and lets users change a value after the initial URL-based load. - Widget initialization and update order: Trace the required placement of deeplink calls and widget changes in the dashboard. State that set_widget_defaults runs at the top of dashboard.py after st.set_page_config and before widgets, while set_params runs at the end after widgets; for date inputs, defaults must be assigned through st.session_state before the widgets rather than also through value.
Why it matters: Correct ordering avoids Streamlit widget-state errors while ensuring the URL reflects every selection a user makes. - Typed query parameter encoding: Explain why raw URL query parameter strings cannot directly restore date inputs and multiselects, and describe the L# and D# encoding scheme. State that set_params serializes lists and dates with type prefixes, while get_param recognizes those prefixes and converts them back into lists or date objects.
Why it matters: Preserving value types allows a pasted dashboard URL to populate date and multi-select widgets without errors.
Key terms: st.query_params, st.session_state, get_param, set_widget_defaults, set_params, from_dict, w:, widget key, query parameters, st.set_page_config
7.7 Sourcing data from a data warehouse
This section motivates replacing the dashboard’s static CSV source with a Google BigQuery data-warehouse table for practical large-scale data handling.
- CSV source limitations: Explain why a static CSV file is an easy initial data source for the dashboard but becomes impractical for large datasets.
Why it matters: Recognizing the limits of file-based data helps you choose a data source that can support a production dashboard. - Data warehouse motivation: Describe how a data warehouse differs from the CSV approach: it is a specialized system for large volumes of structured data and can support querying data at the source rather than loading all of it into application memory first.
Why it matters: A warehouse-based source makes a dashboard more practical when data volume and query needs grow. - BigQuery migration scope: State that the upcoming work replaces the dashboard’s CSV file with a table in Google BigQuery, rather than changing the dashboard’s purpose or user-feedback features.
Why it matters: This establishes the concrete scope of the data-source upgrade before the implementation steps begin.
Key terms: static CSV file, data ingestion, data warehouse, structured data, filtering, aggregations, joins, Google BigQuery, table, CSV file
7.7.1 Getting data into BigQuery
This section introduces BigQuery and walks through creating a dataset and uploading the dashboard CSV data as an auto-detected table.
- BigQuery warehouse role: Explain what Google BigQuery is and what it provides: a cloud-based GCP data warehouse for storing and analyzing massive datasets with SQL without managing infrastructure or scaling.
Why it matters: BigQuery is the managed data source that will replace the dashboard's local file. - GCP project and BigQuery navigation: Describe the GCP setup and navigation needed before loading data: create or use a GCP project, note its unique project ID, and find BigQuery by searching for “bigquery” in the GCP search bar.
Why it matters: A project supplies the GCP container in which the BigQuery dataset and table are created. - CSV table upload workflow: Trace the workflow for loading sales_data.csv into BigQuery: create a dataset under the project, create a table within that dataset, select Upload and CSV, choose the local file and table name, enable Auto Detect for the schema, and create the table.
Why it matters: This workflow moves the dashboard's source data from a local CSV file into a queryable BigQuery table.
Key terms: Google BigQuery, Google Cloud Platform (GCP), data warehouse, Structured Query Language (SQL), GCP account, GCP project, project ID, BigQuery, Explorer, dataset
7.7.2 Setting up the Python-BigQuery connection
This section prepares a Streamlit app to authenticate to BigQuery by enabling required APIs, creating a read-only service account and key, and converting its JSON credentials into Streamlit secrets.
- Required BigQuery APIs: Explain why the BigQuery API and BigQuery Storage API must be enabled in the GCP project before Python can work with BigQuery data. Distinguish the connection-enabling role of the BigQuery API from the Storage API's faster ingestion of data into a Pandas dataframe.
Why it matters: The app needs these cloud services enabled before its Python code can connect to BigQuery and load data efficiently. - Service account authentication: Describe how to create a GCP service account for the application and grant it the Viewer role. Explain that this is an application-owned account, rather than an individual user's account, which lets the app authenticate to and interact with Google Cloud services such as BigQuery.
Why it matters: A dedicated, read-only application identity lets the dashboard access BigQuery programmatically without relying on a person's account. - Service account credential secret: Trace how to create a JSON service account key and turn it into a Streamlit secrets.toml file under the "bigquery" key. State that the downloaded key contains credentials and details such as the project ID, so it must be kept secret because anyone holding it can read the BigQuery data.
Why it matters: The credentials allow the Streamlit app to act as its service account while keeping sensitive access details out of the code.
Key terms: BigQuery API, BigQuery Storage API, GCP project, Pandas dataframe, GCP service account, IAM & Admin, Service Accounts, Viewer, authentication, service account key
7.7.3 Updating the dashboard to load data from BigQuery
This section replaces the dashboard’s CSV-based loader with a BigQuery-backed load_data function while preserving the rest of the modular app.
- BigQuery loader dependencies: State the three Python modules added for the BigQuery implementation and distinguish their roles: the BigQuery and BigQuery Storage API packages provide access to those services, while db-dtypes enables conversion of returned data into a pandas dataframe.
Why it matters: Installing the required packages lets the app connect to BigQuery and turn query results into the dataframe the dashboard expects. - BigQuery data-loading flow: Describe how load_data reads service-account information from st.secrets, creates BigQuery and BigQuery Storage clients with those credentials, builds a fully qualified table reference, runs a SELECT * query, and returns the results as a pandas dataframe using the Storage client.
Why it matters: This flow is the concrete replacement for reading a static CSV file while keeping the dashboard supplied with the same kind of data. - Warehouse filtering advantage: Explain that SQL can request only a needed subset of warehouse data, and that filtering in BigQuery is more efficient than loading an entire very large dataset into memory before filtering it locally.
Why it matters: Pushing filtering into the data warehouse helps the dashboard work more efficiently as its data grows. - Modular replacement and cache refresh: Explain that separation of concerns confines the source change to load_data in data_loader.py so the rest of the app can continue working, and state that after changing this cached function the app must be restarted with streamlit run dashboard.py rather than merely rerun in the browser.
Why it matters: Modular design makes a backend-source swap small, while restarting ensures the app does not serve an old cached dataframe.
Key terms: BigQuery API, BigQuery Storage API, db-dtypes, pandas dataframe, load_data, st.secrets, service_account_info, BigQuery client, BigQuery Storage API client, DATASET
7.7.4 Notes on deployment to Streamlit Community Cloud
This subsection explains the Community Cloud deployment considerations for the upgraded dashboard, depending on whether it uses a checked-in CSV file or BigQuery.
- Dashboard data deployment choices: Distinguish the deployment requirements for a dashboard that reads a static CSV from one that reads data from BigQuery. State that a static CSV must be committed to Git and stored in the GitHub repository, whereas a BigQuery-backed dashboard does not need the CSV in the repository.
Why it matters: The dashboard can only access the data source that has been made available appropriately after deployment. - BigQuery credential configuration: Describe the extra Community Cloud setup needed for a BigQuery-backed dashboard: configure the GCP credentials in Streamlit Community Cloud using the same credentials process introduced in chapter 5.
Why it matters: The deployed dashboard needs GCP credentials to connect to BigQuery without placing a CSV in the repository. - Dashboard dependency file: State that the dashboard deployment needs a requirements.txt file listing all modules Community Cloud must install, and describe using pip freeze to identify the specific library versions.
Why it matters: Community Cloud needs an explicit dependency list to install the Python libraries the dashboard uses.
Key terms: static CSV approach, BigQuery, Git, GitHub repository, Streamlit Community Cloud, GCP credentials, requirements.txt, pip freeze, modules, specific versions
7.8 Summary
This summary recaps how user feedback led to dashboard improvements in interaction, comparison, drilldown, sharing, and scalable data access.
Where this is used later
- Enabling users to create haikus (chapter 8) · The use of st.dialog to insert a modal dialog in a Streamlit app.
- PostgreSQL: A real relational database (chapter 8) · The earlier use of BigQuery as a data source for the dashboard.
- Implementing multiple questions (chapter 9) · Passing configuration and connection arguments while calling an external Python service.
- Relational database concepts (chapter 8) · Using SQL to fetch sales-data rows from Google BigQuery
Concepts explained in this chapter
- st.dialogst.dialog is a Streamlit decorator that presents a function's interface in a modal dialog and supports rerunning that dialog independently.
- drilldown viewA drilldown view is an interface view that presents detailed data for selected dimensions, metrics, or subsets of a broader summary.
- multiselectA multi-select option is a user-interface control that lets a user choose multiple values from a set of options.
- total rowA total row is a table row containing aggregate values for all records or groups represented in the table.
- conditional formattingA conditional formatting rule is a display rule that applies presentation changes when data satisfies a specified condition.
- parameterA query parameter is a named key-value item in a URL query string that conveys request information or application state.
- deep linkingA deep link is a URL that opens an application directly at a specific resource, view, or state.
- BigQueryBigQuery is a fully managed Google Cloud service for storing and analyzing large datasets with SQL.
- st.query_paramsst.query_params is Streamlit's dictionary-like interface for reading and updating the query parameters in an app's URL.
- date range comparisonA comparison date range is a date interval selected or calculated as the reference period for comparing a metric with its current-period value.
- sessionst.session_state is Streamlit's session-scoped state store for retaining values across reruns of an app session.
- widget keyA widget key is an identifier that distinguishes a Streamlit widget from other widgets, especially widgets with identical characteristics.
- dialog elementA modal dialog is an interface panel that temporarily blocks interaction with the underlying content until the dialog is completed or dismissed.
- st.containerst.container is a Streamlit layout function that creates a container whose contents can be populated and rendered separately from the surrounding code order.
- BigQuery APIA BigQuery client is a programmatic client object that provides methods and abstractions for interacting with BigQuery.
- BigQuery Storage APIThe BigQuery Storage API is Google's high-performance interface for reading BigQuery data into client applications.
- set differenceA delta is the difference between a metric's value in a main period and its value in a comparison period.
- st.metricst.metric is a Streamlit display function that presents a labeled metric value and optionally its change from a reference value.
- st.dataframest.dataframe is a Streamlit display function that renders tabular data in an interactive dataframe view.
- metric barA metric bar is a dashboard interface area that presents multiple metrics in a horizontal layout.
- credentialA credential is authentication information, such as an access key identifier and secret key, that authorizes access to a service.
- st.secretsst.secrets is Streamlit's dictionary-like interface for accessing application secrets and confidential configuration values.
- secrets.tomlsecrets.toml is a Streamlit configuration file that stores application secrets such as API keys outside source code.
- SQLA search query is a textual request specifying the items or information to retrieve from a search service.
- database tableA table is a relational data structure consisting of rows and columns that stores records about related entities.
- uriA URL is a standardized web address that identifies where a network resource or service can be accessed.
- dashboardA dashboard is an interface that presents selected metrics or other information for monitoring and decision-making.
- visualizationData visualization is the graphical representation of data to support exploration, interpretation, and communication.
- performanceA metric is a quantified measure used to describe or evaluate a phenomenon, process, or outcome.
- decoratorA decorator is a Python construct that modifies or extends a function or class by wrapping it with additional behavior.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
