Home > Software engineering >  How to plot x axis values over bars?
How to plot x axis values over bars?

Time:05-13

I changed the attributes of the X axis to plot its values over the bars of the chart. But anywhere I put the code, the values are always plotted before ("behind") the bars and therefore we cannot see it.

  //This part of the code is OUTSIDE of the update function (line 44 of the fiddle)
  //append group to plot X axis
  const xAxisGroup = g.append("g")
    .attr("class", "x axis")
    .attr("transform", `translate(0, ${HEIGHT})`)


  //This part of the code is INSIDE the update function (line 92)
  const xAxisCall = d3.axisBottom(x)
  xAxisGroup.call(xAxisCall)
    .selectAll("text")
    .attr("x", "-5") // <<<--- I change this to 50
    .attr("y", "10")
      .attr("text-anchor", "end")
      .attr("transform", "rotate(-45)") // <<<--- I changed this to -90

How would be possible to plot this values over the bars instead?

This is the fiddle of the original chart and this is the modified one. The month values may be behind the bars... :-/

CodePudding user response:

In an SVG, whatever is painted later stays on top. So, just append your x axis <g> element after painting the rectangles. Alternatively, raise it:

xAxisGroup.raise()

Here's your code with that change:

//set general margin, width and height values
const MARGIN = {
  LEFT: 128,
  RIGHT: 8,
  TOP: 32,
  BOTTOM: 128
}
const WIDTH = 400 - MARGIN.LEFT - MARGIN.RIGHT
const HEIGHT = 300 - MARGIN.TOP - MARGIN.BOTTOM

//append svg plot area into div chart area
const svg = d3.select("#chart-area").append("svg")
  .attr("width", WIDTH   MARGIN.LEFT   MARGIN.RIGHT)
  .attr("height", HEIGHT   MARGIN.TOP   MARGIN.BOTTOM)

//append group into svg 
const g = svg.append("g")
  .attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)

//X label
g.append("text")
  .attr("class", "x axis-label")
  .attr("x", WIDTH / 2)
  .attr("y", HEIGHT   60)
  .attr("font-size", "20px")
  .attr("text-anchor", "middle")
  .text("Month")

//Y label
g.append("text")
  .attr("class", "y axis-label")
  .attr("x", -(HEIGHT / 2))
  .attr("y", -60)
  .attr("font-size", "20px")
  .attr("text-anchor", "middle")
  .attr("transform", "rotate(-90)")
  .text("Value")

//set scale for X axis
const x = d3.scaleBand()
  .range([0, WIDTH])
  .paddingInner(0.3)
  .paddingOuter(0.2)

//set scale for Y axis
const y = d3.scaleLinear()
  .range([HEIGHT, 0])

//append group to plot X axis
const xAxisGroup = g.append("g")
  .attr("class", "x axis")
  .attr("transform", `translate(0, ${HEIGHT})`)

//append group to plot Y axis
const yAxisGroup = g.append("g")
  .attr("class", "y axis")

//import data
d3.csv("https://raw.githubusercontent.com/dbahiense/sotabook/main/revenues.csv").then(data => {
  //parse values
  data.forEach(d => {
    d.revenue = Number(d.revenue)
    d.profit = Number(d.profit)
  })

  //listen drop-down lists and trigger update function on change
  //state
  d3.select("#state")
    .on("change", function(event, d) {
      update(data)
    })
  //round
  d3.select("#round")
    .on("change", function(event, d) {
      update(data)
    })

  //plot chart on page first load
  update(data)
})

// update chart function
function update(data) {
  //drop-down list listened values
  let state = d3.select("#state").property("value")
  let round = d3.select("#round").property("value")

  //filter data by drop-down list values
  let filteredData = data.filter(function(d) {
    return d.state == state & d.round == round
  })

  //set domains for X and Y axes
  x.domain(filteredData.map(d => d.month))
  y.domain([0, d3.max(filteredData, d => d.revenue)])

  const xAxisCall = d3.axisBottom(x)

  const yAxisCall = d3.axisLeft(y)
  //.tickFormat(d => d   "m")
  yAxisGroup.call(yAxisCall)

  // JOIN new data with old elements.
  const rects = g.selectAll("rect")
    .data(filteredData)

  // EXIT old elements not present in new data.
  rects.exit().remove()

  // UPDATE old elements present in new data.
  rects
    .attr("y", d => y(d.revenue))
    .attr("x", (d) => x(d.month))
    .attr("width", x.bandwidth)
    .attr("height", d => HEIGHT - y(d.revenue))

  // ENTER new elements present in new data.  
  rects.enter().append("rect")
    .attr("y", d => y(d.revenue))
    .attr("x", (d) => x(d.month))
    .attr("width", x.bandwidth)
    .attr("height", d => HEIGHT - y(d.revenue))
    .attr("fill", "steelblue")

  xAxisGroup.raise()
    .call(xAxisCall)
    .selectAll("text")
    .attr("x", "50")
    .attr("y", "10")
    .attr("text-anchor", "end")
    .attr("transform", "rotate(-90)")
}
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="description" content="">
    <title>5.4</title>
    <!-- Bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3 Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <!-- Custom styling -->
    <link rel="stylesheet" href="css/style.css">
</head>
<body>

    <!-- Bootstrap grid setup -->
    <div >
        <div >
            <select id="state">
                <option value="US">US</option>
                <option value="EU">EU</option>
                <option value="AS">AS</option>
            </select>

            <select id="round">
                <option value="1">1</option>
                <option value="2">2</option>
            </select>
        </div>
        <div >
            <div id="chart-area"></div>
        </div>
    </div>

    <!-- External JS libraries -->
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2 poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft 2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    <!-- Custom JS below-->
</body>
</html>

  • Related