I'm trying to find an easy, up-to-date way to plot transition matrices. Could someone please recommend a method or package? I found advice on Stack, but the posts are very old, or the referenced packages no longer exist (such as in the Oct 23, 2015 answer to post R transition plot).
Note that my transition matrices are dynamic: depending on user inputs, the number of states and the to/from periods vary based on the composition of the underlying data. So going into the code and manually adjusting box/arrow sizes won't help much.
I've been leaning towards the Apr 20, 2013 answer to Graph flow chart of transition from states, using the Diagram package, but I wonder if there's a more up-to-date method.
I don't need anything too complicated. I like the type of plot shown in this image (I believe generated via the package that no longer exists in the above referenced post, "MmgraphR"):
Or this simpler form works for me too:
Below is a stripped-down version of code I've been using to generate transitions:
library(DT)
library(shiny)
library(dplyr)
library(htmltools)
library(data.table)
data <-
data.frame(
ID = c(1,1,1,2,2,2,3,3,3),
Period = c(1, 2, 3, 1, 2, 3, 1, 2, 3),
Values = c(5, 10, 15, 0, 2, 4, 3, 6, 9),
State = c("X0","X1","X2","X0","X2","X0", "X2","X1","X9")
)
numTransit <- function(x, from=1, to=3){
setDT(x)
unique_state <- unique(x$State)
all_states <- setDT(expand.grid(list(from_state = unique_state, to_state = unique_state)))
dcast(x[, .(from_state = State[from],
to_state = State[to]),
by = ID]
[,.N, c("from_state", "to_state")]
[all_states,on = c("from_state", "to_state")],
to_state ~ from_state, value.var = "N"
)
}
ui <- fluidPage(
tags$head(tags$style(".datatables .display {margin-left: 0;}")),
h4(strong("Base data frame:")),
tableOutput("data"),
h4(strong("Transition table inputs:")),
numericInput("transFrom", "From period:", 1, min = 1, max = 3),
numericInput("transTo", "To period:", 2, min = 1, max = 3),
h4(strong("Output transition table:")),
DTOutput("resultsDT"),
)
server <- function(input, output, session) {
results <-
reactive({
results <- numTransit(data, input$transFrom, input$transTo) %>%
replace(is.na(.), 0) %>%
bind_rows(summarise_all(., ~(if(is.numeric(.)) sum(.) else "Sum")))
results <- cbind(results, Sum = rowSums(results[,-1]))
# Express results as percentages:
results %>%
mutate(across(-1, ~ .x / .x[length(.x)])) %>%
replace(is.na(.), 0) %>%
mutate(across(-1, scales::percent_format(accuracy = 0.1)))
})
output$data <- renderTable(data)
output$resultsDT <- renderDT(server=FALSE, {
datatable(
data = results(),
rownames = FALSE,
container = tags$table(
tags$thead(
tags$tr(
tags$th(rowspan = 2,sprintf('To state where end period = %s', input$transTo)),
tags$th(colspan = 10,sprintf('From state where initial period = %s',input$transFrom))),
tags$tr(mapply(tags$th, colnames(results())[-1], SIMPLIFY = FALSE))
)
),
)
})
}
shinyApp(ui, server)