2017-11-22 12 views
-1

私はD3の領域を使用して次のグラフを生成することができるよ:D3のバーに領域をモーフしますか?

enter image description here

私は、次のアニメーションを作成したいです。 Webページが読み込まれると、最初の図が表示されます。次に、各領域がバーに変形されます。最後に、「B」または「D」をクリックして2つの数字を切り替えることができます。

私はボタンと対応するバーを私の人物に追加することができましたが、アニメーションの仕方を理解するのに苦労しています。これは私が今持っているコードです:

HTMLWidgets.widget({ 

    name: 'IMposterior', 

    type: 'output', 

    factory: function(el, width, height) { 

    // TODO: define shared variables for this instance 

    return { 

     renderValue: function(opts) { 

     console.log("threshold: ", opts.threshold); 
     console.log("bars: ", opts.bars); 

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

     xMax = d3.max(opts.data, function(d) { return d.x ; }); 
     yMax = d3.max(opts.data, function(d) { return d.y ; }); 
     xMin = d3.min(opts.data, function(d) { return d.x ; }); 
     yMin = d3.min(opts.data, function(d) { return d.y ; }); 

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

     var x = d3.scaleLinear() 
        .domain([xMin,xMax]) 
        .range([0,width]); 


     var yAxis = d3.axisLeft(y); 
     var xAxis = d3.axisBottom(x); 


     var area = d3.area() 
         .x(function(d){ return x(d.x) ;}) 
         .y0(height-margin.bottom) 
         .y1(function(d){ return y(d.y); }); 

     var svg = d3.select(el).append('svg').attr("height","100%").attr("width","100%"); 
     var chartGroup = svg.append("g").attr("transform","translate("+margin.left+","+margin.top+")"); 


     chartGroup.append("path") 
      .attr("d", area(opts.data.filter(function(d){ return d.x< -opts.MME ;}))) 
      .style("fill", opts.colors[0]); 

     if(opts.MME !==0){ 
      chartGroup.append("path") 
      .attr("d", area(opts.data.filter(function(d){ return (d.x < opts.MME & d.x > -opts.MME) ;}))) 
      .style("fill", opts.colors[1]); 
     } 

     chartGroup.append("path") 
      .attr("d", area(opts.data.filter(function(d){ return d.x > opts.MME ;}))) 
      .style("fill", opts.colors[2]); 




     chartGroup.append("g") 
      .attr("class","axis x") 
      .attr("transform","translate(0,"+(height-margin.bottom)+")") 
      .call(xAxis); 


     var tooltip = d3.tip() 
       .attr('class', 'd3-tip chart-data-tip') 
       .offset([30, 0]) 
       .direction('s') 
       .html(function(d, i) { 
        return "<strong>" + d + "</strong> <span style='color:" + "white" + "'>"+ "</span>"; 
       }); 

     svg.call(tooltip); 

     chartGroup.selectAll("path").data(opts.text).on('mouseover', tooltip.show).on('mouseout', tooltip.hide); 



     // Bars 

     var yBar = d3.scaleLinear() 
        .domain([0,1]) 
        .range([height-margin.bottom,0]); 

     var xBar = d3.scaleBand() 
        .domain(opts.bars.map(function(d) { return d.x; })) 
        .rangeRound([0, width]).padding(0.1); 

     var yAxisBar = d3.axisLeft(yBar); 
     var xAxisBar = d3.axisBottom(xBar); 


     var g = svg.append("g") 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 


     g.append("g") 
     .attr("class", "axis axis--x") 
     .attr("transform","translate(0,"+(height-margin.bottom)+")") 
     .call(d3.axisBottom(xBar)); 


     g.append("g") 
     .attr("class", "axis axis--y") 
     .call(d3.axisLeft(yBar).ticks(10, "%")) 
     .append("text") 
     .attr("transform", "rotate(-90)") 
     .attr("y", 6) 
     .attr("dy", "0.71em") 
     .attr("text-anchor", "end") 
     .text("Probability"); 

     g.selectAll(".bar") 
     .data(opts.bars) 
     .enter().append("rect") 
     .attr("class", "bar") 
     .attr("x", function(d) { return xBar(d.x); }) 
     .attr("y", function(d) { return yBar(d.y); }) 
     .attr("width", xBar.bandwidth()) 
     .style("fill", function(d) { return d.color; }) 
     .attr("height", function(d) { return height - margin.bottom - yBar(d.y); }); 





     // Add buttons 

//container for all buttons 
      var allButtons= svg.append("g") 
           .attr("id","allButtons"); 

      //fontawesome button labels 
      var labels= ["B", "D"]; 

      //colors for different button states 
      var defaultColor= "#E0E0E0"; 
      var hoverColor= "#808080"; 
      var pressedColor= "#000000"; 

      //groups for each button (which will hold a rect and text) 
      var buttonGroups= allButtons.selectAll("g.button") 
            .data(labels) 
            .enter() 
            .append("g") 
            .attr("class","button") 
            .style("cursor","pointer") 
            .on("click",function(d,i) { 
             updateButtonColors(d3.select(this), d3.select(this.parentNode)); 
             d3.select("#numberToggle").text(i+1); 
            }) 
            .on("mouseover", function() { 
             if (d3.select(this).select("rect").attr("fill") != pressedColor) { 
              d3.select(this) 
               .select("rect") 
               .attr("fill",hoverColor); 
             } 
            }) 
            .on("mouseout", function() { 
             if (d3.select(this).select("rect").attr("fill") != pressedColor) { 
              d3.select(this) 
               .select("rect") 
               .attr("fill",defaultColor); 
             } 
            }); 

      var bWidth= 40; //button width 
      var bHeight= 25; //button height 
      var bSpace= 10; //space between buttons 
      var x0= 20; //x offset 
      var y0= 10; //y offset 

      //adding a rect to each toggle button group 
      //rx and ry give the rect rounded corner 
      buttonGroups.append("rect") 
         .attr("class","buttonRect") 
         .attr("width",bWidth) 
         .attr("height",bHeight) 
         .attr("x",function(d,i) {return x0+(bWidth+bSpace)*i;}) 
         .attr("y",y0) 
         .attr("rx",5) //rx and ry give the buttons rounded corners 
         .attr("ry",5) 
         .attr("fill",defaultColor); 

      //adding text to each toggle button group, centered 
      //within the toggle button rect 
      buttonGroups.append("text") 
         .attr("class","buttonText") 
         .attr("x",function(d,i) { 
          return x0 + (bWidth+bSpace)*i + bWidth/2; 
         }) 
         .attr("y",y0+bHeight/2) 
         .attr("text-anchor","middle") 
         .attr("dominant-baseline","central") 
         .attr("fill","white") 
         .text(function(d) {return d;}); 

      function updateButtonColors(button, parent) { 
       parent.selectAll("rect") 
         .attr("fill",defaultColor); 

       button.select("rect") 
         .attr("fill",pressedColor); 

      } 

     }, 



     resize: function(width, height) { 

     // TODO: code to re-render the widget with a new size 

     } 

    }; 
    } 
}); 

そして、これはそのコードが生成する図である。

enter image description here

+0

d3 show reelをご覧ください。私はマイクがこれを行うと確信しているhttps://bl.ocks.org/mbostock/1256572 – Ian

答えて

1

これは、トリックを行います。

HTMLWidgets.widget({ 

    name: 'IMPosterior', 

    type: 'output', 

    factory: function(el, width, height) { 

    // TODO: define shared variables for this instance 

    return { 

     renderValue: function(opts) { 

     //transition 
     var transDuration = 1000; 

     var dataDiscrete = opts.bars.map((b, i) => { 
      b.y = Number(b.y); 
      b.desc = opts.text[i]; 
      return b; 
     }); 

     var distParams = { 
      min: d3.min(opts.data, d => d.x), 
      max: d3.max(opts.data, d => d.x) 
     }; 

     distParams.cuts = [-opts.MME, opts.MME, distParams.max]; 

     opts.data = opts.data.sort((a,b) => a.x - b.x); 

     var dataContinuousGroups = []; 
     distParams.cuts.forEach((c, i) => { 
      let data = opts.data.filter(d => { 
       if (i === 0) { 
        return d.x < c; 
       } else if (i === distParams.cuts.length - 1) { 
        return d.x > distParams.cuts[i - 1]; 
       } else { 
        return d.x < c && d.x > distParams.cuts[i - 1]; 
       } 
      }); 

      data.unshift({x:data[0].x, y:0}); 
      data.push({x:data[data.length - 1].x, y:0}); 

      dataContinuousGroups.push({ 
       color: opts.colors[i], 
       data: data 
      }); 
     }); 

     var margin = { 
       top: 50, 
       right: 20, 
       bottom: 80, 
       left: 70 
      }, 
      dims = { 
       width: width - margin.left - margin.right, 
       height: height - margin.top - margin.bottom 
      }; 

     var xContinuous = d3.scaleLinear() 
      .domain([distParams.min - 1, distParams.max + 1]) 
      .range([0, dims.width]); 

     var xDiscrete = d3.scaleBand() 
      .domain(dataDiscrete.map(function(d) { return d.x; })) 
      .rangeRound([0, dims.width]).padding(0.1); 

     var y = d3.scaleLinear() 
      .domain([0, 1]) 
      .range([dims.height, 0]); 

     var svg = d3.select(el).append("svg") 
      .attr("width", dims.width + margin.left + margin.right) 
      .attr("height", dims.height + margin.top + margin.bottom); 

     var g = svg 
      .append("g") 
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

     var xAxis = d3.axisBottom() 
      .scale(xDiscrete); 

     var yAxis = d3.axisLeft() 
      .scale(y) 
      .ticks(10) 
      .tickFormat(d3.format(".0%")); 

     var yLabel = g.append("text") 
      .attr("class", "y-axis-label") 
      .attr("transform", "rotate(-90)") 
      .attr("y", -52) 
      .attr("x", -160) 
      .attr("dy", ".71em") 
      .style("text-anchor", "end") 
      .style("font-size", 14 + "px") 
      .text("Probability"); 

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

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

     var areas = g.selectAll(".area") 
      .data(dataDiscrete) 
      .enter().append("path") 
       .attr("class", "area") 
       .style("fill", function(d) { return d.color; }) 
       .attr("d", function(d, i) { 
        let numPts = dataContinuousGroups[i].data.length - 2; 
        var path = d3.path() 
        path.moveTo(xDiscrete(d.x), y(0)); 
        for (j=0; j<numPts; j++) { 
         path.lineTo(xDiscrete(d.x) + j*xDiscrete.bandwidth()/(numPts-1), y(d.y)) 
        } 
        path.lineTo(xDiscrete(d.x) + xDiscrete.bandwidth(), y(0)); 
        return path.toString(); 
       }); 

     var tooltip = d3.tip() 
      .attr('class', 'd3-tip chart-data-tip') 
      .offset([30, 0]) 
      .direction('s') 
      .html(function(d, i) { 
       return "<span>" + dataDiscrete[i].desc + "</span>"; 
      }); 

     g.call(tooltip); 

     areas 
      .on('mouseover', tooltip.show) 
      .on('mouseout', tooltip.hide); 

     var thresholdLine = g.append("line") 
      .attr("stroke", "black") 
      .style("stroke-width", "1.5px") 
      .style("stroke-dasharray", "5,5") 
      .style("opacity", 1) 
      .attr("x1", 0) 
      .attr("y1", y(opts.threshold)) 
      .attr("x2", dims.width) 
      .attr("y2", y(opts.threshold)); 


     var updateXAxis = function(type, duration) { 
      if (type === "continuous") { 
       xAxis.scale(xContinuous); 
      } else { 
       xAxis.scale(xDiscrete); 
      } 
      d3.select(".x").transition().duration(duration).call(xAxis);  
     }; 

     var updateYAxis = function(data, duration) { 
      var extent = d3.extent(data, function(d) { 
       return d.y; 
      }); 
      extent[0] = 0; 
      extent[1] = extent[1] + 0.2*(extent[1] - extent[0]); 
      y.domain(extent); 
      d3.select(".y").transition().duration(duration).call(yAxis); 
     }; 

     var toggle = function(to, duration) { 
      if (to === "distribution") { 
       updateYAxis(dataContinuousGroups[0].data.concat(dataContinuousGroups[1].data).concat(dataContinuousGroups[2].data), 0); 
       updateXAxis("continuous", duration); 

       areas 
        .data(dataContinuousGroups) 
        .transition() 
        .duration(duration) 
         .attr("d", function(d) { 
          var gen = d3.line() 
           .x(function(p) { 
            return xContinuous(p.x); 
           }) 
           .y(function(p) { 
            return y(p.y); 
           }); 
          return gen(d.data); 
         }); 

       thresholdLine 
        .style("opacity", 0); 

       g.select(".y.axis") 
        .style("opacity", 0); 

       g.select(".y-axis-label") 
        .style("opacity", 0); 

      } else { 
       y.domain([0, 1]); 
       d3.select(".y").transition().duration(duration).call(yAxis); 

       updateXAxis("discrete", duration); 

       areas 
        .data(dataDiscrete) 
        .transition() 
        .duration(duration) 
         .attr("d", function(d, i) { 
          let numPts = dataContinuousGroups[i].data.length - 2; 
          var path = d3.path() 
          path.moveTo(xDiscrete(d.x), y(0)); 
          for (j=0; j<numPts; j++) { 
           path.lineTo(xDiscrete(d.x) + j*xDiscrete.bandwidth()/(numPts-1), y(d.y)) 
          } 
          path.lineTo(xDiscrete(d.x) + xDiscrete.bandwidth(), y(0)); 
          return path.toString(); 
         }); 

       thresholdLine 
        .transition() 
        .duration(0) 
        .delay(duration) 
         .style("opacity", 1) 
         .attr("y1", y(opts.threshold)) 
         .attr("y2", y(opts.threshold)); 

       g.select(".y.axis") 
        .transition() 
        .duration(0) 
        .delay(duration) 
         .style("opacity", 1); 

       g.select(".y-axis-label") 
        .transition() 
        .duration(0) 
        .delay(duration) 
         .style("opacity", 1); 
      } 
     }; 


     // Add buttons 

     //container for all buttons 
     var allButtons = svg.append("g") 
      .attr("id", "allButtons"); 

     //fontawesome button labels 
     var labels = ["B", "D"]; 

     //colors for different button states 
     var defaultColor = "#E0E0E0"; 
     var hoverColor = "#808080"; 
     var pressedColor = "#000000"; 

     //groups for each button (which will hold a rect and text) 
     var buttonGroups = allButtons.selectAll("g.button") 
      .data(labels) 
      .enter() 
      .append("g") 
      .attr("class", "button") 
      .style("cursor", "pointer") 
      .on("click", function(d, i) { 
      updateButtonColors(d3.select(this), d3.select(this.parentNode)); 
      d3.select("#numberToggle").text(i + 1); 
      if (d === "D") { 
       toggle("distribution", transDuration); 
      } else { 
       toggle("discrete", transDuration); 
      } 

      }) 
      .on("mouseover", function() { 
      if (d3.select(this).select("rect").attr("fill") != pressedColor) { 
       d3.select(this) 
       .select("rect") 
       .attr("fill", hoverColor); 
      } 
      }) 
      .on("mouseout", function() { 
      if (d3.select(this).select("rect").attr("fill") != pressedColor) { 
       d3.select(this) 
       .select("rect") 
       .attr("fill", defaultColor); 
      } 
      }); 

     var bWidth = 40; //button width 
     var bHeight = 25; //button height 
     var bSpace = 10; //space between buttons 
     var x0 = 20; //x offset 
     var y0 = 10; //y offset 

     //adding a rect to each toggle button group 
     //rx and ry give the rect rounded corner 
     buttonGroups.append("rect") 
      .attr("class", "buttonRect") 
      .attr("width", bWidth) 
      .attr("height", bHeight) 
      .attr("x", function(d, i) { 
      return x0 + (bWidth + bSpace) * i; 
      }) 
      .attr("y", y0) 
      .attr("rx", 5) //rx and ry give the buttons rounded corners 
      .attr("ry", 5) 
      .attr("fill", defaultColor); 

     //adding text to each toggle button group, centered 
     //within the toggle button rect 
     buttonGroups.append("text") 
      .attr("class", "buttonText") 
      .attr("x", function(d, i) { 
      return x0 + (bWidth + bSpace) * i + bWidth/2; 
      }) 
      .attr("y", y0 + bHeight/2) 
      .attr("text-anchor", "middle") 
      .attr("dominant-baseline", "central") 
      .attr("fill", "white") 
      .text(function(d) { 
      return d; 
      }); 

     function updateButtonColors(button, parent) { 
      parent.selectAll("rect") 
      .attr("fill", defaultColor); 

      button.select("rect") 
      .attr("fill", pressedColor); 

     } 

     toggle("distribution", 0); 

     setTimeout(() => { 
      toggle("discrete", transDuration); 
     }, 1000); 

     }, 



     resize: function(width, height) { 

     // TODO: code to re-render the widget with a new size 

     } 

    }; 
    } 
}); 

Posterior

関連する問題