Difference between revisions of "Team:TUDelft/js/plotfit"

Line 20: Line 20:
  
 
         // Getting all the data from the form.
 
         // Getting all the data from the form.
         var data = params.data.value;
+
         var data = params.data.value.trim();
 
         var thousands_seperator = params.thousands_seperator.value;
 
         var thousands_seperator = params.thousands_seperator.value;
 
         var thousands_checked = params.thousands_usage.checked;
 
         var thousands_checked = params.thousands_usage.checked;
Line 54: Line 54:
  
 
         Message("Validating data...")
 
         Message("Validating data...")
 +
        aa[0] = aa[0].filter(Boolean);
 +
        aa[1] = aa[1].filter(Boolean);
 +
        console.log(aa);
 
         if (aa.length > 2) {
 
         if (aa.length > 2) {
 
             aa = numeric.transpose(aa);
 
             aa = numeric.transpose(aa);
Line 64: Line 67:
 
         if (aa[0].length !== aa[1].length) {
 
         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.");
 
             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);
+
             var min = Math.min(aa[0].length !== aa[1].length);
 
             if (aa[0].length == min) {
 
             if (aa[0].length == min) {
 
                 aa[1] = aa[1].slice(0, min);
 
                 aa[1] = aa[1].slice(0, min);
Line 94: Line 97:
 
         var t = data[0];
 
         var t = data[0];
 
         var N = data[1];
 
         var N = data[1];
         var initial = [N[0], N[N.length - 1], 1];
+
         var initial = [N[0], N[N.length - 1], 0.005];
 
         var objective = makeObjective(logistic, t, N);
 
         var objective = makeObjective(logistic, t, N);
         var minimiser = numeric.uncmin(objective, initial);
+
         console.log(t);
 +
        console.log(N);
 +
        try {
 +
            var minimiser = numeric.uncmin(objective, initial);
 +
        }
 +
        catch (err) {
 +
            return Error(err)
 +
        }
 
         result("Solution found after " + minimiser.iterations + " iterations.");
 
         result("Solution found after " + minimiser.iterations + " iterations.");
 
         result(minimiser.message);
 
         result(minimiser.message);
Line 170: Line 180:
 
         var N0, K, r;
 
         var N0, K, r;
 
     [N0, K, r] = params;
 
     [N0, K, r] = params;
         return (K * N0 * Math.exp(r * t)) / (K + N0 * (Math.exp(r * t) - 1));
+
         var ans = (K * N0 * Math.exp(r * t)) / (K + N0 * (Math.exp(r * t) - 1));
 +
        var below = (K + N0 * (Math.exp(r * t) - 1));
 +
        if (below === Infinity) {
 +
            ans = 0;
 +
        }
 +
        return ans;
 
     }
 
     }
  
Line 183: Line 198:
 
                 total += delta * delta;
 
                 total += delta * delta;
 
             }
 
             }
 +
            console.log(total);
 
             return total;
 
             return total;
 
         }
 
         }
Line 194: Line 210:
 
         }
 
         }
 
         var latex = katex.renderToString("N(t) = \\frac{K \\cdot N_0 \\cdot e^{rt}}{K + N_0 \\cdot (e^{rt}-1)}");
 
         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:")
 
         result("For the function:")
 
         resultHTML(latex);
 
         resultHTML(latex);

Revision as of 12:13, 11 August 2017

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.trim();
       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...")
       aa[0] = aa[0].filter(Boolean);
       aa[1] = aa[1].filter(Boolean);
       console.log(aa);
       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(aa[0].length !== aa[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], 0.005];
       var objective = makeObjective(logistic, t, N);
       console.log(t);
       console.log(N);
       try {
           var minimiser = numeric.uncmin(objective, initial);
       }
       catch (err) {
           return Error(err)
       }
       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;
       var ans = (K * N0 * Math.exp(r * t)) / (K + N0 * (Math.exp(r * t) - 1));
       var below = (K + N0 * (Math.exp(r * t) - 1));
       if (below === Infinity) {
           ans = 0;
       }
       return ans;
   }
   // 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;
           }
           console.log(total);
           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)}");
       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
       }));
   }

}