I am working on a transition table module and am wrestling with how to make the output understandable for the user. I used to prepare transition tables in Excel; making the table legible was super easy but deriving the data for table output took hours. Now my problem is the opposite with R: takes a few seconds to generate the table output from millions of rows of data but table presentation is far from simple.
To start, I would like to reflect the user's "From" input (object transFrom) in this reactive table's secondary column header as shown in the image below; any suggestions for how to do this? I am completely clueless with respect to html. I had found this solution here R Shiny app - Render Data Table with double header, and I like it because it uses DT, which I use throughout (though I would have preferred the base R table, using Shiny renderTable(), but I could not make that work). I have researched this and found other packages for drafting nice tables but I am avoiding "package bloat" and would rather stick with base R, Shiny, data.table, and DT package IF POSSIBLE.
Note that the columns reflect the transition states FROM, and the rows reflect the transition states TO.
Here is the MWE code for actively rendering the above:
library(data.table)
library(dplyr)
library(shiny)
# custom table container
sketch = htmltools::withTags(table(
class = 'display',
thead(
tr(
th(colspan = 1, ''),
th(colspan = 10, 'From state where initial period is = ')
),
tr(
lapply(colnames(results), th)
)
)
))
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","X0")
)
ui <- fluidPage(
tags$head(tags$style(".datatables .display {margin-left: 0;}")), # < left-align the table
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("results"),
)
server <- function(input, output) {
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"
)
}
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]))
})
output$data <- renderTable(data)
output$results <- renderDT(server=FALSE,{
results() %>%
datatable(rownames = FALSE,
filter = 'none',
container = sketch,
options = list(scrollX = F
, dom = 'ft'
, lengthChange = T
, pagingType = "numbers" # hides Next and Previous buttons
, autoWidth = T
, info = FALSE # hide the "Showing 1 of 2..." at bottom of table
,searching = FALSE # removes search box
),
class = "display"
)
})
}
shinyApp(ui, server)
It seems that htmltools::withTags doesn't play well with using shiny inputs (I filed an issue here).
Please check the following:
library(DT)
library(shiny)
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","X0")
)
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;}")), # < left-align the table
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]))
})
output$data <- renderTable(data)
output$resultsDT <- renderDT(server=FALSE, {
req(results())
datatable(
data = results(),
rownames = FALSE,
filter = 'none',
container = tags$table(
class = 'display',
tags$thead(
tags$tr(
tags$th(colspan = 1, ''),
tags$th(colspan = 10, sprintf('From state where initial period is = %s', input$transFrom))
),
tags$tr(
lapply(colnames(results()), tags$th)
)
)
),
options = list(scrollX = F
, dom = 'ft'
, lengthChange = T
, pagingType = "numbers" # hides Next and Previous buttons
, autoWidth = T
, info = FALSE # hide the "Showing 1 of 2..." at bottom of table
, searching = FALSE # removes search box
),
class = "display"
)
})
}
shinyApp(ui, server)
Related
This is the next step in my attempt to build a user-friendly transition matrix in R, a follow-on to post How to add a vertical line to the first column header in a data table?. I have been spoiled by the ease of drafting eye-friendly tables in Excel and have been struggling with this in R Shiny.
Running the MWE code at the bottom generates the transition table shown on the left side of the image below (with my comments overlaying). Expressing my question in Excel-speak, I'm trying to merge the top 2 cells (rows) in the left-most column (call them cells A1 and A2), eliminate the small bit of line just above "to_state" (cell A2)(item #1 in the image), eliminate that first column's header "to_state" (in cell A2)(item #2 in the image), and into that merged column header space insert an object similar to the object hovering over the "From" columns to the right, that states "To state where end period = x", where x is the value of object transTo() (item #3 in the image). Any suggestions for doing this? Using DT for the table rendering if possible.
I'm open to any other suggestion for drafting a user-friendly, understandable state transition matrix that delineates to/from columns/rows and reactively shows the to/from periods.
Post Shiny: Merge cells in DT::datatable seems promising but it addresses merging rows in the body of the table and not header rows.
Please note that in the fuller code, the table dynamically contracts/expands based on the number of unique states detected in the underlying data. States can range from 2 to 12.
MWE code:
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","X0")
)
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;}")), # < left-align the table
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]))
})
output$data <- renderTable(data)
output$resultsDT <- renderDT(server=FALSE, {
req(results())
datatable(
data = results(),
rownames = FALSE,
filter = 'none',
container = tags$table(
class = 'display',
tags$thead(
tags$tr(
tags$th(colspan = 1, '', style = "border-right: solid 1px;"),
tags$th(colspan = 10, sprintf('From state where initial period = %s', input$transFrom))
),
tags$tr(
mapply(tags$th, colnames(results()), style = sprintf("border-right: solid %spx;", c(1L, rep(0, ncol(results())-1L))), SIMPLIFY = FALSE)
)
)
),
options = list(scrollX = F
, dom = 'ft'
, lengthChange = T
, pagingType = "numbers" # hides Next and Previous buttons
, autoWidth = T
, info = FALSE # hide the "Showing 1 of 2..." at bottom of table
, searching = FALSE # removes search box
),
class = "display"
) %>%
formatStyle(c(1), `border-right` = "solid 1px")
})
}
shinyApp(ui, server)
Please reference these related posts that lead to the solution shown at the bottom. The posts that built up to this solution are How to merge to row cells in data table?, How to add a vertical line to the first column header in a data table?, and How to add reactive object to secondary column header in output table?
Solution:
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","X0")
)
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;}")), # < left-align the table
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]))
})
output$data <- renderTable(data)
output$resultsDT <- renderDT(server=FALSE, {
req(results())
datatable(
data = results(),
rownames = FALSE,
filter = 'none',
container = tags$table(
class = 'display',
tags$thead(
tags$tr(
tags$th(rowspan = 2, sprintf('To state where end period = %s', input$transTo), style = "border-right: solid 1px;"),
tags$th(colspan = 10, sprintf('From state where initial period = %s', input$transFrom))
),
tags$tr(
mapply(tags$th, colnames(results())[-1], style = sprintf("border-right: solid %spx;", rep(0, ncol(results()) - 1L)), SIMPLIFY = FALSE)
)
)
),
options = list(scrollX = F
, dom = 'ft'
, lengthChange = T
, pagingType = "numbers" # hides Next and Previous buttons
, autoWidth = T
, info = FALSE # hide the "Showing 1 of 2..." at bottom of table
, searching = FALSE # removes search box
),
class = "display"
) %>%
formatStyle(c(1), `border-right` = "solid 1px")
})
}
shinyApp(ui, server)
I would like to add a vertical line to a DT table column header. There is guidance for adding this line in post How can I add a vertical line to a datatable?, but it applies to a static table where columns are manually set whereas in my MWE code (at bottom), the columns are set using the lapply() function in a reactive setting. So I'm having trouble using this guidance in my particular circumstances.
Any suggestions for adding a vertical line to the right of the left-most column header labeled "to_state"? As shown in this image which shows a portion of the output window when running the MWE code:
Please note that in the fuller code this MWE derives from, the table expands/contracts dynamically depending on the number of unique states detected in the underlying data. Therefore I can't use a static table set up like in the referenced related post above.
Once this is resolved, I'll have several additional questions as I struggle to make a transition table readily understandable for users (such as change the "to_state" left-most column header to "To end Period = [xxx]", but that will be addressed in another post). I'm tackling this formatting issue incrementally in baby steps.
I am very unfamiliar with HTML, CSS.
Here is the MWE code:
library(DT)
library(shiny)
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","X0")
)
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;}")), # < left-align the table
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]))
})
output$data <- renderTable(data)
output$resultsDT <- renderDT(server=FALSE, {
req(results())
datatable(
data = results(),
rownames = FALSE,
filter = 'none',
container = tags$table(
class = 'display',
tags$thead(
tags$tr(
tags$th(colspan = 1, '', style = "border-right: solid 1px;"),
tags$th(colspan = 10, sprintf('From initial Period = %s', input$transFrom))
),
tags$tr(
lapply(colnames(results()),
tags$th
)
),
)
),
options = list(scrollX = F
, dom = 'ft'
, lengthChange = T
, pagingType = "numbers" # hides Next and Previous buttons
, autoWidth = T
, info = FALSE # hide the "Showing 1 of 2..." at bottom of table
, searching = FALSE # removes search box
),
class = "display"
) %>%
formatStyle(c(1), `border-right` = "solid 1px")
})
}
shinyApp(ui, server)
We can use mapply instead of lapply to control the style parameter:
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","X0")
)
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;}")), # < left-align the table
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]))
})
output$data <- renderTable(data)
output$resultsDT <- renderDT(server=FALSE, {
req(results())
datatable(
data = results(),
rownames = FALSE,
filter = 'none',
container = tags$table(
class = 'display',
tags$thead(
tags$tr(
tags$th(colspan = 1, '', style = "border-right: solid 1px;"),
tags$th(colspan = 10, sprintf('From initial Period = %s', input$transFrom))
),
tags$tr(
mapply(tags$th, colnames(results()), style = sprintf("border-right: solid %spx;", c(1L, rep(0, ncol(results())-1L))), SIMPLIFY = FALSE)
)
)
),
options = list(scrollX = F
, dom = 'ft'
, lengthChange = T
, pagingType = "numbers" # hides Next and Previous buttons
, autoWidth = T
, info = FALSE # hide the "Showing 1 of 2..." at bottom of table
, searching = FALSE # removes search box
),
class = "display"
) %>%
formatStyle(c(1), `border-right` = "solid 1px")
})
}
shinyApp(ui, server)
I am trying to select multiple values from a column on MySQL and Shiny.
Some names with special characters do not return values when queried from a Mysql database.
How can I choose the names but pass to the query the geo instead of the names.
library(shiny)
library(dplyr)
library(sqldf)
library(DT)
library(stringr)
survey <- data.frame("name" = c("Oberösterreich", "Северозападен", "Κύπρος", "Strední Cechy",
"Severovýchod", "Praha"),
"geo" = c("AT31", "BG31", "CY00", " CZ02", "CZ05", "CZ01"),
"population" =c(100409314, 54086980, 30961705, 164741605, 156857074, 93166890))
shinyApp(
ui = fluidPage(
fluidRow(
wellPanel(
selectizeInput(
'Region',
label = "Region Select",
choices = NULL,
options = list(
placeholder = 'Select Region',
maxOptions = 1000,
maxItems = 10,
searchConjunction = 'and'
)
))),
fluidRow(DT::dataTableOutput('table')),
),
server = function(input, output, session){
updateSelectizeInput(session,
"Region",
server = TRUE,
choices = survey$`name`)
geonamesdata <- reactive({
SelectedRegion <-
stringr::str_c(stringr::str_c("'", input$Region, "'"), collapse = ',')
sqldf(paste0("
SELECT DISTINCT c.name, c.geo
FROM survey c
WHERE c.name IN (",
SelectedRegion,
")
"))
})
output$table <- DT::renderDataTable(geonamesdata(),
selection = 'single',
options = list(searching = FALSE,pageLength = 10),
server = FALSE, escape = FALSE,rownames= FALSE)
})
EDIT
I have come up with another demo to illustrate what I would want.
I have a MySQL database but for purposes of this question I will use SQLDF which is similar in syntax on Shiny environment.
library(shiny)
library(dplyr)
library(sqldf)
library(DT)
library(stringr)
df <- data.frame(empName = c("Jon", "Bill", "Maria"),
empID = c("J111", "B222", "M333"),
empAge = c(23, 41, 32),
empSalary = c(21000, 23400, 26800)
)
shinyApp(
ui = fluidPage(
selectizeInput("Search", label = p("Select name"),
choices = as.character(df$empName),
multiple = TRUE),
hr(),
fluidRow(
column(6, DT::dataTableOutput("table1")),
column(6, DT::dataTableOutput("table2"))),
hr(),
hr(),
fluidRow(
column(6, DT::dataTableOutput("table3")),
column(6, DT::dataTableOutput("table4"))
)),
server = function(input, output, session) {
output$table1 = DT::renderDataTable({ df }, options = list(dom = 't'))
df2 <- reactive ({
(df %>% filter(empName %in% input$Search)%>% select(empID))
})
output$table2 = DT::renderDataTable({
req(input$Search)
df2()}, options = list(dom = 't'))
df3 <- reactive({
if (input$Search != "") {
sqldf(paste0("SELECT *
FROM df WHERE empName LIKE '%",input$Search,"%'"))
}})
output$table3 = DT::renderDataTable({
req(input$Search)
df3()}, options = list(dom = 't'))
df4 <- reactive ({
SelectedNames <-stringr::str_c(stringr::str_c("'", input$Search, "'"), collapse = ',')
sqldf(paste0("SELECT empAge, empSalary
FROM df WHERE empName IN (",SelectedNames,") "))
})
output$table4 = DT::renderDataTable({
req(input$Search)
df4()}, options = list(dom = 't'))
})
I am working with MySQL queries.
In Table 1 the data displayed is the whole employee dataframe , I cannot do that for thousands of rows.
In table 2 I select the employee names from selectize but display the corresponding IDs .
In Table 3, it only shows one selected value from the selectize.
In table 4, the code allows to query other details from multiple selection of the selectizeInput.
What I am looking for is to be able to select multiple names from selectizeInput but pass the corresponding multiple employee IDs to the Mysql query to get the results like in Table 4.
Thus basically combine the ability to select names but pass the values of the Id column to allow mutiple select in a query.
I have simplified your reactive expression, added the Geo as a initial selection, and moved selectizeInput to server side. Try this.
EDIT: I have updated the answer to remove initial selection.
###### updated answer on 8Sep2020
survey <- data.frame(name = c("Oberösterreich", "Северозападен", "Κύπρος", "Strední Cechy", "Severovýchod", "Praha"),
geo = c("AT31", "BG31", "CY00", "CZ02", "CZ05", "CZ01"),
population =c(100409314, 54086980, 30961705, 164741605, 156857074, 93166890))
ui = fluidPage(
fluidRow(
wellPanel(
uiOutput("regionorgeo")
)),
fluidRow(DTOutput('table')),
)
server = function(input, output, session){
output$regionorgeo <- renderUI({
selectizeInput(
'Geo',
label = "Geo Select",
choices = survey$geo,
selected=1,
options = list(
placeholder = 'Geo Region',
maxOptions = 1000,
maxItems = 10,
searchConjunction = 'and'
)
)
})
geonamesdata <- reactive({
req(input$Geo)
data <- filter(survey, geo %in% as.character(input$Geo))
data
})
output$table <- DT::renderDataTable(geonamesdata(),
selection = 'single',
options = list(searching = FALSE,pageLength = 10),
server = FALSE, escape = FALSE,rownames= FALSE)
}
shinyApp(ui, server)
I'm using a datatable in a shiny app with custom coloring of the cells. This is done in html (each cell is a div) and by telling DT to not escape these specific columns.
It looks like this with DT :
screenshot
My issue is that I would like the coloring to take the entire height of each cell so that there is no margins. If I could have the different cell colors to touch each other that would be great.
I have try to add margin: 0px; padding: 0px; but it makes no difference.
I've also tried to use the formatstyle from DT to reduce the row height like so :
formatStyle( 0, target = 'row', lineHeight = '80%')
and the result looks like this :
screenshot 2
I'm currently trying with padding: 0px;margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px; but it does not work any better.
It looks to me that this is a margin from DT rather than my div since whatever I try in my div style, I've always the same margins between the colors and the row height limits. The only thing is I do not know how to control it.
Would anyone know how to achieve such a result ?
Thanks ahead of time for your help.
Code used :
for (c in colnames(ranking)[10:13]) {
ranking <- ranking %>%
filter(param %in% input$param) %>%
arrange_(.dots = c) %>%
mutate(!!paste0(c, "_rk") := 1:nrow(ranking %>% filter(param %in% input$param)))
tmp <- ranking %>%
arrange_(.dots = c) %>%
select_(.dots = c)
max <- tmp %>% tidyr::drop_na() %>% .[, 1] %>% max()
min <- tmp %>% tidyr::drop_na() %>% .[, 1] %>% min()
range <- max - min
brks <- vector(length = colors)
for (i in 1:colors) {
brks[i] <- i^pracma::bisect(function(x) range^(1/x) - (colors + 1), 1, 5)$root %>% round(2) + min - 2
}
tmp <- tmp %>%
mutate(brks = ifelse(is.na(tmp[, 1]),
NA,
cut(tmp %>% tidyr::drop_na() %>% .[, 1], brks)))
colfunc <- colorRampPalette(c("#c31432", "#ffc500", "#edde5d", "white"))
clrs <- colfunc(colors + 1)
tmp_nrow <- tmp %>% nrow()
for (i in 1:tmp_nrow) {
row <- which(tmp[i, 1] == ranking[,c])
r <- clrs[tmp[i, 2]] %>% col2rgb() %>% .[1]
g <- clrs[tmp[i, 2]] %>% col2rgb() %>% .[2]
b <- clrs[tmp[i, 2]] %>% col2rgb() %>% .[3]
tmp[i, 1] <- paste0("<center><div style='background: ", "radial-gradient(rgba(", r, ",", g, ",", b, ",", "0), rgba(", r, ",", g, ",", b, ",", "0.25), rgba(", r, ",", g, ",", b, ",", "1)", ")", "; border: solid 0px;font-family: \"Interstate Black\";font-weight: bolder;padding: 0;margin: 0;'>",
tmp[i, 1],
"</div></center>")
ranking[row,paste0(c, "_coloring")] <- tmp[i, 1]
}
}
ranking_m <- as.matrix(ranking %>%
filter(param %in% input$param) %>%
select(4, 47, 40, 38, 31, 32, 41, 42, 43, 44))
DT::datatable(ranking_m,
escape = c(TRUE, FALSE, rep(FALSE, 8)),
filter = 'top',
extensions = list('Responsive' = NULL),
options = list(pageLength = 25,
lengthMenu = c(10, 25, 50, 100),
columnDefs = list(list(width = '400px', targets = 0),
list(width = '25px', targets = 1),
list(className = 'dt-center', targets = 2:9)))) #%>%
# formatStyle( 0, target = 'row', lineHeight = '80%')
The background CSS must be set to the cells, not to the cells contents. This can be achieved with formatStyle. Here is an example with random colors:
library(DT)
dat <- iris[1:5,]
ncols <- ncol(dat)
# background for column 1
r <- sample.int(256, 5, replace = TRUE) - 1L
g <- sample.int(256, 5, replace = TRUE) - 1L
b <- sample.int(256, 5, replace = TRUE) - 1L
dat$RGB1 <- sprintf("radial-gradient(rgba(%s,%s,%s,0),rgba(%s,%s,%s,0.25),rgba(%s,%s,%s,1))",
r, g, b, r, g, b, r, g, b)
# background for column 2
r <- sample.int(256, 5, replace = TRUE) - 1L
g <- sample.int(256, 5, replace = TRUE) - 1L
b <- sample.int(256, 5, replace = TRUE) - 1L
dat$RGB2 <- sprintf("radial-gradient(rgba(%s,%s,%s,0),rgba(%s,%s,%s,0.25),rgba(%s,%s,%s,1))",
r, g, b, r, g, b, r, g, b)
# background for column 4
r <- sample.int(256, 5, replace = TRUE) - 1L
g <- sample.int(256, 5, replace = TRUE) - 1L
b <- sample.int(256, 5, replace = TRUE) - 1L
dat$RGB4 <- sprintf("radial-gradient(rgba(%s,%s,%s,0),rgba(%s,%s,%s,0.25),rgba(%s,%s,%s,1))",
r, g, b, r, g, b, r, g, b)
datatable(dat,
options =
list(
columnDefs =
list(
list(visible = FALSE, targets = ncols + 1:3),
list(className = "dt-center", targets = 1:ncols)
)
)) %>%
formatStyle(1, valueColumns = ncols+1, background = JS("value")) %>%
formatStyle(2, valueColumns = ncols+2, background = JS("value")) %>%
formatStyle(4, valueColumns = ncols+3, background = JS("value")) %>%
formatStyle(1:ncols, `font-family` = "Interstate Black") %>%
formatStyle(1:ncols, fontWeight = "bolder")
I found this code online at http://www.sthda.com/english/wiki/ggplot2-quick-correlation-matrix-heatmap-r-software-and-data-visualization
It provides instructions for how to create a correlation matrix heat map and it works well. However, I was wondering how to get little stars * next to the values in the matrix that are significant. How would I go about doing that. Any help is greatly appreciated!!
mydata <- mtcars[, c(1,3,4,5,6,7)]
head(mydata)
cormat <- round(cor(mydata),2)
head(cormat)
library(reshape2)
melted_cormat <- melt(cormat)
head(melted_cormat)
library(ggplot2)
ggplot(data = melted_cormat, aes(x=Var1, y=Var2, fill=value)) +
geom_tile()
# Get lower triangle of the correlation matrix
get_lower_tri<-function(cormat){
cormat[upper.tri(cormat)] <- NA
return(cormat)
}
# Get upper triangle of the correlation matrix
get_upper_tri <- function(cormat){
cormat[lower.tri(cormat)]<- NA
return(cormat)
}
upper_tri <- get_upper_tri(cormat)
# Melt the correlation matrix
library(reshape2)
melted_cormat <- melt(upper_tri, na.rm = TRUE)
# Heatmap
library(ggplot2)
ggplot(data = melted_cormat, aes(Var2, Var1, fill = value))+
geom_tile(color = "white")+
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1,1), space = "Lab",
name="Pearson\nCorrelation") +
theme_minimal()+
theme(axis.text.x = element_text(angle = 45, vjust = 1,
size = 12, hjust = 1))+
coord_fixed()
reorder_cormat <- function(cormat){
# Use correlation between variables as distance
dd <- as.dist((1-cormat)/2)
hc <- hclust(dd)
cormat <-cormat[hc$order, hc$order]
}
# Reorder the correlation matrix
cormat <- reorder_cormat(cormat)
upper_tri <- get_upper_tri(cormat)
# Melt the correlation matrix
melted_cormat <- melt(upper_tri, na.rm = TRUE)
# Create a ggheatmap
ggheatmap <- ggplot(melted_cormat, aes(Var2, Var1, fill = value))+
geom_tile(color = "white")+
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1,1), space = "Lab",
name="Pearson\nCorrelation") +
theme_minimal()+ # minimal theme
theme(axis.text.x = element_text(angle = 45, vjust = 1,
size = 12, hjust = 1))+
coord_fixed()
# Print the heatmap
print(ggheatmap)
ggheatmap +
geom_text(aes(Var2, Var1, label = value), color = "black", size = 4) +
theme(
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.major = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
axis.ticks = element_blank(),
legend.justification = c(1, 0),
legend.position = c(0.6, 0.7),
legend.direction = "horizontal")+
guides(fill = guide_colorbar(barwidth = 7, barheight = 1,
title.position = "top", title.hjust = 0.5))
cor() doesn't show the significance level, you may have to use rcorr() from Hmisc package
This is quite similar to what you want (the graphic output is not so nice though)
library(ggplot2)
library(reshape2)
library(Hmisc)
library(stats)
abbreviateSTR <- function(value, prefix){ # format string more concisely
lst = c()
for (item in value) {
if (is.nan(item) || is.na(item)) { # if item is NaN return empty string
lst <- c(lst, '')
next
}
item <- round(item, 2) # round to two digits
if (item == 0) { # if rounding results in 0 clarify
item = '<.01'
}
item <- as.character(item)
item <- sub("(^[0])+", "", item) # remove leading 0: 0.05 -> .05
item <- sub("(^-[0])+", "-", item) # remove leading -0: -0.05 -> -.05
lst <- c(lst, paste(prefix, item, sep = ""))
}
return(lst)
}
d <- mtcars
cormatrix = rcorr(as.matrix(d), type='spearman')
cordata = melt(cormatrix$r)
cordata$labelr = abbreviateSTR(melt(cormatrix$r)$value, 'r')
cordata$labelP = abbreviateSTR(melt(cormatrix$P)$value, 'P')
cordata$label = paste(cordata$labelr, "\n",
cordata$labelP, sep = "")
cordata$strike = ""
cordata$strike[cormatrix$P > 0.05] = "X"
txtsize <- par('din')[2] / 2
ggplot(cordata, aes(x=Var1, y=Var2, fill=value)) + geom_tile() +
theme(axis.text.x = element_text(angle=90, hjust=TRUE)) +
xlab("") + ylab("") +
geom_text(label=cordata$label, size=txtsize) +
geom_text(label=cordata$strike, size=txtsize * 4, color="red", alpha=0.4)
Source
difference_p is the P_value of correlation matrix,
ax5 draws the sns.heatmap and return as ax5
data=correlation_p
for y in range(data.shape[0]):
for x in range(data.shape[1]):
if data[y,x]<0.1:
ax4.text(x + 0.5, y + 0.5, '-',size=48,
horizontalalignment='center',
verticalalignment='center',
)