function plot(params) {
$("main.container").addClass("progress"); progress(params, plot); //Globals: var DATA;
// ################ // The rest defines the functions: // ################
// Gets data from form and validates. function progress(params, plot) { // Print an error
// Empty alert box and results box
$('#alert').html(""); $('#results').html(""); Message("Processing...");
// Getting all the data from the form. var data = params.data.value; var thousands_seperator = params.thousands_seperator.value; var thousands_checked = params.thousands_usage.checked; var value_seperator = params.value_seperator.value; var decimal_seperator = params.decimal_seperator.value;
Message("Validating format...");
// validation and manipulation if (thousands_checked) { if (thousands_seperator == value_seperator) { Warning("Your thousands seperator is the same as the value seperator."); } if (thousands_seperator == decimal_seperator) { Warning("Your thousands seperator is the same as the value seperator."); } data = data.replace(thousands_seperator, ); } if (value_seperator == decimal_seperator) { return Error("Your value seperator is the same as the decimal seperator."); } // turn value seperator into ',' and decimal seperator into '.', and preventing those to be mixed up. if (data.indexOf('¬') === -1) { data = data.replace(value_seperator, '¬').replace(decimal_seperator, '.').replace('¬', ','); } else { return Error("¬ cannot be used as delimiter."); }
data = data.replace("\"", "");
Message("Parsing..."); aa = numeric.parseCSV(data);
Message("Validating data...") if (aa.length > 2) { aa = numeric.transpose(aa); }
if (aa.length !== 2) { return Error("Enter data with 2 collumns or rows."); }
if (aa[0].length !== aa[1].length) { Warning("Your two collumns or rows are of different length. The longest one is trancutated to match the other."); var min = Math.min(a[0].length !== a[1].length); if (aa[0].length == min) { aa[1] = aa[1].slice(0, min); } else { aa[0] = aa[0].slice(0, min); } }
aa = numeric.transpose(aa); DATA = aa;
Message("Plotting..."); plot(aa, fit);
}
// Plots the data function plot(data, fit) { result("Your data has size " + data.length + "."); $.plot($("#placeholder"), [{ color: 'yellow', data: data }]); fit(data, plotfit); }
function fit(data, plotfit) { data = numeric.transpose(data); var t = data[0]; var N = data[1]; var initial = [N[0], N[N.length - 1], 1]; var objective = makeObjective(logistic, t, N); var minimiser = numeric.uncmin(objective, initial); result("Solution found after " + minimiser.iterations + " iterations."); result(minimiser.message); draw(minimiser.solution); var t = numeric.linspace(t[0], t[t.length - 1], t.length); var N = vectorize( setParamInFunc(minimiser.solution, logistic), t ); // var N = (func, x) - > { // var res = Array(x.length); // for (var i = 0; i < x.length; i++) { // res[i] = func(x[i]); // } // return res; // }((func, params) - > { // return (x) - > // return func(params, x); // }, t); var datafit = [t, N]; datafit = numeric.transpose(datafit); data = numeric.transpose(data); plotfit(datafit, data, callback); }
function plotfit(datafit, data, callback) { $.plot($("#placeholder"), [{ label: "fitted data", data: datafit, color: 'green' }, { label: "input data", data: data, color: 'yellow' }], { legend: { position: "nw" } }); callback(); }
// Tells user we are done. function callback() { $("main.container").removeClass("progress"); }
// ################ // The following functions are out of the callback work loop // ################
// Decorator for functions to perform vectorized function vectorize(func, x) { var res = new Array(x.length); testtest = func; for (var i = 0; i < x.length; i++) { res[i] = func(x[i]); } return res; }
// Decorator for functions to set params fixed function setParamInFunc(params, func) { function resFunc(x) { return func(params, x); } return resFunc; }
// Function to fit // N = logistic(params,t); function logistic(params, t) { var N0, K, r; [N0, K, r] = params; return (K * N0 * Math.exp(r * t)) / (K + N0 * (Math.exp(r * t) - 1)); }
// Least square objective // Build as factory with a decorator function makeObjective(targetFunc, x, y) { function objective(params) { var total = 0.0 for (var i = 0; i < y.length; i++) { var result = targetFunc(params, x[i]) var delta = result - y[i]; total += delta * delta; } return total; } return objective; }
function draw(params) { param_names = ["N0", "K", "r"]; for (var i = 0; i < param_names.length; i++) { result(param_names[i] + " is " + params[i]); } var latex = katex.renderToString("N(t) = \\frac{K \\cdot N_0 \\cdot e^{rt}}{K + N_0 \\cdot (e^{rt}-1)}"); console.log(latex); result("For the function:") resultHTML(latex); }
function result(e) { $("#results").append($("<p />", { class: "result", text: e })); }
function resultHTML(e) { $("#results").append($("<p />", { class: "result", html: e })); }
// Print an error (This function is usually returned.) function Error(e) { $("#alert").prepend($('<p />', { class: 'error', text: e })); $("main.container").removeClass("progress"); }
// Print a warming function Warning(e) { $("#alert").append($('<p />', { class: 'warning', text: e })); }
// Print a message function Message(e) { $("#alert").append($('<p />', { class: 'message', text: e })); }
}