1

I'm trying to figure out how to add interactive features in a bar chart.

Now I'm stuck about program fuctions for a click action using a button to sort ascending and descending.

This is my code:

const width = 800
const height = 400
const margin = {
    top: 40, 
    bottom: 60, 
    left: 40, 
    right: 10
}
const svg = d3.select("div#chart").append("svg").attr("width", width).attr("height", height)
const elementGroup = svg.append("g").attr("id", "elementGroup").attr("transform", `translate(${margin.left}, ${margin.top})`)
const axisGroup = svg.append("g").attr("id", "axisGroup")
const xAxisGroup = axisGroup.append("g").attr("id", "xAxisGroup").attr("transform", `translate(${margin.left}, ${height - margin.bottom})`)
const yAxisGroup = axisGroup.append("g").attr("id", "yAxisGroup").attr("transform", `translate(${margin.left}, ${margin.top})`)

const x = d3.scaleBand().range([0, width - margin.left - margin.right]).padding(0.1)
const y = d3.scaleLinear().range([height - margin.bottom - margin.top, 0])

const xAxis = d3.axisBottom().scale(x)
const yAxis = d3.axisLeft().scale(y).ticks(5)

d3.csv("WorldCup.csv").then(data => {

  let nest = d3.nest()
  .key(d => d.Winner)
  .entries(data)
nest.map(d => d.values = d.values.length)
console.log(nest)

    
    x.domain(nest.map(d => d.key))
    y.domain([0, d3.max(nest.map(d => d.values))])

    xAxisGroup.call(xAxis)
    yAxisGroup.call(yAxis)

        //Asceding sort

        function sortAscending() {nest.sort((a, b) => d3.ascending(a.values, b.values))
          
          let xLabel = elementGroup.append("text").text("Countries")
          .attr("transform", `translate(${width - margin.right - 30}, ${height - margin.bottom})`)
          .attr("text-anchor", "end").attr("font-weight", 700)
      
          let yLabel = elementGroup.append("text").text("Cups per country")
          .attr("transform", `translate(${-20}, ${-10})`).attr("font-weight", 700)
      
          let elements = elementGroup.selectAll("rect").data(nest)
          elements.enter().append("rect")
              .attr("class", "bar")
              .attr("x", d => x(d.key))
              .attr("width", x.bandwidth())
              .attr("height", d => height - margin.top - margin.bottom - y(d.values))
              .attr("y", d => y(d.values))
        }
        d3.select("#Ascending").on("click", sortAscending)

       //Descending sort

        function sortDescending() {nest.sort((a, b) => d3.descending(a.values, b.values))

          let xLabel = elementGroup.append("text").text("Countries")
          .attr("transform", `translate(${width - margin.right - 30}, ${height - margin.bottom})`)
          .attr("text-anchor", "end").attr("font-weight", 700)
      
          let yLabel = elementGroup.append("text").text("Cups per country")
          .attr("transform", `translate(${-20}, ${-10})`).attr("font-weight", 700)
      
          let elements = elementGroup.selectAll("rect").data(nest)
          elements.enter().append("rect")
              .attr("class", "bar")
              .attr("x", d => x(d.key))
              .attr("width", x.bandwidth())
              .attr("height", d => height - margin.top - margin.bottom - y(d.values))
              .attr("y", d => y(d.values))
        }
        d3.select("#Ascending").on("click", sortDescending)


      })

I tried different examples.

By the moment, I just understood it is about configure a function, and then link the fuction with a button by 'on'.

1
  • My dataset is this: Year,Winner 1930,Uruguay 1934,Italy 1938,Italy 1950,Uruguay 1954,Germany 1958,Brazil 1962,Brazil 1966,England 1970,Brazil 1974,Germany 1978,Argentina 1982,Italy 1986,Argentina 1990,Germany 1994,Brazil 1998,France 2002,Brazil 2006,Italy 2010,Spain 2014,Germany 2018,France 2022,Argentina Commented Jan 31, 2023 at 21:56

1 Answer 1

0

You are close, but you have to separate the code that is used to draw the plot for the first time, and what is needed to update it after the data was sorted. A possible framework that works, based on on your code, is this

const height = 400, width = 600;
const margin = {
    top: 40,
    bottom: 60,
    left: 40,
    right: 10
};
const svg = d3.select("div#chart").append("svg").attr("width", width).attr("height", height)
const elementGroup = svg.append("g").attr("id", "elementGroup").attr("transform", `translate(${margin.left}, ${margin.top})`)
const axisGroup = svg.append("g").attr("id", "axisGroup")
const xAxisGroup = axisGroup.append("g").attr("id", "xAxisGroup").attr("transform", `translate(${margin.left}, ${height - margin.bottom})`)
const yAxisGroup = axisGroup.append("g").attr("id", "yAxisGroup").attr("transform", `translate(${margin.left}, ${margin.top})`)

const x = d3.scaleBand().range([0, width - margin.left - margin.right]).padding(0.1)
const y = d3.scaleLinear().range([height - margin.top - margin.bottom, 0])

const xAxis = d3.axisBottom().scale(x)
const yAxis = d3.axisLeft().scale(y).ticks(5)

function drawBarPlot(nest){
    x.domain(nest.map(d => d.key))
    y.domain([0, d3.max(nest.map(d => d.values))])

    xAxisGroup.call(xAxis)
    yAxisGroup.call(yAxis)

    elementGroup.append("text").text("Countries")
        .attr("transform", `translate(${width - margin.right - 30}, ${height - margin.bottom})`)
        .attr("text-anchor", "end").attr("font-weight", 700);

    elementGroup.append("text").text("Cups per country")
        .attr("transform", `translate(${-20}, ${-10})`).attr("font-weight", 700);

    elementGroup.selectAll("rect").data(nest).enter().append("rect")
        .attr("class", "bar")
        .attr("x", d => x(d.key))
        .attr("width", x.bandwidth())
        .attr("height", d => height - margin.top - margin.bottom - y(d.values))
        .attr("y", d => y(d.values));
}

function updateBarPlot(nest){
    x.domain(nest.map(d => d.key));
    xAxisGroup.call(xAxis);
    elementGroup.selectAll("rect").data(nest).call(update => update
        .attr("height", d => height - margin.top - margin.bottom - y(d.values))
        .attr("y", d => y(d.values)));
}

//Ascending sort
function sortAscending(nest) {
    nest.sort((a, b) => d3.ascending(a.values, b.values));
    updateBarPlot(nest);
}

function sortDescending(nest) {
    nest.sort((a, b) => d3.descending(a.values, b.values));
    updateBarPlot(nest);
}

//d3.csv("WorldCup.csv").then(data => {
new Promise(resolve => resolve(d3.csvParse("Year,Winner\n" + "1930,Uruguay\n" + "1934,Italy\n" + "1938,Italy\n" + "1950,Uruguay\n" +
    "1954,Germany\n" + "1958,Brazil\n" + "1962,Brazil\n" + "1966,England\n" + "1970,Brazil\n" +
    "1974,Germany\n" + "1978,Argentina\n" + "1982,Italy\n" + "1986,Argentina\n" + "1990,Germany\n" +
    "1994,Brazil\n" + "1998,France\n" + "2002,Brazil\n" + "2006,Italy\n" + "2010,Spain\n" +
    "2014,Germany\n" + "2018,France\n" + "2022,Argentina\n"))).then(data => {
    let nest = d3.nest()
        .key(d => d.Winner)
        .entries(data)
    nest.map(d => d.values = d.values.length)

    drawBarPlot(nest);

    d3.select("#Ascending").on("click", ()=>sortAscending(nest));
    d3.select("#Descending").on("click", ()=>sortDescending(nest));
});
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://d3js.org/d3-collection.v1.min.js"></script>

<div id="chart"></div>
<button id="Ascending">Ascending</button><button id="Descending">Descending</button>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.