So, I'm trying to create a tool for a tabletop roleplaying game using R Shiny, allowing players to automatically generate random ghosts. These stats are factors, with the order of "Supreme", "Good", "Moderate", "Poor", "Awful", and "Worst", in order. In order to create the ghosts, I need to take a vector of these factors 25 items long, randomize the order, then put it into a 5x5 data frame before sorting two rows from best to worst.
At the moment, the basic R code (Shiny stuff aside, since it's just complicating things and it's not the primary issue here) looks like this:
arcanaVector <- c(rep("Supreme", 3),
rep(c("Good", "Moderate", "Poor", "Awful"), each = 5),
rep("Worst", 2))
arcanaLevels <- c("Supreme", "Good", "Moderate", "Poor", "Awful", "Worst")
arcanaVector <- factor(arcanaVector, ordered = TRUE, levels = arcanaLevels)
shuffled_arcana <- sample(arcanaVector)
arcana_table <- as.data.frame(matrix(shuffled_arcana,
nrow = 5, ncol = 5))
row.names(arcana_table) <- c("Presence", "Manner", "Expression", "Complexity", "Tradition")
This much of the code is working, and it's producing an output that looks sort of like this:
Row Names | Col1 | Col2 | Col3 | Col4 | Col5 |
---|---|---|---|---|---|
Presence | Awful | Good | Poor | Supreme | Worst |
Manner | Good | Awful | Moderate | Moderate | Supreme |
Expression | Awful | Poor | Poor | Awful | Awful |
Complexity | Poor | Good | Worst | Good | Good |
Tradition | Supreme | Moderate | Moderate | Moderate | Poor |
However, no matter what I do, I can't seem to get it to sort properly. I've tried order(), I've tried sort(), I've looked over all the code I could see on StackExchange and I couldn't find anything that helped. At best, it's done nothing; at worst, it's not only failed to sort, but stripped away the factor values so that it was just displaying the underlying numbers.
Once sorted on the Presence row, for instance, it should look something like this:
Row Names | Col1 | Col2 | Col3 | Col4 | Col5 |
---|---|---|---|---|---|
Presence | Supreme | Good | Poor | Awful | Worst |
Manner | Good | Awful | Moderate | Moderate | Supreme |
Expression | Awful | Poor | Poor | Awful | Awful |
Complexity | Poor | Good | Worst | Good | Good |
Tradition | Supreme | Moderate | Moderate | Moderate | Poor |
CodePudding user response:
In your code, the issue is happening at this line.
arcana_table <- as.data.frame(matrix(shuffled_arcana, nrow = 5, ncol = 5))
shuffled_arcana
is a factored vector but you cannot have a factor-matrix so it changes the vector from factor to character and hence, sorting does not happen as desired.
Here's a way -
set.seed(2022)
arcanaVector <- c(rep("Supreme", 3),
rep(c("Good", "Moderate", "Poor", "Awful"), each = 5),
rep("Worst", 2))
arcanaLevels <- c("Supreme", "Good", "Moderate", "Poor", "Awful", "Worst")
shuffled_arcana <- sample(arcanaVector)
arcana_table <- matrix(shuffled_arcana,nrow = 5, ncol = 5)
row.names(arcana_table) <- c("Presence", "Manner", "Expression", "Complexity", "Tradition")
arcana_table <- apply(arcana_table, 1, function(x) sort(factor(x, arcanaLevels))) |>
t() |>
as.data.frame()
arcana_table
# V1 V2 V3 V4 V5
#Presence Good Good Good Good Awful
#Manner Supreme Moderate Poor Awful Awful
#Expression Supreme Supreme Moderate Moderate Poor
#Complexity Moderate Moderate Poor Poor Worst
#Tradition Good Poor Awful Awful Worst
If you want to change a specific row you may use -
arcana_table[1, ] <- as.character(sort(factor(arcana_table[1, ], arcanaLevels)))
CodePudding user response:
If I understand you correctly, you want to sort the columns of the matrix by a chosen row. If so, I think you simply may do:
chosen <- 'Presence'
arcana_table[, order(factor(arcana_table[chosen, ], levels=arcanaLevels))]
# [,1] [,2] [,3] [,4] [,5]
# Presence "Supreme" "Moderate" "Poor" "Poor" "Poor"
# Manner "Awful" "Worst" "Good" "Worst" "Awful"
# Expression "Awful" "Poor" "Supreme" "Poor" "Good"
# Complexity "Moderate" "Awful" "Moderate" "Good" "Good"
# Tradition "Moderate" "Supreme" "Good" "Awful" "Moderate"
chosen <- 'Manner'
arcana_table[, order(factor(arcana_table[chosen, ], levels=arcanaLevels))]
# [,1] [,2] [,3] [,4] [,5]
# Presence "Poor" "Supreme" "Poor" "Poor" "Moderate"
# Manner "Good" "Awful" "Awful" "Worst" "Worst"
# Expression "Supreme" "Awful" "Good" "Poor" "Poor"
# Complexity "Moderate" "Moderate" "Good" "Good" "Awful"
# Tradition "Good" "Moderate" "Moderate" "Awful" "Supreme"
Note, that the order in a factor
is given by the order how the levels are provided. ordered=TRUE
argument actually further differentiates ordinal scale from nominal scale.
Data:
arcanaVector <- structure(c(1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L,
4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 6L, 6L), .Label = c("Supreme",
"Good", "Moderate", "Poor", "Awful", "Worst"), class = c("ordered",
"factor"))
set.seed(42) ## for sake of reproducibility
arcana_table <- matrix(sample(arcanaVector), nrow=5, ncol=5,
dimnames=list(c("Presence", "Manner", "Expression",
"Complexity", "Tradition"), NULL))
arcanaLevels <- c("Supreme", "Good", "Moderate", "Poor", "Awful", "Worst")