When plotting anything on most 2D graphs (not including pie charts), one needs x-y coordinate pairs. This is even true in bar graphs and histograms (although generally the programs used to plot these other graph types will automatically generate the x-axis data). In JavaScript, the easiest way to store such data is in arrays. A one-dimensional JavaScript array can be likened to a list. It can be a list of numbers:
var myArray = [1,2,3,4,5];
or
var myArray = [1,5,23,43,2,7];
or even
var myArray = [,,,2,3,4];
Where in the last case, the first three elements of the array are undefined. Arrays can also be lists of other things such as strings (representing characters or words):
var myArray = ['Bob','Chris','a','b','c'];
In fact, arrays can be lists of other arrays:
var arr1 = [1,2,3]; var arr2 = [4,5,6]; var arr3 = ['a,'b','c','d']; var myArray = [arr1,arr2,arr3];
Notice in the last case that the outer array (myArray) contains the other previously defined arrays. Also notice that not all arrays contain the same sort of thing. The first two inner arrays contain numbers, while the last one contains strings (in this case letters). Notice also, that the inner arrays are not all of the same length. This is allowable in JavaScript, and once you get used to it, it brings a great deal of flexibility to the table. In this last example, the array, myArray, could also be written like this:
var myArray = [ [1,2,3], [4,5,6], ['a','b','c','d'] ];
or for clarity:
var myArray = [ [1,2,3], [4,5,6], ['a','b','c','d'] ];
although this latter form takes up more space. To see how to access an element of this array, we could type into the Web Console:
>> myArray = [ [1,2,3], [4,5,6], ['a','b','c','d'] ];
which would return:
>> [objectArray]
Clicking on [objectArray] in the console results in the following:
At the right hand side, the contents of the [objectArray] are shown. You can see that it consists of three inner (or sub) arrays and that its length is three. The indices of the sub arrays are shown at the left as 0, 1, and 2. If we click on the third item in the array (index of 2), we see the following:
which exposes the content of the third inner array. Let's say that we wish to access the content of the first inner array (index 0) from command line, we could type:
myArray[0]
Which would result in another [object Array]. If we wished to access the first element of this array, we would type:
myArray[0][0]
And in this case, since it is just a number, we would see its value (1) returned above in the console.
In general, in the future, we will use the language "zeroeth element" to refer to index 0 of an array, "first element" to refer to index 1 of an array and so on. This is in keeping with JavaScript's convention to start indexing arrays at zero rather than one.
After this rather lengthy preamble, we are ready to discuss fitting a line to the data from before. The previous script was as follows:
var R = 0.02275; // m var Ncoils = 100; // Number of coils var Ntrials = 6; // Number of trials // (presume we sample resistance every 100 coils) var pi = Math.PI; // Use pi as a short hand for the JavaScript constant Math.PI var L = new Array(); // Define the array. It's empty now. for (var i=0; i< Ntrials; i++) { var Ntot = (i+1)*Ncoils; // Total number of coils this sample. L[i] = 2*pi*R*Ntot; // This is the ith value of length in the array } resist = [0.6,1.1,1.6,2.1,2.7,3.5]; // Ohms // Graphics commands optsGraphTitles[0].name = 'Length (m)'; // x-axis title optsGraphTitles[1].name = 'Resistance (\\Omega )'; // y-axis title optsGraphTitles[2].name = 'Resistance vs Length'; // main title optsGraphTitles[3].name = 'for a coil of wire'; // sub title optsLegend = false; drawSeriesPlot([L],[resist], 0,0, 'resistivityPlot.svg');
The idea is that we would be fitting a line to the x-y data represented by the array L and resist respectively. The big picture for physics students is that we are trying to determine the resistivity of the wire based on measurements of electrical resistance at given lengths, and knowledge of the wire's cross-sectional area (in this case: A = 4.64e-7 m2). The governing equation here is:
R = ρ L/A
where ρ is the resistivity. So if y corresponds to R and x corresponds to L, then ρ/A is the slope.
For quick fits, we can use the JSvg function "doFit()" which returns, you guessed it, an array! The syntax of the command is:
fitObj = doFit(xvector, yvector, fitOrder, precisionOfoutput);
where xvector is the x-array, yvector is the y-array, fitOrder is 1 for linear, 2 for quadratic, 3 for cubic (and so on), and precisionOfoutput is the number of decimal places to show in the output. The function doFit returns an array that contains the following:
fitObj[0] = 1D array containing the predicted y values for each x data point fitObj[1] = equation of fit (t is default variable) (String) fitObj[2] = 1D array containing the coefficients of fit starting with highest order term
There is a lower level function called by doFit() named polyCor() which contains much of the statistical information about the fit, but that's for another post.
So to modify the code from the prior and get a fit, we need to call doFit() with the appropriate arguments, and then extract the information we wish to display. Finally, we need to put it on our graph.
var fitObj = doFit(L,resist,1,4);
We can then extract the objects we need and calculate the resistivity as follows:
// ********************* New code block *********************************** var fitObj = doFit(L,resist,1,4); var fitData = fitObj[0]; var fitEqu = fitObj[1]; var slope = fitObj[2][0]; var A = 4.64e-7; // m^2 var rho = slope*A; fitEqu = 'R = '+fitEqu.replace('t','L'); // ******************** End new code block ********************************
In the last equation, we have done some other formatting. By default the equation uses "t" as the x-variable. Let's replace it with "L", and then prepend "R = " on the front end to actually make it into an equation.
The only other item of substance is getting this information onto the graph. Recall that the function drawSeriesPlot() takes 2D arrays as its first two arguments. We recast this line as follows:
drawSeriesPlot([L,L],[resist,fitData], 0,0, 'resistivityPlot2.svg');
What we have done is added another 1D array to both the x and y arrays in order to graph a second series on the plot. Below is the final code with all the bells and whistles.
var R = 0.02275; // m var Ncoils = 100; // Number of coils var Ntrials = 6; // Number of trials // (presume we sample resistance every 100 coils) var pi = Math.PI; // Use pi as a short hand for the JavaScript constant Math.PI var L = new Array(); // Define the array. It's empty now. for (var i=0; i< Ntrials; i++) { var Ntot = (i+1)*Ncoils; // Total number of coils this sample. L[i] = 2*pi*R*Ntot; // This is the ith value of length in the array } var resist = [0.6,1.1,1.6,2.1,2.7,3.5]; // Ohms // ********************* New code block *********************************** var fitObj = doFit(L,resist,1,4); var fitData = fitObj[0]; var fitEqu = fitObj[1]; var slope = fitObj[2][0]; var A = 4.64e-7; // m^2 var rho = slope*A; fitEqu = 'R = '+fitEqu.replace('t','L'); // ******************** End new code block ******************************** // Graphics commands optsGraphTitles[0].name = 'Length (m)'; // x-axis title optsGraphTitles[1].name = 'Resistance (\\Omega )'; // y-axis title optsGraphTitles[2].name = 'Resistance vs Length'; // main title optsGraphTitles[3].name = '\\rho = '+rho.toExponential(3)+' \\Omega m; ' // sub title // optsLegend = false; // Old code optsLegend = true; // default optsSeries[0].name = 'Data' optsSeries[1].itype = 1; // make it a line optsSeries[1].name = fitEqu; // show the equation of fit xprec = 1; // Set the precision on the x axis // Old code //drawSeriesPlot([L],[resist], 0,0, 'resistivityPlot.svg'); // New code drawSeriesPlot([L,L],[resist,fitData], 0,0, 'resistivityPlot2.svg');
The resulting graph looks like this.
great
ReplyDelete