
Image by Editor | Midjourney
A real-time data dashboard helps display live information. It updates automatically and shows important data visually. Using R, we can build such dashboards with packages like shiny and shinydashboard. These tools help create interactive charts, tables, and filters.
In this article, we will learn how to build a real-time dashboard in R. We will also add useful features like data filters, CSV exports, and dark mode.
Setting Up the Development Environment
Before developing the dashboard, install the necessary R packages:
install.packages(c("shiny", "shinydashboard", "ggplot2", "DT", "dplyr"))
These packages serve the following purposes:
- shiny – Creates interactive web applications.
- shinydashboard – Provides a structured layout for dashboards.
- ggplot2 – Used for data visualization.
- DT – Displays interactive tables.
- dplyr – Helps in data manipulation.
Designing the User Interface (UI)
The User Interface (UI) is an important part of any Shiny app. It controls how users interact with the app. A good UI makes the app easy to use and look nice. It also improves functionality. In Shiny, we use dashboardPage() to arrange different parts of the UI.
library(shiny)
library(shinydashboard)
library(ggplot2)
library(DT)
# Define UI
ui <- dashboardPage(
dashboardHeader(title = "AirQuality Dashboard"),
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard"))
)
),
dashboardBody(
fluidRow(
box(title = "Real-Time Chart", status = "primary", solidHeader = TRUE, plotOutput("plot1", height = 300), width = 6),
box(title = "Live Data Table", status = "success", solidHeader = TRUE, DTOutput("table1"), width = 6)
)
)
)
Here are the UI elements explained:
- dashboardHeader(): Sets the title of the dashboard.
- dashboardSidebar(): Creates a navigation menu.
- menuItem(): Defines a clickable menu option.
- dashboardBody(): Contains UI elements like charts and tables.
- fluidRow(): Arranges components into a responsive layout.
- box(): Defines containers for visual elements such as charts and tables.
- plotOutput(): Displays a real-time plot.
- DT::dataTableOutput(): Renders an interactive table for displaying live data.
This code creates a Shiny dashboard that displays a real-time data visualization with a plot and a live data table.
Implementing the Server Logic
The server logic controls how the app processes data. It updates the user interface dynamically and works as the backend of the app. It responds to user inputs and creates visual outputs. We use the server function to handle real-time data. This helps process and show live updates in the dashboard.
# Define Server Logic
server <- function(input, output, session) {
# Fetch and update real-time data
reactive_data <- reactivePoll(5000, session,
checkFunc = function() { Sys.time() },
valueFunc = function() {
df <- airquality # Use the full airquality dataset
df$Timestamp <- Sys.time() # Add a timestamp column
return(df)
}
)
# Render the real-time line plot
output$plot1 <- renderPlot({
df <- reactive_data()
ggplot(df, aes(x = Timestamp, y = Temp)) + # Using Temp as the default y-axis variable
geom_line(color = "blue") +
theme_minimal() +
labs(title = "Air Quality Trends", x = "Timestamp", y = "Temperature")
})
# Render the interactive data table
output$table1 <- renderDT({
datatable(reactive_data(), options = list(pageLength = 10))
})
}
Here are the server elements explained:
- reactivePoll(): Polls data at a fixed interval.
- checkFunc(): Determines when the data needs to be refreshed.
- valueFunc(): Retrieves and processes the data.
- mutate(): Adds a timestamp column to the dataset.
- renderPlot(): Generates and updates a real-time line chart.
- renderDataTable(): Updates the interactive data table.
The code creates a Shiny server function that periodically updates a dataset, adds a timestamp, and displays it as both a line plot and an interactive data table.
Running the Dashboard
To launch the dashboard, use the following command:
shinyApp(ui, server)
This function initializes the Shiny app. It connects the UI and server to update and display data in real time. Running this command opens the dashboard in a browser. Users can see and interact with live data.

Enhancing a Real-Time Data Dashboard
To improve the functionality and user experience of your real-time data dashboard, you can add these extra features:
Adding User Input Filters
Make the dashboard interactive by adding filters. Use shinyWidgets to add controls. Sliders, dropdowns, and checkboxes help users filter data.
library(shiny)
library(shinydashboard)
library(ggplot2)
library(DT)
ui <- dashboardPage(
dashboardHeader(title = "Enhanced Real-Time Dashboard"),
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard"))
),
selectInput("variable", "Select Variable:", choices = c("Temp", "Wind")),
sliderInput("obs", "Number of Observations:", min = 5, max = 100, value = 50)
),
dashboardBody(
fluidRow(
box(title = "Filtered Real-Time Chart", status = "primary", plotOutput("plot1", height = 300)),
box(title = "Filtered Live Data Table", status = "success", DT::dataTableOutput("table1"))
)
)
)
server <- function(input, output, session) {
reactive_data <- reactivePoll(5000, session,
checkFunc = function() { Sys.time() },
valueFunc = function() {
df <- airquality[1:input$obs, ]
df$Timestamp <- Sys.time()
return(df)
}
)
output$plot1 <- renderPlot({
df <- reactive_data()
ggplot(df, aes_string(x = "Timestamp", y = input$variable)) +
geom_line(color = "blue") +
theme_minimal()
})
output$table1 <- DT::renderDataTable({
reactive_data()
})
}
shinyApp(ui, server)

Exporting Data to CSV
Allow users to export data as a CSV file. This helps in saving and sharing data easily. Use downloadButton() in UI and downloadHandler() in the server. Users can click a button to download filtered data. This makes the dashboard more useful.
library(shiny)
library(DT)
ui <- fluidPage(
DTOutput("table"),
downloadButton("downloadData", "Download CSV")
)
server <- function(input, output) {
reactive_data <- reactive({
df <- airquality
df$Timestamp <- Sys.time()
return(df)
})
output$table <- renderDT({
reactive_data()
})
output$downloadData <- downloadHandler(
filename = function() { paste("real_time_data", Sys.Date(), ".csv", sep = "") },
content = function(file) {
write.csv(reactive_data(), file, row.names = FALSE)
}
)
}
shinyApp(ui, server)

Adding Dark Mode Theme
Add a dark mode to improve user experience. Use shinythemes or custom CSS for dark mode. Let users switch between light and dark themes.
library(shiny)
library(shinydashboard)
library(ggplot2)
library(DT)
library(shinythemes)
ui <- dashboardPage(
skin = "black", # Dark mode
dashboardHeader(title = "Dark Mode AirQuality Dashboard"),
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard"))
),
selectInput("variable", "Select Variable:", choices = c("Temp", "Wind", "Ozone")),
sliderInput("obs", "Number of Observations:", min = 5, max = nrow(airquality), value = 50)
),
dashboardBody(
tags$head(tags$link(rel = "stylesheet", href = "https://cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/css/bootstrap-dark.min.css")),
fluidRow(
box(title = "Filtered Real-Time Chart", status = "primary", solidHeader = TRUE, plotOutput("plot1", height = 300), width = 6),
box(title = "Filtered Live Data Table", status = "success", solidHeader = TRUE, DTOutput("table1"), width = 6)
),
fluidRow(
downloadButton("downloadData", "Download CSV", class = "btn btn-light")
)
)
)
server <- function(input, output, session) {
reactive_data <- reactivePoll(5000, session,
checkFunc = function() { Sys.time() },
valueFunc = function() {
df <- airquality[1:input$obs, ]
df$Timestamp <- Sys.time()
return(df)
}
)
output$plot1 <- renderPlot({
df <- reactive_data()
ggplot(df, aes_string(x = "Timestamp", y = input$variable)) +
geom_line(color = "cyan") +
theme_minimal(base_family = "Arial") +
theme(plot.background = element_rect(fill = "black"), panel.background = element_rect(fill = "black"),
text = element_text(color = "white"), axis.text = element_text(color = "white"))
})
output$table1 <- renderDT({
datatable(reactive_data(), options = list(dom = 't', pageLength = 10), class = "display dark-table")
})
output$downloadData <- downloadHandler(
filename = function() { paste("real_time_airquality", Sys.Date(), ".csv", sep = "") },
content = function(file) {
write.csv(reactive_data(), file, row.names = FALSE)
}
)
}
shinyApp(ui, server)

Conclusion
Dashboard helps visualize and interact with live data. We combined data sources, processing, and visuals for real-time updates.
First, we set up the environment and designed the UI. Then, we built the server logic to handle updates. We added filters, alerts, CSV exports, and dark mode. These features improved usability and functionality.
Now, try adding your custom features. Experiment and make your dashboard even better!
