{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Data-Driven documents with `d3`\n", "[`d3`](http://d3js.org) is a powerful visualization framework, and powers the [`vega`](https://vega.github.io/vega/) extension for JupyterLab, which provides any kernel with rich display to create." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display.display({\n", "\"application/vnd.vega.v3+json\": {\n", " \"$schema\": \"https://vega.github.io/schema/vega/v3.json\",\n", " \"width\": 400,\n", " \"height\": 200,\n", " \"padding\": 5,\n", "\n", " \"data\": [\n", " {\n", " \"name\": \"table\",\n", " \"values\": [\n", " {\"category\": \"A\", \"amount\": 28},\n", " {\"category\": \"B\", \"amount\": 55},\n", " {\"category\": \"C\", \"amount\": 43},\n", " {\"category\": \"D\", \"amount\": 91},\n", " {\"category\": \"E\", \"amount\": 81},\n", " {\"category\": \"F\", \"amount\": 53},\n", " {\"category\": \"G\", \"amount\": 19},\n", " {\"category\": \"H\", \"amount\": 87}\n", " ]\n", " }\n", " ],\n", "\n", " \"signals\": [\n", " {\n", " \"name\": \"tooltip\",\n", " \"value\": {},\n", " \"on\": [\n", " {\"events\": \"rect:mouseover\", \"update\": \"datum\"},\n", " {\"events\": \"rect:mouseout\", \"update\": \"{}\"}\n", " ]\n", " }\n", " ],\n", "\n", " \"scales\": [\n", " {\n", " \"name\": \"xscale\",\n", " \"type\": \"band\",\n", " \"domain\": {\"data\": \"table\", \"field\": \"category\"},\n", " \"range\": \"width\",\n", " \"padding\": 0.05,\n", " \"round\": true\n", " },\n", " {\n", " \"name\": \"yscale\",\n", " \"domain\": {\"data\": \"table\", \"field\": \"amount\"},\n", " \"nice\": true,\n", " \"range\": \"height\"\n", " }\n", " ],\n", "\n", " \"axes\": [\n", " { \"orient\": \"bottom\", \"scale\": \"xscale\" },\n", " { \"orient\": \"left\", \"scale\": \"yscale\" }\n", " ],\n", "\n", " \"marks\": [\n", " {\n", " \"type\": \"rect\",\n", " \"from\": {\"data\":\"table\"},\n", " \"encode\": {\n", " \"enter\": {\n", " \"x\": {\"scale\": \"xscale\", \"field\": \"category\"},\n", " \"width\": {\"scale\": \"xscale\", \"band\": 1},\n", " \"y\": {\"scale\": \"yscale\", \"field\": \"amount\"},\n", " \"y2\": {\"scale\": \"yscale\", \"value\": 0}\n", " },\n", " \"update\": {\n", " \"fill\": {\"value\": \"steelblue\"}\n", " },\n", " \"hover\": {\n", " \"fill\": {\"value\": \"red\"}\n", " }\n", " }\n", " },\n", " {\n", " \"type\": \"text\",\n", " \"encode\": {\n", " \"enter\": {\n", " \"align\": {\"value\": \"center\"},\n", " \"baseline\": {\"value\": \"bottom\"},\n", " \"fill\": {\"value\": \"#333\"}\n", " },\n", " \"update\": {\n", " \"x\": {\"scale\": \"xscale\", \"signal\": \"tooltip.category\", \"band\": 0.5},\n", " \"y\": {\"scale\": \"yscale\", \"signal\": \"tooltip.amount\", \"offset\": -2},\n", " \"text\": {\"signal\": \"tooltip.amount\"},\n", " \"fillOpacity\": [\n", " {\"test\": \"datum === tooltip\", \"value\": 0},\n", " {\"value\": 1}\n", " ]\n", " }\n", " }\n", " }\n", " ]\n", "}\n", "})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Anyhow, because it's there, and **this is Jyve**, you can have it." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A Hack: `d3` is dead, long live `d3`.\n", "In transitioning to a many-repo development process between `v3` and `v4`, some libraries decided to stay on to the last release of the `v3` line, including the [`vega2-extension`](https://github.com/jupyterlab/jupyterlab/tree/master/packages/vega2-extension). So you get `d3=^3.5.17`, and that's that... for now.\n", "\n", "\n", "> ### _🤔 How might we make multiple versions of a library available, if present?_" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "now = new Date()\n", "scales = {\n", " x: d3.time.scale()\n", " .domain([now, new Date(+now + 60*1000)])\n", " .range([0, 100]),\n", " y: d3.scale.linear()\n", " .domain([0, 255])\n", " .range([200, 0])\n", "}\n", "\n", "color = d3.scale.category10()\n", "\n", "d3.select(document.body)\n", " .selectAll(\"style\").remove()\n", "\n", "d3.select(document.body)\n", " .append(\"style\")\n", " .html(`\n", " .axis text {\n", " font: 10px sans-serif;\n", " }\n", "\n", " .axis path,\n", " .axis line {\n", " fill: none;\n", " stroke: #000;\n", " shape-rendering: crispEdges;\n", " } \n", " `)\n", "\n", "\n", "d3.select(document.body)\n", " .style({display: \"flex\", \"flex-direction\": \"column\"})\n", " .selectAll(\"svg\")\n", " .remove()\n", "\n", "svg = d3.select(document.body)\n", " .append(\"svg\")\n", " .style({\n", " flex: 1,\n", " }) \n", "\n", "g = svg.append(\"g\")\n", " .attr({\"transform\": \"translate(0 20)\"})\n", "\n", "svg.append(\"text\")\n", " .text(\"Files Saved by time and path length\")\n", " .attr({y: 20, x: 200})\n", " .style({\"font-family\": \"sans-serif\", \"text-anchor\": \"middle\"})\n", "\n", "data = []\n", "\n", "axes = {\n", " x: d3.svg.axis().scale(scales.x).orient(\"bottom\"),\n", " y: d3.svg.axis().scale(scales.y).orient(\"right\"),\n", "}\n", "\n", "gax = {\n", " x: svg.append(\"g\").attr({\"class\": \"x axis\", transform: \"translate(0 220)\"}),\n", " y: svg.append(\"g\").attr({\"class\": \"y axis\", transform: \"translate(400 20)\"})\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The update function. This could be improved!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if(this.update) {\n", " JupyterLab.serviceManager.contents.fileChanged.disconnect(this.update);\n", "}\n", "update = function(g) {\n", " scales.x = scales.x.domain([ \n", " now,\n", " new Date(data[data.length - 1].newValue.last_modified)\n", " ])\n", " .range([0, 400])\n", "\n", " gax.x.call(axes.x.scale(scales.x));\n", " gax.y.call(axes.y.scale(scales.y));\n", " \n", " g.selectAll(\"circle\")\n", " .data(data)\n", " .enter()\n", " .append(\"circle\")\n", " .attr({r: 0})\n", "\n", " g.selectAll(\"circle\")\n", " .attr({\n", " cx: (d) => scales.x(new Date(d.newValue.last_modified)),\n", " cy: (d) => scales.y(d.newValue.path.length),\n", " r: 5\n", " })\n", " .style({\n", " fill: (d) => color(d.newValue.path),\n", " stroke: 'transparent'\n", " })\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Install the listener!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "console.log(JupyterLab.serviceManager.contents.fileChanged.connect(function(mgr, msg){\n", " console.log(msg)\n", " data.push(msg)\n", " g.call(window.update)\n", "}))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Great, now save a file." ] } ], "metadata": { "kernelspec": { "display_name": "JS (unsafe) — Jyve", "language": "javascript", "name": "jyve-kyrnel-js-unsafe" }, "language_info": { "codemirror_mode": { "name": "javascript" }, "file_extension": ".js", "mimetype": "text/javascript", "name": "javascript", "nbconvert_exporter": "javascript", "pygments_lexer": "javascript", "version": "ES2015" } }, "nbformat": 4, "nbformat_minor": 2 }