Canvas JavaScript

Graphing a Uniform Distribution

This JavaScript program demonstrates how to generate and graph a uniform distribution. The uniform distribution is generated in the range [0,1].

GraphingAUniformDistribution.html

<!DOCTYPE html>
<html>
  <head>
    <title>XoaX.net's Javascript</title>
    <script type="text/javascript" src="GraphingAUniformDistribution.js"></script>
  </head>
  <body onload="Initialize()">
  	<div style="width:858px;height:430px;">
    	<canvas id="idCanvas" width="800" height ="400" style="background-color: #F0F0F0;float:left;"></canvas>
			<div style="width:58px;height:400px;float:right;">
				<input id="idHighY" type="text" size="9" style="width:50px;height:16px;"/>
				<div style="width:58px;height:356px;"></div>
				<input id="idLowY" type="text" size="9" style="width:50px;height:16px;"/>
			</div>
			<div style="width:800px;height:22px;float:left;">
				<input id="idLowX" type="text" size="9" style="width:50px;height:16px;float:left;"/>
    		<div style="width:684px;height:22px;float:left;"></div>
    		<input id="idHighX" type="text" size="1" value="1.2" style="width:50px;height:16px;float:left;"/> 		
    	</div>
		</div>
  </body>
</html>

GraphingAUniformDistribution.js

class CUniformDistribution {
	#mdaX;
	#mdGraphWidth = 1.2;
	constructor(iCount) {
		// This generates a sorted array of the sample values of the distribution
		// This is a uniform distribution from 0 to 1
		this.#mdaX = new Array(iCount);
		for (let i = 0; i < iCount; ++i) {
			this.#mdaX[i] = Math.random();
			// Insertion sort each point after it is added
			let j = i;
			while (j > 0 && this.#mdaX[j] < this.#mdaX[j - 1]) {
				let dSwap = this.#mdaX[j];
				this.#mdaX[j] = this.#mdaX[j - 1];
				this.#mdaX[j - 1] = dSwap;
				--j;
			}
		}
	}
	Mean() {
		let dMean = 0;
		for (let i = 0; i < this.#mdaX.length; ++i) {
			dMean += this.#mdaX[i]/this.#mdaX.length;
		}
		return dMean;
	}
	StandardDeviation() {
		return Math.sqrt(this.Variance());
	}
	Variance() {
		let dMean = this.Mean();
		let dVariance = 0;
		for (let i = 0; i < this.#mdaX.length; ++i) {
			dVariance += Math.pow(this.#mdaX[i] - dMean, 2)/this.#mdaX.length;
		}
		return dVariance;
	}
	PixelXToGraphX(dPixelX, iCanvasWidth) {
		// Half the size should map to the mean
		let dHalfWidth = this.#mdGraphWidth/2;
		let dMean = this.Mean();
		let dT = ((dPixelX + .5)/iCanvasWidth)*this.#mdGraphWidth - dHalfWidth + dMean;
		return dT;
	}
	Graph(qContext, dBarWidthInPixels) {
		qContext.fillStyle = "#606060";
		// Outline properties
		qContext.strokeStyle = "#F0F0F0";
		qContext.lineWidth = "1";
		// This is the basic transformation to flip the y-axis
		qContext.transform(1, 0, 0, -1, 0, qContext.canvas.height);
		// The canvas width and height in pixels or pixels per canvas
		let iW = qContext.canvas.width;
		let iH = qContext.canvas.height;
		// The canvas graph width: 1.2
		let dGraphW = this.#mdGraphWidth;
		// Pixel width in graph units = graph width / pixels per canvas width
		let dPixW = dGraphW/iW;
		// Bar width in pixels / pixels per canvas width
		let dBarsPerWidth = iW/dBarWidthInPixels;
		// The width of a bar in values
		let dBarWidth = dBarWidthInPixels*dPixW;
		// The middle bar is centered on zero
		// Find the start of the first bar and continue from there until all of them are drawn
		let dStartOfFirstBarPix = iW/2 - dBarWidthInPixels/2 - dBarWidthInPixels*Math.ceil(dBarsPerWidth/2);
		let dStartOfCurrBarPix = dStartOfFirstBarPix;
		let dStartOfCurrBarValue = this.PixelXToGraphX(dStartOfCurrBarPix, iW);
		let iIndexOfNextPoint = 0;
		// Get to the first point that is in the range of the first bar.
		while (iIndexOfNextPoint < this.#mdaX.length && dStartOfCurrBarValue > this.#mdaX[iIndexOfNextPoint]) {
			++iIndexOfNextPoint;
		}
		let iaBins = new Array();
		while (iIndexOfNextPoint < this.#mdaX.length && dStartOfCurrBarPix < iW) {
			let dEndOfCurrBarPix = dStartOfCurrBarPix + dBarWidthInPixels;
			let dEndOfCurrBarValue = this.PixelXToGraphX(dEndOfCurrBarPix, iW);
			let iIndexOfEnd = iIndexOfNextPoint;
			while (iIndexOfEnd < this.#mdaX.length && dEndOfCurrBarValue > this.#mdaX[iIndexOfEnd]) {
				++iIndexOfEnd;
			}
			// The number of points in the bin
			iaBins.push(iIndexOfEnd - iIndexOfNextPoint);
			// The increment for the bar
			dStartOfCurrBarPix = dEndOfCurrBarPix;
			// Increment for the points
			iIndexOfNextPoint = iIndexOfEnd;
		}
		// Get the size of the largest bin
		let iLargestBinSize = 0;
		for (let i = 0; i < iaBins.length; ++i) {
			if (iLargestBinSize < iaBins[i]) {
				iLargestBinSize = iaBins[i];
			}
		}
		// Make the height of the graph 20% higher than the largest bin size.
		let dMaxY = iLargestBinSize*1.2;
		let iBinIndex = 0;
		dStartOfCurrBarPix = dStartOfFirstBarPix;
		// Draw the bars of the graph
		while (iBinIndex < iaBins.length && dStartOfCurrBarPix < iW) {
			let dEndOfCurrBarPix = dStartOfCurrBarPix + dBarWidthInPixels;
			let dRectHeight = iaBins[iBinIndex];
			qContext.fillRect(dStartOfCurrBarPix, 0, dBarWidthInPixels, (dRectHeight/dMaxY)*iH);
			// Draw the half pixel width outline in the background color to frame the bars
			qContext.strokeRect(dStartOfCurrBarPix, 0, dBarWidthInPixels, (dRectHeight/dMaxY)*iH);
			// The increment for the bar
			dStartOfCurrBarPix = dEndOfCurrBarPix;
			++iBinIndex;
		}
		// Fill in the bounds
		let qLowYElement = document.getElementById("idLowY");
		qLowYElement.value = 0;
		let qHighYElement = document.getElementById("idHighY");
		qHighYElement.value = dMaxY.toFixed(1);
		let qLowXElement = document.getElementById("idLowX");
		qLowXElement.value = this.PixelXToGraphX(-.5, iW).toFixed(3);
		let qHighXElement = document.getElementById("idHighX");
		qHighXElement.value = this.PixelXToGraphX(iW-.5, iW).toFixed(3);
	}
}


function Initialize() {
	var qCanvas = document.getElementById("idCanvas");
	var qContext = qCanvas.getContext("2d");
	var qDist = new CUniformDistribution(10000);
	qDist.Graph(qContext, 5);
}

 

Output

 
 

© 2007–2025 XoaX.net LLC. All rights reserved.