Radu Angelescu

Dec 14, 2015

Differential Evolution Visualization

See the Differential Evolution process of getting the coefficients of our quartic polynomial right!

See code :).

The visualization code is not much, it’s actually basic d3js line graph plotting, with quadratic transitions between the sequential generations. If you have trouble understanding the d3js part I recommend you watch this tutorial and read these ones Also this code helped me alot

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
var SIZE_X = 712;
var SIZE_Y = 712;
var myWorker = null;
// define dimensions of graph
var m = [80, 80, 80, 80]; // margins
var w = SIZE_X - m[1] - m[3]; // width
var h = SIZE_Y - m[0] - m[2]; // height
var svg = null;
var dataset = null;
var frameNumber = 0;


function render(data)
{
  dataset = data;

  // create the scale functors that map the data domain to the pixel domain
  var scaleX = d3.scale.linear().domain(d3.extent(data, function(d) { return d.x; })).range([0,w]);
  var scaleY = d3.scale.linear().domain(d3.extent(data, function(d) { return d.y; })).range([h,0]);

  // create a line function that can convert data[] into x and y points
  var lineFunction = d3.svg.line().x(function(d) {return scaleX(d.x);})
                                  .y(function(d) {return scaleY(d.y);})
  // create x axis
  var xAxis = d3.svg.axis().scale(scaleX).tickSize(-h).tickSubdivide(true);

  // add it and make it transparent so it does not interfere with the actual info
    svg.append("svg:g")
              .attr("class", "x axis")
                  .attr("transform", "translate(0," + h + ")")
            .style("stroke-opacity", 0.2)
                  .call(xAxis);

  // create y axis
  var yAxisLeft = d3.svg.axis().scale(scaleY).ticks(4).orient("left");
  // add the y-axis to the left
  svg.append("svg:g")
            .attr("class", "y axis")
            .attr("transform", "translate(-25,0)")
            .call(yAxisLeft);

  //add the title text element that will display the current generation
  textTitle = svg.append('svg:text');
  textTitle.attr("x", (w / 2))
           .attr("y",  -60)
           .attr("text-anchor", "middle")
           .style("font-size", "20px")
           .text("Generation "+frameNumber);

  //add the "best candidate so far" text
  textDetails = svg.append('svg:text');
  textDetails.attr("x", (w / 2))
             .attr("y",  -30)
             .attr("text-anchor", "middle")
             .style("font-size", "12px")
             .text("Generation "+frameNumber);

  //create the reference path (we load it from our data)
  path = svg.append('svg:path');
  path.attr('d',lineFunction(dataset))
      .style('stroke-width', 2)
      .style('stroke', 'steelblue');

  //create the evolution path (will be updated)
  pathEvolution = svg.append("path");
 // we check browser support for web workers
  if(typeof(Worker) !== "undefined")
  {
    //we create the web worker because the algorithm is intensive and we don't want it to block our interface
     myWorker = new Worker("diffevolution.js");
     function updateDiffEvo()
     {
       //keep track of the current generation
       frameNumber = frameNumber + 1;
       //posting the message advances the algorithm
       myWorker.postMessage(dataset);
     }
     //we do a generation every half a second
     setInterval(updateDiffEvo, 500);

     myWorker.onmessage = function(event)
     {
       // we received an end message
       if(event.data.graphdata == null)
       {
         myWorker.terminate();
         return;
       }

       textTitle.text("Generation "+frameNumber);
       textDetails.text( "BestFit: "
                    +event.data.bestCandidate[0].toFixed(4) + " \n"
                    +event.data.bestCandidate[1].toFixed(4) + " \n"
                    +event.data.bestCandidate[2].toFixed(4) + " \n"
                    +event.data.bestCandidate[3].toFixed(4) + " \n"
                    +event.data.bestCandidate[4].toFixed(4) + " \n"
                  +" Error: "+event.data.bestFitness.toFixed(2));

      pathEvolution.transition()
                   .attr("class", "line")
                   .style("stroke", "red")
                   .duration(500)
                   .ease("quad")
                   .attr("d", lineFunction(event.data.graphdata));
      };
   }
   else
   {
    // we don't support browsers that don't have web workers  :( )
    alert("Sorry no webworker support for your browser, the example will not work:( ")
   }
   // end of render function
}


// converts string data from the csv object entry to numeric values
function type(d)
{
  d.x = +d.x;
  d.y = +d.y;
  return d;
}

//load the reference function data from a csv file
function loadDataFromCSV(filename)
{
    data = d3.csv(filename,type,render);
}

// Reset the svg element
function resetSVGElement()
{
  var div = document.getElementById('d3-chartid');
  div.innerHTML = "";

}

function generateSVGElement()
{
  svg = d3.select(".d3-chart").append("svg")
                              .attr("width",SIZE_X)
                              .attr("height", SIZE_Y)
                              .append("svg:g")
                              .attr("transform", "translate(" + m[3] + "," + m[0] + ")");
}

//Function used to switch data inputs based on listbox selection
function onListElementClick(data,domid)
{
  // clear selection
  var oldSelectedListElements = document.getElementsByClassName("selectedul");
  for (i = 0; i < oldSelectedListElements.length; i++)
  {
    oldSelectedListElements[i].className ="";
  }

  listElement = document.getElementById(domid);
  listElement.className  = "selectedul";

  if(myWorker != null)
  {
//Clear the "screen" :)
    resetSVGElement();
//Regenerate the graph
    generateSVGElement()

//Terminate the current worker
    myWorker.terminate();
    myWorker = undefined;
//Clear dataset
    dataset  = null;
//Reset generation counter
    frameNumber = 0;
  }
//Load the data using the hash as a filename
  loadDataFromCSV(data);
}
//The initialization function
function visInit()
{
//Create the main graph element
  generateSVGElement();
//Start with the first element in the list
  onListElementClick('data/sin.csv','lst0');

};
// add the initialization function on the dom content loaded event
document.addEventListener("DOMContentLoaded",visInit);

Back to visualization

If you want to see about the differential evolution code you should go here

You can find the full source code on my github or “view source” :D.

· This is not your average Footer