我正在尝试使用 D3 创建一个直方图,它对条形图和轴都有很好的动画过渡。让酒吧工作很简单,但我很难看到如何用轴做同样的事情。在下面的示例中,过渡看起来正在发生,但实际上每次都添加一个新轴,而不会删除旧轴。
我的最终目标是使用 R2D3 开发这样的小部件,然后将 javascript 交给其他人在 Java 应用程序中实现,所以我需要确保它是可转移的并且不使用 R/shiny/R2D3 javascript 文件中的特定内容。
这是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)