From 52c92c28707572a2adb958131eda573aa9f0ce2a Mon Sep 17 00:00:00 2001
From: Sebastien GOYON <shinedday@gmail.com>
Date: Wed, 3 Aug 2022 08:56:39 +0200
Subject: [PATCH] Last push

---
 ping/consumers.py             |   1 +
 ping/models.py                |  14 +++-
 ping/templates/ping/play.html | 130 ++++++++++++++++++++++------------
 ping/views/play.py            |  36 +++++++---
 ping/views/tool.py            |  11 ++-
 5 files changed, 128 insertions(+), 64 deletions(-)

diff --git a/ping/consumers.py b/ping/consumers.py
index 0e45079..add2989 100644
--- a/ping/consumers.py
+++ b/ping/consumers.py
@@ -3,6 +3,7 @@ from channels.generic.websocket import AsyncWebsocketConsumer
 
 import json
 
+
 class GraphConsumer(AsyncWebsocketConsumer):
     async def connect(self):
         self.room_name = 'event'
diff --git a/ping/models.py b/ping/models.py
index 174903d..3c99ce0 100644
--- a/ping/models.py
+++ b/ping/models.py
@@ -69,6 +69,12 @@ class CurrentExperiment(models.Model):
     com_fun = models.CharField(default="linear", max_length=64)
     com_refresh = models.PositiveIntegerField(default=1)
 
+    graph = models.BooleanField(default=False)
+    graph_height = models.PositiveIntegerField(default=1)
+    graph_width = models.PositiveIntegerField(default=1)
+    graph_refresh = models.PositiveIntegerField(default=1)
+
+
 
 class Network(models.Model):
     broker_ip = models.CharField(max_length=60)
@@ -98,4 +104,10 @@ class Canvas(models.Model):
 
     color = models.CharField(max_length=60)
 
-    cycle = models.PositiveIntegerField(default=0)
\ No newline at end of file
+    cycle = models.PositiveIntegerField(default=0)
+
+class GraphPoint(models.Model):
+
+    name = models.CharField(max_length=60)
+    cycle = models.PositiveIntegerField(default=0)
+    y = models.IntegerField(default=0)
\ No newline at end of file
diff --git a/ping/templates/ping/play.html b/ping/templates/ping/play.html
index f9f3e07..08d91f1 100644
--- a/ping/templates/ping/play.html
+++ b/ping/templates/ping/play.html
@@ -127,50 +127,6 @@ text {
   </script>
   {% endif %}
 
-
-  {% if canvas %}
-<canvas id="line-chart" width="800" height="450"></canvas>
-<script>
-
-chart_data = {
-    labels: ["t-9","t-8","t-7","t-6","t-5","t-4","t-3","t-2","t-1","t"],
-    datasets: [{
-        data: [0,0,0,0,0,0,0,0,0,0],
-        label: "Colored agents",
-        borderColor: "#3e95cd",
-        fill: false
-      }
-    ]
-  };
-
-const myChart = new Chart(document.getElementById("line-chart"), {
-  type: 'line',
-  data: chart_data,
-  options: {}
-});
-
-
-    const graphSocket = new WebSocket(
-      'ws://'
-      + window.location.host
-      + '/ws/graph/'
-    );
-
-    graphSocket.onmessage = function (e) {
-      const metrics = JSON.parse(e.data).message;
-      new_graph_data = chart_data.datasets[0].data;
-      new_graph_data.shift();
-      new_graph_data.push(metrics[0]);
-
-      chart_data.datasets[0].data = new_graph_data;
-
-      myChart.update();
-
-    };
-</script>
-  {% endif %}
-
-
   {% if com_graph %}
 <svg width="500" height="500" style="border:1px solid #000000;"></svg>
 <script>
@@ -224,8 +180,6 @@ const comSocket = new WebSocket(
 
 comSocket.onmessage = function (e) {
   graph = JSON.parse(e.data).message;
-  console.log(graph);
-  console.log(typeof graph);
 
   svg.selectAll("*").remove();
   link = svg.append("g").attr("class", "links").selectAll("line").data(graph.links).enter().append("line")
@@ -245,6 +199,90 @@ comSocket.onmessage = function (e) {
   {% endif %}
 
 
+<div id="my_dataviz"></div>
+<script>
+
+// set the dimensions and margins of the graph
+const margin = {top: 10, right: 30, bottom: 30, left: 60},
+    width =500 - margin.left - margin.right, //self.innerWidth - margin.left - margin.right,
+    height = 400 - margin.top - margin.bottom;
+
+var svg = d3.select("#my_dataviz")
+  .append("svg")
+    .attr("width", width + margin.left + margin.right)
+    .attr("height", height + margin.top + margin.bottom)
+  .append("g")
+    .attr("transform", `translate(${margin.left},${margin.top})`);
+
+const graphSocket = new WebSocket(
+  'ws://'
+  + window.location.host
+  + '/ws/graph/'
+);
+
+graphSocket.onmessage = function (e) {
+  data = JSON.parse(e.data).message;
+  console.log(data)
+  console.log(data[0])
+// group the data: I want to draw one line per group
+  const sumstat = d3.group(data, d => d.name); // nest function allows to group the calculation per level of a factor
+
+svg.selectAll("*").remove();
+
+  // Add X axis --> it is a date format
+  const x = d3.scaleLinear()
+    .domain(d3.extent(data, function(d) { return d.x; }))
+    .range([ 0, width ]);
+  svg.append("g")
+    .attr("transform", `translate(0, ${height})`)
+    .call(d3.axisBottom(x).ticks(5));
+
+  // Add Y axis
+  const y = d3.scaleLinear()
+    .domain([0, d3.max(data, function(d) { return +d.y; })])
+    .range([ height, 0 ]);
+  svg.append("g")
+    .call(d3.axisLeft(y));
+
+  // color palette
+  const color = d3.scaleOrdinal()
+    .range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33','#a65628','#f781bf','#999999'])
+
+  // Draw the line
+  svg.selectAll(".line")
+      .data(sumstat)
+      .join("path")
+        .attr("fill", "none")
+        .attr("stroke", function(d){ return color(d[0]) })
+        .attr("stroke-width", 1.5)
+        .attr("d", function(d){
+          return d3.line()
+            .x(function(d) { return x(d.x); })
+            .y(function(d) { return y(+d.y); })
+            (d[1])
+        })
+
+  var legendItemSize = 12;
+  var legendSpacing = 4;
+
+  var lineLegend = svg.selectAll(".lineLegend").data([...sumstat.keys()])
+    .enter().append("g")
+    .attr("class","lineLegend")
+    .attr("transform", function (d,i) {
+            return "translate(" + width + "," + (i*50)+")";
+        });
+
+lineLegend.append("text").text(function (d) {return d;})
+    .attr('x', legendItemSize + 3)
+   .attr('y', (d, i) => (legendItemSize + legendSpacing) * i + 10);
+
+lineLegend.append("rect")
+    .attr("fill", function (d, i) {return color(d); })
+    .attr("width", 10).attr("height", 10);
+
+  };
+</script>
+
 </body>
 
 </html>
\ No newline at end of file
diff --git a/ping/views/play.py b/ping/views/play.py
index cddfaaa..99ecc1c 100644
--- a/ping/views/play.py
+++ b/ping/views/play.py
@@ -17,7 +17,7 @@ from iotAmak.tool.ssh_client import Cmd
 from paho.mqtt.client import Client as MQTTClient
 
 from .tool import delete_folder, get_ssh_client, canvas_event_triger, graph_event_triger, com_event_triger
-from ..models import Experiment, CurrentExperiment, Metrics, Network, Link, Node, Canvas
+from ..models import Experiment, CurrentExperiment, Metrics, Network, Link, Node, Canvas, GraphPoint
 
 client = MQTTClient(client_id="django-ihm")
 
@@ -54,15 +54,6 @@ def agent_metric(client, userdata, message) -> None:
     metrics = Metrics(cycle=exp.cycle, metrics=results)
     metrics.save()
 
-    if False:
-        data = 0
-        for metric in results:
-            if metric == {}:
-                pass
-            elif metric.get("color") != "#000000":
-                data += 1
-        graph_event_triger([data, exp.cycle])
-
 
 def agent_canvas(client, userdata, message) -> None:
     results = literal_eval(message.payload.decode("utf-8"))
@@ -119,6 +110,14 @@ def cycle_done(client, userdata, message) -> None:
 
         canvas_event_triger(canvas)
 
+    if cur_exp.graph and (cur_exp.cycle % cur_exp.graph_refresh == 0):
+        data = [
+            {"name": elem.name, "x":elem.cycle, "y":elem.y}
+            for elem in GraphPoint.objects.all()
+        ]
+        graph_event_triger(data)
+
+
     cur_exp.cycle += 1
     cur_exp.save()
 
@@ -142,6 +141,12 @@ def update_nbr_agent(client, userdata, message) -> None:
     exp.nbr_agent += 1
     exp.save()
 
+def agent_graph(client, userdata, message) -> None:
+    results = literal_eval(message.payload.decode("utf-8"))
+
+    for elem in results.get("point"):
+        point = GraphPoint(name=elem.get("name"),cycle=results.get("cycle"),y=elem.get("value"))
+        point.save()
 
 def experiment_load(request):
     delete_folder(str(settings.MEDIA_ROOT) + "current_experiment")
@@ -180,6 +185,13 @@ def experiment_load(request):
         cur_exp.canvas_width = config.get("canvas").get("width")
         Canvas.objects.all().delete()
 
+    if "graph" in config:
+        cur_exp.graph = True
+        cur_exp.graph_height = config.get("graph").get("height")
+        cur_exp.graph_width = config.get("graph").get("width")
+        cur_exp.graph_refresh = config.get("graph").get("refresh")
+        GraphPoint.objects.all().delete()
+
     cur_exp.scheduling = config.get("scheduling_type")
 
     cur_exp.save()
@@ -230,6 +242,7 @@ def experiment_start(request):
     client.loop_start()
     subscribe(client, "amas/agent/new", update_nbr_agent)
     subscribe(client, "scheduler/cycledone", cycle_done)
+    subscribe(client, "amas/graph", agent_graph)
     subscribe(client, "amas/all_metric", agent_metric)
 
     delete_nohup()
@@ -249,7 +262,8 @@ def experiment_start(request):
         "seed": exp.seed,
         "iot_path": n.path_to_iotamak + "example/",
         "broker_username": n.broker_username,
-        "broker_password": n.broker_password
+        "broker_password": n.broker_password,
+        "experiment_folder": exp.name
     }
     if not exp.scheduling == "sync":
         amas_dict["wait_delay"] = str(5)
diff --git a/ping/views/tool.py b/ping/views/tool.py
index 35036dc..4a4efc7 100644
--- a/ping/views/tool.py
+++ b/ping/views/tool.py
@@ -45,21 +45,20 @@ def canvas_event_triger(metrics):
         }
     )
 
-
-def graph_event_triger(metrics):
+def com_event_triger(data):
     channel_layer = get_channel_layer()
     async_to_sync(channel_layer.group_send)(
-        'event_graph',
+        'event_com',
         {
             'type': 'send_message_to_frontend',
-            'message': metrics
+            'message': data
         }
     )
 
-def com_event_triger(data):
+def graph_event_triger(data):
     channel_layer = get_channel_layer()
     async_to_sync(channel_layer.group_send)(
-        'event_com',
+        'event_graph',
         {
             'type': 'send_message_to_frontend',
             'message': data
-- 
GitLab