Update multiple charts simultaneously in d3.js

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite












I've created 3 different charts all drawn from the same dataset,
my reasoning for building it this way is so that it'll be easier to add and remove additional rows of charts.



What I'm mainly interested in knowing is if the code is well structured and/or if it's idiomatic d3 code.



Here's a link to all the code: Plunker



And here's the same code but with hardcoded data:






var durations = 0;

var z = d3.scaleOrdinal()
.range(["orange", "steelblue"]);

var margin =
top: 35, right: 35, bottom: 35, left: 35, pad: 25
;

var csvData =
`AgeRange,female,male,Woman_one,Man_one,Woman_two,Man_two,Woman_three,Man_three
"17 - 19",50,36,23,22,3,0,5,5
"20 - 24",145,99,80,72,22,3,27,14
"25 - 29",123,109,40,80,28,3,42,22
"30 - 34",121,52,54,35,21,2,32,13
"35 - 39",88,65,23,30,15,4,44,28
"40 - 44",79,52,28,22,8,4,40,23
"45 - 49",89,51,21,27,14,1,47,20
"50 - 54",67,31,15,12,10,1,38,15
"55 - 59",55,25,7,3,7,3,39,17
"60 - 64",40,21,5,5,4,2,30,14
"65 - 69",26,11,1,0,1,0,22,11
"70 - 74",10,6,0,0,0,0,9,5
"75 +",9,1,0,0,0,0,9,1`;

var dataSet = d3.csvParse(csvData)

row1(dataSet);

function row1(data)

var check = false;

update(check);

function update(check)

var team = d3.selectAll(".select1").property("value")

data.forEach(function(d, i, columns)
d.male = +(d.male);
d.female = +(d.female);
d["Woman" + team] = +d["Woman" + team];
d["Man" + team] = +d["Man" + team];
return d;
)

if (check)
pyramid.update(data, team)
percent.update(data, team)
totals.update(data, team)
else
pyramid(data, team);
percent(data, team);
totals(data, team);



d3.selectAll(".select1").on("change", function()
check = true;
durations = 750;
update(check);
)



function pyramid(data, team)

var width = 550 - (margin.left + margin.right);
var height = 420 - (margin.top + margin.bottom);

var x = d3.scaleLinear()
.rangeRound([(width/2) + margin.pad, width]),
x2 = d3.scaleLinear()
.rangeRound([(width/2) - margin.pad, 0]),
y = d3.scaleBand()
.rangeRound([height, 0]).padding(0.1);

var xAxis = d3.axisBottom(x).ticks(6)
.tickSize(-height),
xAxis2 = d3.axisBottom(x2).ticks(6)
.tickSize(-height),
yAxis = d3.axisLeft(y);

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

svg.append("g")
.attr("class", "axis axis--x hide")
.attr("transform", "translate(0," + height + ")")
svg.append("g")
.attr("class", "axis axis--x2 hide")
.attr("transform", "translate(0," + height + ")")
svg.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(" + (width/2 + 10) + ",0)")

svg.append("text")
.attr("x", width/2)
.attr("y", 0)
.attr("text-anchor", "middle")
.text("Age");

update(data, team);

function update(data, team)

x.domain([0, d3.max(data,
d => Math.max(d.male, d.female))
]).nice();

x2.domain(x.domain())

y.domain(data.map(d => d.AgeRange));

svg.selectAll(".axis.axis--x")
.call(xAxis);

svg.selectAll(".axis.axis--x2")
.call(xAxis2);

svg.selectAll(".axis.axis--y")
.call(customYAxis);

function customYAxis(g)
g.call(yAxis);
g.selectAll("text").style("text-anchor", "middle")
g.select(".domain").remove();
g.selectAll("line").remove();


// ==== Men bar ====

var menTtl = svg.selectAll(".menTtl")
.data(data).enter()
.insert("g", ".axis--x")
.append("rect")
.attr("class", "M menTtl")
.attr("opacity",.6)
.attr("x", x(0))
.attr("y", d => y(d.AgeRange))
.attr("height", y.bandwidth())
.attr("width", d => Math.abs(x(d.male) - x(0)));

var menTeam = svg.selectAll(".menTeam")
.data(data);

menTeam = menTeam
.enter()
.insert("g", ".axis--x")
.append("rect")
.attr("class", "M menTeam")
.attr("x", x(0))
.attr("y", d => y(d.AgeRange))
.attr("height", y.bandwidth())
.merge(menTeam)

menTeam.transition().duration(durations)
.attr("width", d => Math.abs(x(d["Man" + team]) - x(0)));

// ==== Women bar ====

var womenTtl = svg.selectAll(".womenTtl")
.data(data).enter()
.append("rect")
.attr("class", "W womenTtl")
.attr("opacity",.6)
.attr("y", d => y(d.AgeRange))
.attr("x", d => x2(d.female))
.attr("height", y.bandwidth())
.attr("width", d => Math.abs(x2(d.female) - x2(0)));

var womenTeam = svg.selectAll(".womenTeam")
.data(data);

womenTeam = womenTeam
.enter()
.append("rect")
.attr("class", "W womenTeam")
.attr("y", d => y(d.AgeRange))
.attr("height", y.bandwidth())
.merge(womenTeam)

womenTeam.transition().duration(durations)
.attr("x", d => x2(d["Woman" + team]))
.attr("width", d => Math.abs(x2(d["Woman" + team]) - x2(0)));


pyramid.update = update;



function percent(data, team)

var width = 150 - (margin.left + margin.right),
height = 420 - (margin.top + margin.bottom);

var x0 = d3.scaleBand().rangeRound([0, width]),
x1 = d3.scaleBand().paddingOuter(0.2),
x2 = d3.scaleBand().paddingOuter(0.2),
y = d3.scaleLinear().rangeRound([height, 0]);

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

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

svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");

svg.append("g")
.attr("class", "axis axis--y");

update(data, team);

function update(data, team)

var ttlKey = data.columns.slice(1, 3);

var teamKey = ["Woman" + team, "Man" + team]

x0.domain(["Women & Men"]);
x1.domain(ttlKey).rangeRound([0, x0.bandwidth()]);
x2.domain(teamKey).rangeRound([0, x0.bandwidth()]);

y.domain([0, d3.sum(data, function(d)
return d3.max(ttlKey, key => d[key]);
)]).nice();

svg.selectAll(".axis.axis--y")
.call(yAxis);

svg.selectAll(".axis.axis--x")
.call(xAxis);

var barGroups = svg.selectAll("g.layer")
.data(["empty"]);

barGroups.exit().remove();

barGroups = barGroups
.enter()
.append("g")
.classed('layer', true);

var bars = svg.selectAll("g.layer").selectAll(".bars")
.data(function()
return ttlKey.map(function(key)
var sum = d3.sum(data, e => e[key] )
return key: key, value: sum;
);
).enter()
.append("rect")
.attr("class", "bars")
.attr("fill", d => z(d.key))
.attr("opacity", .6)
.attr("x", d => x1(d.key))
.attr("y", d => y(d.value))
.attr("width", x1.bandwidth())
.attr("height", d => height - y(d.value));

var barsTeam = svg.selectAll("g.layer").selectAll(".barsTeam")
.data(function()
return teamKey.map(function(key)
var sum = d3.sum(data, e => e[key] )
return key: key, value: sum;
);
);

barsTeam.exit().remove();

barsTeam = barsTeam
.enter()
.append("rect")
.attr("class", "barsTeam")
.attr("fill", d => z(d.key))
.attr("x", d => x2(d.key))
.attr("width", x1.bandwidth())
.merge(barsTeam);

barsTeam.transition().duration(durations)
.attr("y", d => y(d.value))
.attr("height", d => height - y(d.value));


percent.update = update;



function totals(data, team)

var width = 110 - (margin.left + margin.right),
height = 420 - (margin.top + margin.bottom);

var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);

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

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

svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");

svg.append("g")
.attr("class", "axis axis--y");

update(data, team);

function update(data, team)

var sum = d3.sum(data, d => d3.sum([d.male, d.female]));

var sumTeam = d3.sum(data, function(d)
return d3.sum([d["Woman" + team], d["Man" + team]])
);

y.domain([0, sum]).nice();

x.domain(["Total"]);

svg.selectAll(".axis.axis--y")
.call(yAxis);

svg.selectAll(".axis.axis--x")
.call(xAxis);

var ttlBar = svg.selectAll(".ttlBar")
.data(["empty"]).enter()
.append("rect")
.attr("class", "ttlBar")
.attr("fill", "#ccc")
.attr("x", x(["Total"]))
.attr("y", y(sum))
.attr("width", x.bandwidth())
.attr("height", height - y(sum));

var ttlTeam = svg.selectAll(".ttlTeam")
.data(["empty"]);

ttlTeam = ttlTeam
.enter()
.append("rect")
.attr("class", "ttlTeam")
.attr("fill", "#999")
.attr("x", x(["Total"]))
.attr("width", x.bandwidth())
.merge(ttlTeam);

ttlTeam.transition().duration(durations)
.attr("height", height - y(sumTeam))
.attr("y", y(sumTeam))



totals.update = update


body 
font: 12px arial;
margin: auto;
width: 850px;
padding-top:25px;

select
border: 1px solid #fff;
border-bottom: 1px solid #ccc;
cursor: pointer;

.M fill: steelblue;
.W fill: orange;
.hide path
display: none;

.hide .tick:not(:first-of-type) line
opacity: .25;

<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<div style="margin-left: 25px;">
<b>Choose Team:</b>
<select class="select1">
<option value="_one">Team 1</option>
<option value="_two">Team 2</option>
<option value="_three">Team 3</option>
</select>
</div>

<div id="row1"></div>









share|improve this question



























    up vote
    2
    down vote

    favorite












    I've created 3 different charts all drawn from the same dataset,
    my reasoning for building it this way is so that it'll be easier to add and remove additional rows of charts.



    What I'm mainly interested in knowing is if the code is well structured and/or if it's idiomatic d3 code.



    Here's a link to all the code: Plunker



    And here's the same code but with hardcoded data:






    var durations = 0;

    var z = d3.scaleOrdinal()
    .range(["orange", "steelblue"]);

    var margin =
    top: 35, right: 35, bottom: 35, left: 35, pad: 25
    ;

    var csvData =
    `AgeRange,female,male,Woman_one,Man_one,Woman_two,Man_two,Woman_three,Man_three
    "17 - 19",50,36,23,22,3,0,5,5
    "20 - 24",145,99,80,72,22,3,27,14
    "25 - 29",123,109,40,80,28,3,42,22
    "30 - 34",121,52,54,35,21,2,32,13
    "35 - 39",88,65,23,30,15,4,44,28
    "40 - 44",79,52,28,22,8,4,40,23
    "45 - 49",89,51,21,27,14,1,47,20
    "50 - 54",67,31,15,12,10,1,38,15
    "55 - 59",55,25,7,3,7,3,39,17
    "60 - 64",40,21,5,5,4,2,30,14
    "65 - 69",26,11,1,0,1,0,22,11
    "70 - 74",10,6,0,0,0,0,9,5
    "75 +",9,1,0,0,0,0,9,1`;

    var dataSet = d3.csvParse(csvData)

    row1(dataSet);

    function row1(data)

    var check = false;

    update(check);

    function update(check)

    var team = d3.selectAll(".select1").property("value")

    data.forEach(function(d, i, columns)
    d.male = +(d.male);
    d.female = +(d.female);
    d["Woman" + team] = +d["Woman" + team];
    d["Man" + team] = +d["Man" + team];
    return d;
    )

    if (check)
    pyramid.update(data, team)
    percent.update(data, team)
    totals.update(data, team)
    else
    pyramid(data, team);
    percent(data, team);
    totals(data, team);



    d3.selectAll(".select1").on("change", function()
    check = true;
    durations = 750;
    update(check);
    )



    function pyramid(data, team)

    var width = 550 - (margin.left + margin.right);
    var height = 420 - (margin.top + margin.bottom);

    var x = d3.scaleLinear()
    .rangeRound([(width/2) + margin.pad, width]),
    x2 = d3.scaleLinear()
    .rangeRound([(width/2) - margin.pad, 0]),
    y = d3.scaleBand()
    .rangeRound([height, 0]).padding(0.1);

    var xAxis = d3.axisBottom(x).ticks(6)
    .tickSize(-height),
    xAxis2 = d3.axisBottom(x2).ticks(6)
    .tickSize(-height),
    yAxis = d3.axisLeft(y);

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

    svg.append("g")
    .attr("class", "axis axis--x hide")
    .attr("transform", "translate(0," + height + ")")
    svg.append("g")
    .attr("class", "axis axis--x2 hide")
    .attr("transform", "translate(0," + height + ")")
    svg.append("g")
    .attr("class", "axis axis--y")
    .attr("transform", "translate(" + (width/2 + 10) + ",0)")

    svg.append("text")
    .attr("x", width/2)
    .attr("y", 0)
    .attr("text-anchor", "middle")
    .text("Age");

    update(data, team);

    function update(data, team)

    x.domain([0, d3.max(data,
    d => Math.max(d.male, d.female))
    ]).nice();

    x2.domain(x.domain())

    y.domain(data.map(d => d.AgeRange));

    svg.selectAll(".axis.axis--x")
    .call(xAxis);

    svg.selectAll(".axis.axis--x2")
    .call(xAxis2);

    svg.selectAll(".axis.axis--y")
    .call(customYAxis);

    function customYAxis(g)
    g.call(yAxis);
    g.selectAll("text").style("text-anchor", "middle")
    g.select(".domain").remove();
    g.selectAll("line").remove();


    // ==== Men bar ====

    var menTtl = svg.selectAll(".menTtl")
    .data(data).enter()
    .insert("g", ".axis--x")
    .append("rect")
    .attr("class", "M menTtl")
    .attr("opacity",.6)
    .attr("x", x(0))
    .attr("y", d => y(d.AgeRange))
    .attr("height", y.bandwidth())
    .attr("width", d => Math.abs(x(d.male) - x(0)));

    var menTeam = svg.selectAll(".menTeam")
    .data(data);

    menTeam = menTeam
    .enter()
    .insert("g", ".axis--x")
    .append("rect")
    .attr("class", "M menTeam")
    .attr("x", x(0))
    .attr("y", d => y(d.AgeRange))
    .attr("height", y.bandwidth())
    .merge(menTeam)

    menTeam.transition().duration(durations)
    .attr("width", d => Math.abs(x(d["Man" + team]) - x(0)));

    // ==== Women bar ====

    var womenTtl = svg.selectAll(".womenTtl")
    .data(data).enter()
    .append("rect")
    .attr("class", "W womenTtl")
    .attr("opacity",.6)
    .attr("y", d => y(d.AgeRange))
    .attr("x", d => x2(d.female))
    .attr("height", y.bandwidth())
    .attr("width", d => Math.abs(x2(d.female) - x2(0)));

    var womenTeam = svg.selectAll(".womenTeam")
    .data(data);

    womenTeam = womenTeam
    .enter()
    .append("rect")
    .attr("class", "W womenTeam")
    .attr("y", d => y(d.AgeRange))
    .attr("height", y.bandwidth())
    .merge(womenTeam)

    womenTeam.transition().duration(durations)
    .attr("x", d => x2(d["Woman" + team]))
    .attr("width", d => Math.abs(x2(d["Woman" + team]) - x2(0)));


    pyramid.update = update;



    function percent(data, team)

    var width = 150 - (margin.left + margin.right),
    height = 420 - (margin.top + margin.bottom);

    var x0 = d3.scaleBand().rangeRound([0, width]),
    x1 = d3.scaleBand().paddingOuter(0.2),
    x2 = d3.scaleBand().paddingOuter(0.2),
    y = d3.scaleLinear().rangeRound([height, 0]);

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

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

    svg.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + height + ")");

    svg.append("g")
    .attr("class", "axis axis--y");

    update(data, team);

    function update(data, team)

    var ttlKey = data.columns.slice(1, 3);

    var teamKey = ["Woman" + team, "Man" + team]

    x0.domain(["Women & Men"]);
    x1.domain(ttlKey).rangeRound([0, x0.bandwidth()]);
    x2.domain(teamKey).rangeRound([0, x0.bandwidth()]);

    y.domain([0, d3.sum(data, function(d)
    return d3.max(ttlKey, key => d[key]);
    )]).nice();

    svg.selectAll(".axis.axis--y")
    .call(yAxis);

    svg.selectAll(".axis.axis--x")
    .call(xAxis);

    var barGroups = svg.selectAll("g.layer")
    .data(["empty"]);

    barGroups.exit().remove();

    barGroups = barGroups
    .enter()
    .append("g")
    .classed('layer', true);

    var bars = svg.selectAll("g.layer").selectAll(".bars")
    .data(function()
    return ttlKey.map(function(key)
    var sum = d3.sum(data, e => e[key] )
    return key: key, value: sum;
    );
    ).enter()
    .append("rect")
    .attr("class", "bars")
    .attr("fill", d => z(d.key))
    .attr("opacity", .6)
    .attr("x", d => x1(d.key))
    .attr("y", d => y(d.value))
    .attr("width", x1.bandwidth())
    .attr("height", d => height - y(d.value));

    var barsTeam = svg.selectAll("g.layer").selectAll(".barsTeam")
    .data(function()
    return teamKey.map(function(key)
    var sum = d3.sum(data, e => e[key] )
    return key: key, value: sum;
    );
    );

    barsTeam.exit().remove();

    barsTeam = barsTeam
    .enter()
    .append("rect")
    .attr("class", "barsTeam")
    .attr("fill", d => z(d.key))
    .attr("x", d => x2(d.key))
    .attr("width", x1.bandwidth())
    .merge(barsTeam);

    barsTeam.transition().duration(durations)
    .attr("y", d => y(d.value))
    .attr("height", d => height - y(d.value));


    percent.update = update;



    function totals(data, team)

    var width = 110 - (margin.left + margin.right),
    height = 420 - (margin.top + margin.bottom);

    var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
    y = d3.scaleLinear().rangeRound([height, 0]);

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

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

    svg.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + height + ")");

    svg.append("g")
    .attr("class", "axis axis--y");

    update(data, team);

    function update(data, team)

    var sum = d3.sum(data, d => d3.sum([d.male, d.female]));

    var sumTeam = d3.sum(data, function(d)
    return d3.sum([d["Woman" + team], d["Man" + team]])
    );

    y.domain([0, sum]).nice();

    x.domain(["Total"]);

    svg.selectAll(".axis.axis--y")
    .call(yAxis);

    svg.selectAll(".axis.axis--x")
    .call(xAxis);

    var ttlBar = svg.selectAll(".ttlBar")
    .data(["empty"]).enter()
    .append("rect")
    .attr("class", "ttlBar")
    .attr("fill", "#ccc")
    .attr("x", x(["Total"]))
    .attr("y", y(sum))
    .attr("width", x.bandwidth())
    .attr("height", height - y(sum));

    var ttlTeam = svg.selectAll(".ttlTeam")
    .data(["empty"]);

    ttlTeam = ttlTeam
    .enter()
    .append("rect")
    .attr("class", "ttlTeam")
    .attr("fill", "#999")
    .attr("x", x(["Total"]))
    .attr("width", x.bandwidth())
    .merge(ttlTeam);

    ttlTeam.transition().duration(durations)
    .attr("height", height - y(sumTeam))
    .attr("y", y(sumTeam))



    totals.update = update


    body 
    font: 12px arial;
    margin: auto;
    width: 850px;
    padding-top:25px;

    select
    border: 1px solid #fff;
    border-bottom: 1px solid #ccc;
    cursor: pointer;

    .M fill: steelblue;
    .W fill: orange;
    .hide path
    display: none;

    .hide .tick:not(:first-of-type) line
    opacity: .25;

    <meta charset="utf-8">
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <div style="margin-left: 25px;">
    <b>Choose Team:</b>
    <select class="select1">
    <option value="_one">Team 1</option>
    <option value="_two">Team 2</option>
    <option value="_three">Team 3</option>
    </select>
    </div>

    <div id="row1"></div>









    share|improve this question























      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      I've created 3 different charts all drawn from the same dataset,
      my reasoning for building it this way is so that it'll be easier to add and remove additional rows of charts.



      What I'm mainly interested in knowing is if the code is well structured and/or if it's idiomatic d3 code.



      Here's a link to all the code: Plunker



      And here's the same code but with hardcoded data:






      var durations = 0;

      var z = d3.scaleOrdinal()
      .range(["orange", "steelblue"]);

      var margin =
      top: 35, right: 35, bottom: 35, left: 35, pad: 25
      ;

      var csvData =
      `AgeRange,female,male,Woman_one,Man_one,Woman_two,Man_two,Woman_three,Man_three
      "17 - 19",50,36,23,22,3,0,5,5
      "20 - 24",145,99,80,72,22,3,27,14
      "25 - 29",123,109,40,80,28,3,42,22
      "30 - 34",121,52,54,35,21,2,32,13
      "35 - 39",88,65,23,30,15,4,44,28
      "40 - 44",79,52,28,22,8,4,40,23
      "45 - 49",89,51,21,27,14,1,47,20
      "50 - 54",67,31,15,12,10,1,38,15
      "55 - 59",55,25,7,3,7,3,39,17
      "60 - 64",40,21,5,5,4,2,30,14
      "65 - 69",26,11,1,0,1,0,22,11
      "70 - 74",10,6,0,0,0,0,9,5
      "75 +",9,1,0,0,0,0,9,1`;

      var dataSet = d3.csvParse(csvData)

      row1(dataSet);

      function row1(data)

      var check = false;

      update(check);

      function update(check)

      var team = d3.selectAll(".select1").property("value")

      data.forEach(function(d, i, columns)
      d.male = +(d.male);
      d.female = +(d.female);
      d["Woman" + team] = +d["Woman" + team];
      d["Man" + team] = +d["Man" + team];
      return d;
      )

      if (check)
      pyramid.update(data, team)
      percent.update(data, team)
      totals.update(data, team)
      else
      pyramid(data, team);
      percent(data, team);
      totals(data, team);



      d3.selectAll(".select1").on("change", function()
      check = true;
      durations = 750;
      update(check);
      )



      function pyramid(data, team)

      var width = 550 - (margin.left + margin.right);
      var height = 420 - (margin.top + margin.bottom);

      var x = d3.scaleLinear()
      .rangeRound([(width/2) + margin.pad, width]),
      x2 = d3.scaleLinear()
      .rangeRound([(width/2) - margin.pad, 0]),
      y = d3.scaleBand()
      .rangeRound([height, 0]).padding(0.1);

      var xAxis = d3.axisBottom(x).ticks(6)
      .tickSize(-height),
      xAxis2 = d3.axisBottom(x2).ticks(6)
      .tickSize(-height),
      yAxis = d3.axisLeft(y);

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

      svg.append("g")
      .attr("class", "axis axis--x hide")
      .attr("transform", "translate(0," + height + ")")
      svg.append("g")
      .attr("class", "axis axis--x2 hide")
      .attr("transform", "translate(0," + height + ")")
      svg.append("g")
      .attr("class", "axis axis--y")
      .attr("transform", "translate(" + (width/2 + 10) + ",0)")

      svg.append("text")
      .attr("x", width/2)
      .attr("y", 0)
      .attr("text-anchor", "middle")
      .text("Age");

      update(data, team);

      function update(data, team)

      x.domain([0, d3.max(data,
      d => Math.max(d.male, d.female))
      ]).nice();

      x2.domain(x.domain())

      y.domain(data.map(d => d.AgeRange));

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      svg.selectAll(".axis.axis--x2")
      .call(xAxis2);

      svg.selectAll(".axis.axis--y")
      .call(customYAxis);

      function customYAxis(g)
      g.call(yAxis);
      g.selectAll("text").style("text-anchor", "middle")
      g.select(".domain").remove();
      g.selectAll("line").remove();


      // ==== Men bar ====

      var menTtl = svg.selectAll(".menTtl")
      .data(data).enter()
      .insert("g", ".axis--x")
      .append("rect")
      .attr("class", "M menTtl")
      .attr("opacity",.6)
      .attr("x", x(0))
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .attr("width", d => Math.abs(x(d.male) - x(0)));

      var menTeam = svg.selectAll(".menTeam")
      .data(data);

      menTeam = menTeam
      .enter()
      .insert("g", ".axis--x")
      .append("rect")
      .attr("class", "M menTeam")
      .attr("x", x(0))
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .merge(menTeam)

      menTeam.transition().duration(durations)
      .attr("width", d => Math.abs(x(d["Man" + team]) - x(0)));

      // ==== Women bar ====

      var womenTtl = svg.selectAll(".womenTtl")
      .data(data).enter()
      .append("rect")
      .attr("class", "W womenTtl")
      .attr("opacity",.6)
      .attr("y", d => y(d.AgeRange))
      .attr("x", d => x2(d.female))
      .attr("height", y.bandwidth())
      .attr("width", d => Math.abs(x2(d.female) - x2(0)));

      var womenTeam = svg.selectAll(".womenTeam")
      .data(data);

      womenTeam = womenTeam
      .enter()
      .append("rect")
      .attr("class", "W womenTeam")
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .merge(womenTeam)

      womenTeam.transition().duration(durations)
      .attr("x", d => x2(d["Woman" + team]))
      .attr("width", d => Math.abs(x2(d["Woman" + team]) - x2(0)));


      pyramid.update = update;



      function percent(data, team)

      var width = 150 - (margin.left + margin.right),
      height = 420 - (margin.top + margin.bottom);

      var x0 = d3.scaleBand().rangeRound([0, width]),
      x1 = d3.scaleBand().paddingOuter(0.2),
      x2 = d3.scaleBand().paddingOuter(0.2),
      y = d3.scaleLinear().rangeRound([height, 0]);

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

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

      svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")");

      svg.append("g")
      .attr("class", "axis axis--y");

      update(data, team);

      function update(data, team)

      var ttlKey = data.columns.slice(1, 3);

      var teamKey = ["Woman" + team, "Man" + team]

      x0.domain(["Women & Men"]);
      x1.domain(ttlKey).rangeRound([0, x0.bandwidth()]);
      x2.domain(teamKey).rangeRound([0, x0.bandwidth()]);

      y.domain([0, d3.sum(data, function(d)
      return d3.max(ttlKey, key => d[key]);
      )]).nice();

      svg.selectAll(".axis.axis--y")
      .call(yAxis);

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      var barGroups = svg.selectAll("g.layer")
      .data(["empty"]);

      barGroups.exit().remove();

      barGroups = barGroups
      .enter()
      .append("g")
      .classed('layer', true);

      var bars = svg.selectAll("g.layer").selectAll(".bars")
      .data(function()
      return ttlKey.map(function(key)
      var sum = d3.sum(data, e => e[key] )
      return key: key, value: sum;
      );
      ).enter()
      .append("rect")
      .attr("class", "bars")
      .attr("fill", d => z(d.key))
      .attr("opacity", .6)
      .attr("x", d => x1(d.key))
      .attr("y", d => y(d.value))
      .attr("width", x1.bandwidth())
      .attr("height", d => height - y(d.value));

      var barsTeam = svg.selectAll("g.layer").selectAll(".barsTeam")
      .data(function()
      return teamKey.map(function(key)
      var sum = d3.sum(data, e => e[key] )
      return key: key, value: sum;
      );
      );

      barsTeam.exit().remove();

      barsTeam = barsTeam
      .enter()
      .append("rect")
      .attr("class", "barsTeam")
      .attr("fill", d => z(d.key))
      .attr("x", d => x2(d.key))
      .attr("width", x1.bandwidth())
      .merge(barsTeam);

      barsTeam.transition().duration(durations)
      .attr("y", d => y(d.value))
      .attr("height", d => height - y(d.value));


      percent.update = update;



      function totals(data, team)

      var width = 110 - (margin.left + margin.right),
      height = 420 - (margin.top + margin.bottom);

      var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
      y = d3.scaleLinear().rangeRound([height, 0]);

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

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

      svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")");

      svg.append("g")
      .attr("class", "axis axis--y");

      update(data, team);

      function update(data, team)

      var sum = d3.sum(data, d => d3.sum([d.male, d.female]));

      var sumTeam = d3.sum(data, function(d)
      return d3.sum([d["Woman" + team], d["Man" + team]])
      );

      y.domain([0, sum]).nice();

      x.domain(["Total"]);

      svg.selectAll(".axis.axis--y")
      .call(yAxis);

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      var ttlBar = svg.selectAll(".ttlBar")
      .data(["empty"]).enter()
      .append("rect")
      .attr("class", "ttlBar")
      .attr("fill", "#ccc")
      .attr("x", x(["Total"]))
      .attr("y", y(sum))
      .attr("width", x.bandwidth())
      .attr("height", height - y(sum));

      var ttlTeam = svg.selectAll(".ttlTeam")
      .data(["empty"]);

      ttlTeam = ttlTeam
      .enter()
      .append("rect")
      .attr("class", "ttlTeam")
      .attr("fill", "#999")
      .attr("x", x(["Total"]))
      .attr("width", x.bandwidth())
      .merge(ttlTeam);

      ttlTeam.transition().duration(durations)
      .attr("height", height - y(sumTeam))
      .attr("y", y(sumTeam))



      totals.update = update


      body 
      font: 12px arial;
      margin: auto;
      width: 850px;
      padding-top:25px;

      select
      border: 1px solid #fff;
      border-bottom: 1px solid #ccc;
      cursor: pointer;

      .M fill: steelblue;
      .W fill: orange;
      .hide path
      display: none;

      .hide .tick:not(:first-of-type) line
      opacity: .25;

      <meta charset="utf-8">
      <script src="https://d3js.org/d3.v5.min.js"></script>
      <div style="margin-left: 25px;">
      <b>Choose Team:</b>
      <select class="select1">
      <option value="_one">Team 1</option>
      <option value="_two">Team 2</option>
      <option value="_three">Team 3</option>
      </select>
      </div>

      <div id="row1"></div>









      share|improve this question













      I've created 3 different charts all drawn from the same dataset,
      my reasoning for building it this way is so that it'll be easier to add and remove additional rows of charts.



      What I'm mainly interested in knowing is if the code is well structured and/or if it's idiomatic d3 code.



      Here's a link to all the code: Plunker



      And here's the same code but with hardcoded data:






      var durations = 0;

      var z = d3.scaleOrdinal()
      .range(["orange", "steelblue"]);

      var margin =
      top: 35, right: 35, bottom: 35, left: 35, pad: 25
      ;

      var csvData =
      `AgeRange,female,male,Woman_one,Man_one,Woman_two,Man_two,Woman_three,Man_three
      "17 - 19",50,36,23,22,3,0,5,5
      "20 - 24",145,99,80,72,22,3,27,14
      "25 - 29",123,109,40,80,28,3,42,22
      "30 - 34",121,52,54,35,21,2,32,13
      "35 - 39",88,65,23,30,15,4,44,28
      "40 - 44",79,52,28,22,8,4,40,23
      "45 - 49",89,51,21,27,14,1,47,20
      "50 - 54",67,31,15,12,10,1,38,15
      "55 - 59",55,25,7,3,7,3,39,17
      "60 - 64",40,21,5,5,4,2,30,14
      "65 - 69",26,11,1,0,1,0,22,11
      "70 - 74",10,6,0,0,0,0,9,5
      "75 +",9,1,0,0,0,0,9,1`;

      var dataSet = d3.csvParse(csvData)

      row1(dataSet);

      function row1(data)

      var check = false;

      update(check);

      function update(check)

      var team = d3.selectAll(".select1").property("value")

      data.forEach(function(d, i, columns)
      d.male = +(d.male);
      d.female = +(d.female);
      d["Woman" + team] = +d["Woman" + team];
      d["Man" + team] = +d["Man" + team];
      return d;
      )

      if (check)
      pyramid.update(data, team)
      percent.update(data, team)
      totals.update(data, team)
      else
      pyramid(data, team);
      percent(data, team);
      totals(data, team);



      d3.selectAll(".select1").on("change", function()
      check = true;
      durations = 750;
      update(check);
      )



      function pyramid(data, team)

      var width = 550 - (margin.left + margin.right);
      var height = 420 - (margin.top + margin.bottom);

      var x = d3.scaleLinear()
      .rangeRound([(width/2) + margin.pad, width]),
      x2 = d3.scaleLinear()
      .rangeRound([(width/2) - margin.pad, 0]),
      y = d3.scaleBand()
      .rangeRound([height, 0]).padding(0.1);

      var xAxis = d3.axisBottom(x).ticks(6)
      .tickSize(-height),
      xAxis2 = d3.axisBottom(x2).ticks(6)
      .tickSize(-height),
      yAxis = d3.axisLeft(y);

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

      svg.append("g")
      .attr("class", "axis axis--x hide")
      .attr("transform", "translate(0," + height + ")")
      svg.append("g")
      .attr("class", "axis axis--x2 hide")
      .attr("transform", "translate(0," + height + ")")
      svg.append("g")
      .attr("class", "axis axis--y")
      .attr("transform", "translate(" + (width/2 + 10) + ",0)")

      svg.append("text")
      .attr("x", width/2)
      .attr("y", 0)
      .attr("text-anchor", "middle")
      .text("Age");

      update(data, team);

      function update(data, team)

      x.domain([0, d3.max(data,
      d => Math.max(d.male, d.female))
      ]).nice();

      x2.domain(x.domain())

      y.domain(data.map(d => d.AgeRange));

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      svg.selectAll(".axis.axis--x2")
      .call(xAxis2);

      svg.selectAll(".axis.axis--y")
      .call(customYAxis);

      function customYAxis(g)
      g.call(yAxis);
      g.selectAll("text").style("text-anchor", "middle")
      g.select(".domain").remove();
      g.selectAll("line").remove();


      // ==== Men bar ====

      var menTtl = svg.selectAll(".menTtl")
      .data(data).enter()
      .insert("g", ".axis--x")
      .append("rect")
      .attr("class", "M menTtl")
      .attr("opacity",.6)
      .attr("x", x(0))
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .attr("width", d => Math.abs(x(d.male) - x(0)));

      var menTeam = svg.selectAll(".menTeam")
      .data(data);

      menTeam = menTeam
      .enter()
      .insert("g", ".axis--x")
      .append("rect")
      .attr("class", "M menTeam")
      .attr("x", x(0))
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .merge(menTeam)

      menTeam.transition().duration(durations)
      .attr("width", d => Math.abs(x(d["Man" + team]) - x(0)));

      // ==== Women bar ====

      var womenTtl = svg.selectAll(".womenTtl")
      .data(data).enter()
      .append("rect")
      .attr("class", "W womenTtl")
      .attr("opacity",.6)
      .attr("y", d => y(d.AgeRange))
      .attr("x", d => x2(d.female))
      .attr("height", y.bandwidth())
      .attr("width", d => Math.abs(x2(d.female) - x2(0)));

      var womenTeam = svg.selectAll(".womenTeam")
      .data(data);

      womenTeam = womenTeam
      .enter()
      .append("rect")
      .attr("class", "W womenTeam")
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .merge(womenTeam)

      womenTeam.transition().duration(durations)
      .attr("x", d => x2(d["Woman" + team]))
      .attr("width", d => Math.abs(x2(d["Woman" + team]) - x2(0)));


      pyramid.update = update;



      function percent(data, team)

      var width = 150 - (margin.left + margin.right),
      height = 420 - (margin.top + margin.bottom);

      var x0 = d3.scaleBand().rangeRound([0, width]),
      x1 = d3.scaleBand().paddingOuter(0.2),
      x2 = d3.scaleBand().paddingOuter(0.2),
      y = d3.scaleLinear().rangeRound([height, 0]);

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

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

      svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")");

      svg.append("g")
      .attr("class", "axis axis--y");

      update(data, team);

      function update(data, team)

      var ttlKey = data.columns.slice(1, 3);

      var teamKey = ["Woman" + team, "Man" + team]

      x0.domain(["Women & Men"]);
      x1.domain(ttlKey).rangeRound([0, x0.bandwidth()]);
      x2.domain(teamKey).rangeRound([0, x0.bandwidth()]);

      y.domain([0, d3.sum(data, function(d)
      return d3.max(ttlKey, key => d[key]);
      )]).nice();

      svg.selectAll(".axis.axis--y")
      .call(yAxis);

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      var barGroups = svg.selectAll("g.layer")
      .data(["empty"]);

      barGroups.exit().remove();

      barGroups = barGroups
      .enter()
      .append("g")
      .classed('layer', true);

      var bars = svg.selectAll("g.layer").selectAll(".bars")
      .data(function()
      return ttlKey.map(function(key)
      var sum = d3.sum(data, e => e[key] )
      return key: key, value: sum;
      );
      ).enter()
      .append("rect")
      .attr("class", "bars")
      .attr("fill", d => z(d.key))
      .attr("opacity", .6)
      .attr("x", d => x1(d.key))
      .attr("y", d => y(d.value))
      .attr("width", x1.bandwidth())
      .attr("height", d => height - y(d.value));

      var barsTeam = svg.selectAll("g.layer").selectAll(".barsTeam")
      .data(function()
      return teamKey.map(function(key)
      var sum = d3.sum(data, e => e[key] )
      return key: key, value: sum;
      );
      );

      barsTeam.exit().remove();

      barsTeam = barsTeam
      .enter()
      .append("rect")
      .attr("class", "barsTeam")
      .attr("fill", d => z(d.key))
      .attr("x", d => x2(d.key))
      .attr("width", x1.bandwidth())
      .merge(barsTeam);

      barsTeam.transition().duration(durations)
      .attr("y", d => y(d.value))
      .attr("height", d => height - y(d.value));


      percent.update = update;



      function totals(data, team)

      var width = 110 - (margin.left + margin.right),
      height = 420 - (margin.top + margin.bottom);

      var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
      y = d3.scaleLinear().rangeRound([height, 0]);

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

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

      svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")");

      svg.append("g")
      .attr("class", "axis axis--y");

      update(data, team);

      function update(data, team)

      var sum = d3.sum(data, d => d3.sum([d.male, d.female]));

      var sumTeam = d3.sum(data, function(d)
      return d3.sum([d["Woman" + team], d["Man" + team]])
      );

      y.domain([0, sum]).nice();

      x.domain(["Total"]);

      svg.selectAll(".axis.axis--y")
      .call(yAxis);

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      var ttlBar = svg.selectAll(".ttlBar")
      .data(["empty"]).enter()
      .append("rect")
      .attr("class", "ttlBar")
      .attr("fill", "#ccc")
      .attr("x", x(["Total"]))
      .attr("y", y(sum))
      .attr("width", x.bandwidth())
      .attr("height", height - y(sum));

      var ttlTeam = svg.selectAll(".ttlTeam")
      .data(["empty"]);

      ttlTeam = ttlTeam
      .enter()
      .append("rect")
      .attr("class", "ttlTeam")
      .attr("fill", "#999")
      .attr("x", x(["Total"]))
      .attr("width", x.bandwidth())
      .merge(ttlTeam);

      ttlTeam.transition().duration(durations)
      .attr("height", height - y(sumTeam))
      .attr("y", y(sumTeam))



      totals.update = update


      body 
      font: 12px arial;
      margin: auto;
      width: 850px;
      padding-top:25px;

      select
      border: 1px solid #fff;
      border-bottom: 1px solid #ccc;
      cursor: pointer;

      .M fill: steelblue;
      .W fill: orange;
      .hide path
      display: none;

      .hide .tick:not(:first-of-type) line
      opacity: .25;

      <meta charset="utf-8">
      <script src="https://d3js.org/d3.v5.min.js"></script>
      <div style="margin-left: 25px;">
      <b>Choose Team:</b>
      <select class="select1">
      <option value="_one">Team 1</option>
      <option value="_two">Team 2</option>
      <option value="_three">Team 3</option>
      </select>
      </div>

      <div id="row1"></div>








      var durations = 0;

      var z = d3.scaleOrdinal()
      .range(["orange", "steelblue"]);

      var margin =
      top: 35, right: 35, bottom: 35, left: 35, pad: 25
      ;

      var csvData =
      `AgeRange,female,male,Woman_one,Man_one,Woman_two,Man_two,Woman_three,Man_three
      "17 - 19",50,36,23,22,3,0,5,5
      "20 - 24",145,99,80,72,22,3,27,14
      "25 - 29",123,109,40,80,28,3,42,22
      "30 - 34",121,52,54,35,21,2,32,13
      "35 - 39",88,65,23,30,15,4,44,28
      "40 - 44",79,52,28,22,8,4,40,23
      "45 - 49",89,51,21,27,14,1,47,20
      "50 - 54",67,31,15,12,10,1,38,15
      "55 - 59",55,25,7,3,7,3,39,17
      "60 - 64",40,21,5,5,4,2,30,14
      "65 - 69",26,11,1,0,1,0,22,11
      "70 - 74",10,6,0,0,0,0,9,5
      "75 +",9,1,0,0,0,0,9,1`;

      var dataSet = d3.csvParse(csvData)

      row1(dataSet);

      function row1(data)

      var check = false;

      update(check);

      function update(check)

      var team = d3.selectAll(".select1").property("value")

      data.forEach(function(d, i, columns)
      d.male = +(d.male);
      d.female = +(d.female);
      d["Woman" + team] = +d["Woman" + team];
      d["Man" + team] = +d["Man" + team];
      return d;
      )

      if (check)
      pyramid.update(data, team)
      percent.update(data, team)
      totals.update(data, team)
      else
      pyramid(data, team);
      percent(data, team);
      totals(data, team);



      d3.selectAll(".select1").on("change", function()
      check = true;
      durations = 750;
      update(check);
      )



      function pyramid(data, team)

      var width = 550 - (margin.left + margin.right);
      var height = 420 - (margin.top + margin.bottom);

      var x = d3.scaleLinear()
      .rangeRound([(width/2) + margin.pad, width]),
      x2 = d3.scaleLinear()
      .rangeRound([(width/2) - margin.pad, 0]),
      y = d3.scaleBand()
      .rangeRound([height, 0]).padding(0.1);

      var xAxis = d3.axisBottom(x).ticks(6)
      .tickSize(-height),
      xAxis2 = d3.axisBottom(x2).ticks(6)
      .tickSize(-height),
      yAxis = d3.axisLeft(y);

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

      svg.append("g")
      .attr("class", "axis axis--x hide")
      .attr("transform", "translate(0," + height + ")")
      svg.append("g")
      .attr("class", "axis axis--x2 hide")
      .attr("transform", "translate(0," + height + ")")
      svg.append("g")
      .attr("class", "axis axis--y")
      .attr("transform", "translate(" + (width/2 + 10) + ",0)")

      svg.append("text")
      .attr("x", width/2)
      .attr("y", 0)
      .attr("text-anchor", "middle")
      .text("Age");

      update(data, team);

      function update(data, team)

      x.domain([0, d3.max(data,
      d => Math.max(d.male, d.female))
      ]).nice();

      x2.domain(x.domain())

      y.domain(data.map(d => d.AgeRange));

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      svg.selectAll(".axis.axis--x2")
      .call(xAxis2);

      svg.selectAll(".axis.axis--y")
      .call(customYAxis);

      function customYAxis(g)
      g.call(yAxis);
      g.selectAll("text").style("text-anchor", "middle")
      g.select(".domain").remove();
      g.selectAll("line").remove();


      // ==== Men bar ====

      var menTtl = svg.selectAll(".menTtl")
      .data(data).enter()
      .insert("g", ".axis--x")
      .append("rect")
      .attr("class", "M menTtl")
      .attr("opacity",.6)
      .attr("x", x(0))
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .attr("width", d => Math.abs(x(d.male) - x(0)));

      var menTeam = svg.selectAll(".menTeam")
      .data(data);

      menTeam = menTeam
      .enter()
      .insert("g", ".axis--x")
      .append("rect")
      .attr("class", "M menTeam")
      .attr("x", x(0))
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .merge(menTeam)

      menTeam.transition().duration(durations)
      .attr("width", d => Math.abs(x(d["Man" + team]) - x(0)));

      // ==== Women bar ====

      var womenTtl = svg.selectAll(".womenTtl")
      .data(data).enter()
      .append("rect")
      .attr("class", "W womenTtl")
      .attr("opacity",.6)
      .attr("y", d => y(d.AgeRange))
      .attr("x", d => x2(d.female))
      .attr("height", y.bandwidth())
      .attr("width", d => Math.abs(x2(d.female) - x2(0)));

      var womenTeam = svg.selectAll(".womenTeam")
      .data(data);

      womenTeam = womenTeam
      .enter()
      .append("rect")
      .attr("class", "W womenTeam")
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .merge(womenTeam)

      womenTeam.transition().duration(durations)
      .attr("x", d => x2(d["Woman" + team]))
      .attr("width", d => Math.abs(x2(d["Woman" + team]) - x2(0)));


      pyramid.update = update;



      function percent(data, team)

      var width = 150 - (margin.left + margin.right),
      height = 420 - (margin.top + margin.bottom);

      var x0 = d3.scaleBand().rangeRound([0, width]),
      x1 = d3.scaleBand().paddingOuter(0.2),
      x2 = d3.scaleBand().paddingOuter(0.2),
      y = d3.scaleLinear().rangeRound([height, 0]);

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

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

      svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")");

      svg.append("g")
      .attr("class", "axis axis--y");

      update(data, team);

      function update(data, team)

      var ttlKey = data.columns.slice(1, 3);

      var teamKey = ["Woman" + team, "Man" + team]

      x0.domain(["Women & Men"]);
      x1.domain(ttlKey).rangeRound([0, x0.bandwidth()]);
      x2.domain(teamKey).rangeRound([0, x0.bandwidth()]);

      y.domain([0, d3.sum(data, function(d)
      return d3.max(ttlKey, key => d[key]);
      )]).nice();

      svg.selectAll(".axis.axis--y")
      .call(yAxis);

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      var barGroups = svg.selectAll("g.layer")
      .data(["empty"]);

      barGroups.exit().remove();

      barGroups = barGroups
      .enter()
      .append("g")
      .classed('layer', true);

      var bars = svg.selectAll("g.layer").selectAll(".bars")
      .data(function()
      return ttlKey.map(function(key)
      var sum = d3.sum(data, e => e[key] )
      return key: key, value: sum;
      );
      ).enter()
      .append("rect")
      .attr("class", "bars")
      .attr("fill", d => z(d.key))
      .attr("opacity", .6)
      .attr("x", d => x1(d.key))
      .attr("y", d => y(d.value))
      .attr("width", x1.bandwidth())
      .attr("height", d => height - y(d.value));

      var barsTeam = svg.selectAll("g.layer").selectAll(".barsTeam")
      .data(function()
      return teamKey.map(function(key)
      var sum = d3.sum(data, e => e[key] )
      return key: key, value: sum;
      );
      );

      barsTeam.exit().remove();

      barsTeam = barsTeam
      .enter()
      .append("rect")
      .attr("class", "barsTeam")
      .attr("fill", d => z(d.key))
      .attr("x", d => x2(d.key))
      .attr("width", x1.bandwidth())
      .merge(barsTeam);

      barsTeam.transition().duration(durations)
      .attr("y", d => y(d.value))
      .attr("height", d => height - y(d.value));


      percent.update = update;



      function totals(data, team)

      var width = 110 - (margin.left + margin.right),
      height = 420 - (margin.top + margin.bottom);

      var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
      y = d3.scaleLinear().rangeRound([height, 0]);

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

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

      svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")");

      svg.append("g")
      .attr("class", "axis axis--y");

      update(data, team);

      function update(data, team)

      var sum = d3.sum(data, d => d3.sum([d.male, d.female]));

      var sumTeam = d3.sum(data, function(d)
      return d3.sum([d["Woman" + team], d["Man" + team]])
      );

      y.domain([0, sum]).nice();

      x.domain(["Total"]);

      svg.selectAll(".axis.axis--y")
      .call(yAxis);

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      var ttlBar = svg.selectAll(".ttlBar")
      .data(["empty"]).enter()
      .append("rect")
      .attr("class", "ttlBar")
      .attr("fill", "#ccc")
      .attr("x", x(["Total"]))
      .attr("y", y(sum))
      .attr("width", x.bandwidth())
      .attr("height", height - y(sum));

      var ttlTeam = svg.selectAll(".ttlTeam")
      .data(["empty"]);

      ttlTeam = ttlTeam
      .enter()
      .append("rect")
      .attr("class", "ttlTeam")
      .attr("fill", "#999")
      .attr("x", x(["Total"]))
      .attr("width", x.bandwidth())
      .merge(ttlTeam);

      ttlTeam.transition().duration(durations)
      .attr("height", height - y(sumTeam))
      .attr("y", y(sumTeam))



      totals.update = update


      body 
      font: 12px arial;
      margin: auto;
      width: 850px;
      padding-top:25px;

      select
      border: 1px solid #fff;
      border-bottom: 1px solid #ccc;
      cursor: pointer;

      .M fill: steelblue;
      .W fill: orange;
      .hide path
      display: none;

      .hide .tick:not(:first-of-type) line
      opacity: .25;

      <meta charset="utf-8">
      <script src="https://d3js.org/d3.v5.min.js"></script>
      <div style="margin-left: 25px;">
      <b>Choose Team:</b>
      <select class="select1">
      <option value="_one">Team 1</option>
      <option value="_two">Team 2</option>
      <option value="_three">Team 3</option>
      </select>
      </div>

      <div id="row1"></div>





      var durations = 0;

      var z = d3.scaleOrdinal()
      .range(["orange", "steelblue"]);

      var margin =
      top: 35, right: 35, bottom: 35, left: 35, pad: 25
      ;

      var csvData =
      `AgeRange,female,male,Woman_one,Man_one,Woman_two,Man_two,Woman_three,Man_three
      "17 - 19",50,36,23,22,3,0,5,5
      "20 - 24",145,99,80,72,22,3,27,14
      "25 - 29",123,109,40,80,28,3,42,22
      "30 - 34",121,52,54,35,21,2,32,13
      "35 - 39",88,65,23,30,15,4,44,28
      "40 - 44",79,52,28,22,8,4,40,23
      "45 - 49",89,51,21,27,14,1,47,20
      "50 - 54",67,31,15,12,10,1,38,15
      "55 - 59",55,25,7,3,7,3,39,17
      "60 - 64",40,21,5,5,4,2,30,14
      "65 - 69",26,11,1,0,1,0,22,11
      "70 - 74",10,6,0,0,0,0,9,5
      "75 +",9,1,0,0,0,0,9,1`;

      var dataSet = d3.csvParse(csvData)

      row1(dataSet);

      function row1(data)

      var check = false;

      update(check);

      function update(check)

      var team = d3.selectAll(".select1").property("value")

      data.forEach(function(d, i, columns)
      d.male = +(d.male);
      d.female = +(d.female);
      d["Woman" + team] = +d["Woman" + team];
      d["Man" + team] = +d["Man" + team];
      return d;
      )

      if (check)
      pyramid.update(data, team)
      percent.update(data, team)
      totals.update(data, team)
      else
      pyramid(data, team);
      percent(data, team);
      totals(data, team);



      d3.selectAll(".select1").on("change", function()
      check = true;
      durations = 750;
      update(check);
      )



      function pyramid(data, team)

      var width = 550 - (margin.left + margin.right);
      var height = 420 - (margin.top + margin.bottom);

      var x = d3.scaleLinear()
      .rangeRound([(width/2) + margin.pad, width]),
      x2 = d3.scaleLinear()
      .rangeRound([(width/2) - margin.pad, 0]),
      y = d3.scaleBand()
      .rangeRound([height, 0]).padding(0.1);

      var xAxis = d3.axisBottom(x).ticks(6)
      .tickSize(-height),
      xAxis2 = d3.axisBottom(x2).ticks(6)
      .tickSize(-height),
      yAxis = d3.axisLeft(y);

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

      svg.append("g")
      .attr("class", "axis axis--x hide")
      .attr("transform", "translate(0," + height + ")")
      svg.append("g")
      .attr("class", "axis axis--x2 hide")
      .attr("transform", "translate(0," + height + ")")
      svg.append("g")
      .attr("class", "axis axis--y")
      .attr("transform", "translate(" + (width/2 + 10) + ",0)")

      svg.append("text")
      .attr("x", width/2)
      .attr("y", 0)
      .attr("text-anchor", "middle")
      .text("Age");

      update(data, team);

      function update(data, team)

      x.domain([0, d3.max(data,
      d => Math.max(d.male, d.female))
      ]).nice();

      x2.domain(x.domain())

      y.domain(data.map(d => d.AgeRange));

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      svg.selectAll(".axis.axis--x2")
      .call(xAxis2);

      svg.selectAll(".axis.axis--y")
      .call(customYAxis);

      function customYAxis(g)
      g.call(yAxis);
      g.selectAll("text").style("text-anchor", "middle")
      g.select(".domain").remove();
      g.selectAll("line").remove();


      // ==== Men bar ====

      var menTtl = svg.selectAll(".menTtl")
      .data(data).enter()
      .insert("g", ".axis--x")
      .append("rect")
      .attr("class", "M menTtl")
      .attr("opacity",.6)
      .attr("x", x(0))
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .attr("width", d => Math.abs(x(d.male) - x(0)));

      var menTeam = svg.selectAll(".menTeam")
      .data(data);

      menTeam = menTeam
      .enter()
      .insert("g", ".axis--x")
      .append("rect")
      .attr("class", "M menTeam")
      .attr("x", x(0))
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .merge(menTeam)

      menTeam.transition().duration(durations)
      .attr("width", d => Math.abs(x(d["Man" + team]) - x(0)));

      // ==== Women bar ====

      var womenTtl = svg.selectAll(".womenTtl")
      .data(data).enter()
      .append("rect")
      .attr("class", "W womenTtl")
      .attr("opacity",.6)
      .attr("y", d => y(d.AgeRange))
      .attr("x", d => x2(d.female))
      .attr("height", y.bandwidth())
      .attr("width", d => Math.abs(x2(d.female) - x2(0)));

      var womenTeam = svg.selectAll(".womenTeam")
      .data(data);

      womenTeam = womenTeam
      .enter()
      .append("rect")
      .attr("class", "W womenTeam")
      .attr("y", d => y(d.AgeRange))
      .attr("height", y.bandwidth())
      .merge(womenTeam)

      womenTeam.transition().duration(durations)
      .attr("x", d => x2(d["Woman" + team]))
      .attr("width", d => Math.abs(x2(d["Woman" + team]) - x2(0)));


      pyramid.update = update;



      function percent(data, team)

      var width = 150 - (margin.left + margin.right),
      height = 420 - (margin.top + margin.bottom);

      var x0 = d3.scaleBand().rangeRound([0, width]),
      x1 = d3.scaleBand().paddingOuter(0.2),
      x2 = d3.scaleBand().paddingOuter(0.2),
      y = d3.scaleLinear().rangeRound([height, 0]);

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

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

      svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")");

      svg.append("g")
      .attr("class", "axis axis--y");

      update(data, team);

      function update(data, team)

      var ttlKey = data.columns.slice(1, 3);

      var teamKey = ["Woman" + team, "Man" + team]

      x0.domain(["Women & Men"]);
      x1.domain(ttlKey).rangeRound([0, x0.bandwidth()]);
      x2.domain(teamKey).rangeRound([0, x0.bandwidth()]);

      y.domain([0, d3.sum(data, function(d)
      return d3.max(ttlKey, key => d[key]);
      )]).nice();

      svg.selectAll(".axis.axis--y")
      .call(yAxis);

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      var barGroups = svg.selectAll("g.layer")
      .data(["empty"]);

      barGroups.exit().remove();

      barGroups = barGroups
      .enter()
      .append("g")
      .classed('layer', true);

      var bars = svg.selectAll("g.layer").selectAll(".bars")
      .data(function()
      return ttlKey.map(function(key)
      var sum = d3.sum(data, e => e[key] )
      return key: key, value: sum;
      );
      ).enter()
      .append("rect")
      .attr("class", "bars")
      .attr("fill", d => z(d.key))
      .attr("opacity", .6)
      .attr("x", d => x1(d.key))
      .attr("y", d => y(d.value))
      .attr("width", x1.bandwidth())
      .attr("height", d => height - y(d.value));

      var barsTeam = svg.selectAll("g.layer").selectAll(".barsTeam")
      .data(function()
      return teamKey.map(function(key)
      var sum = d3.sum(data, e => e[key] )
      return key: key, value: sum;
      );
      );

      barsTeam.exit().remove();

      barsTeam = barsTeam
      .enter()
      .append("rect")
      .attr("class", "barsTeam")
      .attr("fill", d => z(d.key))
      .attr("x", d => x2(d.key))
      .attr("width", x1.bandwidth())
      .merge(barsTeam);

      barsTeam.transition().duration(durations)
      .attr("y", d => y(d.value))
      .attr("height", d => height - y(d.value));


      percent.update = update;



      function totals(data, team)

      var width = 110 - (margin.left + margin.right),
      height = 420 - (margin.top + margin.bottom);

      var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
      y = d3.scaleLinear().rangeRound([height, 0]);

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

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

      svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")");

      svg.append("g")
      .attr("class", "axis axis--y");

      update(data, team);

      function update(data, team)

      var sum = d3.sum(data, d => d3.sum([d.male, d.female]));

      var sumTeam = d3.sum(data, function(d)
      return d3.sum([d["Woman" + team], d["Man" + team]])
      );

      y.domain([0, sum]).nice();

      x.domain(["Total"]);

      svg.selectAll(".axis.axis--y")
      .call(yAxis);

      svg.selectAll(".axis.axis--x")
      .call(xAxis);

      var ttlBar = svg.selectAll(".ttlBar")
      .data(["empty"]).enter()
      .append("rect")
      .attr("class", "ttlBar")
      .attr("fill", "#ccc")
      .attr("x", x(["Total"]))
      .attr("y", y(sum))
      .attr("width", x.bandwidth())
      .attr("height", height - y(sum));

      var ttlTeam = svg.selectAll(".ttlTeam")
      .data(["empty"]);

      ttlTeam = ttlTeam
      .enter()
      .append("rect")
      .attr("class", "ttlTeam")
      .attr("fill", "#999")
      .attr("x", x(["Total"]))
      .attr("width", x.bandwidth())
      .merge(ttlTeam);

      ttlTeam.transition().duration(durations)
      .attr("height", height - y(sumTeam))
      .attr("y", y(sumTeam))



      totals.update = update


      body 
      font: 12px arial;
      margin: auto;
      width: 850px;
      padding-top:25px;

      select
      border: 1px solid #fff;
      border-bottom: 1px solid #ccc;
      cursor: pointer;

      .M fill: steelblue;
      .W fill: orange;
      .hide path
      display: none;

      .hide .tick:not(:first-of-type) line
      opacity: .25;

      <meta charset="utf-8">
      <script src="https://d3js.org/d3.v5.min.js"></script>
      <div style="margin-left: 25px;">
      <b>Choose Team:</b>
      <select class="select1">
      <option value="_one">Team 1</option>
      <option value="_two">Team 2</option>
      <option value="_three">Team 3</option>
      </select>
      </div>

      <div id="row1"></div>








      share|improve this question












      share|improve this question




      share|improve this question








      edited May 24 at 13:41
























      asked May 24 at 13:18









      Robert Andersson

      1667




      1667




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          My answer here will focus on refactoring the row1 function. Right now that's an awkward function, with some unnecessary logic.



          Let's examine the it:



          function row1(data) 

          var check = false;

          update(check);

          function update(check)

          var team = d3.selectAll(".select1").property("value")

          data.forEach(function(d, i, columns)
          d.male = +(d.male);
          d.female = +(d.female);
          d["Woman" + team] = +d["Woman" + team];
          d["Man" + team] = +d["Man" + team];
          return d;
          )

          if (check)
          pyramid.update(data, team)
          percent.update(data, team)
          totals.update(data, team)
          else
          pyramid(data, team);
          percent(data, team);
          totals(data, team);



          d3.selectAll(".select1").on("change", function()
          check = true;
          durations = 750;
          update(check);
          )




          In the linked Plunker, which uses a real CSV, you get the result of the promise and pass it to the row1 function. So far, so good.



          However, inside that function, you're calling another function, named update, which gets the selected value of a <select> element. Then, based on that option, you're coercing only some values of the data array to numbers, but keeping the whole structure of the data array (you're not filtering or anything like that).



          The forEach inside update is also strange: you don't need to return the object row. Also, the third argument, columns, is probably a reminiscent of the third parameter in the d3.csv: in a forEach method the third argument is not the array of headers.



          Continuing, you're using a check variable (which is always true after the user changes the select) to choose what functions to call, and finally setting a listener to the select that never listens to the value of the select! It just calls update again...



          This is my proposition to simplify this row1 function:



          function row1(data) 

          data.forEach(function(d)
          for (var key in d)
          if (key !== "AgeRange")
          d[key] = +d[key]


          );

          pyramid(data, "_one");
          percent(data, "_two");
          totals(data, "_three");

          d3.selectAll(".select1").on("change", function()
          durations = 750;
          pyramid.update(data, this.value)
          percent.update(data, this.value)
          totals.update(data, this.value)
          );




          These are the changes:



          1. The forEach coerces all the values, except for AgeRange;

          2. You call the drawing functions with the data and the teams;

          3. Since you know what values you're using for the first time, I just hardcoded them. If you don't like that just use another selection to get the selected option (again, hardcoded!)

          4. You use the listener to get the value of the select with this.value, and call the update functions.

          Also, if you put the drawing functions inside row1, you don't even need to pass the data to them (since the data never changes).



          Here is the updated Plunker: https://plnkr.co/edit/UzFnmxC80ThA5VeGmFek?p=preview






          share|improve this answer























            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195086%2fupdate-multiple-charts-simultaneously-in-d3-js%23new-answer', 'question_page');

            );

            Post as a guest






























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            1
            down vote



            accepted










            My answer here will focus on refactoring the row1 function. Right now that's an awkward function, with some unnecessary logic.



            Let's examine the it:



            function row1(data) 

            var check = false;

            update(check);

            function update(check)

            var team = d3.selectAll(".select1").property("value")

            data.forEach(function(d, i, columns)
            d.male = +(d.male);
            d.female = +(d.female);
            d["Woman" + team] = +d["Woman" + team];
            d["Man" + team] = +d["Man" + team];
            return d;
            )

            if (check)
            pyramid.update(data, team)
            percent.update(data, team)
            totals.update(data, team)
            else
            pyramid(data, team);
            percent(data, team);
            totals(data, team);



            d3.selectAll(".select1").on("change", function()
            check = true;
            durations = 750;
            update(check);
            )




            In the linked Plunker, which uses a real CSV, you get the result of the promise and pass it to the row1 function. So far, so good.



            However, inside that function, you're calling another function, named update, which gets the selected value of a <select> element. Then, based on that option, you're coercing only some values of the data array to numbers, but keeping the whole structure of the data array (you're not filtering or anything like that).



            The forEach inside update is also strange: you don't need to return the object row. Also, the third argument, columns, is probably a reminiscent of the third parameter in the d3.csv: in a forEach method the third argument is not the array of headers.



            Continuing, you're using a check variable (which is always true after the user changes the select) to choose what functions to call, and finally setting a listener to the select that never listens to the value of the select! It just calls update again...



            This is my proposition to simplify this row1 function:



            function row1(data) 

            data.forEach(function(d)
            for (var key in d)
            if (key !== "AgeRange")
            d[key] = +d[key]


            );

            pyramid(data, "_one");
            percent(data, "_two");
            totals(data, "_three");

            d3.selectAll(".select1").on("change", function()
            durations = 750;
            pyramid.update(data, this.value)
            percent.update(data, this.value)
            totals.update(data, this.value)
            );




            These are the changes:



            1. The forEach coerces all the values, except for AgeRange;

            2. You call the drawing functions with the data and the teams;

            3. Since you know what values you're using for the first time, I just hardcoded them. If you don't like that just use another selection to get the selected option (again, hardcoded!)

            4. You use the listener to get the value of the select with this.value, and call the update functions.

            Also, if you put the drawing functions inside row1, you don't even need to pass the data to them (since the data never changes).



            Here is the updated Plunker: https://plnkr.co/edit/UzFnmxC80ThA5VeGmFek?p=preview






            share|improve this answer



























              up vote
              1
              down vote



              accepted










              My answer here will focus on refactoring the row1 function. Right now that's an awkward function, with some unnecessary logic.



              Let's examine the it:



              function row1(data) 

              var check = false;

              update(check);

              function update(check)

              var team = d3.selectAll(".select1").property("value")

              data.forEach(function(d, i, columns)
              d.male = +(d.male);
              d.female = +(d.female);
              d["Woman" + team] = +d["Woman" + team];
              d["Man" + team] = +d["Man" + team];
              return d;
              )

              if (check)
              pyramid.update(data, team)
              percent.update(data, team)
              totals.update(data, team)
              else
              pyramid(data, team);
              percent(data, team);
              totals(data, team);



              d3.selectAll(".select1").on("change", function()
              check = true;
              durations = 750;
              update(check);
              )




              In the linked Plunker, which uses a real CSV, you get the result of the promise and pass it to the row1 function. So far, so good.



              However, inside that function, you're calling another function, named update, which gets the selected value of a <select> element. Then, based on that option, you're coercing only some values of the data array to numbers, but keeping the whole structure of the data array (you're not filtering or anything like that).



              The forEach inside update is also strange: you don't need to return the object row. Also, the third argument, columns, is probably a reminiscent of the third parameter in the d3.csv: in a forEach method the third argument is not the array of headers.



              Continuing, you're using a check variable (which is always true after the user changes the select) to choose what functions to call, and finally setting a listener to the select that never listens to the value of the select! It just calls update again...



              This is my proposition to simplify this row1 function:



              function row1(data) 

              data.forEach(function(d)
              for (var key in d)
              if (key !== "AgeRange")
              d[key] = +d[key]


              );

              pyramid(data, "_one");
              percent(data, "_two");
              totals(data, "_three");

              d3.selectAll(".select1").on("change", function()
              durations = 750;
              pyramid.update(data, this.value)
              percent.update(data, this.value)
              totals.update(data, this.value)
              );




              These are the changes:



              1. The forEach coerces all the values, except for AgeRange;

              2. You call the drawing functions with the data and the teams;

              3. Since you know what values you're using for the first time, I just hardcoded them. If you don't like that just use another selection to get the selected option (again, hardcoded!)

              4. You use the listener to get the value of the select with this.value, and call the update functions.

              Also, if you put the drawing functions inside row1, you don't even need to pass the data to them (since the data never changes).



              Here is the updated Plunker: https://plnkr.co/edit/UzFnmxC80ThA5VeGmFek?p=preview






              share|improve this answer

























                up vote
                1
                down vote



                accepted







                up vote
                1
                down vote



                accepted






                My answer here will focus on refactoring the row1 function. Right now that's an awkward function, with some unnecessary logic.



                Let's examine the it:



                function row1(data) 

                var check = false;

                update(check);

                function update(check)

                var team = d3.selectAll(".select1").property("value")

                data.forEach(function(d, i, columns)
                d.male = +(d.male);
                d.female = +(d.female);
                d["Woman" + team] = +d["Woman" + team];
                d["Man" + team] = +d["Man" + team];
                return d;
                )

                if (check)
                pyramid.update(data, team)
                percent.update(data, team)
                totals.update(data, team)
                else
                pyramid(data, team);
                percent(data, team);
                totals(data, team);



                d3.selectAll(".select1").on("change", function()
                check = true;
                durations = 750;
                update(check);
                )




                In the linked Plunker, which uses a real CSV, you get the result of the promise and pass it to the row1 function. So far, so good.



                However, inside that function, you're calling another function, named update, which gets the selected value of a <select> element. Then, based on that option, you're coercing only some values of the data array to numbers, but keeping the whole structure of the data array (you're not filtering or anything like that).



                The forEach inside update is also strange: you don't need to return the object row. Also, the third argument, columns, is probably a reminiscent of the third parameter in the d3.csv: in a forEach method the third argument is not the array of headers.



                Continuing, you're using a check variable (which is always true after the user changes the select) to choose what functions to call, and finally setting a listener to the select that never listens to the value of the select! It just calls update again...



                This is my proposition to simplify this row1 function:



                function row1(data) 

                data.forEach(function(d)
                for (var key in d)
                if (key !== "AgeRange")
                d[key] = +d[key]


                );

                pyramid(data, "_one");
                percent(data, "_two");
                totals(data, "_three");

                d3.selectAll(".select1").on("change", function()
                durations = 750;
                pyramid.update(data, this.value)
                percent.update(data, this.value)
                totals.update(data, this.value)
                );




                These are the changes:



                1. The forEach coerces all the values, except for AgeRange;

                2. You call the drawing functions with the data and the teams;

                3. Since you know what values you're using for the first time, I just hardcoded them. If you don't like that just use another selection to get the selected option (again, hardcoded!)

                4. You use the listener to get the value of the select with this.value, and call the update functions.

                Also, if you put the drawing functions inside row1, you don't even need to pass the data to them (since the data never changes).



                Here is the updated Plunker: https://plnkr.co/edit/UzFnmxC80ThA5VeGmFek?p=preview






                share|improve this answer















                My answer here will focus on refactoring the row1 function. Right now that's an awkward function, with some unnecessary logic.



                Let's examine the it:



                function row1(data) 

                var check = false;

                update(check);

                function update(check)

                var team = d3.selectAll(".select1").property("value")

                data.forEach(function(d, i, columns)
                d.male = +(d.male);
                d.female = +(d.female);
                d["Woman" + team] = +d["Woman" + team];
                d["Man" + team] = +d["Man" + team];
                return d;
                )

                if (check)
                pyramid.update(data, team)
                percent.update(data, team)
                totals.update(data, team)
                else
                pyramid(data, team);
                percent(data, team);
                totals(data, team);



                d3.selectAll(".select1").on("change", function()
                check = true;
                durations = 750;
                update(check);
                )




                In the linked Plunker, which uses a real CSV, you get the result of the promise and pass it to the row1 function. So far, so good.



                However, inside that function, you're calling another function, named update, which gets the selected value of a <select> element. Then, based on that option, you're coercing only some values of the data array to numbers, but keeping the whole structure of the data array (you're not filtering or anything like that).



                The forEach inside update is also strange: you don't need to return the object row. Also, the third argument, columns, is probably a reminiscent of the third parameter in the d3.csv: in a forEach method the third argument is not the array of headers.



                Continuing, you're using a check variable (which is always true after the user changes the select) to choose what functions to call, and finally setting a listener to the select that never listens to the value of the select! It just calls update again...



                This is my proposition to simplify this row1 function:



                function row1(data) 

                data.forEach(function(d)
                for (var key in d)
                if (key !== "AgeRange")
                d[key] = +d[key]


                );

                pyramid(data, "_one");
                percent(data, "_two");
                totals(data, "_three");

                d3.selectAll(".select1").on("change", function()
                durations = 750;
                pyramid.update(data, this.value)
                percent.update(data, this.value)
                totals.update(data, this.value)
                );




                These are the changes:



                1. The forEach coerces all the values, except for AgeRange;

                2. You call the drawing functions with the data and the teams;

                3. Since you know what values you're using for the first time, I just hardcoded them. If you don't like that just use another selection to get the selected option (again, hardcoded!)

                4. You use the listener to get the value of the select with this.value, and call the update functions.

                Also, if you put the drawing functions inside row1, you don't even need to pass the data to them (since the data never changes).



                Here is the updated Plunker: https://plnkr.co/edit/UzFnmxC80ThA5VeGmFek?p=preview







                share|improve this answer















                share|improve this answer



                share|improve this answer








                edited May 25 at 3:32


























                answered May 24 at 14:13









                Gerardo Furtado

                1,1342420




                1,1342420






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195086%2fupdate-multiple-charts-simultaneously-in-d3-js%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    Greedy Best First Search implementation in Rust

                    Function to Return a JSON Like Objects Using VBA Collections and Arrays

                    C++11 CLH Lock Implementation