Creating Graphs and Charts

In this article by Bhushan Purushottam Joshi author of the book Canvas Cookbook, highlights data representation in the form of graphs and charts with the following topics:

  • Drawing the axes
  • Drawing a simple equation
  • Drawing a sinusoidal wave
  • Drawing a line graph
  • Drawing a bar graph
  • Drawing a pie chart

(For more resources related to this topic, see here.)

Drawing the axes

In school days, we all might have used a graph paper and drawn a vertical line called y axis and a horizontal line called as x axis. Here, in the first recipe of ours, we do only the drawing of axes. Also, we mark the points at equal intervals. The output looks like this:

How to do it…

The HTML code is as follows:

<html>
<head>
  <title>Axes</title>
  <script src="graphaxes.js"></script>
</head>
<body onload=init()>
  <canvas width="600" height="600" id="MyCanvasArea" style="border:2px solid blue;" tabindex="0">
    Canvas tag is not supported by your browser
  </canvas>
  <br>

  <form id="myform">
  Select your starting value
  <select name="startvalue" onclick="init()">
    <option value=-10>-10</option>
    <option value=-9>-9</option>
    <option value=-8>-8</option>
    <option value=-7>-7</option>
    <option value=-6>-6</option>
    <option value=-5>-5</option>
    <option value=-4>-4</option>
    <option value=-3>-3</option>
    <option value=-2>-2</option>
  </select>
  </form>
</body>
</html>

The JavaScript code is as follows:

varxMin=-10;varyMin=-10;varxMax=10;varyMax=10;
//draw the x-axis
varcan;varctx;varxaxisx;varxaxisy;varyaxisx;varyaxisy;
varinterval;var length;
functioninit(){
  can=document.getElementById('MyCanvasArea');
  ctx=can.getContext('2d'); 
  ctx.clearRect(0,0,can.width,can.height);
  varsel=document.forms['myform'].elements['startvalue'];
  xMin=sel.value;
  yMin=xMin;
  xMax=-xMin;
  yMax=-xMin;
  drawXAxis();
  drawYAxis();
}
functiondrawXAxis(){
  //x axis drawing and marking on the same
  xaxisx=10;
  xaxisy=can.height/2; 
  ctx.beginPath();
  ctx.lineWidth=2;
  ctx.strokeStyle="black";
  ctx.moveTo(xaxisx,xaxisy);
  xaxisx=can.width-10;
  ctx.lineTo(xaxisx,xaxisy);
  ctx.stroke();
  ctx.closePath();
  length=xaxisx-10;
  noofxfragments=xMax-xMin;
  interval=length/noofxfragments;
  //mark the x-axis
  xaxisx=10;
  ctx.beginPath();
  ctx.font="bold 10pt Arial";
  for(vari=xMin;i<=xMax;i++)
  {
    ctx.lineWidth=0.15;
    ctx.strokeStyle="grey";
    ctx.fillText(i,xaxisx-5,xaxisy-10); 
    ctx.moveTo(xaxisx,xaxisy-(can.width/2));
    ctx.lineTo(xaxisx,(xaxisy+(can.width/2)));
    ctx.stroke();
    xaxisx=Math.round(xaxisx+interval);
  }
  ctx.closePath();
}
functiondrawYAxis(){
  yaxisx=can.width/2;
  yaxisy=can.height-10;
  ctx.beginPath();
  ctx.lineWidth=2;
  ctx.strokeStyle="black";
  ctx.moveTo(yaxisx,yaxisy);
  yaxisy=10
  ctx.lineTo(yaxisx,yaxisy);
  ctx.stroke();
  ctx.closePath(); 
  yaxisy=can.height-10;
  length=yaxisy-10;
  noofxfragments=yMax-yMin;
  interval=length/noofxfragments;
  //mark the y-axis
  ctx.beginPath();
  ctx.font="bold 10pt Arial";
  for(vari=yMin;i<=yMax;i++)
  {
    ctx.lineWidth=0.15; 
    ctx.strokeStyle="grey"; 
    ctx.fillText(i,yaxisx-20,yaxisy+5); 
    ctx.moveTo(yaxisx-(can.height/2),yaxisy);
    ctx.lineTo((yaxisx+(can.height/2)),yaxisy);
    ctx.stroke();
    yaxisy=Math.round(yaxisy-interval);
  }   
  ctx.closePath();   
}

How it works...

There are two functions in the JavaScript code viz. drawXAxis and drawYAxis. A canvas is not calibrated the way a graph paper is. A simple calculation is used to do the same.

In both the functions, there are two parts. One part draws the axis and the second marks the axis on regular intervals. These are delimited by ctx.beginPath() and ctx.closePath().

In the first part, the canvas width and height are used to draw the axis.

In the second part, we do some calculation. The length of the axis is divided by the number of markers to get the interval. If the starting point is -3, then we have -3, -2, -1, 0, 1, 2, and 3 on the axis, which makes 7 marks and 6 parts. The interval is used to generate x and y coordinate value for the starting point and plot the markers.

There is more...

Try to replace the following:

ctx.moveTo(xaxisx,xaxisy-(can.width/2)); (in drawXAxis())
ctx.lineTo(xaxisx,(xaxisy+(can.width/2)));(in drawXAxis())

ctx.moveTo(yaxisx-(can.height/2),yaxisy);(in drawYAxis())
ctx.lineTo((yaxisx+(can.height/2)),yaxisy);(in drawYAxis())
WITH
ctx.moveTo(xaxisx,xaxisy-5);
ctx.lineTo(xaxisx,(xaxisy+5));

ctx.moveTo(yaxisx-5,yaxisy);
ctx.lineTo((yaxisx+5),yaxisy);

Also, instead of grey color for markers, you can use red.

Drawing a simple equation

This recipe is a simple line drawing on a graph using an equation. The output looks like this:

How to do it…

The HTML code is as follows:

<html>
<head>
  <title>Equation</title>
  <script src="graphaxes.js"></script>
  <script src="plotequation.js"></script>
</head>
<body onload=init()>
  <canvas width="600" height="600" id="MyCanvasArea" style="border:2px solid blue;" tabindex="0">
    Canvas tag is not supported by your browser
  </canvas>
  <br>

  <form id="myform">
  Select your starting value
  <select name="startvalue" onclick="init()">
    <option value=-10>-10</option>
    <option value=-9>-9</option>
    <option value=-8>-8</option>
    <option value=-7>-7</option>
    <option value=-6>-6</option>
    <option value=-5>-5</option>
    <option value=-4>-4</option>
    <option value=-3>-3</option>
    <option value=-2>-2</option>
  </select>
  <br>
  Enter the coeficient(c) for the equation y=cx
  <input type="text" size=5 name="coef">
  <input type="button" value="Click to plot" onclick="plotEquation()">
  <input type="button" value="Reset" onclick="init()">
  </form>
</body>
</html>

The JavaScript code is as follows:

functionplotEquation(){
  varcoef=document.forms['myform'].elements['coef'];
  var s=document.forms['myform'].elements['startvalue'];
  var c=coef.value;
  var x=parseInt(s.value);
  varxPos;  varyPos;
  while(x<=xMax)
  {
    y=c*x;
    xZero=can.width/2;
    yZero=can.height/2;

    if(x!=0)
      xPos=xZero+x*interval;
    else
      xPos=xZero-x*interval; 

    if(y!=0)
      yPos=yZero-y*interval;
    else
      yPos=yZero+y*interval;
    ctx.beginPath();
    ctx.fillStyle="blue";
    ctx.arc(xPos,yPos,5,Math.PI/180,360*Math.PI/180,false);
    ctx.fill();
    ctx.closePath();
    if(x<xMax)
    {
      ctx.beginPath();
      ctx.lineWidth=3;
      ctx.strokeStyle="green";
      ctx.moveTo(xPos,yPos);
      nextX=x+1;
      nextY=c*nextX;
      if(nextX!=0)
        nextXPos=xZero+nextX*interval;
      else
        nextXPos=xZero-nextX*interval;
      if(nextY!=0)
        nextYPos=yZero-nextY*interval;
      else
        nextYPos=yZero+nextY*interval;
      ctx.lineTo(nextXPos,nextYPos);
      ctx.stroke();
      ctx.closePath();
    }
    x=x+1;
  } 
}

How it works...

We use one more script in this recipe. There are two scripts referred by the HTML file. One is the previous recipe named graphaxes.js, and the other one is the current one named plotequation.js. JavaScript allows you to use the variables created in one file into the other, and this is done in this new recipe. You already know how the axes are drawn.

This recipe is to plot an equation y=cx, where c is the coefficient entered by the user. We take the minimum of the x value from the drop-down list and calculate the values for y in a loop. We plot the current and next coordinate and draw a line between the two. This happens till we reach the maximum value of x. Remember that the maximum and minimum value of x and y is same.

There is more...

Try the following:

  • Input positive as well as negative value for coefficient.

Drawing a sinusoidal wave

This recipe also uses the previous recipe of axes drawing. The output looks like this:

How to do it…

The HTML code is as follows:

<html>
<head>
  <title>Equation</title>
  <script src="graphaxes.js"></script>
  <script src="plotSineEquation.js"></script>
</head>
<body onload=init()>
  <canvas width="600" height="600" id="MyCanvasArea" style="border:2px solid blue;" tabindex="0">
    Canvas tag is not supported by your browser
  </canvas>
  <br>

  <form id="myform">
  Select your starting value
  <select name="startvalue" onclick="init()">
    <option value=-10>-10</option>
    <option value=-9>-9</option>
    <option value=-8>-8</option>
    <option value=-7>-7</option>
    <option value=-6>-6</option>
    <option value=-5>-5</option>
    <option value=-4>-4</option>
    <option value=-3>-3</option>
    <option value=-2>-2</option>
  </select>
  <br>
  <input type="button" value="Click to plot a sine wave" onclick="plotEquation()">
  <input type="button" value="Reset" onclick="init()">
  </form>
</body>
</html>

The JavaScript code is as follows:

functionplotEquation()
{
  var s=document.forms['myform'].elements['startvalue']; 
  var x=parseInt(s.value);
  //ctx.fillText(x,100,100);
  varxPos;
  varyPos;
  varnoofintervals=Math.round((2*Math.abs(x)+1)/2);
  xPos=10;
  yPos=can.height/2;
  xEnd=xPos+(2*interval);
  yEnd=yPos;
  xCtrl1=xPos+Math.ceil(interval/2);
  yCtrl1=yPos-200;
  xCtrl2=xEnd-Math.ceil(interval/2);
  yCtrl2=yPos+200;
  drawBezierCurve(ctx,xPos,yPos,xCtrl1,yCtrl1,xCtrl2,yCtrl2,xEnd,yEnd,"red",2);   
  for(vari=1;i<noofintervals;i++)
  {
    xPos=xEnd;
    xEnd=xPos+(2*interval);
    xCtrl1=xPos+Math.floor(interval/2)+15;
    xCtrl2=xEnd-Math.floor(interval/2)-15;
    drawBezierCurve(ctx,xPos,yPos,xCtrl1,yCtrl1,xCtrl2,yCtrl2,xEnd,yEnd,"red",2);   
  } 
}
function drawBezierCurve(ctx,xstart,ystart,xctrl1,yctrl1,xctrl2,yctrl2,xend,yend,color,width)
{  
  ctx.strokeStyle=color;
  ctx.lineWidth=width;
  ctx.beginPath();
  ctx.moveTo(xstart,ystart);
  ctx.bezierCurveTo(xctrl1,yctrl1,xctrl2,yctrl2,xend,yend);
  ctx.stroke();          
}

How it works...

We use the Bezier curve to draw the sine wave along the x axis. A bit of calculation using the interval between two points, which encompasses a phase, is done to achieve this. The number of intervals is calculated in the following statement:

varnoofintervals=Math.round((2*Math.abs(x)+1)/2);

where x is the value in the drop-down list. One phase is initially drawn before the for loop begins. The subsequent phases are drawn in the for loop. The start and end x coordinate changes in every iteration. The ending coordinate for the first sine wave is the first coordinate for the subsequent sine wave.

Drawing a line graph

Graphs are always informative. The basic graphical representation can be a line graph, which is demonstrated here:

How to do it…

The HTML code is as follows:

<html>
<head>
  <title>A simple Line chart</title>
  <script src="linechart.js"></script>
</head>
<body onload=init()>
  <h1>Your WhatsApp Usage</h1>
  <canvas width="600" height="500" id="MyCanvasArea" style="border:2px solid blue;" tabindex="0">
    Canvas tag is not supported by your browser
  </canvas>
</body>
</html>

The JavaScript code is as follows:

functioninit() {
  vargCanvas = document.getElementById('MyCanvasArea');
  // Ensure that the element is available within the DOM
  varctx = gCanvas.getContext('2d');
  // Bar chart data
  var data = new Array(7);
  data[0] = "1,130";    data[1] = "2,140";    data[2] = "3,150";    data[3] = "4,140";
  data[4] = "5,180";  data[5] = "6,240";  data[6] = "7,340";
  // Draw the bar chart
  drawLineGraph(ctx, data, 70, 100, (gCanvas.height - 40), 50);
}
functiondrawLineGraph(ctx, data, startX, barWidth, chartHeight, markDataIncrementsIn) {
  // Draw the x axis
ctx.lineWidth = "3.0";
var max=0;  
varstartY = chartHeight;
drawLine(ctx, startX, startY, startX, 1);
drawLine(ctx, startX, startY, 490, startY);     
for(vari=0,m=0;i<data.length;i++,m+=60)
  {
  ctx.lineWidth=0.3;
  drawLine(ctx,startX,startY-m,490,startY-m)     
  ctx.font="bold 12pt Arial";
  ctx.fillText(m,startX-30,startY-m); 
  }   
for(vari=0,m=0;i<data.length;i++,m+=61)
  { 
  ctx.lineWidth=0.3;
  drawLine(ctx, startX+m, startY, startX+m, 1);         
  var values=data[i].split(",");
  var day;
  switch(values[0])
  {
    case "1":
      day="MO";
      break;
    case "2":
      day="TU";
      break;
    case "3":
      day="WE";
      break; 
    case "4":
      day="TH";
      break; 
    case "5":
      day="FR";
      break;
    case "6":
      day="SA";
      break;
    case "7":
      day="SU";
      break;
  }
  ctx.fillText(day,startX+m-10, startY+20); 
  }
  //plot the points and draw lines between them
varstartAngle =   0 * (Math.PI/180);
varendAngle   = 360 * (Math.PI/180);
varnewValues;   
for(vari=0,m=0;i<data.length;i++,m+=60)
  {
  ctx.beginPath();

  var values=data[i].split(",");
  varxPos=startX+parseInt(values[0])+m;
  varyPos=chartHeight-parseInt(values[1]); 
  ctx.arc(xPos, yPos, 5, startAngle,endAngle, false); 
  ctx.fillStyle="red";
  ctx.fill();
  ctx.fillStyle="blue";
  ctx.fillText(values[1],xPos, yPos);
  ctx.stroke();
  ctx.closePath();
  if(i>0){
    ctx.strokeStyle="green";
    ctx.lineWidth=1.5;
    ctx.moveTo(oldxPos,oldyPos);
    ctx.lineTo(xPos,yPos); 
    ctx.stroke();     
  }
  oldxPos=xPos;
  oldyPos=yPos;
}   
}
functiondrawLine(ctx, startx, starty, endx, endy) {
ctx.beginPath(); 
ctx.moveTo(startx, starty);
ctx.lineTo(endx, endy);
ctx.closePath();
ctx.stroke();
}

How it works...

All the graphs in the subsequent recipes also work on an array named data. The array element has two parts: one indicates the day and the second indicates the usage in minutes. A split function down the code splits the element into two independent elements.

The coordinates are calculated using a parameter named m, which is used in calculating the value of the x coordinate. The value in minutes and the chart height is used to calculate the position of y coordinate.

Inside the loop, there are two coordinates, which are used to draw a line. One in the moveTo() method and the other in the lineTo() method. However, the coordinates oldxPos and oldyPos are not calculated in the first iteration, for the simple reason that we cannot draw a line with a single coordinate. Next iteration onwards, we have two coordinates and then the line is drawn between the prior and current coordinates.

There is more...

Use your own data

Drawing a bar graph

Another typical representation, which is widely used, is the bar graph. Here is an output of this recipe:

How to do it…

The HTML code is as follows:

<html>
<head>
  <title>A simple Bar chart</title>
  <script src="bargraph.js"></script>
</head>
<body onload=init()>
  <h1>Your WhatsApp Usage</h1>
  <canvas width="600" height="500" id="MyCanvasArea" style="border:2px solid blue;" tabindex="0">
    Canvas tag is not supported by your browser
  </canvas>
</body>
</html>

The JavaScript code is as follows:

functioninit(){
  vargCanvas = document.getElementById('MyCanvasArea');
  // Ensure that the element is available within the DOM
  varctx = gCanvas.getContext('2d');
  // Bar chart data
  var data = new Array(7);
  data[0] = "MON,130";    data[1] = "TUE,140";    data[2] = "WED,150";
  data[3] = "THU,140";    data[4] = "FRI,170";  data[5] = "SAT,250";
  data[6] = "SUN,340";
 
  // Draw the bar chart
  drawBarChart(ctx, data, 70, 100, (gCanvas.height - 40), 50);
}
functiondrawBarChart(ctx, data, startX, barWidth, chartHeight, markDataIncrementsIn) {
  // Draw the x and y axes
ctx.lineWidth = "3.0";
varstartY = chartHeight;
  //drawLine(ctx, startX, startY, startX, 30);
drawBarGraph(ctx, startX, startY, startX, 30,data,chartHeight);  
drawLine(ctx, startX, startY, 570, startY);     
}

functiondrawLine(ctx, startx, starty, endx, endy) {
ctx.beginPath();
ctx.moveTo(startx, starty);
ctx.lineTo(endx, endy);
ctx.closePath();
ctx.stroke();
}

functiondrawBarGraph(ctx, startx, starty, endx, endy,data,chartHeight) { 
ctx.beginPath();
ctx.moveTo(startx, starty);
ctx.lineTo(endx, endy);
ctx.closePath();
ctx.stroke();
var max=0; 
  //code to label x-axis
for(i=0;i<data.length;i++)
  {
  varxValues=data[i].split(","); 
  varxName=xValues[0];
  ctx.textAlign="left";
  ctx.fillStyle="#b90000";
  ctx.font="bold 15px Arial";
  ctx.fillText(xName,startx+i*50+i*20,chartHeight+15,200); 
  var height=parseInt(xValues[1]);
  if(parseInt(height)>parseInt(max))
    max=height;
  varcolor='#'+Math.floor(Math.random()*16777215).toString(16);
  drawBar(ctx,startx+i*50+i*20,(chartHeight-height),height,50,color);
  ctx.fillText(Math.round(height/60)+" hrs",startx+i*50+i*20,(chartHeight-height-20),200);
  } 
  //title the x-axis 
ctx.beginPath();
ctx.fillStyle="black";
ctx.font="bolder 20pt Arial";   
ctx.fillText("<------------Weekdays------------>",startx+150,chartHeight+35,200); 
ctx.closePath();     

  //y-axis labelling  
varylabels=Math.ceil(max/60);
varyvalue=0;
ctx.font="bold 15pt Arial";
for(i=0;i<=ylabels;i++)
  {
  ctx.textAlign="right";
  ctx.fillText(yvalue,startx-5,(chartHeight-yvalue),50);
  yvalue+=60;
  } 
  //title the y-axis
ctx.beginPath();
ctx.font = 'bolder 20pt Arial';
ctx.save();
ctx.translate(20,70);
ctx.rotate(-0.5*Math.PI);
varrText = 'Rotated Text';
ctx.fillText("<--------Time in minutes--------->" , 0, 0);
ctx.closePath();
ctx.restore();

}
functiondrawBar(ctx,xPos,yPos,height,width,color){
  ctx.beginPath();
  ctx.fillStyle=color;
  ctx.rect(xPos,yPos,width,height);   
  ctx.closePath();
  ctx.stroke();
  ctx.fill();
}

How it works...

The processing is similar to that of a line graph, except that here there are rectangles drawn, which represent bars. Also, the number 1, 2, 3… are represented as day of the week (for example, 1 means Monday).

This line in the code:

varcolor='#'+Math.floor(Math.random()*16777215).toString(16);

is used to generate random colors for the bars. The number 16777215 is a decimal value for #FFFFF.

Note that the value of the control variable i is not directly used for drawing the bar. Rather i is manipulated to get the correct coordinates on the canvas and then the bar is drawn using the drawBar() function.

drawBar(ctx,startx+i*50+i*20,(chartHeight-height),height,50,color);

There is more...

Use your own data and change the colors.

Drawing a pie chart

A share can be easily represented in form of a pie chart. This recipe demonstrates a pie chart:

How to do it…

The HTML code is as follows:

<html>
<head>
  <title>A simple Pie chart</title>
  <script src="piechart.js"></script>
</head>
<body onload=init()>
  <h1>Your WhatsApp Usage</h1>
  <canvas width="600" height="500" id="MyCanvasArea" style="border:2px solid blue;" tabindex="0">
    Canvas tag is not supported by your browser
  </canvas>
</body>
</html>

The JavaScript code is as follows:

functioninit()
{
  var can = document.getElementById('MyCanvasArea');
  varctx = can.getContext('2d');
  var data = [130,140,150,140,170,250,340];
  varcolors = ["crimson", "blue", "yellow", "navy", "aqua", "purple","red"];
  var names=["MON","TUE","WED","THU","FRI","SAT","SUN"];
  varcenterX=can.width/2;
  varcenterY=can.height/2;
  //varcenter = [can.width/2,can.height / 2];
  var radius = (Math.min(can.width,can.height) / 2)-50;
  varstartAngle=0, total=0;
  for(vari in data) {
    total += data[i];
  }
  varincrFactor=-(centerX-centerX/2);
  var angle=0;
  for (vari = 0; i<data.length; i++){
    ctx.fillStyle = colors[i];
    ctx.beginPath();
    ctx.moveTo(centerX,centerY);    ctx.arc(centerX,centerY,radius,startAngle,startAngle+(Math.PI*2*(data[i]/total)),false);
    ctx.lineTo(centerX,centerY); 
    ctx.rect(centerX+incrFactor,20,20,10);
    ctx.fill();
    ctx.fillStyle="black";
    ctx.font="bold 10pt Arial";
    ctx.fillText(names[i],centerX+incrFactor,15);
    ctx.save();
    ctx.translate(centerX,centerY);
    ctx.rotate(startAngle);
    var dx=Math.floor(can.width*0.5)-100;
    vardy=Math.floor(can.height*0.20);
    ctx.fillText(names[i],dx,dy);
    ctx.restore();
    startAngle += Math.PI*2*(data[i]/total);
    incrFactor+=50; 
  }
}

How it works...

Again the data here is the same, but instead of bars, we use arcs here. The trick is done by changing the end angle as per the data available. Translation and rotation helps in naming the weekdays for the pie chart.

There is more...

Use your own data and change the colors to get acquainted.

Summary

Managers make decisions based on the data representations. The data is usually represented in a report form and in the form of graph or charts. The latter representation plays a major role in providing a quick review of the data.

In this article, we represent dummy data in the form of graphs and chart.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Canvas Cookbook

Explore Title