Skip to contents

Most people who need IRT results never open R: teachers who want to know which questions worked, a client who commissioned a survey, a committee reviewing a test form, or students in a measurement course. A results dashboard gives them the findings in a form they can explore on their own.

mirtverse has three ways to look at an analysis, each for a different reader:

Tool What it is for Who uses it
Workbench (launch_workbench()) Doing an analysis: load data, fit and compare models, score people You, the analyst
Report (mv_report()) A complete, static record of the analysis Reviewers, appendices, archives
Dashboard (mv_dashboard()) Exploring finished results: click items, move a slider, look someone up People who do not use R

Open a live example dashboard. It is a single HTML file built from the code below, so it runs in your browser with nothing installed.

Build a dashboard in one line

Fit a model as usual and pass it to mv_dashboard():

library(mirtverse)

data <- key2binary(SAT12, key = c(1,4,5,2,3,1,2,1,3,1,2,4,2,1,5,3,4,4,1,4,3,3,
                                  4,1,3,5,1,3,1,5,4,5))
mod <- mirt(data, 1, verbose = FALSE)

mv_dashboard(mod, title = "SAT12 results",
             subtitle = "A 32-item science test, scored 0/1 (N = 600)")

The dashboard opens in your browser. The model can be any unidimensional mirt() model, or the result of select_model(), in which case the recommended model is shown. Assign the result (app <- mv_dashboard(...)) to keep it without opening it.

The summary panel: headline numbers and the plain-language interpretation.
The summary panel: headline numbers and the plain-language interpretation.

The summary panel puts the numbers people ask for first at the top: respondents, items, reliability and how many items need review. The text below them is the same plain-language summary you get from interpret(), so a reader does not need to know what an M2 statistic is to understand the results.

The panels

Choose the panels you need with panels, in the order you want them:

Panel What it shows
"summary" Respondents, items, reliability and items to review, with the plain-language interpretation and model details
"items" The item table with a traffic-light status; select a row to see that item’s health card
"curves" Trace curves for chosen items, with an ability slider that reads off the response probabilities
"information" Test information and standard error, and item information curves
"wright" The Wright map of people and items on one scale
"scores" The distribution of ability estimates and the sum-score conversion table
"persons" A searchable table of each person’s score, standard error and percentile (off by default)
"dif" Differential item functioning results from dif()
"rt" Response-time results from fit_rt()

By default you get summary, items, curves, information, Wright map and scores, plus DIF and response times when you pass those results in.

The items panel is usually the one item writers spend most time on. They can sort and search the table, and selecting an item shows its item health card, with the trace curve, the response distribution, information and observed against expected scores:

The items panel with the health card of a flagged item.
The items panel with the health card of a flagged item.

The curves panel makes the model concrete. Readers tick the items they want and move the slider to an ability level. A dashed line marks that level on every curve, and a table lists the expected score and the probability of each response category there:

Item curves for a polytomous survey, read at an ability of 1.
Item curves for a polytomous survey, read at an ability of 1.

The curves, information, Wright map, scores and persons panels need a unidimensional model; for other models they are left out with a message.

Add your own title, logo, DIF and response times

res <- dif(data, group = gender)

mv_dashboard(mod,
             panels = c("summary", "items", "curves", "dif"),
             dif = res,
             title = "Grade 8 science: fairness review",
             subtitle = "Spring 2026 field test",
             logo = "school-logo.png")

The logo can be a PNG, JPEG or SVG file. The DIF panel shows the plain-language DIF summary, the test table, the effect sizes and the item curves by group for flagged items. The response-time panel (rt = fit_rt(...)) shows the interpretation, item parameters and rapid-guessing plots.

Share it

export_dashboard() saves a dashboard in one of two forms. Pass it the model and the same arguments you gave mv_dashboard(), or the app itself.

As one HTML file (no server needed)

export_dashboard(mod, "sat12-dashboard.html", format = "html",
                 title = "SAT12 results")

This writes one self-contained file. It needs no server, no R and no internet connection, so you can email it, put it on a shared drive, a course page or a learning management system, and anyone can open it in a browser. The tabs, item table, item health cards, item curves with the slider, item information and person lookup all still work; the other plots are pictures. With item health cards for a long test the file can run to a few megabytes.

This is the easiest option for most people, and it is what the live example on this site is.

As a Shiny app

export_dashboard(mod, "sat12-dashboard", title = "SAT12 results")

shiny::runApp("sat12-dashboard")          # try it locally
rsconnect::deployApp("sat12-dashboard")   # publish to shinyapps.io or Posit Connect

This writes a folder with app.R and dashboard.rds, ready to publish to shinyapps.io or Posit Connect. A hosted app suits an organization that already runs a Shiny server, or a dashboard you want to update in place at a fixed address. The server installs mirtverse the same way you installed it, so install it from r-universe or GitHub, not from a local copy, before you deploy.

HTML file Shiny app
Needs a server No Yes (shinyapps.io, Posit Connect, Shiny Server)
Works offline Yes No
Share by Email, shared drive, course page A web address
Interactive Tables, item cards, curves and slider, item information, person lookup Everything

What a dashboard contains, and privacy

Everything a dashboard shows is computed once, when you build it. The app never refits or rescores anything, so it opens quickly, and the saved dashboard holds only summaries: item statistics and parameters, curves, the binned score distribution and pictures of the item cards. It never contains the item responses, in either format.

Individual scores are included only when you add the "persons" panel, and export_dashboard() then reminds you to check that you may share them. Use ids to show your own identifiers instead of row numbers:

mv_dashboard(mod, panels = c("summary", "scores", "persons"), ids = students$id)

Leave the persons panel out of anything you post publicly: the scores panel already shows the score distribution and the sum-score conversion table without identifying anyone.

Tips

  • Keep it short. Three or four panels are easier to read than nine. For an item review meeting, c("summary", "items", "curves") is often enough.
  • Write a subtitle. Say what the test is, who took it and when; the reader of a dashboard has not seen your data.
  • Long tests. Item health cards are drawn for tests of up to 40 items. Use cards = TRUE to draw them for longer tests (it takes a little longer and makes HTML files larger) or cards = FALSE to skip them; without cards, selecting an item shows its trace curve instead.
  • Scores. method sets the scoring method ("EAP" by default) for the scores and persons panels.