1

I have the following arrays that a want to display as a stacked bar chart with p5js (javascript).

Below you can see an arrayOfMonths (month1, month2,...) that is going to be displayed on the X Axis of the Stacked Bar Chart. Now, Each month has a number of other (0-to many) elements. Those are the elements that I want to display on Y Axis so for example month1 has 2 elements i want to create two rectangles on the first element on X Axis and so on as shown below:

4|     ▭

3|     ▭   ▭

2| ▭  ▭    ▭

1| ▭  ▭ ▭ ▭
▬▬▬▬▬▬▬▬▬▬▬▬▬▬
   m1 m2 m3 m4

let me know if you know how to handle 2Dimensional Arrays :) Thanks...

/* Needed Variables Declaration */
var month1 = ["M01V01","M01V02"];
var month2 = ["M02V01","M02V02","M02V03","M02V04"];
var month3 = ["M03V01"];
var month4 = ["M04V01","M04V02","M04V03"];
var arrayOfMonths = [month1,month2,month3,month4];
var arrayOfResponses = ["1", "2", "3","4","5"];

function addValues(){

 var locX = canvasWidth-(canvasWidth-125);
  var locY = canvasHeight-25;
  var barWidth = 50; 
  var barData = canvasHeight/(numOfResponses+2);
  
  for(var x=0; x<arrayOfMonths.length; x++){
    /* Draw Stack Bars (rectangles) */
    for(var y=0; y<arrayOfMonths[x].length; y++){
      
      
      /* ADD TEXT TO X AXIS */
      if(y<=x){
        
       locX = canvasWidth-(canvasWidth-125);
        locY -= 125;
        text(arrayOfMonths[x][y], locX, locY);
        
        fill(random(255),random(255),random(255));
      rect(locX, locY, barWidth, barData);
      }
      // locX+=canvasWidth/(numOfMonths+1);
      
    locX+=100;    
   
      //locY -= 150; 
    }
    //locX = canvasWidth-(canvasWidth-125);  
    //locY = canvasHeight-210;
  }
}
Loizos Vasileiou
  • 674
  • 10
  • 37
  • What errors are you getting ? – Pogrindis Apr 13 '18 at 14:06
  • related : https://stackoverflow.com/questions/29464535/creating-a-p5-js-2-dimensional-array – Pogrindis Apr 13 '18 at 14:08
  • Im not getting any errors i just want to display the array of elements correctly on the graph.. Basically, Lets say the 1st element in the array has two values in it, I want to draw the rectangles one above each other and then continue on the next element in the array by changing the location.. More information in the function (method) addValues at the end of the javascript file. – Loizos Vasileiou Apr 13 '18 at 14:11
  • Sorry, but your question is pretty unclear. The code you posted already uses a nested `for` loop to iterate over all of the elements in your array. Can you please post a simplified [mcve] instead of your full program? – Kevin Workman Apr 13 '18 at 16:17
  • I have edited my question please let me know if its more clear now – Loizos Vasileiou Apr 13 '18 at 17:13

1 Answers1

1

Based on your data this is one way you could do it. You could map number of elements on x and y axes to size of your graph or size of those axes, so each index is scaled between 0 - data.length and start - end of axis. You could also use first element of xTicks for space size between them and then you just draw axes based on that data.

And for data you just loop xData which is 2D array and use current index for x and y position from xTicks and yTicks. You also need to adjust rects a bit (+ - 5) which is half of 10, and same for ticks text.

Note that y position of rects is based on its index in months array and not on its text so for example if you have var month1 = ["M01V03", "M01V04"] it will still be on first two y position, instead you could take last char of text Fiddle

var month1 = ["M01V01", "M01V02"];
var month2 = ["M02V01", "M02V02", "M02V03", "M02V04"];
var month3 = ["M03V01"];
var month4 = ["M04V01", "M04V02", "M04V03"];
var months = [month1, month2, month3, month4];
var responses = ["1", "2", "3", "4", "5"];

let graph;

function setup() {
  createCanvas(400, 250);
  graph = new Graph(months, responses, 200, 300);
}

function draw() {
  background(50, 50, 150);
  graph.show();
  graph.showData();
}

class Graph {
  constructor(xData, yData, height, width) {
    this.xData = xData;
    this.yData = yData;
    this.height = height;
    this.width = width;
    this.xStart = 60;
    this.yStart = window.height - 30;

    this.xTicks = this.xData.map((e, i) => {
      return map(i, 0, this.xData.length, this.xStart, this.width);
    })

    this.yTicks = this.yData.map((e, i) => {
      return map(i, 0, this.yData.length, this.yStart - this.height, this.yStart);
    })

    this.xSpace = this.xTicks[0];
  }

  show() {
    this.xAxis();
    this.yAxis();
  }

  xAxis() {
    stroke(255);
    strokeWeight(1);
    line(this.xStart, this.yStart, this.xStart + this.width, this.yStart);
    strokeWeight(2)
    this.xTicks.forEach((x, i) => {
      stroke(255)
      line(x + this.xSpace, this.yStart + 2, x + this.xSpace, this.yStart - 2)
      noStroke()
      fill(255);
      text(`m${i + 1}`, x + this.xSpace - 7, this.yStart + 14)
    })
  }

  yAxis() {
    stroke(255);
    strokeWeight(1);
    line(this.xStart, this.yStart, this.xStart, this.yStart - this.height);
    strokeWeight(2)
    this.yTicks.forEach((y, i) => {
      stroke(255)
      line(this.xStart - 2, this.yStart - y, this.xStart + 2, this.yStart - y);
      noStroke()
      fill(255);
      textSize(10)
      text(this.yData[i], this.xStart - 15, this.yStart - y + 3)
    })
  }

  showData() {
    this.xData.forEach((arr, i) => {
      arr.forEach((item, j) => {
        noFill();
        stroke(255);
        rect(this.xTicks[i] + this.xSpace - 5, this.yStart - this.yTicks[j] - 5, 10, 10)
      })
    })
  }

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176