Javascript D3.js图表之间的转换

Javascript D3.js图表之间的转换,javascript,d3.js,charts,Javascript,D3.js,Charts,我正在尝试在我的条形图代码中创建一个转换,这将允许用户单击特定的条形图,并显示与该条形图相关的一组不同的数据 这是一个示例数据集: module_category,component_category,date_repair,actual,predicted M1,P06,2009/01,39,63 M1,P06,2009/10,3,4 M1,P06,2009/11,4,3 M1,P06,2009/12,4,2 M1,P06,2009/02,29,45 M1,P06,2009/03,29,32

我正在尝试在我的条形图代码中创建一个转换,这将允许用户单击特定的条形图,并显示与该条形图相关的一组不同的数据

这是一个示例数据集:

module_category,component_category,date_repair,actual,predicted
M1,P06,2009/01,39,63
M1,P06,2009/10,3,4
M1,P06,2009/11,4,3
M1,P06,2009/12,4,2
M1,P06,2009/02,29,45
M1,P06,2009/03,29,32
M1,P06,2009/04,10,22
M1,P06,2009/05,13,15
M1,P06,2009/06,9,16
M1,P06,2009/07,7,12
完整数据集可在以下位置找到:

因此,根据我当前的代码,我可以创建以下条形图:

但现在我想添加交互功能,允许用户在点击条形图(例如“M2”)后,将图形更新为显示与该模块相关的“组件_类别”中的组件,相应的“实际”和“预测”值也显示为条形图

这是我当前的代码:

var margin={top:20,right:90,bottom:30,left:60},
宽度=980-边距.左-边距.右,
高度=500-margin.top-margin.bottom;
var x0=d3.scale.ordinal()
.rangeRoundBands([0,宽度],.1);
var x1=d3.scale.ordinal();
变量y=d3.scale.linear()
.范围([高度,0]);
var color=d3.scale.category10();
var xAxis=d3.svg.axis()
.比例(x0)
.东方(“底部”);
var yAxis=d3.svg.axis()
.比例(y)
.东方(“左”)
.tick格式(d3格式(“.2s”);
var svg=d3.选择(#maincontent”).追加(“svg”)
.attr('id','chart'))
.attr('viewBox','0 0 980 500')
.attr('perserveAspectRatio','xMinYMid')
.attr('width',width+margin.right+margin.left)
.attr('height',height+margin.top+margin.bottom)
.附加(“g”)
.attr(“转换”、“平移”(+margin.left+)、“+margin.top+”);
var tip=d3.tip()
.attr(“类别”、“d3提示”)
.偏移量([-10,0])
.html(函数(d){返回“修复次数:”+d.value;});
d3.csv(“数据/合并结果.csv”),函数(错误,数据){
如果(错误)抛出错误;
data=d3.nest()
.key(函数(d){return d.module_category;}).sortkey(d3.ascending)
.rollup(函数(值){
变量计数={},键=['actual','predicted']
键。forEach(功能(键){
counts[key]=d3.sum(值,函数(d){返回d[key]})
})
返回计数
})
.条目(数据);
控制台日志(数据);
域(data.map(函数(d){return d.key;}));
x1.domain(['actual','predicted']).rangeRoundBands([0,x0.rangeBand()]);
//将所有值存储在一个数组中
var yval=[];
data.forEach(函数(d){
yval.推力(d.值.实际值);
yval.push(预测的d值);
});
y、 域([0,d3.max(yval)]);
svg.call(tip);
svg.append(“g”)
.attr(“类”、“x轴”)
.attr(“变换”、“平移(0)”、“高度+”)
.呼叫(xAxis);
svg.append(“g”)
.attr(“类”、“y轴”)
.呼叫(yAxis)
.append(“文本”)
.attr(“变换”、“旋转(-90)”)
.attr(“y”,0-页边距。左)
.attr(“x”,0-(高度/2))
.attr(“dy”、“1em”)
.style(“文本锚定”、“中间”)
.文本(“维修次数”);
var module=svg.selectAll(“.module”)
.数据(数据)
.enter().append(“g”)
.attr(“类别”、“g”)
.attr(“transform”,函数(d){return”translate(“+x0(d.key)+”,0)”;});
模块。选择全部(“rect”)
.数据(功能(d){
var ary=[];
push({name:“actual”,value:d.values.actual});
push({name:'predicted',value:d.values.predicted});
回归分析;
})
.enter().append(“rect”)
.on('mouseover',tip.show)
.on('mouseout',tip.hide)
.打开(“单击”,功能(d){
d3.选择(“svg”)
.style(“不透明度”,0)
.删除()
tip.hide()
设置超时(componentgroupedchart,1000);
})
/*
.打开(“单击”,功能(d){
d3.选择(本)
setTimeout(updateChart(名称),500);
})*/
.attr(“宽度”,x1.rangeBand())
.attr(“x”,函数(d){返回x1(d.name);})
.attr(“y”,函数(d){返回y(d.value);})
.attr(“高度”,函数(d){返回高度-y(d.value);})
.style(“fill”,函数(d){返回颜色(d.name);});
var legend=svg.selectAll(“.legend”)
.数据([‘实际’、‘预测’])
.enter().append(“g”)
.attr(“类”、“图例”)
.attr(“transform”,函数(d,i){return“translate(0,+i*20+”);});
图例。追加(“rect”)
.attr(“x”,宽度-18)
.attr(“宽度”,18)
.attr(“高度”,18)
.样式(“填充”,功能(d){
返回颜色(d)
});
图例。追加(“文本”)
.attr(“x”,宽度-24)
.attr(“y”,9)
.attr(“dy”,“.35em”)
.style(“文本锚定”、“结束”)
.text(函数(d){return d;});

});这可以通过制作一个用于制作模块图的函数和另一个用于制作深入类别图的函数来实现。在函数中定义域,因为y轴域x轴域将随模块/类别图的变化而变化

我在代码中添加了注释;如果您有任何问题,请随时提问

  var margin = {
      top: 20,
      right: 90,
      bottom: 30,
      left: 60
    },
    width = 980 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
  var x0 = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

  var x1 = d3.scale.ordinal();

  var y = d3.scale.linear()
    .range([height, 0]);

  var color = d3.scale.category10();

  var xAxis = d3.svg.axis()
    .scale(x0)
    .orient("bottom");

  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .tickFormat(d3.format(".2s"));

  var svg = d3.select("body").append("svg")
    .attr('width', width + margin.right + margin.left)
    .attr('height', height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  var tip = d3.tip()
    .attr("class", "d3-tip")
    .offset([-10, 0])
    .html(function(d) {
      return "No. of repairs: " + d.value;
    });

  d3.csv("my.csv", function(error, data) {
    if (error) throw error;
    fullData = data;
    data = d3.nest()
      .key(function(d) {
        return d.module_category;
      })
      .rollup(function(values) {
        var counts = {},
          keys = ['actual', 'predicted']
        keys.forEach(function(key) {
          counts[key] = d3.sum(values, function(d) {
            return d[key];
          })
        })
        return counts
      })
      .entries(data);
      //make the x axis
    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
      //make the y axis
    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
      .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 0 - margin.left)
      .attr("x", 0 - (height / 2))
      .attr("dy", "1em")
      .style("text-anchor", "middle")
      .text("Number of Repairs");

    makeModuleGraph(data)

    var legend = svg.selectAll(".legend")
      .data(['actual', 'predicted'])
      .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function(d, i) {
        return "translate(0," + i * 20 + ")";
      });

    legend.append("rect")
      .attr("x", width - 18)
      .attr("width", 18)
      .attr("height", 18)
      .style("fill", function(d) {
        return color(d);
      });

    legend.append("text")
      .attr("x", width - 24)
      .attr("y", 9)
      .attr("dy", ".35em")
      .style("text-anchor", "end")
      .text(function(d) {
        return d;
      });
  });

  function makeModuleGraph(data) {
    var yval = [];
    data.forEach(function(d) {
      yval.push(d.values.actual);
      yval.push(d.values.predicted);
    });
    x0.domain(data.map(function(d) {
      return d.key;
    }));
    x1.domain(['actual', 'predicted']).rangeRoundBands([0, x0.rangeBand()]);

    y.domain([0, d3.max(yval)]);

    svg.call(tip);

    svg.selectAll("g .x")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

    svg.selectAll("g .y")
      .attr("class", "y axis")
      .call(yAxis);

    var module = svg.selectAll(".module")
      .data(data)
      .enter().append("g")
      .attr("class", "module")
      .attr("transform", function(d) {
        return "translate(" + x0(d.key) + ",0)";
      });

    module.selectAll("rect")
      .data(function(d) {
        var ary = [];
        ary.push({
          name: "actual",
          value: d.values.actual,
          key: d.key
        });
        ary.push({
          name: "predicted",
          value: d.values.predicted,
          key: d.key
        });
        return ary;
      })
      .enter().append("rect")
      .attr("width", x1.rangeBand())
      .attr("x", function(d) {
        return x1(d.name);
      })
      .attr("y", function(d) {
        return y(d.value);
      })
      .attr("height", function(d) {
        return height - y(d.value);
      })
      .style("fill", function(d) {
        return color(d.name);
      }).on("click", function(d) {
        makeComponentCategoryGraph(d);//make the graph for category
      });

  }

  function makeComponentCategoryGraph(d){
    var filtered = fullData.filter(function(k){ if(d.key == k.module_category){return true;}else {return false;}})
    var data = d3.nest()
      .key(function(d) {
        return d.component_category;
      })
      .rollup(function(values) {
        var counts = {},
          keys = ['actual', 'predicted']
        keys.forEach(function(key) {
          counts[key] = d3.sum(values, function(d) {
            return d[key];
          })
        })
        return counts
      })
      .entries(filtered);
          var yval = [];
    data.forEach(function(d) {
      yval.push(d.values.actual);
      yval.push(d.values.predicted);
    });
    x0.domain(data.map(function(d) {
      return d.key;
    }));
    x1.domain(['actual', 'predicted']).rangeRoundBands([0, x0.rangeBand()]);

    y.domain([0, d3.max(yval)]);

    svg.call(tip);

    svg.selectAll("g .x")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

    svg.selectAll("g .y")
      .attr("class", "y axis")
      .call(yAxis);
    svg.selectAll(".module").remove();//remove alll the bar graphs
    var module = svg.selectAll(".module")
      .data(data)
      .enter().append("g")
      .attr("class", "module")
      .attr("transform", function(d) {
        return "translate(" + x0(d.key) + ",0)";
      });

    module.selectAll("rect")
      .data(function(d) {
        var ary = [];
        ary.push({
          name: "actual",
          value: d.values.actual,
          key: d.key
        });
        ary.push({
          name: "predicted",
          value: d.values.predicted,
          key: d.key
        });
        return ary;
      })
      .enter().append("rect")
      .attr("width", x1.rangeBand())
      .attr("x", function(d) {
        return x1(d.name);
      })
      .attr("y", function(d) {
        return y(d.value);
      })
      .attr("height", function(d) {
        return height - y(d.value);
      })
      .style("fill", function(d) {
        return color(d.name);
      })
  }

工作代码。

您的数据集不清楚您有一条像这样的记录M1,P062009/01,39,63,所以当您单击M1时,它将显示P06?数据集中没有M2。您好,很抱歉,我将完整的数据集放在这里:您的M1数据有多个组件_类别的值有时是p12有时是p16,所有这些数据都有不同的实际值、预测值M1、P122009/01,35,40 M1、P122009/10,3,4 M1、P122009/11,2,3 M1、P162009/04,9,12 M1,P162009/05,10,9等等,向下钻取应该显示哪些值…您能否澄清您的问题,以便对可能回答问题的人有所帮助。好的,现在编辑问题是的,这就是我要找的:)。谢谢。使用filter函数比较module_类别是我的想法,但无法将其可视化。再次感谢