From 74d5053f15df9dfb6a0f37f331eda9fa7c92365e Mon Sep 17 00:00:00 2001
From: sebastien curt <sebastien.curt@tetras-libre.fr>
Date: Tue, 10 Nov 2020 17:20:45 +0100
Subject: [PATCH] monetdb dashboard sample

---
 dashboards/MonetDB.ipynb  | 522 ++++++++++++++++++++++++++++++++++++--
 dashboards/naissances.sql |  43 ++++
 2 files changed, 541 insertions(+), 24 deletions(-)
 create mode 100644 dashboards/naissances.sql

diff --git a/dashboards/MonetDB.ipynb b/dashboards/MonetDB.ipynb
index c4c0b01..e176b28 100644
--- a/dashboards/MonetDB.ipynb
+++ b/dashboards/MonetDB.ipynb
@@ -1,44 +1,518 @@
 {
  "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Affichage des données"
+   ]
+  },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 63,
    "metadata": {},
    "outputs": [
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Successfully connected to localDB with default credentials, please change the monetdb password by running docker-compose exec localDB -d monetdb-r /root/set-monetdb-password.sh <password>\n"
-     ]
+     "data": {
+      "application/javascript": [
+       "\n",
+       "(function(root) {\n",
+       "  function now() {\n",
+       "    return new Date();\n",
+       "  }\n",
+       "\n",
+       "  var force = true;\n",
+       "\n",
+       "  if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n",
+       "    root._bokeh_onload_callbacks = [];\n",
+       "    root._bokeh_is_loading = undefined;\n",
+       "  }\n",
+       "\n",
+       "  if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n",
+       "    root._bokeh_timeout = Date.now() + 5000;\n",
+       "    root._bokeh_failed_load = false;\n",
+       "  }\n",
+       "\n",
+       "  function run_callbacks() {\n",
+       "    try {\n",
+       "      root._bokeh_onload_callbacks.forEach(function(callback) {\n",
+       "        if (callback != null)\n",
+       "          callback();\n",
+       "      });\n",
+       "    } finally {\n",
+       "      delete root._bokeh_onload_callbacks\n",
+       "    }\n",
+       "    console.debug(\"Bokeh: all callbacks have finished\");\n",
+       "  }\n",
+       "\n",
+       "  function load_libs(css_urls, js_urls, callback) {\n",
+       "    if (css_urls == null) css_urls = [];\n",
+       "    if (js_urls == null) js_urls = [];\n",
+       "\n",
+       "    root._bokeh_onload_callbacks.push(callback);\n",
+       "    if (root._bokeh_is_loading > 0) {\n",
+       "      console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n",
+       "      return null;\n",
+       "    }\n",
+       "    if (js_urls == null || js_urls.length === 0) {\n",
+       "      run_callbacks();\n",
+       "      return null;\n",
+       "    }\n",
+       "    console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n",
+       "    root._bokeh_is_loading = css_urls.length + js_urls.length;\n",
+       "\n",
+       "    function on_load() {\n",
+       "      root._bokeh_is_loading--;\n",
+       "      if (root._bokeh_is_loading === 0) {\n",
+       "        console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n",
+       "        run_callbacks()\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "    function on_error() {\n",
+       "      console.error(\"failed to load \" + url);\n",
+       "    }\n",
+       "\n",
+       "    for (var i = 0; i < css_urls.length; i++) {\n",
+       "      var url = css_urls[i];\n",
+       "      const element = document.createElement(\"link\");\n",
+       "      element.onload = on_load;\n",
+       "      element.onerror = on_error;\n",
+       "      element.rel = \"stylesheet\";\n",
+       "      element.type = \"text/css\";\n",
+       "      element.href = url;\n",
+       "      console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n",
+       "      document.body.appendChild(element);\n",
+       "    }\n",
+       "\n",
+       "    var skip = [];\n",
+       "    if (window.requirejs) {\n",
+       "      require([], function() {\n",
+       "      })\n",
+       "    }\n",
+       "    for (var i = 0; i < js_urls.length; i++) {\n",
+       "      var url = js_urls[i];\n",
+       "      if (skip.indexOf(url) >= 0) { on_load(); continue; }\n",
+       "      var element = document.createElement('script');\n",
+       "      element.onload = on_load;\n",
+       "      element.onerror = on_error;\n",
+       "      element.async = false;\n",
+       "      element.src = url;\n",
+       "      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n",
+       "      document.head.appendChild(element);\n",
+       "    }\n",
+       "\tif (!js_urls.length) {\n",
+       "      on_load()\n",
+       "    }\n",
+       "  };\n",
+       "\n",
+       "  function inject_raw_css(css) {\n",
+       "    const element = document.createElement(\"style\");\n",
+       "    element.appendChild(document.createTextNode(css));\n",
+       "    document.body.appendChild(element);\n",
+       "  }\n",
+       "\n",
+       "  var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-2.2.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.2.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.2.3.min.js\", \"https://unpkg.com/@holoviz/panel@^0.10.1/dist/panel.min.js\"];\n",
+       "  var css_urls = [\"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/widgets.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/alerts.css\"];\n",
+       "\n",
+       "  var inline_js = [\n",
+       "    function(Bokeh) {\n",
+       "      Bokeh.set_log_level(\"info\");\n",
+       "    },\n",
+       "    function(Bokeh) {} // ensure no trailing comma for IE\n",
+       "  ];\n",
+       "\n",
+       "  function run_inline_js() {\n",
+       "    if ((root.Bokeh !== undefined) || (force === true)) {\n",
+       "      for (var i = 0; i < inline_js.length; i++) {\n",
+       "        inline_js[i].call(root, root.Bokeh);\n",
+       "      }} else if (Date.now() < root._bokeh_timeout) {\n",
+       "      setTimeout(run_inline_js, 100);\n",
+       "    } else if (!root._bokeh_failed_load) {\n",
+       "      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n",
+       "      root._bokeh_failed_load = true;\n",
+       "    }\n",
+       "  }\n",
+       "\n",
+       "  if (root._bokeh_is_loading === 0) {\n",
+       "    console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n",
+       "    run_inline_js();\n",
+       "  } else {\n",
+       "    load_libs(css_urls, js_urls, function() {\n",
+       "      console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n",
+       "      run_inline_js();\n",
+       "    });\n",
+       "  }\n",
+       "}(window));"
+      ],
+      "application/vnd.holoviews_load.v0+json": "\n(function(root) {\n  function now() {\n    return new Date();\n  }\n\n  var force = true;\n\n  if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n    root._bokeh_onload_callbacks = [];\n    root._bokeh_is_loading = undefined;\n  }\n\n  if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n    root._bokeh_timeout = Date.now() + 5000;\n    root._bokeh_failed_load = false;\n  }\n\n  function run_callbacks() {\n    try {\n      root._bokeh_onload_callbacks.forEach(function(callback) {\n        if (callback != null)\n          callback();\n      });\n    } finally {\n      delete root._bokeh_onload_callbacks\n    }\n    console.debug(\"Bokeh: all callbacks have finished\");\n  }\n\n  function load_libs(css_urls, js_urls, callback) {\n    if (css_urls == null) css_urls = [];\n    if (js_urls == null) js_urls = [];\n\n    root._bokeh_onload_callbacks.push(callback);\n    if (root._bokeh_is_loading > 0) {\n      console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n      return null;\n    }\n    if (js_urls == null || js_urls.length === 0) {\n      run_callbacks();\n      return null;\n    }\n    console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n    root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n    function on_load() {\n      root._bokeh_is_loading--;\n      if (root._bokeh_is_loading === 0) {\n        console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n        run_callbacks()\n      }\n    }\n\n    function on_error() {\n      console.error(\"failed to load \" + url);\n    }\n\n    for (var i = 0; i < css_urls.length; i++) {\n      var url = css_urls[i];\n      const element = document.createElement(\"link\");\n      element.onload = on_load;\n      element.onerror = on_error;\n      element.rel = \"stylesheet\";\n      element.type = \"text/css\";\n      element.href = url;\n      console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n      document.body.appendChild(element);\n    }\n\n    var skip = [];\n    if (window.requirejs) {\n      require([], function() {\n      })\n    }\n    for (var i = 0; i < js_urls.length; i++) {\n      var url = js_urls[i];\n      if (skip.indexOf(url) >= 0) { on_load(); continue; }\n      var element = document.createElement('script');\n      element.onload = on_load;\n      element.onerror = on_error;\n      element.async = false;\n      element.src = url;\n      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n      document.head.appendChild(element);\n    }\n\tif (!js_urls.length) {\n      on_load()\n    }\n  };\n\n  function inject_raw_css(css) {\n    const element = document.createElement(\"style\");\n    element.appendChild(document.createTextNode(css));\n    document.body.appendChild(element);\n  }\n\n  var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-2.2.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.2.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.2.3.min.js\", \"https://unpkg.com/@holoviz/panel@^0.10.1/dist/panel.min.js\"];\n  var css_urls = [\"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/widgets.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.10.1/dist/css/alerts.css\"];\n\n  var inline_js = [\n    function(Bokeh) {\n      Bokeh.set_log_level(\"info\");\n    },\n    function(Bokeh) {} // ensure no trailing comma for IE\n  ];\n\n  function run_inline_js() {\n    if ((root.Bokeh !== undefined) || (force === true)) {\n      for (var i = 0; i < inline_js.length; i++) {\n        inline_js[i].call(root, root.Bokeh);\n      }} else if (Date.now() < root._bokeh_timeout) {\n      setTimeout(run_inline_js, 100);\n    } else if (!root._bokeh_failed_load) {\n      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n      root._bokeh_failed_load = true;\n    }\n  }\n\n  if (root._bokeh_is_loading === 0) {\n    console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n    run_inline_js();\n  } else {\n    load_libs(css_urls, js_urls, function() {\n      console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n      run_inline_js();\n    });\n  }\n}(window));"
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/javascript": [
+       "\n",
+       "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n",
+       "  window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n",
+       "}\n",
+       "\n",
+       "\n",
+       "    function JupyterCommManager() {\n",
+       "    }\n",
+       "\n",
+       "    JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n",
+       "      if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n",
+       "        var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n",
+       "        comm_manager.register_target(comm_id, function(comm) {\n",
+       "          comm.on_msg(msg_handler);\n",
+       "        });\n",
+       "      } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n",
+       "        window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n",
+       "          comm.onMsg = msg_handler;\n",
+       "        });\n",
+       "      } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n",
+       "        google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n",
+       "          var messages = comm.messages[Symbol.asyncIterator]();\n",
+       "          function processIteratorResult(result) {\n",
+       "            var message = result.value;\n",
+       "            console.log(message)\n",
+       "            var content = {data: message.data, comm_id};\n",
+       "            var buffers = []\n",
+       "            for (var buffer of message.buffers || []) {\n",
+       "              buffers.push(new DataView(buffer))\n",
+       "            }\n",
+       "            var metadata = message.metadata || {};\n",
+       "            var msg = {content, buffers, metadata}\n",
+       "            msg_handler(msg);\n",
+       "            return messages.next().then(processIteratorResult);\n",
+       "          }\n",
+       "          return messages.next().then(processIteratorResult);\n",
+       "        })\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "    JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n",
+       "      if (comm_id in window.PyViz.comms) {\n",
+       "        return window.PyViz.comms[comm_id];\n",
+       "      } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n",
+       "        var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n",
+       "        var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n",
+       "        if (msg_handler) {\n",
+       "          comm.on_msg(msg_handler);\n",
+       "        }\n",
+       "      } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n",
+       "        var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n",
+       "        comm.open();\n",
+       "        if (msg_handler) {\n",
+       "          comm.onMsg = msg_handler;\n",
+       "        }\n",
+       "      } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n",
+       "        var comm_promise = google.colab.kernel.comms.open(comm_id)\n",
+       "        comm_promise.then((comm) => {\n",
+       "          window.PyViz.comms[comm_id] = comm;\n",
+       "          if (msg_handler) {\n",
+       "            var messages = comm.messages[Symbol.asyncIterator]();\n",
+       "            function processIteratorResult(result) {\n",
+       "              var message = result.value;\n",
+       "              var content = {data: message.data};\n",
+       "              var metadata = message.metadata || {comm_id};\n",
+       "              var msg = {content, metadata}\n",
+       "              msg_handler(msg);\n",
+       "              return messages.next().then(processIteratorResult);\n",
+       "            }\n",
+       "            return messages.next().then(processIteratorResult);\n",
+       "          }\n",
+       "        }) \n",
+       "        var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n",
+       "          return comm_promise.then((comm) => {\n",
+       "            comm.send(data, metadata, buffers, disposeOnDone);\n",
+       "          });\n",
+       "        };\n",
+       "        var comm = {\n",
+       "          send: sendClosure\n",
+       "        };\n",
+       "      }\n",
+       "      window.PyViz.comms[comm_id] = comm;\n",
+       "      return comm;\n",
+       "    }\n",
+       "    window.PyViz.comm_manager = new JupyterCommManager();\n",
+       "    \n",
+       "\n",
+       "\n",
+       "var JS_MIME_TYPE = 'application/javascript';\n",
+       "var HTML_MIME_TYPE = 'text/html';\n",
+       "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n",
+       "var CLASS_NAME = 'output';\n",
+       "\n",
+       "/**\n",
+       " * Render data to the DOM node\n",
+       " */\n",
+       "function render(props, node) {\n",
+       "  var div = document.createElement(\"div\");\n",
+       "  var script = document.createElement(\"script\");\n",
+       "  node.appendChild(div);\n",
+       "  node.appendChild(script);\n",
+       "}\n",
+       "\n",
+       "/**\n",
+       " * Handle when a new output is added\n",
+       " */\n",
+       "function handle_add_output(event, handle) {\n",
+       "  var output_area = handle.output_area;\n",
+       "  var output = handle.output;\n",
+       "  if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n",
+       "    return\n",
+       "  }\n",
+       "  var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n",
+       "  var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n",
+       "  if (id !== undefined) {\n",
+       "    var nchildren = toinsert.length;\n",
+       "    var html_node = toinsert[nchildren-1].children[0];\n",
+       "    html_node.innerHTML = output.data[HTML_MIME_TYPE];\n",
+       "    var scripts = [];\n",
+       "    var nodelist = html_node.querySelectorAll(\"script\");\n",
+       "    for (var i in nodelist) {\n",
+       "      if (nodelist.hasOwnProperty(i)) {\n",
+       "        scripts.push(nodelist[i])\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "    scripts.forEach( function (oldScript) {\n",
+       "      var newScript = document.createElement(\"script\");\n",
+       "      var attrs = [];\n",
+       "      var nodemap = oldScript.attributes;\n",
+       "      for (var j in nodemap) {\n",
+       "        if (nodemap.hasOwnProperty(j)) {\n",
+       "          attrs.push(nodemap[j])\n",
+       "        }\n",
+       "      }\n",
+       "      attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n",
+       "      newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n",
+       "      oldScript.parentNode.replaceChild(newScript, oldScript);\n",
+       "    });\n",
+       "    if (JS_MIME_TYPE in output.data) {\n",
+       "      toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n",
+       "    }\n",
+       "    output_area._hv_plot_id = id;\n",
+       "    if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n",
+       "      window.PyViz.plot_index[id] = Bokeh.index[id];\n",
+       "    } else {\n",
+       "      window.PyViz.plot_index[id] = null;\n",
+       "    }\n",
+       "  } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n",
+       "    var bk_div = document.createElement(\"div\");\n",
+       "    bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n",
+       "    var script_attrs = bk_div.children[0].attributes;\n",
+       "    for (var i = 0; i < script_attrs.length; i++) {\n",
+       "      toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n",
+       "    }\n",
+       "    // store reference to server id on output_area\n",
+       "    output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n",
+       "  }\n",
+       "}\n",
+       "\n",
+       "/**\n",
+       " * Handle when an output is cleared or removed\n",
+       " */\n",
+       "function handle_clear_output(event, handle) {\n",
+       "  var id = handle.cell.output_area._hv_plot_id;\n",
+       "  var server_id = handle.cell.output_area._bokeh_server_id;\n",
+       "  if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n",
+       "  var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n",
+       "  if (server_id !== null) {\n",
+       "    comm.send({event_type: 'server_delete', 'id': server_id});\n",
+       "    return;\n",
+       "  } else if (comm !== null) {\n",
+       "    comm.send({event_type: 'delete', 'id': id});\n",
+       "  }\n",
+       "  delete PyViz.plot_index[id];\n",
+       "  if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n",
+       "    var doc = window.Bokeh.index[id].model.document\n",
+       "    doc.clear();\n",
+       "    const i = window.Bokeh.documents.indexOf(doc);\n",
+       "    if (i > -1) {\n",
+       "      window.Bokeh.documents.splice(i, 1);\n",
+       "    }\n",
+       "  }\n",
+       "}\n",
+       "\n",
+       "/**\n",
+       " * Handle kernel restart event\n",
+       " */\n",
+       "function handle_kernel_cleanup(event, handle) {\n",
+       "  delete PyViz.comms[\"hv-extension-comm\"];\n",
+       "  window.PyViz.plot_index = {}\n",
+       "}\n",
+       "\n",
+       "/**\n",
+       " * Handle update_display_data messages\n",
+       " */\n",
+       "function handle_update_output(event, handle) {\n",
+       "  handle_clear_output(event, {cell: {output_area: handle.output_area}})\n",
+       "  handle_add_output(event, handle)\n",
+       "}\n",
+       "\n",
+       "function register_renderer(events, OutputArea) {\n",
+       "  function append_mime(data, metadata, element) {\n",
+       "    // create a DOM node to render to\n",
+       "    var toinsert = this.create_output_subarea(\n",
+       "    metadata,\n",
+       "    CLASS_NAME,\n",
+       "    EXEC_MIME_TYPE\n",
+       "    );\n",
+       "    this.keyboard_manager.register_events(toinsert);\n",
+       "    // Render to node\n",
+       "    var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n",
+       "    render(props, toinsert[0]);\n",
+       "    element.append(toinsert);\n",
+       "    return toinsert\n",
+       "  }\n",
+       "\n",
+       "  events.on('output_added.OutputArea', handle_add_output);\n",
+       "  events.on('output_updated.OutputArea', handle_update_output);\n",
+       "  events.on('clear_output.CodeCell', handle_clear_output);\n",
+       "  events.on('delete.Cell', handle_clear_output);\n",
+       "  events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n",
+       "\n",
+       "  OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n",
+       "    safe: true,\n",
+       "    index: 0\n",
+       "  });\n",
+       "}\n",
+       "\n",
+       "if (window.Jupyter !== undefined) {\n",
+       "  try {\n",
+       "    var events = require('base/js/events');\n",
+       "    var OutputArea = require('notebook/js/outputarea').OutputArea;\n",
+       "    if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n",
+       "      register_renderer(events, OutputArea);\n",
+       "    }\n",
+       "  } catch(err) {\n",
+       "  }\n",
+       "}\n"
+      ],
+      "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n  window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n    function JupyterCommManager() {\n    }\n\n    JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n      if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n        var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n        comm_manager.register_target(comm_id, function(comm) {\n          comm.on_msg(msg_handler);\n        });\n      } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n        window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n          comm.onMsg = msg_handler;\n        });\n      } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n        google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n          var messages = comm.messages[Symbol.asyncIterator]();\n          function processIteratorResult(result) {\n            var message = result.value;\n            console.log(message)\n            var content = {data: message.data, comm_id};\n            var buffers = []\n            for (var buffer of message.buffers || []) {\n              buffers.push(new DataView(buffer))\n            }\n            var metadata = message.metadata || {};\n            var msg = {content, buffers, metadata}\n            msg_handler(msg);\n            return messages.next().then(processIteratorResult);\n          }\n          return messages.next().then(processIteratorResult);\n        })\n      }\n    }\n\n    JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n      if (comm_id in window.PyViz.comms) {\n        return window.PyViz.comms[comm_id];\n      } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n        var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n        var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n        if (msg_handler) {\n          comm.on_msg(msg_handler);\n        }\n      } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n        var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n        comm.open();\n        if (msg_handler) {\n          comm.onMsg = msg_handler;\n        }\n      } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n        var comm_promise = google.colab.kernel.comms.open(comm_id)\n        comm_promise.then((comm) => {\n          window.PyViz.comms[comm_id] = comm;\n          if (msg_handler) {\n            var messages = comm.messages[Symbol.asyncIterator]();\n            function processIteratorResult(result) {\n              var message = result.value;\n              var content = {data: message.data};\n              var metadata = message.metadata || {comm_id};\n              var msg = {content, metadata}\n              msg_handler(msg);\n              return messages.next().then(processIteratorResult);\n            }\n            return messages.next().then(processIteratorResult);\n          }\n        }) \n        var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n          return comm_promise.then((comm) => {\n            comm.send(data, metadata, buffers, disposeOnDone);\n          });\n        };\n        var comm = {\n          send: sendClosure\n        };\n      }\n      window.PyViz.comms[comm_id] = comm;\n      return comm;\n    }\n    window.PyViz.comm_manager = new JupyterCommManager();\n    \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n  var div = document.createElement(\"div\");\n  var script = document.createElement(\"script\");\n  node.appendChild(div);\n  node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n  var output_area = handle.output_area;\n  var output = handle.output;\n  if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n    return\n  }\n  var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n  var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n  if (id !== undefined) {\n    var nchildren = toinsert.length;\n    var html_node = toinsert[nchildren-1].children[0];\n    html_node.innerHTML = output.data[HTML_MIME_TYPE];\n    var scripts = [];\n    var nodelist = html_node.querySelectorAll(\"script\");\n    for (var i in nodelist) {\n      if (nodelist.hasOwnProperty(i)) {\n        scripts.push(nodelist[i])\n      }\n    }\n\n    scripts.forEach( function (oldScript) {\n      var newScript = document.createElement(\"script\");\n      var attrs = [];\n      var nodemap = oldScript.attributes;\n      for (var j in nodemap) {\n        if (nodemap.hasOwnProperty(j)) {\n          attrs.push(nodemap[j])\n        }\n      }\n      attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n      newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n      oldScript.parentNode.replaceChild(newScript, oldScript);\n    });\n    if (JS_MIME_TYPE in output.data) {\n      toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n    }\n    output_area._hv_plot_id = id;\n    if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n      window.PyViz.plot_index[id] = Bokeh.index[id];\n    } else {\n      window.PyViz.plot_index[id] = null;\n    }\n  } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n    var bk_div = document.createElement(\"div\");\n    bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n    var script_attrs = bk_div.children[0].attributes;\n    for (var i = 0; i < script_attrs.length; i++) {\n      toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n    }\n    // store reference to server id on output_area\n    output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n  }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n  var id = handle.cell.output_area._hv_plot_id;\n  var server_id = handle.cell.output_area._bokeh_server_id;\n  if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n  var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n  if (server_id !== null) {\n    comm.send({event_type: 'server_delete', 'id': server_id});\n    return;\n  } else if (comm !== null) {\n    comm.send({event_type: 'delete', 'id': id});\n  }\n  delete PyViz.plot_index[id];\n  if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n    var doc = window.Bokeh.index[id].model.document\n    doc.clear();\n    const i = window.Bokeh.documents.indexOf(doc);\n    if (i > -1) {\n      window.Bokeh.documents.splice(i, 1);\n    }\n  }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n  delete PyViz.comms[\"hv-extension-comm\"];\n  window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n  handle_clear_output(event, {cell: {output_area: handle.output_area}})\n  handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n  function append_mime(data, metadata, element) {\n    // create a DOM node to render to\n    var toinsert = this.create_output_subarea(\n    metadata,\n    CLASS_NAME,\n    EXEC_MIME_TYPE\n    );\n    this.keyboard_manager.register_events(toinsert);\n    // Render to node\n    var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n    render(props, toinsert[0]);\n    element.append(toinsert);\n    return toinsert\n  }\n\n  events.on('output_added.OutputArea', handle_add_output);\n  events.on('output_updated.OutputArea', handle_update_output);\n  events.on('clear_output.CodeCell', handle_clear_output);\n  events.on('delete.Cell', handle_clear_output);\n  events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n  OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n    safe: true,\n    index: 0\n  });\n}\n\nif (window.Jupyter !== undefined) {\n  try {\n    var events = require('base/js/events');\n    var OutputArea = require('notebook/js/outputarea').OutputArea;\n    if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n      register_renderer(events, OutputArea);\n    }\n  } catch(err) {\n  }\n}\n"
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "e3be3d541f804695896911ad8c8f1895",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Column\n",
+       "    [0] Select(name='y axis values', options=['nombre', 'taux'], value='nombre')\n",
+       "    [1] ParamFunction(function)"
+      ]
+     },
+     "execution_count": 63,
+     "metadata": {},
+     "output_type": "execute_result"
     }
    ],
    "source": [
     "import pymonetdb\n",
+    "from bokeh.plotting import figure, output_file, show\n",
+    "from bokeh.models import ColumnDataSource\n",
+    "import pandas as pd\n",
+    "import numpy as np\n",
+    "import panel as pn\n",
+    "\n",
+    "pn.extension(comms='ipywidgets')\n",
+    "\n",
+    "def create_connection():\n",
+    "    return pymonetdb.connect(username=\"monetdb\", password=\"monetdb\",\n",
+    "                                        hostname=\"localDB\", database=\"db\")\n",
+    "\n",
+    "def checkTableExists(dbcon, tablename):\n",
+    "    dbcur = dbcon.cursor()\n",
+    "    dbcur.execute(\"\"\"\n",
+    "        SELECT COUNT(*)\n",
+    "        FROM tables\n",
+    "        WHERE name = '{0}'\n",
+    "        \"\"\".format(tablename.replace('\\'', '\\'\\'')))\n",
+    "    if dbcur.fetchone()[0] == 1:\n",
+    "        dbcur.close()\n",
+    "        return True\n",
+    "\n",
+    "    dbcur.close()\n",
+    "    return False\n",
     "\n",
-    "# set up a connection. arguments below are the defaults\n",
-    "connection = pymonetdb.connect(username=\"monetdb\", password=\"monetdb\",\n",
-    "                                    hostname=\"localDB\", database=\"db\")\n",
+    "def get_sql_script_content(filename):\n",
+    "    sql_script_file = open(filename, \"r\") \n",
+    "    sql_script_content = sql_script_file.read()\n",
+    "    sql_script_file.close()\n",
+    "    return sql_script_content\n",
     "\n",
-    "# create a cursor\n",
-    "cursor = connection.cursor()\n",
+    "def execute_file_script(dbcon, filename):\n",
+    "    sql_script_content = get_sql_script_content(filename)\n",
+    "    execute_moneydb_script(connection, sql_script_content)\n",
+    "    dbcon.command(sqlscript)\n",
+    "    connection.commit()\n",
+    "    \n",
+    "def create_database():\n",
+    "    execute_file_script(connection, \"naissances.sql\")\n",
     "\n",
-    "# increase the rows fetched to increase performance (optional)\n",
-    "cursor.arraysize = 100\n",
+    "def execute_db_command(connection, sql_command):\n",
+    "    # create a cursor\n",
+    "    cursor = connection.cursor()\n",
     "\n",
-    "# execute a query (return the number of rows to fetch)\n",
-    "res=cursor.execute('SELECT * FROM tables')\n",
+    "    # increase the rows fetched to increase performance (optional)\n",
+    "    cursor.arraysize = 100\n",
+    "    \n",
+    "    # execute the query\n",
+    "    cursor.execute(sql_command)\n",
+    "    \n",
+    "    # fetch results\n",
+    "    result = cursor.fetchall()\n",
+    "    \n",
+    "    # close cursor\n",
+    "    cursor.close()\n",
+    "    return result\n",
+    "    \n",
     "\n",
-    "if (res > 0):\n",
-    "    print('Successfully connected to localDB with default credentials, please change the monetdb password by running docker-compose exec localDB -d monetdb-r /root/set-monetdb-password.sh <password>')"
+    "def get_db_data(connection, y_axis):\n",
+    "    return execute_db_command(connection, 'SELECT annee, {} FROM naissances'.format(y_axis))\n",
+    "\n",
+    "\n",
+    "condb = create_connection()\n",
+    "if checkTableExists(condb, \"naissances\") == False:\n",
+    "    create_database(condb)\n",
+    "condb.close()\n",
+    "\n",
+    "selector = pn.widgets.Select(name='y axis values', options=['nombre', 'taux'])\n",
+    "\n",
+    "# fetch data\n",
+    "\n",
+    "@pn.depends(selector.param.value)\n",
+    "def getplot(y_axis):\n",
+    "    connection = create_connection()\n",
+    "    data=get_db_data(connection, y_axis)\n",
+    "    \n",
+    "    if y_axis == 'nombre':\n",
+    "        y_axis_name='Nombre de naissance'\n",
+    "    else:\n",
+    "        y_axis_name='Taux de naissance'\n",
+    "\n",
+    "    df = pd.DataFrame(np.array(data), columns = [ 'annee', y_axis])\n",
+    "    plot = figure(x_axis_label='annee',\n",
+    "                  y_axis_label=y_axis_name,\n",
+    "                 title=\"Naissances en france depuis 1982\")\n",
+    "    plot.line('annee', y_axis, source=df)\n",
+    "    \n",
+    "    connection.close()\n",
+    "    return plot\n",
+    "\n",
+    "#graph\n",
+    "pn.Column(selector, getplot).servable()\n",
+    "#pn.panel(graph)\n"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {
diff --git a/dashboards/naissances.sql b/dashboards/naissances.sql
new file mode 100644
index 0000000..12a57a9
--- /dev/null
+++ b/dashboards/naissances.sql
@@ -0,0 +1,43 @@
+-- drop table if necessary
+drop table if exists naissances cascade;
+
+create table naissances(annee int, nombre bigint, taux real);
+
+insert into naissances values
+(2019,753000,11.2),
+(2018,758590,11.3),
+(2017,769553,11.5),
+(2016,783640,11.8),
+(2015,798948,12.0),
+(2013,811510,12.3),
+(2012,821047,12.6),
+(2011,823394,12.7),
+(2010,832799,12.9),
+(2009,824641,12.8),
+(2008,828404,12.9),
+(2007,818705,12.8),
+(2006,829352,13.1),
+(2005,806822,12.8),
+(2004,799361,12.8),
+(2003,793044,12.8),
+(2002,792745,12.9),
+(2001,803234,13.1),
+(2000,807405,13.3),
+(1999,775796,12.9),
+(1998,767906,12.8),
+(1997,757384,12.7),
+(1996,764028,12.8),
+(1995,759058,12.8),
+(1994,740774,12.5),
+(1993,741306,12.6),
+(1992,774755,13.2),
+(1991,790078,13.5),
+(1990,793071,13.6),
+(1989,796101,13.8),
+(1988,800560,13.9),
+(1987,795790,13.9),
+(1986,805543,14.2),
+(1985,796138,14.1),
+(1984,787429,14.0),
+(1983,775441,13.8),
+(1982,823260,14.8);
\ No newline at end of file
-- 
GitLab