【问题标题】:How do you animate axis transitions with d3 in r2d3?您如何在 r2d3 中使用 d3 为轴过渡设置动画?
【发布时间】:2021-05-23 23:26:15
【问题描述】:

我正在尝试使用 D3 创建一个直方图,它对条形图和坐标轴都有很好的动画过渡。让酒吧工作很简单,但我很难看到如何用轴做同样的事情。在下面的示例中,过渡看起来正在发生,但实际上每次都添加一个新轴,而不会删除旧轴。

我的最终目标是使用 R2D3 开发这样的小部件,然后将 javascript 交给其他人在 Java 应用程序中实现,所以我需要确保它是可转移的并且不使用 R/ javascript 文件中的闪亮/R2D3 特定内容。

这是hist.js 脚本

// !preview r2d3 data=data.frame(density = c(10,20,5), from = c(0, 1, 3), to = c(1, 3, 4))
//
// r2d3: https://rstudio.github.io/r2d3
//

var margin = {left:40, right:30, top:10, bottom:30, axis_offset:10};

var min_from = d3.min(data, function(d) {return d.from;});
var max_to = d3.max(data, function(d) {return d.to;});
var max_density = d3.max(data, function(d) { return d.density;});

svg.append('g')
  .attr('transform', 'translate('+(margin.left - margin.axis_offset)+', 0)')
  .attr("class", "y_axis");

svg.append('g')
  .attr('transform', 'translate(0, '+(height - margin.bottom + margin.axis_offset)+')')
  .attr("class", "x_axis");

var x = d3.scaleLinear()
  .domain([min_from, max_to])
  .range([margin.left, width-margin.right])
  .nice();

var y = d3.scaleLinear()
  .domain([0, max_density])
  .range([height-margin.bottom, margin.top])
  .nice();

svg.selectAll('.y_axis')
  .transition()
  .duration(500)
  .call(d3.axisLeft(y));

svg.selectAll('.x_axis')
  .transition()
  .duration(500)
  .call(d3.axisBottom(x));

var bars = svg.selectAll('rect').data(data);

bars.enter().append('rect')
  .attr('x', function(d) { return x(d.from); })
  .attr('width', function(d) { return x(d.to) - x(d.from)-1;})
  .attr('y', function(d) { return y(d.density); })
  .attr('height', function(d) { return y(0) - y(d.density); })
  .attr('fill', 'steelblue');

bars.exit().remove();

bars.transition()
  .duration(500)
  .attr('x', function(d) { return x(d.from); })
  .attr('width', function(d) { return x(d.to) - x(d.from)-1;})
  .attr('y', function(d) { return y(d.density); })
  .attr('height', function(d) { return y(0) - y(d.density); });

这是我运行它的闪亮应用程序

library(shiny)
library(r2d3)
library(data.table)
library(jsonlite)

get_hist <- function(x) {
  buckets <- seq(0, mean(x)+3*sd(x), length.out = 21)
  h <- hist(x, breaks = c(buckets, Inf), plot = FALSE)
  y <- data.table(count = h$counts, from = head(h$breaks, -1), to = head(shift(h$breaks, -1), -1))[-.N]
  y[, density := count/(to-from)]
  y[]
}

new_data <- function() {
  sh <- 1
  rgamma(10, sh, 1/sh)
}

ui <- fluidPage(
  actionButton("add_data", "Add more data"),
  d3Output('d3_hist')
)

server <- function(input, output, session) {
  samp <- reactiveVal(new_data())
  observeEvent(input$add_data, {
    samp(c(samp(), new_data()))
  })
  output$d3_hist <- renderD3({
    y <- get_hist(samp())
    r2d3(data = toJSON(y), script = 'hist.js')
  })
}

shinyApp(ui, server)

【问题讨论】:

    标签: r d3.js shiny r2d3


    【解决方案1】:

    每次更新数据时,都会为每个轴创建一个新的g 元素。这将创建多个 g 元素,其类为 x_axis / y_axis,您可以在所有这些元素上调用轴生成器:

     svg.append('g') // append a new g every update for x axis
        .attr('transform', 'translate(0, '+(height - margin.bottom + margin.axis_offset)+')')
        .attr("class", "x_axis");    
    
    svg.selectAll('.x_axis')  // call axis generator for every x axis g.
     .transition()
     .duration(500)
     .call(d3.axisBottom(x));
    

    r2d3 的设置有点不同,因为通常您会为每个轴创建一个 g,然后使用更新函数来更新数据和轴。这里整个 javascript 脚本每次都会运行,所以我们需要避免在每个轴上附加一个 g

    例如:

      if(svg.select(".y_axis").empty()) {
        svg.append('g')
           .attr('transform', 'translate('+(margin.left - margin.axis_offset)+', 0)')
           .attr("class", "y_axis");
      }
      if(svg.select(".x_axis").empty()) {
         svg.append('g')
            .attr('transform', 'translate(0, '+(height - margin.bottom + margin.axis_offset)+')')
            .attr("class", "x_axis");    
      }
    

    在 javascript 中可以采用不同的方法,但这可能是最直接的。理想情况下,r2d3 更容易让您运行更新函数,而不是每次更新时运行整个脚本。

    【讨论】:

    • 谢谢,这很好用。根据你的说法,我想我应该调查一下我的同事将如何实现更新功能并相应地构建我的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2018-10-19
    • 2018-04-28
    • 1970-01-01
    相关资源
    最近更新 更多