The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
This vignette walks through common dashboard scenarios that data scientists and Shiny developers encounter, showing how the BID framework transforms user experience while maintaining analytical rigor.
Each example includes:
You’re a data scientist at a SaaS company. Your stakeholders asked for “a dashboard that shows everything about user engagement.” Being thorough, you built exactly that.
# The "show everything" approach
ui_before <- navbarPage(
"User Engagement Analytics",
tabPanel(
"Overview",
fluidRow(
# 12 KPIs across the top
column(2, valueBoxOutput("dau")),
column(2, valueBoxOutput("wau")),
column(2, valueBoxOutput("mau")),
column(2, valueBoxOutput("retention")),
column(2, valueBoxOutput("churn")),
column(2, valueBoxOutput("ltv"))
),
fluidRow(
column(2, valueBoxOutput("sessions")),
column(2, valueBoxOutput("session_duration")),
column(2, valueBoxOutput("pages_per_session")),
column(2, valueBoxOutput("bounce_rate")),
column(2, valueBoxOutput("conversion")),
column(2, valueBoxOutput("revenue"))
),
# Multiple complex charts
fluidRow(
column(6, plotOutput("engagement_trend", height = "400px")),
column(6, plotOutput("cohort_analysis", height = "400px"))
),
fluidRow(
column(4, plotOutput("funnel_chart")),
column(4, plotOutput("retention_curve")),
column(4, plotOutput("ltv_distribution"))
)
),
tabPanel("Segments", "More detailed segmentation..."),
tabPanel("Cohorts", "Cohort analysis details..."),
tabPanel("Funnels", "Conversion funnel details..."),
tabPanel("Revenue", "Revenue analytics..."),
tabPanel("Product", "Product usage analytics...")
)
User feedback: “I can’t find what I’m looking for” and “It’s overwhelming”
What’s happening: - 12+ metrics compete for attention simultaneously - No clear hierarchy of importance - Users don’t know where to look first - Analysis paralysis from too many options
Let’s apply the systematic BID approach:
# Stage 1: Interpret - Understand the real user need
interpret_result <- bid_interpret(
central_question = "How is our user engagement trending, and what needs attention?",
data_story = list(
hook = "User engagement metrics are spread across multiple systems",
context = "Leadership needs quick insights for weekly business reviews",
tension = "Current dashboards take too long to interpret",
resolution = "Provide immediate key insights with drill-down capability"
),
user_personas = list(
list(
name = "Sarah (Product Manager)",
goals = "Quickly spot concerning trends and dive deeper when needed",
pain_points = "Too many metrics to process in limited meeting time",
technical_level = "Intermediate"
),
list(
name = "Mike (Executive)",
goals = "Understand overall health at a glance",
pain_points = "Gets lost in details when just needs the big picture",
technical_level = "Basic"
)
)
)
# Stage 2: Notice - Identify the specific problem
notice_result <- bid_notice(
previous_stage = interpret_result,
problem = "Users experience information overload with 12+ simultaneous metrics",
evidence = "User interviews show 80% struggle to prioritize information, average time-to-insight is 5+ minutes"
)
# Stage 3: Anticipate - Consider cognitive biases
anticipate_result <- bid_anticipate(
previous_stage = notice_result,
bias_mitigations = list(
attention_bias = "Use size and color to direct focus to most important metrics first",
choice_overload = "Implement progressive disclosure - show key metrics, hide advanced analytics until requested",
anchoring = "Lead with the most important business metric to set proper context"
)
)
# Stage 4: Structure - Organize for cognitive efficiency
structure_result <- bid_structure(previous_stage = anticipate_result)
# Stage 5: Validate - Ensure actionable insights
validate_result <- bid_validate(
previous_stage = structure_result,
summary_panel = "Executive summary highlighting key trends and required actions",
collaboration = "Enable commenting and sharing of specific insights",
next_steps = c(
"Focus on the primary engagement metric trend",
"Investigate any red-flag indicators",
"Use drill-down for detailed analysis only when needed"
)
)
# The BID-informed approach: Progressive disclosure with clear hierarchy
ui_after <- page_fillable(
theme = bs_theme(version = 5),
# Primary insight first (addresses anchoring bias)
layout_columns(
col_widths = c(8, 4),
# Key insight panel
card(
card_header(
"📈 Engagement Health Score",
class = "bg-primary text-white"
),
layout_columns(
value_box(
title = "Overall Score",
value = "87/100",
showcase = bs_icon("speedometer2", size = "2em"),
theme = "success",
p(
"↑ 5 points vs. last month",
style = "font-size: 0.9em; color: #666;"
)
),
div(
h5("Key Drivers", style = "margin-bottom: 10px;"),
tags$ul(
tags$li("DAU trending up (+12%)"),
tags$li("Retention stable (73%)"),
tags$li("⚠️ Session duration declining (-8%)")
)
)
)
),
# Action panel
card(
card_header("🎯 Focus Areas"),
div(
tags$div(
class = "alert alert-warning",
tags$strong("Attention needed:"),
br(),
"Session duration declining. Investigate user experience."
),
actionButton(
"investigate_sessions",
"Investigate Session Trends",
class = "btn btn-warning btn-sm"
)
)
)
),
# Secondary metrics (progressive disclosure)
card(
card_header(
div(
style = "display: flex; justify-content: space-between; align-items: center;",
span("📊 Detailed Metrics"),
actionButton(
"toggle_details",
"Show Details",
class = "btn btn-outline-secondary btn-sm"
)
)
),
# Hidden by default, shown on demand
conditionalPanel(
condition = "input.toggle_details % 2 == 1",
layout_columns(
col_widths = c(3, 3, 3, 3),
value_box("DAU", "45.2K", icon = "people"),
value_box("Retention", "73%", icon = "arrow-clockwise"),
value_box("Sessions", "2.1M", icon = "activity"),
value_box("Revenue", "$127K", icon = "currency-dollar")
),
# Charts appear only when details are requested
layout_columns(
col_widths = c(6, 6),
card(
card_header("Engagement Trend"),
plotOutput("engagement_trend_focused", height = "300px")
),
card(
card_header("Key Drivers Analysis"),
plotOutput("drivers_analysis", height = "300px")
)
)
)
)
)
Key improvements:
You’ve built a comprehensive sales dashboard that shows everything the sales team could possibly need. It’s technically perfect but nobody uses it.
ui_sales_before <- fluidPage(
titlePanel("Q4 Sales Performance Dashboard"),
# Massive filter section
sidebarLayout(
sidebarPanel(
dateRangeInput("date_range", "Date Range"),
selectInput("region", "Region", choices = regions, multiple = TRUE),
selectInput(
"product",
"Product Line",
choices = products,
multiple = TRUE
),
selectInput("salesperson", "Sales Rep", choices = reps, multiple = TRUE),
selectInput(
"customer_segment",
"Customer Segment",
choices = segments,
multiple = TRUE
),
selectInput(
"deal_size",
"Deal Size",
choices = deal_sizes,
multiple = TRUE
),
checkboxGroupInput("deal_stage", "Deal Stages", choices = stages),
numericInput("min_value", "Minimum Deal Value", value = 0),
numericInput("max_value", "Maximum Deal Value", value = 1000000),
radioButtons("currency", "Currency", choices = c("USD", "EUR", "GBP")),
actionButton("apply_filters", "Apply Filters", class = "btn-primary")
),
mainPanel(
tabsetPanel(
tabPanel(
"Summary",
fluidRow(
column(3, valueBoxOutput("total_revenue")),
column(3, valueBoxOutput("deal_count")),
column(3, valueBoxOutput("avg_deal_size")),
column(3, valueBoxOutput("win_rate"))
),
plotOutput("revenue_chart", height = "600px")
),
tabPanel("By Region", dataTableOutput("region_table")),
tabPanel("By Product", dataTableOutput("product_table")),
tabPanel("By Rep", dataTableOutput("rep_table")),
tabPanel("Pipeline", dataTableOutput("pipeline_table")),
tabPanel("Forecasting", plotOutput("forecast_chart"))
)
)
)
)
User feedback: “Takes forever to find what I need” and “I just export to Excel instead”
# Apply BID framework focusing on sales manager workflow
sales_interpret <- bid_interpret(
central_question = "What deals need my attention this week?",
data_story = list(
hook = "Sales managers spend 2+ hours weekly creating status reports",
context = "They need to quickly identify at-risk deals and top opportunities",
tension = "Current data requires extensive filtering and analysis",
resolution = "Provide intelligent prioritization with drill-down capability"
),
user_personas = list(
list(
name = "Jennifer (Regional Sales Manager)",
goals = "Identify at-risk deals, spot top opportunities, prepare for team meetings",
pain_points = "Too much filtering required to find actionable insights",
technical_level = "Intermediate"
)
)
)
sales_notice <- bid_notice(
previous_stage = sales_interpret,
problem = "Sales managers overwhelmed by filter complexity and data volume",
evidence = "Users spend average 15 minutes per session just setting up filters, 40% abandon before getting insights"
)
sales_anticipate <- bid_anticipate(
previous_stage = sales_notice,
bias_mitigations = list(
recency_bias = "Show deals by urgency, not just recent activity",
confirmation_bias = "Highlight both positive and concerning trends",
choice_overload = "Limit initial choices to most common use cases"
)
)
sales_structure <- bid_structure(previous_stage = sales_anticipate)
ui_sales_after <- page_navbar(
title = "Sales Command Center",
theme = bs_theme(version = 5, preset = "bootstrap"),
nav_panel(
"🚨 Needs Attention",
layout_columns(
# Immediate action items
card(
card_header(
"🔥 Urgent - Deals at Risk",
class = "bg-danger text-white"
),
card_body(
p("3 deals worth $340K need immediate attention"),
layout_columns(
col_widths = c(6, 6),
div(
h6("MegaCorp Deal - $180K"),
p(
"❌ No activity in 14 days",
style = "color: #dc3545; margin: 0;"
),
p("Owner: Mike Chen", style = "font-size: 0.9em; color: #666;")
),
div(
actionButton(
"view_megacorp",
"View Details",
class = "btn btn-sm btn-outline-danger"
),
actionButton(
"contact_mike",
"Contact Mike",
class = "btn btn-sm btn-danger"
)
)
)
)
),
# Opportunities
card(
card_header("⭐ Hot Opportunities", class = "bg-success text-white"),
card_body(
p("2 deals worth $280K ready to close"),
actionButton(
"view_opportunities",
"Review Opportunities",
class = "btn btn-success btn-sm"
)
)
)
),
# Smart filters (only show when needed)
conditionalPanel(
condition = "input.show_filters",
card(
card_header("🔍 Refine Focus"),
layout_columns(
col_widths = c(3, 3, 3, 3),
selectInput("quick_region", "Region", choices = c("All", regions)),
selectInput(
"quick_timeframe",
"Timeframe",
choices = c("This Week", "This Month", "This Quarter")
),
selectInput(
"quick_value",
"Deal Size",
choices = c("All", ">$50K", ">$100K", ">$250K")
),
actionButton(
"show_all_filters",
"More Filters...",
class = "btn btn-outline-secondary btn-sm"
)
)
)
)
),
nav_panel(
"📊 Performance",
layout_columns(
col_widths = c(4, 4, 4),
value_box(
"This Month",
"$1.2M",
"vs. $980K target (+22%)",
showcase = bs_icon("graph-up"),
theme = "success"
),
value_box(
"Pipeline Health",
"Strong",
"3.2x coverage ratio",
showcase = bs_icon("speedometer2"),
theme = "info"
),
value_box(
"Team Status",
"On Track",
"8 of 10 reps hitting quota",
showcase = bs_icon("people"),
theme = "success"
)
),
card(
card_header("📈 Key Trends"),
plotOutput("performance_trends", height = "400px")
)
),
nav_panel(
"🎯 Team Focus",
# Team-specific insights
p("Individual rep performance and coaching opportunities...")
)
)
Key improvements:
You’re monitoring application performance with detailed technical metrics. Your dashboard is perfect for engineers but executives get lost.
# Interpret stage: Understand different user needs
technical_interpret <- bid_interpret(
central_question = "How is our application performing and what needs attention?",
user_personas = list(
list(
name = "DevOps Engineer",
goals = "Identify performance bottlenecks and system issues",
pain_points = "Needs detailed metrics and historical trends",
technical_level = "Expert"
),
list(
name = "Engineering Manager",
goals = "Understand overall system health and team priorities",
pain_points = "Needs summary view but ability to drill down",
technical_level = "Advanced"
),
list(
name = "Executive",
goals = "Understand business impact of technical issues",
pain_points = "Technical details are overwhelming",
technical_level = "Basic"
)
)
)
# Adaptive interface based on user role
ui_technical_after <- page_sidebar(
sidebar = sidebar(
# Role selector affects entire interface
radioButtons(
"user_role",
"View Mode:",
choices = c(
"Executive Summary" = "executive",
"Management View" = "manager",
"Technical Details" = "engineer"
),
selected = "executive"
)
),
# Executive view: Business impact focus
conditionalPanel(
condition = "input.user_role == 'executive'",
h2("🟢 System Health: Good"),
layout_columns(
col_widths = c(6, 6),
card(
card_header("Business Impact"),
value_box(
"Service Availability",
"99.8%",
"Within SLA targets",
theme = "success"
),
value_box(
"User Experience",
"Good",
"Page loads < 2 seconds",
theme = "success"
)
),
card(
card_header("Action Items"),
div(
class = "alert alert-info",
"✅ No critical issues requiring immediate attention"
),
p("Next scheduled maintenance: Friday 2am")
)
)
),
# Manager view: Balance of summary and detail
conditionalPanel(
condition = "input.user_role == 'manager'",
layout_columns(
col_widths = c(3, 3, 3, 3),
value_box("Uptime", "99.8%", theme = "success"),
value_box("Response Time", "1.2s", theme = "success"),
value_box("Error Rate", "0.02%", theme = "success"),
value_box("Throughput", "15K/min", theme = "info")
),
card(
card_header("System Trends"),
plotOutput("system_trends", height = "300px")
),
card(
card_header("Team Alerts"),
p("2 minor alerts resolved this week"),
actionButton("view_alerts", "View Alert History")
)
),
# Engineer view: Full technical detail
conditionalPanel(
condition = "input.user_role == 'engineer'",
# Comprehensive technical metrics
tabsetPanel(
tabPanel("Performance", "Detailed performance metrics..."),
tabPanel("Infrastructure", "Server and database metrics..."),
tabPanel("Alerts", "Full alert history and configuration..."),
tabPanel("Logs", "System logs and debugging info...")
)
)
)
Key insight: Same data, different presentations based on user cognitive needs and technical expertise.
# ❌ Data-structure driven
ui_wrong <- tabPanel(
"Database Tables",
tabPanel("Users Table", dataTableOutput("users")),
tabPanel("Orders Table", dataTableOutput("orders")),
tabPanel("Products Table", dataTableOutput("products"))
)
# ✅ User-intent driven
ui_right <- tabPanel(
"Customer Insights",
card_body(
h4("What customers need your attention?"),
# Show actionable customer insights
)
)
# ❌ Everything visible at once
ui_dense <- fluidRow(
column(2, metric1),
column(2, metric2),
column(2, metric3),
column(2, metric4),
column(2, metric5),
column(2, metric6)
)
# ✅ Key information first, details on demand
ui_progressive <- div(
value_box("Key Metric", "Primary value"),
actionButton("show_details", "View Supporting Metrics"),
conditionalPanel(
condition = "input.show_details",
# Additional metrics here
)
)
Remember: The goal isn’t to become a UX expert, it’s to apply your analytical thinking to user experience and create more effective data products.
Use bid_concepts()
to explore behavioral science
principles, and check out the behavioral-science-primer
vignette for deeper understanding of the psychological principles behind
these improvements.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.