Fe Curve

Fractional solubility of aerosol iron .charts { width: 100%; display: block; clear: both; overflow: hidden; } .hidden { opacity: 0; } .sliders { text-align: center; } circle { fill: rgba(51, 102, 204, 0.2) !important; r: 4 !important; }
FeT =
DFe =
//##################################################### //### For plots //##################################################### //Increase this if graph resolution is too low var numPoints = 1000; //The bounds for the values on the sliders var feMin = 0; var feMax = 500; var feDefault = 100; var solMin = 0; var solMax = 10; var solDefault = 3; function ratio(fn, sol) { return sol / fn; } //##################################################### // Some google plot options //##################################################### // hAxis.title and vAxis.title can now use and tags // to respectively designate superscript and subscript text in the // labels. Note, this is actually not supported by the google // visualization API, so we had to do some hacks to get there. var scatterOptions = { hAxis: { title: ‘FeT‘ }, vAxis: { title: ‘DFe’ }, legend: { position: ‘none’ }, seriesType: ‘scatter’ }; var ratioOptions = { hAxis: { title: ‘FeT‘ }, vAxis: { title: ‘%DFe’, viewWindowMode: ‘explicit’, viewWindow: { max: 100, min: 0 } }, legend: { position: ‘none’ }, seriesType: ‘scatter’ }; var logOptions = { hAxis: { title: ‘LogFeT‘, viewWindowMode: ‘explicit’, viewWindow: { max: 2, min: 0 } }, vAxis: { title: ‘Log%DFe’, }, legend: { position: ‘none’ }, seriesType: ‘scatter’, series: { 1: { type: “line” } } }; //##################################################### // Everything below this shouldn’t // need to be changed unless you // need different functionality //##################################################### //Used for processing – shouldn’t have to change var sliderMin = 0; var sliderMax = 1000; var variableInformation = { sol: { min: solMin, max: solMax, default: solDefault }, fe: { min: feMin, max: feMax, default: feDefault } }; init(); function init() { bindInputs(“fe”); bindInputs(“sol”); google.charts.load(‘current’, { packages: [‘corechart’, ‘line’, ‘scatter’] }); google.charts.setOnLoadCallback(initializeCharts); } function initializeCharts() { var feMax = Number(document.getElementById(“fe-value”).value); var solMax = Number(document.getElementById(“sol-value”).value); if (feMax == NaN || solMax == NaN) { alert(“Error”); return; } var rawData = generateScatterData(feMax, solMax); var scatterData = createChartData(rawData); renderData(“scatter”, scatterData, scatterOptions); var ratioData = createChartData(generateRatioData(rawData)); renderData(“ratio”, ratioData, ratioOptions); var logData = createDoubleChartData(generateLogData(rawData)); renderData(“log”, logData, logOptions); } function createChartData(rawDataPoints) { var data = new google.visualization.DataTable(); data.addColumn(‘number’, ‘Scatter Col 1’); data.addColumn(‘number’, ‘Scatter Col 2’); data.addRows(rawDataPoints); return data; } function createDoubleChartData(rawDataPoints) { var data = new google.visualization.DataTable(); data.addColumn(‘number’, ‘Scatter Col 1’); data.addColumn(‘number’, ‘Scatter Col 2’); data.addColumn(‘number’, ‘Scatter Col 3’); data.addRows(rawDataPoints); return data; } function renderData(prefix, data, options) { var renderElem = document.getElementById(prefix + ‘-chart’); var chart = new google.visualization.ComboChart(renderElem); options = JSON.parse(JSON.stringify(options)); var titleMap = { hLabel: { guid: guid(), label: options.hAxis.title }, vLabel: { guid: guid(), label: options.vAxis.title } }; options.hAxis.title = titleMap.hLabel.guid; options.vAxis.title = titleMap.vLabel.guid; function fixMarkup(labelText){ var result = labelText .replace(/(.*?)/, “$1”) .replace(/(.*?)/, “$1”); return result; } function fixLabels(guid, labelSvg) { var htmlCollection = renderElem.getElementsByTagName(“text”); var texts = [].slice.call(htmlCollection); var label = texts.filter(function(txt) { return txt.innerHTML == guid; })[0]; label.innerHTML = fixMarkup(labelSvg); } renderElem.className += “hidden” chart.draw(data, options); setTimeout(function(){ fixLabels(titleMap.hLabel.guid, titleMap.hLabel.label); fixLabels(titleMap.vLabel.guid, titleMap.vLabel.label); renderElem.className = “”; }); } function generateScatterData(feMax, solMax) { var data = []; for (var i = 0; i < numPoints; i++) { data.push([ random(feMin, feMax), random(solMin, solMax) ]); } return data; } function generateRatioData(rawData) { var data = []; for (var i = 0; i < rawData.length; i++) { var fe = rawData[i][0]; var sol = rawData[i][1]; data.push([fe, 100 * sol / fe]); } return data; } function generateLogData(rawData) { var data = generateRatioData(rawData); for (var i = 0; i < data.length; i++) { data[i][0] = Math.log10(data[i][0]); data[i][1] = Math.log10(data[i][1]); data[i][2] = null; } var fit = fitData(data); var note = document.getElementById("fit-note"); note.innerHTML = "y = " + fit.slope.toFixed(2) + "x + " + fit.intercept.toFixed(2) + " ; R2 = ” + fit.rSquared.toFixed(2); var allXs = data.map(function(pt) { return pt[0]; }); var minX = Math.min(…allXs); var maxX = Math.max(…allXs); data.push([minX, null, fit.intercept + fit.slope * minX]); data.push([maxX, null, fit.intercept + fit.slope * maxX]); return data; } function random(min, max) { return min + Math.random() * (max – min); } function bindInputs(prefix) { var slider = document.getElementById(prefix + “-slider”); var valueElem = document.getElementById(prefix + “-value”); var defaultVal = variableInformation[prefix].default; var varMin = variableInformation[prefix].min; var varMax = variableInformation[prefix].max; setSliderValue(defaultVal); valueElem.value = defaultVal; slider.oninput = function() { var rawSliderVal = slider.value; var sliderPercent = rawSliderVal / (sliderMax – sliderMin); var actualValue = varMin + sliderPercent * (varMax – varMin); valueElem.value = actualValue; initializeCharts(); } valueElem.onchange = function() { var y = Number(valueElem.value); if (y != NaN) { if (y > varMax) { y = varMax; } if (y < varMin) { y = varMin; } } valueElem.value = y; setSliderValue(y); initializeCharts(); } function setSliderValue(y) { var percent = (y – varMin) / (varMax – varMin); slider.value = sliderMin + percent * (sliderMax – sliderMin); } } //Courtesy of https://stackoverflow.com/questions/50257760/regression-that-fits-best-scatter-plot function fitData(points) { var rV = {}, N = points.length, sumX = 0, sumY = 0, sumXx = 0, sumYy = 0, sumXy = 0; // can't fit with 0 or 1 point if (N < 2) { return rV; } for (var i = 0; i < N; i++) { var x = points[i][0], y = points[i][1]; sumX += x; sumY += y; sumXx += (x * x); sumYy += (y * y); sumXy += (x * y); } // calc slope and intercept rV['slope'] = ((N * sumXy) – (sumX * sumY)) / (N * sumXx – (sumX * sumX)); rV['intercept'] = (sumY – rV['slope'] * sumX) / N; rV['rSquared'] = Math.abs((rV['slope'] * (sumXy – (sumX * sumY) / N)) / (sumYy – ((sumY * sumY) / N))); return rV; } function guid() { function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); } return s4() + s4(); }