Otter Tail County Dashboard

About

About This Dashboard

The Otter Tail County Family Service Collaborative has been working together, serving families, and improving lives for nearly 30 years. Collaborative partners believe data matters as we work together for a responsive, flexible system of education and on support and services that focus positively on the needs, strengths, and potential of each child and family.

This data dashboard points to demographic groups that are currently experiencing success just as it helps the Collaborative focus on groups who are not yet thriving. The dashboard has the following metrics for Ottertail County overall and school districts within Otter Tail County:

  • Student Data: Student data around enrollment count and percentage, consistent attendance, discipline, and primary language.
  • Student Achievement: Student proficiency rates on the math and reading MCAs.
  • Graduation Rates: Four, five, six, and seven-year graduation rates.
  • Teacher Data: Teacher assignment by licensure type, teacher racial/ethnic demographic, teacher experience, and teacher highest educational attainment levels.
  • U.S. Census: Includes data around educational attainment, health insurance, labor force participation, median property value, median household income levels, and marital status.

To learn more about the Otter Tail Family Services Collaborative, visit us here.


About the Data

The data for this dashboard was gathered from publicly available data sources:

  • The Minnesota Department of Education (MDE): Data for student enrollment, consistent attendance, discipline, primary language, student achievement, and graduation rates were gathered from the Minnesota Department of Education’s data center.
  • The American Community Survey: Data for educational attainment, health insurance, labor force participation, median property value, median household income levels, and marital status were gathered from the U.S. Census Bureau’s American Community Survey.
  • The Professional Educator Licensing and Standards Board (PELSB): Data for teacher assignment by licensure type, teacher racial/ethnic demographic, teacher experience, and teacher highest educational attainment levels came from the Professional Educator Licensing and Standards Board.

Colophon

Author:


Questions? Send us an email!

  • Originally published January 18, 2024

Student Enrollment - Count

Column

ottertail_enroll_fy1823_long <- read_csv("data/processed_data/ottertail_enroll_fy1823_long_use.csv")
Rows: 924 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): district, demographic, year
dbl (1): enrollment

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(

  sidebarLayout(
    sidebarPanel(
      selectInput("district", "Select District:", choices = unique(ottertail_enroll_fy1823_long$district)),
      selectInput("demographic", "Select Demographic:", choices = unique(ottertail_enroll_fy1823_long$demographic))
    ),

    mainPanel(
      plotlyOutput("lineChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    ottertail_enroll_fy1823_long %>%
      filter(district == input$district, demographic == input$demographic)
  })

  # Create the interactive Plotly line chart
  output$lineChart <- renderPlotly({
    filtered_data_df <- filtered_data()

    plot_ly(data = filtered_data_df, x = ~year, y = ~enrollment, type = 'scatter', mode = 'lines+markers',
            text = ~paste("Year: ", year, "<br>",
                          "Enrollment: ", enrollment),
            hoverinfo = 'text',
             marker = list(color = '#212B46', width = 1)) %>%
      layout(
        title = paste("Enrollment Trends for", input$demographic, "in", input$district),
        xaxis = list(title = 'Year'),
        yaxis = list(title = 'Enrollment'),
        config = list(displayModeBar = TRUE),  # Enable mode bar
        autosize = TRUE,  # Disable autosizing
        textfont = list(size = 12),  # Adjust text size within the points
        showlegend = FALSE  # Hide legend for a cleaner look
      )
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Column

During the 2022-2023, there were 870,019 students enrolled in Minnesota public schools

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
total_actions <- sum(mn_data$mn_total_enroll)

# Render value box
valueBox(
  value = format(total_actions, big.mark = ",", scientific = FALSE),
  color = "lightblue"
)
870,019

About the Student Enrollment Data

The Minnesota Department of Education annually collects unduplicated counts of students reported as enrolled on October 1. Public school enrollment counts are disaggregated by schools, district, county, and statewide.

Student Enrollment - Percent

Column

# Load your data
ottertail_pct_fy1823 <- read.csv("data/processed_data/ottertail_pct_fy1823_use.csv")

# Define UI
ui <- fluidPage(

  sidebarLayout(
    sidebarPanel(
      selectInput("demographic", "Select Demographic:", choices = unique(ottertail_pct_fy1823$demographic)),
      selectInput("district", "Select District:", choices = unique(ottertail_pct_fy1823$district))
    ),

    mainPanel(
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    ottertail_pct_fy1823 %>%
      filter(demographic == input$demographic, district == input$district)
  })

             
  # Create the interactive Plotly bar chart
  output$barChart <- renderPlotly({
    filtered_data_df <- filtered_data()

    plot_ly(data = filtered_data_df, x = ~year, y = ~percent, type = 'bar',
            text = ~paste("Year: ", year, "<br>",
                          "Percent: ", paste0(round(percent * 100, 1), "%")),
            hoverinfo = 'text',
             marker = list(color = '#212B46', width = 1)) %>%
      layout(
        title = paste("Student Percentage Trends for", input$demographic, "in", input$district),
        xaxis = list(title = 'Year'),
        yaxis = list(title = 'Percentage', tickformat = ',.1%'),
        config = list(displayModeBar = TRUE),  # Enable mode bar
        autosize = TRUE,  # Disable autosizing
        textfont = list(size = 12),  # Adjust text size within the bars
        bargap = 0.05  # Adjust the gap between bars for better visibility
      )
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Column

During the 2022-2023, 37.7% of Minnesota public school students identified as students of color.

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
total_actions <- sum(mn_data$mn_bipoc_student_pct)

# Render value box
valueBox(
  value = paste0(format(total_actions * 100, big.mark = ",", scientific = FALSE), "%"),
  color = "lightblue"
)
37.7%

About the Student Enrollment Data

The Minnesota Department of Education annually collects unduplicated counts of students reported as enrolled on October 1. Public school enrollment counts are disaggregated by schools, district, county, and statewide.

Consistent Attendance

Column

ottertail_district_chronic_absenteeism_fy1819 <- read_csv("data/processed_data/ottertail_district_chronic_absenteeism_fy1819.csv")
Rows: 116 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): year, district, student_group
dbl (1): percent

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(ottertail_district_chronic_absenteeism_fy1819$district)),
      selectInput("student_group", "Select Student Group:", choices = unique(ottertail_district_chronic_absenteeism_fy1819$student_group))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {
  
  # Filter data based on selected inputs
  filtered_data <- reactive({
    ottertail_district_chronic_absenteeism_fy1819 |>
      filter(district == input$district, student_group == input$student_group)
  })
  
  # Create the interactive Plotly bar chart
  output$barChart <- renderPlotly({
    filtered_data_df <- filtered_data()
    
    plot_ly(data = filtered_data_df, x = ~year, y = ~percent, type = 'bar',
            text = ~paste("Year: ", year, "<br>",
                           "Percent: ", paste0(round(percent * 100, 1), "%")),
            hoverinfo = 'text',
             marker = list(color = '#212B46', width = 1)) %>%
      layout(
        title = paste("Chronic Absenteeism Trends for", input$student_group, "in", input$district),
        xaxis = list(title = 'Year'),
        yaxis = list(title = 'Percentage', tickformat = ',.1%'),  # Format y-axis as percentage
        config = list(displayModeBar = TRUE),  # Enable mode bar
        autosize = TRUE,  # Disable autosizing
        textfont = list(size = 12),  # Adjust text size within the bars
        bargap = 0.05  # Adjust the gap between bars for better visibility
      )
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Column

During the 2022-2023, 68.9% of Minnesota public school students consistently attended school, meaning they attended 90% or more of the school days.

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
total_actions <- sum(mn_data$consistent_attendance_pct)

# Render value box
valueBox(
  value = paste0(format(total_actions * 100, big.mark = ",", scientific = FALSE), "%"),
  color = "lightblue"
)
69.8%

About Consistent Attendance Data

The Minnesota Department of Education includes consistent attendance in their federal Every Student Succeeds Act (ESSA) accountability plan. Under the Minnesota Department of Education’s definition, a student will be considered to be consistently attending school if they attend more than 90 percent of school days. Consistent attendance is the opposite of chronic absenteeism, which is defined as missing at least 10 percent of school days (the equivalent of missing one day out of every two traditional school weeks).

There are only 2 years of consistent attendance data due to the COVID-19 pandemic. There were validity concerns with the attendance data when schools shut down and transitioned to virtual learning.

Discipline Data

Column

# Discipline data 
ottertail_discipline_join <- read_csv("data/processed_data/ottertail_discipline_join.csv")
Rows: 43 Columns: 12
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): district, year
dbl (10): indigenous_enroll, asian_enroll, black_enroll, latino_enroll, whit...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Disciplinary districts 
districts_discipline <- unique(ottertail_discipline_join$district)

# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
           selectInput("district", "Select District:", choices = districts_discipline), 
           selectInput("action_type", "Select Action Type:", choices = c("Total Actions", "White Discipline Actions", "BIPOC Discipline Actions"))
    ),
    column(
      9,
      div(
        style = "display: flex; align-items: center; justify-content: center;",
        plotlyOutput("disciplinaryPlot")
      )
    )
  )
)

# Define server logic
server <- function(input, output) {
  
  # Filter data based on selected district
  filtered_data <- reactive({
    ottertail_discipline_join |>
      filter(district == input$district)
  })
  
  # Create the Plotly chart
  output$disciplinaryPlot <- renderPlotly({
    data <- filtered_data()
    
    if (input$action_type == "Total Actions") {
      # Total disciplinary actions bar chart
      total_actions_chart <- plot_ly(data = data, x = ~year, y = ~total_enroll, type = 'bar',
                                     name = 'Total Disciplinary Actions',
                                     text = ~paste("Year: ", year, "<br>",
                                                   "Total Actions: ", total_enroll),
                                     hoverinfo = 'text',
                                     marker = list(color = '#212B46')) |>
        layout(barmode = 'relative', title = paste("Total Disciplinary Actions for", input$district),
               xaxis = list(title = "Year"), yaxis = list(title = "Total Disciplinary Actions"))
      
      total_actions_chart
    } else if (input$action_type == "White Discipline Actions") {
      # White discipline actions bar chart
      white_discipline_chart <- plot_ly(data = data, x = ~year, y = ~white_enroll, type = 'bar',
                                        name = 'White Discipline Actions',
                                        text = ~paste("Year: ", year, "<br>",
                                                      "White Actions: ", white_enroll, "<br>",
                                                      "Total Actions: ", total_enroll),
                                        hoverinfo = 'text',
                                        marker = list(color = '#212B46')) |>
        layout(barmode = 'relative', title = paste("White Discipline Actions for", input$district),
               xaxis = list(title = "Year"), yaxis = list(title = "White Discipline Actions"))
      
      white_discipline_chart
    } else {
      # BIPOC discipline actions bar chart
      bipoc_discipline_chart <- plot_ly(data = data, x = ~year, y = ~bipoc_total, type = 'bar',
                                        name = 'BIPOC Discipline Actions',
                                        text = ~paste("Year: ", year, "<br>",
                                                      "BIPOC Actions: ", bipoc_total, "<br>",
                                                      "Total Actions: ", total_enroll),
                                        hoverinfo = 'text',
                                        marker = list(color = '#212B46')) |>
        layout(barmode = 'relative', title = paste("BIPOC Discipline Actions for", input$district),
               xaxis = list(title = "Year"), yaxis = list(title = "BIPOC Discipline Actions"))
      
      bipoc_discipline_chart
    }
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Column

During the 2021-2022 school, there were 48,735 total disciplinary actions reported in Minnesota

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
total_actions <- sum(mn_data$disciplinary_actions)

# Render value box
valueBox(
  value = format(total_actions, big.mark = ",", scientific = FALSE),
  color = "lightblue"
)
48,735

About the Discipline Data

Public school districts self-report student disciplinary data through the Minnesota Department of Education’s electronic disciplinary incident reporting system (DIRS). The data summarize the disciplinary incident data for disciplinary actions (suspensions, exclusions and expulsions). Due to COVID-19, there was a decrease in the number of reported disciplinary incidents and disciplinary actions during the 2019-20 and 2020-21 school years. Trends and analyses with 2019-20 and 2020-21 discipline data should be interpreted with caution.

All discipline data was gathered from the Minnesota Department of Education’s Data Center.

Primary Language Data

Primary Language by District and Overall for Otter Tail County, FY18 to FY23

# Read primary language data
primary_language_data <- read_csv("data/processed_data/fy1823_primary_language.csv") %>%
  select(year, district, primary_language, primary_language_enroll)
Rows: 548 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): district, primary_language, year
dbl (1): primary_language_enroll

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Unique districts and years
districts <- unique(primary_language_data$district)
years <- unique(primary_language_data$year)

# Define UI
ui <- fluidPage(
  titlePanel("Primary Language Data, FY18 to FY23"),
  fluidRow(
    column(
      width = 8, # Adjust the width here
      selectInput("selected_district", "Select District:", choices = districts, selected = districts[1]),
      br(),
      DTOutput("language_table")
    )
  )
)

# Define server logic
server <- function(input, output) {
  
  # Filter data based on selected district
  filtered_data <- reactive({
    primary_language_data %>%
      filter(district == input$selected_district)
  })
  
output$language_table <- renderDT({
    datatable(filtered_data(), 
              options = list(
                scrollY = '300px' # Adjust the height here, e.g., '500px'
              ),
              filter = "top", # Place filters at the top of the table
              rownames = FALSE, # Remove row numbers
              colnames = c("Year", "District", "Primary Language", "Student Count")) # Rename columns as needed
})
}

# Run the application
shinyApp(ui = ui, server = server)

Reading MCA Proficiency

Column

# Reading proficiency data 
ottertail_proficient_reading_fy1823 <- read_csv("data/processed_data/ottertail_proficient_reading_fy1823.csv")
Rows: 256 Columns: 9
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): district, year, student_group
dbl (6): mca_total_test, meets_count, exceeds_count, does_not_meet_count, pa...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Reading districts 
district_reading_proficiency <- unique(ottertail_proficient_reading_fy1823$district)
student_groups <- unique(ottertail_proficient_reading_fy1823$student_group)

# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = district_reading_proficiency),
      selectInput("student_group", "Select Student Group:", choices = student_groups)
    ),
    column(9,
      plotlyOutput("mathPlot")
    )
  )
)



# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    ottertail_proficient_reading_fy1823 |>
      filter(district == input$district & student_group == input$student_group) 
  })

  # Create the interactive Plotly chart with reordered years
  output$mathPlot <- renderPlotly({
    filtered_data_ordered <- filtered_data() |>
      mutate(year = factor(year, levels = c("2017-2018", "2018-2019", "2020-2021", "2021-2022", "2022-2023")))

    plot_ly(filtered_data_ordered, x = ~year, y = ~pct_proficient, type = 'bar',
            marker = list(color = '#212B46', width = 1),
            hoverinfo = 'text',
            text = ~paste("Year: ", year, "<br>",
                          "Proficient: ", scales::percent(pct_proficient)),
            textposition = 'auto'  # Position text labels inside the bars automatically
    ) |>
      layout(
        title = paste("Reading Proficiency for", input$student_group, "in", input$district),
        xaxis = list(title = ''),  # Remove x-axis title
        yaxis = list(title = 'Reading Proficient', tickformat = ',.0%'),
        autosize = TRUE,  # Disable autosizing
        # margin = list(l = 50, r = 50, b = 50, t = 50, pad = 4),  # Set margins
        textfont = list(size = 4),  # Adjust text size within the bars
        bargap = 0.05  # Adjust the gap between bars)  # Adjust text size within the bars
      )
  })
}


# Run the application
shinyApp(ui = ui, server = server)

Column

During the 2022-2023 school year, 47.6% of all students in Minnesota were proficient on the Reading MCAs

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
proficiency_value <- sum(mn_data$mca_reading_pct)

# Render value box
valueBox(
  value = paste0(proficiency_value * 100, "%"),  # Add percent symbol
  color = "lightblue"
)
47.6%

About the MCA Reading Proficiency Data

Under the Every Student Succeeds Act (ESSA), Minnesota is required to administer an annual English Language Arts assessment in grades 3-8 and once in high school. To meet this federal requirement, Minnesota administers the Minnesota Comprehensive Assessments (MCAs), which are aligned to Minnesota’s academic standards. A few notes on the data:

  • For the 2019-2020 school year, the federal government provided an assessment waiver to states. Minnesota did not administer the MCAs because of the COVID-19 pandemic.

  • For the 2017-2018 school year, the Minnesota Department of Education data did not include the MCA data disaggregated by student groups.

All MCA data was gathered from the Minnesota Department of Education’s Data Center.

Math MCA Proficiency

Column

MCA Math Proficienc

# Reading proficiency data 
ottertail_proficient_math_fy1823 <- read_csv("data/processed_data/ottertail_proficient_math_fy1823.csv") 
Rows: 246 Columns: 9
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): district, year, student_group
dbl (6): mca_total_test, meets_count, exceeds_count, does_not_meet_count, pa...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Reading districts 
district_reading_proficiency <- unique(ottertail_proficient_math_fy1823$district)
student_groups <- unique(ottertail_proficient_math_fy1823$student_group)

# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = district_reading_proficiency),
      selectInput("student_group", "Select Student Group:", choices = student_groups)
    ),
    column(9,
      plotlyOutput("mathPlot")
    )
  )
)



# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    ottertail_proficient_math_fy1823 |>
      filter(district == input$district & student_group == input$student_group) 
  })

  # Create the interactive Plotly chart with reordered years
  output$mathPlot <- renderPlotly({
    filtered_data_ordered <- filtered_data() |>
      mutate(year = factor(year, levels = c("2017-2018", "2018-2019", "2020-2021", "2021-2022", "2022-2023")))

    plot_ly(filtered_data_ordered, x = ~year, y = ~pct_proficient, type = 'bar',
            marker = list(color = '#212B46', width = 1),
            hoverinfo = 'text',
            text = ~paste("Year: ", year, "<br>",
                          "Proficient: ", scales::percent(pct_proficient)),
            textposition = 'auto'  # Position text labels inside the bars automatically
    ) |>
      layout(
        title = paste("Math Proficiency for", input$student_group, "in", input$district),
        xaxis = list(title = ''),  # Remove x-axis title
        yaxis = list(title = 'Math Proficient', tickformat = ',.0%'),
        autosize = TRUE,  # Disable autosizing
        # margin = list(l = 50, r = 50, b = 50, t = 50, pad = 4),  # Set margins
        textfont = list(size = 4),  # Adjust text size within the bars
        bargap = 0.05  # Adjust the gap between bars)  # Adjust text size within the bars
      )
  })
}


# Run the application
shinyApp(ui = ui, server = server)

Column

During the 2022-2023 school year, 42.8% of all students in Minnesota were proficient on the Math MCAs

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
proficiency_value <- sum(mn_data$mca_math_pct)

# Render value box
valueBox(
  value = paste0(proficiency_value * 100, "%"),  # Add percent symbol
  color = "lightblue"
)
42.8%

About the MCA Math Proficiency Data

Under the Every Student Succeeds Act (ESSA), Minnesota is required to administer an annual Mathematics assessment in grades 3-8 and once in high school. To meet this federal requirement, Minnesota administers the Minnesota Comprehensive Assessments (MCAs), which are aligned to Minnesota’s academic standards. A few notes on the data:

  • For the 2019-2020 school year, the federal government provided an assessment waiver to states. Minnesota did not administer the MCAs because of the COVID-19 pandemic.

  • For the 2017-2018 school year, the Minnesota Department of Education data did not include the MCA data disaggregated by student groups.

All MCA data was gathered from the Minnesota Department of Education’s Data Center

Four-Year Graduation Rates

Column

# Graduation Rate data 
graduation_data <- read_csv("data/processed_data/ottertail_all_graduation_pct_use.csv") |>
  rename(student_group = demographic) 
Rows: 337 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): year, district, demographic
dbl (4): four_yr_pct, five_yr_pct, six_yr_pct, seven_yr_pct

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Reading districts 
district_grad_rate <- unique(graduation_data$district)
student_groups <- unique(graduation_data$student_group)

# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = district_grad_rate),
      selectInput("student_group", "Select Student Group:", choices = student_groups)
    ),
    column(9,
      plotlyOutput("mathPlot")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    graduation_data |>
      filter(district == input$district & student_group == input$student_group) 
  })

  # Create the interactive Plotly chart with reordered years
  output$mathPlot <- renderPlotly({
    filtered_data_ordered <- filtered_data() |>
      mutate(year = factor(year, levels = c("2017-2018", "2018-2019", "2020-2021", "2021-2022")))

    plot_ly(filtered_data_ordered, x = ~year, y = ~four_yr_pct, type = 'bar',
            marker = list(color = '#212B46', width = 1),
            hoverinfo = 'text',
            text = ~paste("Year: ", year, "<br>",
                          "4-Year Grad Rate: ", scales::percent(four_yr_pct)),
            textposition = 'auto'  # Position text labels inside the bars automatically
    ) |>
      layout(
        title = paste("Four-Year Graduation Rates for", input$student_group, "in", input$district),
        xaxis = list(title = ''),  # Remove x-axis title
        yaxis = list(title = 'Graduation Rates', tickformat = ',.0%'),
        autosize = TRUE,  # Disable autosizing
        textfont = list(size = 12),  # Adjust text size within the bars
        bargap = 0.05  # Adjust the gap between bars
      )
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Column

For the 2021-2022 school year, 83.6% of Minnesota’s students graduated in four years

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
grad_rate <- sum(mn_data$four_yr_grad_rate)

# Render value box
valueBox(
  value = paste0(grad_rate * 100, "%"),  # Add percent symbol
  color = "lightblue"
)
83.6%

About the Minnesota Graduation Data

Starting in 2012, Minnesota began using the federally-required “adjusted cohort graduation rate” model. This model follows students in a group, or a “cohort,” throughout high school and determines if they graduate within four, five, six or seven years. The four-year graduation rate shows the number of students graduating from high school within four years after entering grade nine. To determine this rate, we identify all students who entered ninth grade four years ago. The next step is to add in any students who moved into the school and subtract out any students who moved away. This adjusted number represents the total number of students who are eligible to graduate. The actual graduation rate is determined by dividing the total number of students who actually graduated by the number of those eligible to graduate.

All schools that serve 12th grade students receive a four-, five-, six- and seven-year graduation rate, including traditional high schools and alternative high schools. Schools must have at least 10 students in the graduating cohort to receive a graduation rate and have it displayed publicly on this page.

Five-Year Graduation Rates

Column

# Graduation Rate data 
five_yr_graduation_data <- read_csv("data/processed_data/ottertail_all_graduation_pct_use.csv") |>
  rename(student_group = demographic) 
Rows: 337 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): year, district, demographic
dbl (4): four_yr_pct, five_yr_pct, six_yr_pct, seven_yr_pct

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Reading districts 
district_grad_rate <- unique(five_yr_graduation_data$district)
student_groups <- unique(five_yr_graduation_data$student_group)

# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = district_grad_rate),
      selectInput("student_group", "Select Student Group:", choices = student_groups)
    ),
    column(9,
      plotlyOutput("mathPlot")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    five_yr_graduation_data |>
      filter(district == input$district & student_group == input$student_group) 
  })

  # Create the interactive Plotly chart with reordered years
  output$mathPlot <- renderPlotly({
    filtered_data_ordered <- filtered_data() |>
      mutate(year = factor(year, levels = c("2017-2018", "2018-2019", "2020-2021", "2021-2022")))

    plot_ly(filtered_data_ordered, x = ~year, y = ~five_yr_pct, type = 'bar',
            marker = list(color = '#212B46', width = 1),
            hoverinfo = 'text',
            text = ~paste("Year: ", year, "<br>",
                          "5-Year Grad Rate: ", scales::percent(five_yr_pct)),
            textposition = 'auto'  # Position text labels inside the bars automatically
    ) |>
      layout(
        title = paste("Five-Year Graduation Rates for", input$student_group, "in", input$district),
        xaxis = list(title = ''),  # Remove x-axis title
        yaxis = list(title = 'Graduation Rates', tickformat = ',.0%'),
        autosize = TRUE,  # Disable autosizing
        textfont = list(size = 12),  # Adjust text size within the bars
        bargap = 0.05  # Adjust the gap between bars
      )
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Column

For the 2021-2022 school year, 86.5% of Minnesota’s students graduated in five years

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
grad_rate <- sum(mn_data$five_yr_grad_rate)

# Render value box
valueBox(
  value = paste0(grad_rate * 100, "%"),  # Add percent symbol
  color = "lightblue"
)
86.5%

About the Minnesota Graduation Data

Starting in 2012, Minnesota began using the federally-required “adjusted cohort graduation rate” model. This model follows students in a group, or a “cohort,” throughout high school and determines if they graduate within four, five, six or seven years. The five-, six- and seven-year graduation rates show the number of students who graduated in four years added to the number of students who took additional time to earn sufficient credits or meet other graduation requirements and to receive a high school diploma from their district. These three extended year graduation rates are calculated in the same way as the four-year rate but instead determine the percentage of students graduating in five, six and seven years.

All schools that serve 12th grade students receive a four-, five-, six- and seven-year graduation rate, including traditional high schools and alternative high schools. Schools must have at least 10 students in the graduating cohort to receive a graduation rate and have it displayed publicly on this page.

Six-Year Graduation Rates

Column

# Graduation Rate data 
six_yr_graduation_data <- read_csv("data/processed_data/ottertail_all_graduation_pct_use.csv")  |>
  rename(student_group = demographic)
Rows: 337 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): year, district, demographic
dbl (4): four_yr_pct, five_yr_pct, six_yr_pct, seven_yr_pct

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Reading districts 
district_grad_rate <- unique(six_yr_graduation_data$district)
student_groups <- unique(six_yr_graduation_data$student_group)

# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = district_grad_rate),
      selectInput("student_group", "Select Student Group:", choices = student_groups)
    ),
    column(9,
      plotlyOutput("mathPlot")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    six_yr_graduation_data |>
      filter(district == input$district & student_group == input$student_group) 
  })

  # Create the interactive Plotly chart with reordered years
  output$mathPlot <- renderPlotly({
    filtered_data_ordered <- filtered_data() |>
      mutate(year = factor(year, levels = c("2017-2018", "2018-2019", "2020-2021", "2021-2022")))

    plot_ly(filtered_data_ordered, x = ~year, y = ~six_yr_pct, type = 'bar',
            marker = list(color = '#212B46', width = 1),
            hoverinfo = 'text',
            text = ~paste("Year: ", year, "<br>",
                          "6-Year Grad Rate: ", scales::percent(six_yr_pct)),
            textposition = 'auto'  # Position text labels inside the bars automatically
    ) |>
      layout(
        title = paste("Six-Year Graduation Rates for", input$student_group, "in", input$district),
        xaxis = list(title = ''),  # Remove x-axis title
        yaxis = list(title = 'Graduation Rates', tickformat = ',.0%'),
        autosize = TRUE,  # Disable autosizing
        textfont = list(size = 12),  # Adjust text size within the bars
        bargap = 0.05  # Adjust the gap between bars
      )
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Column

For the 2021-2022 school year, 87.9% of Minnesota’s students graduated in six years

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
grad_rate <- sum(mn_data$six_yr_grad_rate)

# Render value box
valueBox(
  value = paste0(grad_rate * 100, "%"),  # Add percent symbol
  color = "lightblue"
)
87.9%

About the Minnesota Graduation Data

Starting in 2012, Minnesota began using the federally-required “adjusted cohort graduation rate” model. This model follows students in a group, or a “cohort,” throughout high school and determines if they graduate within four, five, six or seven years. The five-, six- and seven-year graduation rates show the number of students who graduated in four years added to the number of students who took additional time to earn sufficient credits or meet other graduation requirements and to receive a high school diploma from their district. These three extended year graduation rates are calculated in the same way as the four-year rate but instead determine the percentage of students graduating in five, six and seven years.

All schools that serve 12th grade students receive a four-, five-, six- and seven-year graduation rate, including traditional high schools and alternative high schools. Schools must have at least 10 students in the graduating cohort to receive a graduation rate and have it displayed publicly on this page.

Seven-Year Graduation Rates

Column

# Graduation Rate data 
seven_yr_graduation_data <- read_csv("data/processed_data/ottertail_all_graduation_pct_use.csv")  |>
  rename(student_group = demographic)
Rows: 337 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): year, district, demographic
dbl (4): four_yr_pct, five_yr_pct, six_yr_pct, seven_yr_pct

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Reading districts 
district_grad_rate <- unique(seven_yr_graduation_data$district)
student_groups <- unique(seven_yr_graduation_data$student_group)

# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = district_grad_rate),
      selectInput("student_group", "Select Student Group:", choices = student_groups)
    ),
    column(9,
      plotlyOutput("mathPlot")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    seven_yr_graduation_data |>
      filter(district == input$district & student_group == input$student_group) 
  })

  # Create the interactive Plotly chart with reordered years
  output$mathPlot <- renderPlotly({
    filtered_data_ordered <- filtered_data() |>
      mutate(year = factor(year, levels = c("2017-2018", "2018-2019", "2020-2021", "2021-2022")))

    plot_ly(filtered_data_ordered, x = ~year, y = ~seven_yr_pct, type = 'bar',
            marker = list(color = '#212B46', width = 1),
            hoverinfo = 'text',
            text = ~paste("Year: ", year, "<br>",
                          "6-Year Grad Rate: ", scales::percent(seven_yr_pct)),
            textposition = 'auto'  # Position text labels inside the bars automatically
    ) |>
      layout(
        title = paste("Six-Year Graduation Rates for", input$student_group, "in", input$district),
        xaxis = list(title = ''),  # Remove x-axis title
        yaxis = list(title = 'Graduation Rates', tickformat = ',.0%'),
        autosize = TRUE,  # Disable autosizing
        textfont = list(size = 12),  # Adjust text size within the bars
        bargap = 0.05  # Adjust the gap between bars
      )
  })
}

# Run the application
shinyApp(ui = ui, server = server)

Column

For the 2021-2022 school year, 89.1% of Minnesota’s students graduated in seven years

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
grad_rate <- sum(mn_data$seven_yr_grad_rate)

# Render value box
valueBox(
  value = paste0(grad_rate * 100, "%"),  # Add percent symbol
  color = "lightblue"
)
89.1%

About the Minnesota Graduation Data

Starting in 2012, Minnesota began using the federally-required “adjusted cohort graduation rate” model. This model follows students in a group, or a “cohort,” throughout high school and determines if they graduate within four, five, six or seven years. The five-, six- and seven-year graduation rates show the number of students who graduated in four years added to the number of students who took additional time to earn sufficient credits or meet other graduation requirements and to receive a high school diploma from their district. These three extended year graduation rates are calculated in the same way as the four-year rate but instead determine the percentage of students graduating in five, six and seven years.

All schools that serve 12th grade students receive a four-, five-, six- and seven-year graduation rate, including traditional high schools and alternative high schools. Schools must have at least 10 students in the graduating cohort to receive a graduation rate and have it displayed publicly on this page.

Teacher Assignments

Column

# read in the data 

dashboard_teacher_assignment_fy2023 <- read_csv("data/processed_data/dashboard_teacher_assignment_fy2023.csv")
Rows: 220 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): year, district, licensure_type
dbl (1): count

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(dashboard_teacher_assignment_fy2023$district)),
      selectInput("licensure_type", "Teacher License:", choices = unique(dashboard_teacher_assignment_fy2023$licensure_type))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    dashboard_teacher_assignment_fy2023 |>
      filter(district == input$district, licensure_type == input$licensure_type)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~count, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Count: ", count),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) |>
    layout(
      title = paste("Teacher License:", input$licensure_type, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Count'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

During the 2022-2023 school year, 78.9% of all teachers in Minnesota held a Tier 4 license.

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
tier_4_rate <- sum(mn_data$tier_4_pct)

# Render value box
valueBox(
  value = paste0(tier_4_rate * 100, "%"),  # Add percent symbol
  color = "lightblue"
)
78.9%

About the Teacher Assignment Data

The Professional Educator Licensing and Standards Board (PELSB) collects and provides assignment data from the Staff Automated Reporting (STAR) report, which provides educator assignment and employment data as reported by each school district. Data from STAR is currently collected on an annual basis in the late fall or early winter.

The assignment data starts in the 2019-2020 school year because that is when the new, four-tiered license system was fully implemented in Minnesota.

Teacher Demographics

Column

# Load in the data
teacher_race_long <- read_csv("data/processed_data/teacher_race_long.csv")
Rows: 66 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): district, race, year
dbl (1): percentage

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(teacher_race_long$district)),
      selectInput("race", "Teacher Race:", choices = unique(teacher_race_long$race))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    teacher_race_long |>
      filter(district == input$district, race == input$race)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~percentage, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Percentage: ", paste0(round(percentage * 100, 1), "%")),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) %>%
    layout(
      title = paste("Teacher Race:", input$race, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Percentage', tickformat = ',.0%'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

During the 2022-2023 school year, 6.16% of teachers in Minnesota identified as a person of color

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
bipoc_pct <- sum(mn_data$bipoc_pct)

# Render value box
valueBox(
  value = paste0(bipoc_pct  * 100, "%"),  # Add percent symbol
  color = "lightblue"
)
6.16%

About the Teacher Race Data

The Professional Educator Licensing and Standards Board (PELSB) annually collects teacher racial data by employing districts in the Staff Automated Report (STAR). License applicants may also identify their race and/or ethnicity on their application. If this information is provided, it overrides the race/ethnicity data provided from the district in PELSB’s data tables. PELSB uses the following categories for race/ethnicity:

  • American Indiana/Alaskan Native: the federal definition includes persons having origins in any of the original peoples of Central, North, or South American and who maintains cultural identification through tribal affiliation or community recognition.
  • Asian: the federal definition includes persons having origins in any of the original peoples of the Far East, Southeast Asia, or the Indian subcontinent (including, but not limited to, Asian Indian, Burmese, Chinese, Filipino, Hmong, Karen, Korean, Vietnamese, etc.).
  • Black: the federal definition includes persons having origins in any of the black racial groups of Africa (including, but not limited to, African-American, Ethiopian, Oromo, Liberian, Nigerian, Somali, etc.)
  • Hispanic/Latinx: the federal definition includes persons of Mexican, Puerto Rican, Cuban, Central or South American or other Spanish culture or origin, regardless of race. Note: If a person identifies as Hispanic/Latinx, they are not counted in any other race/ethnicity categories.
  • Multiracial: a person who identifies belonging to more than one racial/ethnic group. Note: Individuals who select multiple racial/ethnic categories are counted as “multiracial” only in data reports.
  • Undeclared: no information provided.
  • White: the federal definition includes persons having origins in any of the original peoples of Europe, the Middle East, or North Africa.

Teacher Experience

Column

# Load in the data
teacher_experience_long <- read_csv("data/processed_data/teacher_experience_long.csv")
Rows: 264 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): district, experience, year
dbl (1): percentage

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(teacher_experience_long$district)),
      selectInput("experience", "Years Teaching:", choices = unique(teacher_experience_long$experience))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    teacher_experience_long |>
      filter(district == input$district, experience == input$experience)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~percentage, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Percentage: ", paste0(round(percentage * 100, 1), "%")),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) %>%
    layout(
      title = paste("Years Teaching:", input$experience, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Percentage', tickformat = ',.0%'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

During the 2022-2023 school year, Minnesota’s classroom teachers had an average of 12 years of experience

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
avg_yrs_classroom <- sum(mn_data$average_years_in_classroom)

# Render value box
valueBox(
  value = paste0(avg_yrs_classroom),  
  color = "lightblue"
)
12

About the Teacher Classroom Experience Data

The Professional Educator Licensing and Standards Board (PELSB) collects and provides assignment data from the Staff Automated Reporting (STAR) report, which provides educator assignment and employment data as reported by each school district. Data from STAR is currently collected on an annual basis in the late fall or early winter. The categories for years of experience are:

  • New Teacher: Less than one year of classroom experience
  • 1-5 Years: Has between 1-5 years of classroom experience
  • 6-10 Years: Has between 6-10 years of classroom experience
  • 11-15 Years: Has between 11-15 years of classroom experience
  • 16-20 Years: Has between 16-20 years of classroom experience
  • 21-25 Years: Has between 21-25 years of classroom experience
  • 26-30 Years: Has between 26-30 years of classroom experience
  • 31+ Years: Has 31 or more years of classroom experience

The assignment data starts in the 2019-2020 school year because that is when the new, four-tiered license system was fully implemented in Minnesota.

Teacher Educational Attainment

Column

# Load in the data
teacher_education_long <- read_csv("data/processed_data/teacher_education_long.csv")
Rows: 99 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): district, education_level, year
dbl (1): percentage

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(teacher_education_long$district)),
      selectInput("education_level", "Educational Attainment:", choices = unique(teacher_education_long$education_level))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    teacher_education_long |>
      filter(district == input$district, education_level == input$education_level)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~percentage, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Percentage: ", paste0(round(percentage * 100, 1), "%")),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) %>%
    layout(
      title = paste("Educational Attainment:", input$education_level, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Percentage', tickformat = ',.0%'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

During the 2022-2023 school year, 57.4% of Minnesota’s teachers had a master’s degree

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
masters_pct <- sum(mn_data$masters_pct)

# Render value box
valueBox(
  value = paste0(masters_pct  * 100, "%"),  
  color = "lightblue"
)
57.4%

About the Teacher Educational Attainment Data

The Professional Educator Licensing and Standards Board (PELSB) collects and provides assignment data from the Staff Automated Reporting (STAR) report, which provides educator assignment and employment data as reported by each school district. Data from STAR is currently collected on an annual basis in the late fall or early winter. The categories for highest level of educational attainment are:

  • Less than a Bachelor’s Degree
  • Bachelor’s Degree
  • Master’s Degree

The assignment data starts in the 2019-2020 school year because that is when the new, four-tiered license system was fully implemented in Minnesota.

Educational Attainment

Column

# read in the data 

educational_attainment_fy1722_long <- read_csv("data/processed_data/educational_attainment_fy1722_long.csv")
Rows: 324 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): district, education_level
dbl (2): year, percentage

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(educational_attainment_fy1722_long$district)),
      selectInput("education_level", "Select Education Level:", choices = unique(educational_attainment_fy1722_long$education_level))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    educational_attainment_fy1722_long %>%
      filter(district == input$district, education_level == input$education_level)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~percentage, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Percentage: ", paste0(round(percentage * 100, 1), "%")),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) %>%
    layout(
      title = paste("Education Level:", input$education_level, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Percentage', tickformat = ',.0%'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

In 2022, 24.9% of Minnesota residents had a bachelor’s degree

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
bachelors_pct <- sum(mn_data$bachleors_pct)

# Render value box
valueBox(
  value = paste0(bachelors_pct  * 100, "%"),  
  color = "lightblue"
)
24.9%

About the Educational Attainment Data

The American Community Survey (ACS) is administered by the U.S. Census Bureau and is a nationwide annual survey designed to provide communities with reliable and timely social, economic, housing, and demographic data every year. The educational attainment data provides information about the highest levels of education of the population that are 25 years or older. The categories are:

  • Less than a high school diploma or its equivalent
  • High school graduate
  • Some college, but didn’t complete a degree
  • Completed an associate’s degree
  • Completed a bachelor’s degree
  • Completed a graduate degree, like a master’s degree, professional degree, or a doctoral degree

Health Insurance

Column

# read in the data 

health_insurance_fy1722_long <- read_csv("data/processed_data/health_insurance_fy1722_long.csv")
Rows: 162 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): district, health_insurance
dbl (2): year, percentage

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(health_insurance_fy1722_long$district)),
      selectInput("health_insurance", "Select Health Insurance Status:", choices = unique(health_insurance_fy1722_long$health_insurance))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    health_insurance_fy1722_long %>%
      filter(district == input$district, health_insurance == input$health_insurance)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~percentage, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Percentage: ", paste0(round(percentage * 100, 1), "%")),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) %>%
    layout(
      title = paste("Health Insurance Status:", input$health_insurance, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Percentage', tickformat = ',.0%'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

In 2022, 95.1% of Minnesota residents had private or public health insurance

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
health_insurance <- sum(mn_data$health_insurance)

# Render value box
valueBox(
  value = paste0(health_insurance * 100, "%"),  
  color = "lightblue"
)
95.1%

About the Health Insurance Data

The American Community Survey (ACS) is administered by the U.S. Census Bureau and is a nationwide annual survey designed to provide communities with reliable and timely social, economic, housing, and demographic data every year. The health insurance data provides data on how many people have private or public health insurance, or who do not have any health insurance. The total percentage may exceed 100% for the following reasons:

  • Multiple Coverage: Individuals may have both private and public health insurance coverage simultaneously. For example, someone might have private health insurance through their employer and also qualify for public health insurance programs like Medicaid or Medicare.
  • Multiple Responses: In surveys, respondents may provide multiple responses or select more than one option when asked about their health insurance coverage. This can lead to double-counting in specific categories, contributing to the total health insurance coverage being higher than expected.
  • Underreporting or Misclassification: Respondents might underreport or misclassify their health insurance coverage due to misunderstanding survey questions or not accurately reflecting their actual coverage. This can lead to inconsistencies in the reported data.
  • Changes Over Time: Health insurance coverage can change throughout the year or over different survey periods. Individuals may switch between private and public insurance during the survey timeframe.
  • Data Processing Errors: Errors in data processing, coding, or data entry can contribute to discrepancies. Mistakes in categorizing responses or aggregating data may lead to inconsistencies in the reported figures.

Labor Force Participation

Column

# read in the data 

labor_force_fy1722_long <- read_csv("data/processed_data/dashboard_labor_force_fy1722_long.csv")
Rows: 108 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): district, employment_status
dbl (2): percentage, year

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(labor_force_fy1722_long$district)),
      selectInput("employment_status", "Employment Status:", choices = unique(labor_force_fy1722_long$employment_status))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    labor_force_fy1722_long |>
      filter(district == input$district, employment_status == input$employment_status)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~percentage, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Percentage: ", paste0(round(percentage * 100, 1), "%")),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) %>%
    layout(
      title = paste("Employment Status:", input$employment_status, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Percentage', tickformat = ',.0%'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

In 2022, 96% of Minnesota residents were employed

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

# Calculate total disciplinary actions
employment_pct <- sum(mn_data$employment_pct)

# Render value box
valueBox(
  value = paste0(employment_pct * 100, "%"),  
  color = "lightblue"
)
96%

About the Labor Force Participation Data

The American Community Survey (ACS) is administered by the U.S. Census Bureau and is a nationwide annual survey designed to provide communities with reliable and timely social, economic, housing, and demographic data every year. The labor force participation data provides information on the percentage of individuals who do or do not have employment.

Occupations

Column

# read in the data 

mn_occupations_fy1722_long <- read_csv("data/processed_data/dashboard_occupations_fy1722_long.csv")
Rows: 270 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): district, occupation_area
dbl (2): percentage, year

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(mn_occupations_fy1722_long$district)),
      selectInput("occupation_area", "Occupation:", choices = unique(mn_occupations_fy1722_long$occupation_area))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    mn_occupations_fy1722_long|>
      filter(district == input$district, occupation_area == input$occupation_area)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~percentage, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Percentage: ", paste0(round(percentage * 100, 1), "%")),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) %>%
    layout(
      title = paste("Occupation:", input$occupation_area, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Percentage', tickformat = ',.0%'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

In 2022, about two-fifths of Otter Tail Residents who are 16+ years of age had jobs in Management or Business.

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

management_business_pct <- sum(mn_data$management_business_pct)

# Render value box
valueBox(
  value = paste0(management_business_pct * 100, "%"),  
  color = "lightblue"
)
43.8%

About the Labor Force Occupations Data

The American Community Survey (ACS) is administered by the U.S. Census Bureau and is a nationwide annual survey designed to provide communities with reliable and timely social, economic, housing, and demographic data every year. The labor force occupation data provides information about which industry residents have employment. The five major categories are:

  • Management/Business: This code represents the percentage of individuals in the labor force working in occupations related to management, business, science, and arts fields.
  • Services: This code signifies the percentage of individuals in the labor force engaged in service occupations, which often include jobs like food service, healthcare support, cleaning, etc.
  • Sales/Office: This variable represents the percentage of individuals in the labor force working in sales and office-related occupations, including retail, administrative roles, etc.
  • Construction/Maintenance: This code signifies the percentage of individuals in the labor force engaged in occupations related to natural resources, construction, and maintenance, such as agriculture, construction work, and maintenance jobs.
  • Transportation: This code represents the percentage of individuals in the labor force working in production, transportation, and material moving occupations, which include manufacturing, transportation, and logistics roles.

Median Property Value

Column

# Load in the data 
all_mpv_fy1722 <- read_csv("data/processed_data/all_mpv_fy1722.csv")
Rows: 54 Columns: 3
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): district
dbl (2): year, mpv

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(all_mpv_fy1722$district))
    ),
    column(9,
      plotlyOutput("mpvbarChart")
    )
  )
)

# Define server logic
server <- function(input, output) {
  
  # Filter data based on selected district
  filtered_data <- reactive({
    all_mpv_fy1722 %>%
      filter(district == input$district)
  })
  
  # Create the interactive Plotly bar chart
  output$mpvbarChart <- renderPlotly({
    filtered_data_df <- filtered_data()
    
    plot_ly(data = filtered_data_df, x = ~year, y = ~mpv, type = 'bar',
            text = ~paste("Year: ", year, "<br>",
                          "MPV: $", scales::comma(mpv)),
            hoverinfo = 'text',
            marker = list(color = '#212B46')) %>%
      layout(
        title = paste("Median Property Value in", input$district),
        xaxis = list(title = 'Year'),
        yaxis = list(title = 'Median Property Value', tickprefix = '$'),
        showlegend = FALSE,
        textfont = list(size = 12),
        bargap = 0.05,
        autosize = TRUE,
        config = list(displayModeBar = TRUE)
      )
  })
}

# Run the app
shinyApp(ui = ui, server = server)

Column

In 2022, the median property value in Minnesota $286,800

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

mn_mpv <- sum(mn_data$mn_mpv)

formatted_value <- paste0("$", format(mn_mpv, big.mark = ",", scientific = FALSE))


# Render value box
valueBox(
  value = formatted_value,  
  color = "lightblue"
)
$286,800

About the Median Property Value Data

The American Community Survey (ACS) is administered by the U.S. Census Bureau and is a nationwide annual survey designed to provide communities with reliable and timely social, economic, housing, and demographic data every year. The median property value data provides information on only owner-occupied units, which are defined as one-family houses on less than 10 acres without a business or medical office on the property. These data exclude mobile homes, houses with a business or medical office, houses on 10 or more acres, and housing units in multi-unit structures. A unit is owner-occupeed if the owner or co-owner lives in the unit, even if it is mortgaged or not fully paid for.

The median divides the value distribution into two equal parts: one-half of the cases falling below the median value of the property (house and lot) and one-half above the median. Median value calculations are rounded to the nearest hundred dollars.

Median Household Income

Column

# read in the data 

mhi_dashboard <- read_csv("data/processed_data/mhi_dashboard.csv")
Rows: 54 Columns: 3
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): district
dbl (2): year, mhi

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(mhi_dashboard$district))
    ),
    column(9,
      plotlyOutput("mhibarChart")
    )
  )
)

# Define server logic
server <- function(input, output) {
  
  # Filter data based on selected district
  filtered_data <- reactive({
    mhi_dashboard %>%
      filter(district == input$district)
  })
  
  # Create the interactive Plotly bar chart
  output$mhibarChart <- renderPlotly({
    filtered_data_df <- filtered_data()
    
    plot_ly(data = filtered_data_df, x = ~year, y = ~mhi, type = 'bar',
            text = ~paste("Year: ", year, "<br>",
                          "MHI: $", scales::comma(mhi)),
            hoverinfo = 'text',
            marker = list(color = '#212B46')) %>%
      layout(
        title = paste("Median Household Income in", input$district),
        xaxis = list(title = 'Year'),
        yaxis = list(title = 'Median Household Income', tickprefix = '$'),
        showlegend = FALSE,
        textfont = list(size = 12),
        bargap = 0.05,
        autosize = TRUE,
        config = list(displayModeBar = TRUE)
      )
  })
}

# Run the app
shinyApp(ui = ui, server = server)

Column

In 2022, the median household income in Minnesota was $84,313

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

mn_mhi <- sum(mn_data$mn_mhi)

formatted_value <- paste0("$", format(mn_mhi,  big.mark = ",", scientific = FALSE))


# Render value box
valueBox(
  value = formatted_value,  
  color = "lightblue"
)
$84,313

About the Median Household Income Data

The American Community Survey (ACS) is administered by the U.S. Census Bureau and is a nationwide annual survey designed to provide communities with reliable and timely social, economic, housing, and demographic data every year. The median household income refers to the midpoint value of household incomes in a specified geographic (e.g. city, county or state) region over a specific period of time (usually one year).

The median household income is often used as a measure of the economic well-being of an area’s residents. It provides a central tendency value that isn’t influenced by extremely high or low incomes, unlike the mean (average) household income, which can be skewed by outliers.

Marital Status

Column

# read in the data 

marital_status_fy1722_long <- read_csv("data/processed_data/dashboard_marital_status_fy1722_long.csv")
Rows: 270 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): district, marital_status
dbl (2): percentage, year

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Define UI
ui <- fluidPage(
  fluidRow(
    column(3,
      selectInput("district", "Select District:", choices = unique(marital_status_fy1722_long$district)),
      selectInput("marital_status", "Marital Status:", choices = unique(marital_status_fy1722_long$marital_status))
    ),
    column(9,
      plotlyOutput("barChart")
    )
  )
)

# Define server logic
server <- function(input, output) {

  # Filter data based on selected inputs
  filtered_data <- reactive({
    marital_status_fy1722_long |>
      filter(district == input$district, marital_status == input$marital_status)
  })

  # Create the interactive Plotly bar chart
output$barChart <- renderPlotly({
  filtered_data_df <- filtered_data()

  plot_ly(data = filtered_data_df, x = ~year, y = ~percentage, type = 'bar',
          text = ~paste("Year: ", year, "<br>",
                        "Percentage: ", paste0(round(percentage * 100, 1), "%")),
          hoverinfo = 'text',
          marker = list(color = '#212B46')) %>%
    layout(
      title = paste("Marital Status:", input$marital_status, "in", input$district),
      xaxis = list(title = 'Year'),
      yaxis = list(title = 'Percentage', tickformat = ',.0%'), # Display percentages
      config = list(displayModeBar = TRUE),  # Enable mode bar
      autosize = TRUE,  # Disable autosizing
      textfont = list(size = 12),  # Adjust text size within the bars
      bargap = 0.05)  # Adjust the gap between bars)  # Adjust text size here
    
})
}

# Run the app
shinyApp(ui = ui, server = server)

Column

In 2022, half of Minnesota residents were currently married.

mn_data <- read_excel("data/processed_data/Minnesota data for Otter Tail.xlsx")

married_pct <- sum(mn_data$married_pct)

# Render value box
valueBox(
  value = paste0(married_pct * 100, "%"),  
  color = "lightblue"
)
51%

About the Marital Status Data

The American Community Survey (ACS) is administered by the U.S. Census Bureau and is a nationwide annual survey designed to provide communities with reliable and timely social, economic, housing, and demographic data every year. The marital status data refers to the legal relationship status of individuals in terms of their marriage or partnership. The five categories are:

  • Never Married: Individuals who have never been legally married or are not currently in a marriage or a legal union.
  • Married: Individuals who are legally married and not separated or divorced.
  • Separated: Individuals who are legally married but living apart from their spouse due to reasons other than divorce. Separation can be temporary or lead to divorce.
  • Divorced: Individuals whose marriage has legally ended through divorce or dissolution.
  • Widowed: Individuals whose spouse has passed away, and they have not remarried.