Visualizing Item Analysis: Creating Interactive Plots for Educational Assessments

R Psychometric

In this post, I demonstrate how to create interactive item analysis plots for educational assessments using R packages.

(5 min read)


Published

Jan. 11, 2025

Citation

Wongvorachan, 2025


Introduction

Show code
datatable(df, options = list(pageLength = 10))
Show code
# Subset Non-French
df_non_french <- df %>% filter(language == "Non-French")

# Subset French
df_french <- df %>% filter(language == "French")

# Subset Field Test Item
df_field_test <- df %>% filter(item_type == "field test")

# Subset Operational Item
df_operational <- df %>% filter(item_type == "operational")

All Data Points

Show code
# Define color mapping
flag_colors <- c("Good" = "green", "Caution" = "orange", "Poor" = "red")

# Create ggplot
p <- ggplot(df, aes(x = Discrimination, y = Difficulty, color = flag)) +
  geom_point(size = 1, aes(text = paste("Item:", Item,
                                        "<br>N:", N,
                                        "<br>Language:", language,
                                        "<br>Item Type:", item_type))) +
  geom_vline(xintercept = 0.20, linetype = "dashed", color = "blue") +
  geom_hline(yintercept = 0.50, linetype = "dashed", color = "blue") + 
  scale_color_manual(values = flag_colors) +
  labs(title = "Difficulty vs. Discrimination (all)",
       x = "Discrimination",
       y = "Difficulty") +
  theme_minimal()

# Convert ggplot to plotly
ggplotly(p)
-1.0-0.50.00.50.250.500.751.00
flagCautionGoodPoorDifficulty vs. Discrimination (all)DiscriminationDifficulty

Language

Non-French

Show code
# Create ggplot
p <- ggplot(df_non_french, aes(x = Discrimination, y = Difficulty, color = flag)) +
  geom_point(size = 1, aes(text = paste("Item:", Item,
                                        "<br>N:", N,
                                        "<br>Language:", language,
                                        "<br>Item Type:", item_type))) +
  geom_vline(xintercept = 0.20, linetype = "dashed", color = "blue") +
  geom_hline(yintercept = 0.50, linetype = "dashed", color = "blue") + 
  scale_color_manual(values = flag_colors) +
  labs(title = "Difficulty vs. Discrimination (Non-French)",
       x = "Discrimination",
       y = "Difficulty") +
  theme_minimal()

# Convert ggplot to plotly
ggplotly(p)
0.00.10.20.30.40.50.40.60.81.0
flagCautionGoodPoorDifficulty vs. Discrimination (Non-French)DiscriminationDifficulty

French

Show code
# Create ggplot
p <- ggplot(df_french, aes(x = Discrimination, y = Difficulty, color = flag)) +
  geom_point(size = 1, aes(text = paste("Item:", Item,
                                        "<br>N:", N,
                                        "<br>Language:", language,
                                        "<br>Item Type:", item_type))) +
  geom_vline(xintercept = 0.20, linetype = "dashed", color = "blue") +
  geom_hline(yintercept = 0.50, linetype = "dashed", color = "blue") + 
  scale_color_manual(values = flag_colors) +
  labs(title = "Difficulty vs. Discrimination (French)",
       x = "Discrimination",
       y = "Difficulty") +
  theme_minimal()

# Convert ggplot to plotly
ggplotly(p)
-1.0-0.50.00.50.250.500.751.00
flagCautionGoodPoorDifficulty vs. Discrimination (French)DiscriminationDifficulty

Item Type

Field Test Item

Show code
# Create ggplot
p <- ggplot(df_field_test, aes(x = Discrimination, y = Difficulty, color = flag)) +
  geom_point(size = 1, aes(text = paste("Item:", Item,
                                        "<br>N:", N,
                                        "<br>Language:", language,
                                        "<br>Item Type:", item_type))) +
  geom_vline(xintercept = 0.20, linetype = "dashed", color = "blue") +
  geom_hline(yintercept = 0.50, linetype = "dashed", color = "blue") + 
  scale_color_manual(values = flag_colors) +
  labs(title = "Difficulty vs. Discrimination (Field Test)",
       x = "Discrimination",
       y = "Difficulty") +
  theme_minimal()

# Convert ggplot to plotly
ggplotly(p)
-1.0-0.50.00.50.250.500.751.00
flagCautionGoodPoorDifficulty vs. Discrimination (Field Test)DiscriminationDifficulty

Operational Item

Show code
# Create ggplot
p <- ggplot(df_operational, aes(x = Discrimination, y = Difficulty, color = flag)) +
  geom_point(size = 1, aes(text = paste("Item:", Item,
                                        "<br>N:", N,
                                        "<br>Language:", language,
                                        "<br>Item Type:", item_type))) +
  geom_vline(xintercept = 0.20, linetype = "dashed", color = "blue") +
  geom_hline(yintercept = 0.50, linetype = "dashed", color = "blue") + 
  scale_color_manual(values = flag_colors) +
  labs(title = "Difficulty vs. Discrimination (Operational Item)",
       x = "Discrimination",
       y = "Difficulty") +
  theme_minimal()

# Convert ggplot to plotly
ggplotly(p)
0.20.30.40.50.60.40.60.81.0
flagCautionGoodPoorDifficulty vs. Discrimination (Operational Item)DiscriminationDifficulty

Concluding remark

Footnotes

    Reuse

    Text and figures are licensed under Creative Commons Attribution CC BY 4.0. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".

    Citation

    For attribution, please cite this work as

    Wongvorachan (2025, Jan. 12). Tarid Wongvorachan: Visualizing Item Analysis: Creating Interactive Plots for Educational Assessments. Retrieved from https://taridwong.github.io/posts/2025-01-12-cttplotly/

    BibTeX citation

    @misc{wongvorachan2025visualizing,
      author = {Wongvorachan, Tarid},
      title = {Tarid Wongvorachan: Visualizing Item Analysis: Creating Interactive Plots for Educational Assessments},
      url = {https://taridwong.github.io/posts/2025-01-12-cttplotly/},
      year = {2025}
    }