双条形图的创建

用户名

我想创建一个像这样的条形图:

在此处输入图片说明

下方有两个图表条,第一个向上生长,第二个向下生长。他们有不同的规模和数据。

这是我创建的:

var doublebarSvg1 = d3.select('#doublebar')
    .append('svg')
    .attr('class', 'doublebarSvg1')
    .attr('width', 700)
    .attr('height', 400);

var doublebarSvg2 = d3.select('#doublebar')
    .append('svg')
    .attr('class', 'doublebarSvg2')
    .attr('width', 700)
    .attr('height', 400);

var margin = {top: 0, right: 0, bottom: 0, left: 50};

var width = doublebarSvg1.attr('width') - margin.left - margin.right;
var height = doublebarSvg1.attr('height') - margin.top - margin.bottom;

var x = d3.scaleBand()
    .rangeRound([0, width])
    .padding(0.1)
    .domain(years);

var y1 = d3.scaleLinear()
    .rangeRound([height, 0])
    .domain([0, 100]);

var y2 = d3.scaleSqrt()
    .rangeRound([height, 0])
    .domain([813, 0.1]); // max value 812.05 but domain is [0, 100000]

var doublebarSvgG1 = doublebarSvg1.append('g').attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
var doublebarSvgG2 = doublebarSvg2.append('g').attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

////////////////////////////////////////////////////////////////////////
// Tooltip.
////////////////////////////////////////////////////////////////////////
var svgTip = doublebarSvg1.append('svg').attr('id', 'tooltip');

var tip = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-5, 0])
    .html(function(d) {
        return '<div><span>Country:</span> <span style=\'color:white\'>' + d.country + '</span></div>' +
                 '<div><span>Perc:</span> <span style=\'color:white\'>' + d.perc + '%</span></div>' +
                 '<div><span>Rate:</span> <span style=\'color:white\'>' + d.rate + '%</span></div>';
    });
svgTip.call(tip);

////////////////////////////////////////////////////////////////////////
// Draw a single double bar
////////////////////////////////////////////////////////////////////////
makeDoublebar1();

function makeDoublebar1() {
    // define the axes
    var xAxis = d3.axisBottom(x); 
    var yAxis1 = d3.axisLeft(y1);

    // create x axis
    doublebarSvgG1.append('g')
        .attr('class', 'x axis')
        .attr('transform', 'translate(0, ' + height + ')') 
        .call(xAxis)
        .selectAll('text')  
        .style('text-anchor', 'end')
        .attr('dx', '-.8em')
        .attr('dy', '.15em')
        .attr('transform', 'rotate(-65)');

    // create y axis
    doublebarSvgG1.append('g')
        .attr('class', 'y axis')
        .call(yAxis1)
        .append('text')
        .attr('transform', 'rotate(-90)')
        .attr('y', 6)
        .attr('dy', '.71em')
        .style('text-anchor', 'end');

    // create bar rect
    doublebarSvgG1.selectAll('.bar')
        .data(testData1) //.data(covFiltered)
        .enter().append('rect')
        .attr('fill', 'steelblue')
        .attr('class', 'bar')
        .attr('x', function(d) {
            return x(d.year); 
        })
        .attr('y', function(d) { 
            if(isNaN(d.perc)) {
                d.perc = 0;
            }
            return y1(d.perc); 
        })
        .attr('width', x.bandwidth())
        .attr('height', function(d) { 
            if(isNaN(d.perc)) {
                d.perc = 0;
            }
            return height - y1(d.perc); 
        })
        .on('mouseover', function(d) {
            d3.select(this).attr('fill', 'darkblue');
            tip.show(d);
        })
        .on('mouseout', function(d) {
            d3.select(this).attr('fill', 'steelblue');
            tip.hide(d);
        });
}

////////////////////////////////////////////////////////////////////////
// Draw a single double bar
////////////////////////////////////////////////////////////////////////
makeDoublebar2();

function makeDoublebar2() {
    // define the axes
    var xAxis = d3.axisBottom(x); 
    var yAxis2 = d3.axisLeft(y2);

    // create x axis
    doublebarSvgG2.append('g')
        .attr('class', 'x axis')
        .attr('transform', 'translate(0, 0)') 
        .call(xAxis)
        .selectAll('text')  
        .style('text-anchor', 'end')
        .attr('dx', '-.8em')
        .attr('dy', '.15em')
        .attr('transform', 'rotate(-65)');

    // create y axis
    doublebarSvgG2.append('g')
        .attr('class', 'y axis')
        .call(yAxis2)
        .append('text')
        .style('text-anchor', 'end');

    // create bar rect
    doublebarSvgG2.selectAll('.bar')
        .data(testData2)
        .enter().append('rect')
        .attr('fill', 'tomato')
        .attr('class', 'bar')
        .attr('x', function(d) { // left start point
            return x(d.year); 
        })
        .attr('y', function(d) { // top start point
            if(isNaN(d.rate)) {
                d.rate = 0;
            }
            return 0; 
        })
        .attr('width', x.bandwidth())
        .attr('height', function(d) { 
            if(isNaN(d.rate)) {
                d.perc = 0;
            }
            return y2(d.rate); 
        })
        .on('mouseover', function(d) {
            d3.select(this).attr('fill', 'red');
            tip.show(d);
        })
        .on('mouseout', function(d) {
            d3.select(this).attr('fill', 'tomato');
            tip.hide(d);
        });
}

在这里

有一些问题:

  1. 如果我替换.axis {display: initial;}.axis {display: none;},则所有轴均消失,但我希望两个图表之间的水平线

  2. 我只希望有一个工具提示,当用户将鼠标悬停在任何栏上时,它会显示一个同时显示percrate价值的工具提示

而且,更重要的是,这是创建此类图表的最明智的方法吗?

杰拉尔多·富塔多

关于轴,由于要保留水平线,因此只需隐藏刻度线和文本即可:

.x.axis text,.x.axis line {
  opacity: 0;
}

工具提示问题要复杂一些。问题是您要将不同的数据数组绑定到每组柱。

因此,最好的办法是将鼠标悬停在给定年份上并在每个数组中找到所需的对象并获取各自的属性:

var thisPerc = testData1.find(function(e){return e.year === d.year}).perc;
var thisRate = testData2.find(function(e){return e.year === d.year}).rate;

然后,您可以使用这些属性来设置工具提示的文本。

这是更新的Plunker:http ://plnkr.co/edit/tfB4TpkETgzp5GF1677p?p=preview

最后,对于最后一个问题(“更重要的是,这是创建类似图表的最明智的方法吗?”),答案是否定的这里有很多事情可以(并且必须)进行更改,但这涉及很多重构,并且在Stack Overflow上可以说是不合时宜的话题。但是,这对于Code Review是一个足够的问题但是,请先阅读他们的文档,以使您的问题保持在主题上,询问与此处提出的问题不同。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章