{{ env_id }} <- readRDS(file.path(datadir, "{{ env_id }}.rds")) is_shiny <- identical(knitr::opts_knit$get("rmarkdown.runtime"), "shiny") library(magrittr) data_{{ env_id }} <- {{ env_id }}$data group_filter_{{ env_id }} <- {{ env_id }}$group_filter exprs_values_{{ env_id }} <- round({{ env_id }}$exprs_values,3) featurenames <- rownames(exprs_values_{{ env_id }}) reduced_dim_{{ env_id }} <- {{ env_id }}$use_dimred group_by_{{ env_id }} <- {{ env_id }}$group_by string_counts_{{ env_id }} <- apply(exprs_values_{{ env_id }}, 1, paste0, collapse = ";") string_group_by_{{ env_id }} <- paste0(group_by_{{ env_id }}[,1], collapse = ";")
# # Store expression data in <div> elements # data_divs <- lapply(featurenames, function(feature) { e <- string_counts_{{ env_id }}[[feature]] htmltools::div(id = paste0("expression-", feature), `data-feature` = feature, `data-expression` = e) }) htmltools::div(data_divs) htmltools::HTML(paste0("<div id='group_by_{{ env_id }}' data-grouping='",string_group_by_{{ env_id }},"'></div>"))
```{js, eval=!is_shiny} /* * Function to link a div-container with a plotly scatterplot (needs to have only two traces), change the color values and the title of the plot. * @param {string} plot_id The id of the scatterplot that should be changed. * @param {string} div_id The id of the div container. * @param {string} color_by_tag The tag of the div container containing the values for the colorchange (currently as a semicolon separated string). * @param {string} title The new title of the scatterplot. / function linking_plotly_scatter(plot_id, div_id, color_by_tag, title = "") {
color_by = document.getElementById(div_id).getAttribute(color_by_tag);
// (decode the data) or split the datastring var color_by = color_by.split(';').map(function(item){return parseFloat(item);});
// get min and max values from expression var min = Math.min(...color_by); var max = Math.max(...color_by);
// update scatterplot data var scatter_update_0 = { 'marker.color': [color_by], 'marker.cmax': max, 'marker.cmin': min, 'marker.line.cmax': max, 'marker.line.cmin': min, 'marker.line.color': [color_by]};
var scatter_update_1 = { 'marker.color': [min, max], 'marker.cmax': max, 'marker.cmin': min};
// update scatterplot layout var scatter_layout_update = {title: title};
// restyle and relayout of the scatterplot Plotly.restyle(plot_id, scatter_update_0, [0]); Plotly.restyle(plot_id, scatter_update_1, [1]); Plotly.relayout(plot_id, scatter_layout_update); console.log(document.getElementById(plot_id).data) }
```{js, eval=!is_shiny} /** * Function to link a div-container with a plotly scatterplot (needs to have only two traces), change the color values and the title of the plot. * @param {string} plot_id The id of the scatterplot that should be changed. * @param {string} samples_div_id * @param {string} samples_attribute * @param {string} group_div_id * @param {string} group_attribute * @param {string} title The new title of the scatterplot. */ function linking_plotly_violin(plot_id, samples_div_id, samples_attribute, group_div_id, group_attribute, title = "") { plot_div = document.getElementById(plot_id) values_str = document.getElementById(samples_div_id).getAttribute(samples_attribute); grouping_str = document.getElementById(group_div_id).getAttribute(group_attribute); // (decode the data) or split the datastring var values = values_str.split(';').map(function(item){return parseFloat(item);}); var group = grouping_str.split(';'); // update scatterplot layout var violin_layout_update = {'title': title, 'xaxis.type': 'category'}; // create dict; key = number of level of group_by; value = indexes extractet from the whole expression array according to the level level_indices = {} for (i = 0; i < plot_div.data.length; i++){ level_name = plot_div.data[i].name; level_indices[i] = getAllIndexes(group, level_name); } // update each trace of the violinplot according to the indexes traces_values = [] for (var key in level_indices){ var values_of_level = level_indices[key].map(key => values[key]); traces_values.push(values_of_level); } var violin_update = { y: traces_values } // restyle and relayout of the violinplot Plotly.restyle(plot_id, violin_update); Plotly.relayout(plot_id, violin_layout_update); console.log(document.getElementById(plot_id).data) }
```{js, eval=!is_shiny} // https://stackoverflow.com/a/20798567/7508349 function getAllIndexes(arr, val) { var indexes = [], i; for(i = 0; i < arr.length; i++) if (arr[i] === val) indexes.push(i); return indexes; }
```r data_{{ env_id }} %>% dplyr::filter(group_by == !!group_filter_{{ env_id }}) %>% dplyr::group_by(level, feature) %>% dplyr::mutate(is_non_zero_exprs = expression > 0) %>% dplyr::summarise(n_samples = dplyr::n(), n_nonzero = sum(is_non_zero_exprs)) %>% dplyr::mutate(freq = round(n_nonzero / n_samples * 100, 2)) %>% dplyr::mutate(info = paste0(n_nonzero, " / ", n_samples, " (", freq, "%)")) %>% dplyr::select(level, feature, info) %>% tidyr::spread(level, info) %>% as.data.frame -> metadata_{{ env_id }} row.names(metadata_{{ env_id }}) <- row.names(exprs_values_{{ env_id }}) DT::datatable(metadata_{{ env_id }}, elementId = "dt_{{ env_id }}", filter = 'top', caption = 'Table: No. of cells with positive expression (>0)', selection = list(mode = 'single', target = 'row'), options = list( columnDefs = list(list(visible = FALSE, targets = c(1))), pageLength = 100 ), callback=DT::JS(" table.on('click.dt', 'tr', function() { // highlight selected row of the table if ( $(this).hasClass('selected') ) { $(this).removeClass('selected'); } else { table.$('tr.selected').removeClass('selected'); $(this).addClass('selected'); } var feature_name = table.row(this).data()[0], feature_div_id = 'expression-'.concat(feature_name); // changing the scatterplot var id_scatter = 'scatter_{{ env_id }}'; linking_plotly_scatter(plot_id = id_scatter, div_id = feature_div_id, color_by_tag = 'data-expression', title = feature_name); //changing the violinplot var id_violin = 'violin_{{ env_id }}', id_group = 'group_by_{{ env_id }}'; linking_plotly_violin(plot_id = id_violin, samples_div_id = feature_div_id, samples_attribute = 'data-expression', group_div_id = id_group, group_attribute = 'data-grouping', title = feature_name); }) ") )
ui_list <- list() # selection field for grouping ui_list <- rlist::list.append(ui_list, selectInput("select_grouping_{{ env_id }}", label = "Select column for grouping:", choices = unique(data_{{ env_id }}$group_by), selected = group_filter_{{ env_id }})) # # subsetting data according to the selected grouping column # df_table_{{ env_id }} <- shiny::reactive({ selected_group <- input$select_grouping_{{ env_id }} data_{{ env_id }} %>% dplyr::filter(group_by == !!selected_group) }) # # Dropdown menu with shiny input-widgets # shinyWidgets::dropdownButton(div(style='height: 300px; overflow-x: auto;',do.call(shiny::inputPanel, ui_list)), circle = TRUE, status = "danger", icon = icon("gear"), width = "300px", tooltip = shinyWidgets::tooltipOptions(title = "Click, to change plot settings:")) # # DT::datatable with calculated statistic # output$tbl_{{ env_id }} <- DT::renderDataTable({ #options(DT.options = list(scrollY="400px",scrollX="300px", pageLength = 100, autoWidth = TRUE)) options(DT.options = list(scrollY="20vh", scrollX="300px", pageLength = 100, autoWidth = TRUE)) df_table_{{ env_id }}() %>% dplyr::group_by(level, feature) %>% dplyr::mutate(is_non_zero_exprs = expression > 0) %>% dplyr::summarise(n_samples = dplyr::n(), n_nonzero = sum(is_non_zero_exprs)) %>% dplyr::mutate(freq = round(n_nonzero / n_samples * 100, 2)) %>% dplyr::mutate(info = paste0(n_nonzero, " / ", n_samples, " (", freq, "%)")) %>% dplyr::select(level, feature, info) %>% tidyr::spread(level, info) %>% dplyr::mutate(feature = row.names(exprs_values_{{ env_id }})) %>% DT::datatable(filter = 'top', selection = list(mode = 'single', selected = 1, target = 'row'), caption = 'Table: No. of cells with positive expression (>0)') }) renderUI({DT::dataTableOutput('tbl_{{ env_id }}')})
# compare with colormaps if(is.factor(group_by_{{ env_id }}[,1])){ if(colnames(group_by_{{ env_id }})[1] %in% names(colormaps)) colors_{{ env_id }} <- colormaps[[colnames(group_by_{{ env_id }})[1]]] else colors_{{ env_id }} <- "Set1" } i2dash.scrnaseq::plotly_violinplot(y = exprs_values_{{ env_id }}[1,], group_by = group_by_{{ env_id }}[,1], y_title = "Expression", group_by_title = "Group", , colors = colors_{{ env_id }}) %>% plotly::layout( title = row.names(exprs_values_{{ env_id }})[1] ) -> violin_{{ env_id }} # %>% # plotly::config(fillFrame = TRUE) -> violin_{{ env_id }} violin_{{ env_id }}$elementId <- "violin_{{ env_id }}" violin_{{ env_id }}
# # subsetting the data.frame for the violinplot according to the transmitted keys from scatterplot # df2_{{ env_id }} <- shiny::reactive({ keys <- plotly::event_data("plotly_selected", source = "scatter_{{ env_id }}")$key if(!is.null(plotly::event_data("plotly_selected", source = "scatter_2_{{ env_id }}")$key)) keys <- plotly::event_data("plotly_selected", source = "scatter_2_{{ env_id }}")$key df <- data.frame(df_{{ env_id }}()$df, "level" = as.factor(group_by_{{ env_id }}[[input$select_grouping_{{ env_id }}]])) if(!is.null(keys)) { return(df[keys, ]) } return(df) }) # # creating a violinplot with the primitive function of i2dash.scrnaseq::plotly_violinplot # output$violin_{{ env_id }} <- plotly::renderPlotly({ # compare with colormaps if(input$select_grouping_{{ env_id }} %in% names(colormaps)) colors <- colormaps[[input$select_grouping_{{ env_id }}]] else colors <- "Set1" i2dash.scrnaseq::plotly_violinplot(y = df2_{{ env_id }}()$expression, group_by = df2_{{ env_id }}()$level, y_title = "Expression", group_by_title = input$select_grouping_{{ env_id }}, colors = colors) %>% plotly::layout(title = df_{{ env_id }}()$feature) -> violin }) renderUI({plotly::plotlyOutput("violin_{{ env_id }}", height = "100%")})
i2dash.scrnaseq::plotly_scatterplot(x =reduced_dim_{{ env_id }}[,1], y = reduced_dim_{{ env_id }}[,2], color = exprs_values_{{ env_id }}[1,], colors = "YlOrRd", text = row.names(reduced_dim_{{ env_id }}), hoverinfo = "x+y+text", y_title = "Dimension 2", x_title = "Dimension 1") %>% plotly::layout( title = row.names(exprs_values_{{ env_id }})[1], autosize = F, xaxis = list(title = "Dimension 1", automargin = T), yaxis = list(title = "Dimension 2", automargin = T) ) %>% htmlwidgets::onRender("function(el) { // -------------------- // workaround for plotly.js bug (https://github.com/ropensci/plotly/issues/1546) // get size of parents div container document.getElementById('scatter_{{ env_id }}').parentElement.id = 'parent_scatter_{{ env_id }}' var clientHeight = document.getElementById('parent_scatter_{{ env_id }}').clientHeight; var clientWidth = document.getElementById('parent_scatter_{{ env_id }}').clientWidth; // avoid errors at 0 width and height if (clientHeight === 0){ clientHeight = 450 // plotly's default value } if (clientWidth === 0){ clientWidth = 700 // plotly's default value } // get current layout and relayout plotly chart var layout = el.layout; layout.height = clientHeight; layout.width = clientWidth; Plotly.relayout(el, layout) // -------------------- var id_violin = 'violin_{{ env_id }}'; var violin_div = document.getElementById(id_violin); var div_group_by = document.getElementById('group_by_{{ env_id }}'); var group_str = div_group_by.getAttribute('data-grouping'); var group = group_str.split(';'); level_indices = {} for (i = 0; i < violin_div.data.length; i++){ level_name = violin_div.data[i].name; level_indices[i] = getAllIndexes(group, level_name); } el.on('plotly_selected', function(eventData){ if(eventData == undefined){ console.log('Nothing is selected'); } else { feature_name = el.layout.title.text; var div_exprs = document.getElementById('expression-'.concat(feature_name)); var exprs_str = div_exprs.getAttribute('data-expression'); var expr = exprs_str.split(';').map(function(item){return parseFloat(item);}); // get the array of the selected points var selection = eventData.points[0].data.selectedpoints; // create dict with subsetted trace indexes updated_dict = {} for (var key in level_indices){ updated_dict[key] = selection.filter(value => -1 !== level_indices[key].indexOf(value)) } // restyle each trace of the violinplot according to the indexes traces_exprs = [] for (var key in updated_dict){ if (updated_dict[key].length === 0){ var exprs_of_level = [0]; traces_exprs.push(exprs_of_level); } else { var exprs_of_level = updated_dict[key].map(key => expr[key]); traces_exprs.push(exprs_of_level); } } var violin_update = { y: traces_exprs } Plotly.restyle(id_violin, violin_update); var violin_layout_update = {'xaxis.type': 'category'}; Plotly.relayout(id_violin, violin_layout_update); // when deselected the violin plot is restyled with the old values el.on('plotly_deselect', function(eventData){ feature_name = el.layout.title.text; var div_exprs = document.getElementById('expression-'.concat(feature_name)); var exprs_str = div_exprs.getAttribute('data-expression'); var expr = exprs_str.split(';').map(function(item){return parseFloat(item);}); traces_exprs = []; // restyle each trace of the violinplot according to the indexes for (var key in level_indices){ var exprs_of_level = level_indices[key].map(key => expr[key]); traces_exprs.push(exprs_of_level); }; var violin_update = { y: traces_exprs }; // all_traces = [...range(0, violin_div.data.length - 1)]; Plotly.restyle(id_violin, violin_update); var violin_layout_update = {'xaxis.type': 'category'}; Plotly.relayout(id_violin, violin_layout_update); }) } }); }") %>% plotly::toWebGL() -> scatter_{{ env_id }} # %>% # plotly::config(fillFrame = TRUE) -> scatter_{{ env_id }} scatter_{{ env_id }}$elementId <- "scatter_{{ env_id }}" scatter_{{ env_id }}
# # Create reactive data table for the scatterplot according to the selected feature # df_{{ env_id }} <- shiny::reactive({ selected_gene <- input$tbl_{{ env_id }}_row_last_clicked if(is.null(selected_gene)){ expression <- exprs_values_{{ env_id }}[1,] featurename <- featurenames[1] } else { expression <- exprs_values_{{ env_id }}[selected_gene,] featurename <- featurenames[selected_gene] } df <- data.frame("x" = reduced_dim_{{ env_id }}[,1], "y" = reduced_dim_{{ env_id }}[,2], "expression" = expression) return(list("df" = df, "feature" = featurename)) }) # # Output # output$scatter_{{ env_id }} <- plotly::renderPlotly({ i2dash.scrnaseq::plotly_scatterplot(x = df_{{ env_id }}()$df$x, y = df_{{ env_id }}()$df$y, color = df_{{ env_id }}()$df$expression, colors = "YlOrRd", text = rownames(df_{{ env_id }}()$df), hoverinfo = "x+y+text", source = "scatter_{{ env_id }}", key = rownames(df_{{ env_id }}()$df), y_title = "Dimension 2", x_title = "Dimension 1") %>% plotly::layout( title = df_{{ env_id }}()$feature ) %>% plotly::event_register("plotly_selected") %>% plotly::toWebGL() -> plot plot }) renderUI({plotly::plotlyOutput("scatter_{{ env_id }}", height = "100%")})
# compare with colormaps if(is.factor(group_by_{{ env_id }}[,1])){ if(colnames(group_by_{{ env_id }})[1] %in% names(colormaps)) colors_{{ env_id }} <- colormaps[[colnames(group_by_{{ env_id }})[1]]] else colors_{{ env_id }} <- "Set1" } i2dash.scrnaseq::plotly_scatterplot(x =reduced_dim_{{ env_id }}[,1], y = reduced_dim_{{ env_id }}[,2], color = group_by_{{ env_id }}[,1], text = row.names(reduced_dim_{{ env_id }}), hoverinfo = "x+y+text", y_title = "Dimension 2", x_title = "Dimension 1", colors = colors_{{ env_id }}) %>% plotly::layout( title = paste0("Coloured by: ", colnames(group_by_{{ env_id }})[1]) ) -> scatter_2_{{ env_id }} # %>% # plotly::config(fillFrame = TRUE) -> scatter_{{ env_id }} scatter_2_{{ env_id }}$elementId <- "scatter_2_{{ env_id }}" scatter_2_{{ env_id }}
# # Output # output$scatter_2_{{ env_id }} <- plotly::renderPlotly({ # compare with colormaps if(input$select_grouping_{{ env_id }} %in% names(colormaps)) colors <- colormaps[[input$select_grouping_{{ env_id }}]] else colors <- "Set1" i2dash.scrnaseq::plotly_scatterplot(x = reduced_dim_{{ env_id }}[,1], y = reduced_dim_{{ env_id }}[,2], color = as.factor(group_by_{{ env_id }}[[input$select_grouping_{{ env_id }}]]), text = rownames(reduced_dim_{{ env_id }}[,1]), hoverinfo = "x+y+text", source = "scatter_2_{{ env_id }}", key = rownames(reduced_dim_{{ env_id }}), y_title = "Dimension 2", x_title = "Dimension 1", colors = colors) %>% plotly::layout( title = paste0("Coloured by: ", input$select_grouping_{{ env_id }}) ) %>% plotly::event_register("plotly_selected") %>% plotly::toWebGL() -> plot plot }) renderUI({plotly::plotlyOutput("scatter_2_{{ env_id }}", height = "100%")})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.