R Markdown标签页中非首个桑基图的htmlwidgets::onRender失效问题
Hey there! Let’s work through your two Sankey plot issues in R Markdown—first getting htmlwidgets::onRender to work for plots in non-initial tabs, then controlling those node labels exactly how you want.
Fixing onRender for Tabbed Sankey Plots
The problem happens because only the first active tab’s content gets rendered into the DOM when your HTML document loads. Plots in inactive tabs are hidden, so the onRender callback can’t find their elements to apply your custom adjustments. Here’s a solid fix:
- Assign unique IDs to each Sankey plot: Use the
elementIdparameter insankeyNetworkto give every plot a distinct identifier. - Listen for tab activation: Use Bootstrap’s tab events (since R Markdown uses Bootstrap tabs) to trigger your custom JavaScript only when the tab containing the plot becomes visible.
Here’s how to implement this in your code:
--- title: "Sankey Tabs Fix" output: html_document --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = FALSE) library(networkD3) library(htmlwidgets) # Sample data (replace with your actual nodes/links) nodes1 <- data.frame(name = c("A", "B", "C")) links1 <- data.frame(source = c(0,1), target = c(2,2), value = c(10,20)) nodes2 <- data.frame(name = c("X", "Y", "Z")) links2 <- data.frame(source = c(0,1), target = c(2,2), value = c(15,25))
Sankey Plots in Tabs
tabsetPanel( tabPanel("First Plot", sankeyNetwork(Links = links1, Nodes = nodes1, Source = "source", Target = "target", Value = "value", NodeID = "name", elementId = "sankey-plot-1") %>% onRender("function(el, x) { // Apply adjustments immediately since this is the initial active tab d3.select(el).selectAll('.node text') .style('font-size', '12px') .attr('x', x.nodeWidth + 8); }") ), tabPanel("Second Plot", sankeyNetwork(Links = links2, Nodes = nodes2, Source = "source", Target = "target", Value = "value", NodeID = "name", elementId = "sankey-plot-2") %>% onRender("function(el, x) { var tabPane = $(el).closest('.tab-pane'); // If tab isn't active yet, wait for it to be shown if (!tabPane.hasClass('active')) { tabPane.one('shown.bs.tab', function() { // Your custom adjustments here d3.select(el).selectAll('.node text') .style('font-size', '12px') .attr('x', x.nodeWidth + 8); }); } else { // Tab is already active, apply changes right away d3.select(el).selectAll('.node text') .style('font-size', '12px') .attr('x', x.nodeWidth + 8); } }") ) )
### Controlling Node Labels You have two options here—quick R-side adjustments, or more flexible control with JavaScript. #### Option 1: R-Side Control (Simple) - **Change label text**: Modify the `name` column in your `nodes` data frame to set custom labels: ```r nodes$name <- paste("Category:", nodes$name) # Add a prefix to all labels
- Adjust font size: Use the
fontSizeparameter insankeyNetworkto set label size globally:sankeyNetwork(..., fontSize = 14) # Larger 14px font for all labels
Option 2: Advanced Control with JavaScript (via onRender)
For precise control over label position, alignment, or conditional styling, use D3 in your onRender callback:
sankeyNetwork(...) %>% onRender("function(el, x) { // Move labels to the right of left nodes, left of right nodes d3.select(el).selectAll('.node text') .attr('x', function(d) { // Align based on node position relative to plot center return d.x < x.width / 2 ? x.nodeWidth + 10 : -10; }) .attr('text-anchor', function(d) { return d.x < x.width / 2 ? 'start' : 'end'; }) .style('fill', '#2c3e50') // Dark gray text color .style('font-weight', '600'); // Semi-bold labels }")
内容的提问来源于stack exchange,提问作者Yorgos
相关产品推荐
相关产品推荐

