# GETTING STARTED WITH JULIA

###### A BRIEF INTRODUCTION TO JULIA COMPUTING LANGUAGE
3

JULIA

MEDIUM

last hacked on Jul 24, 2017

Julia is a high-level, high-performance, dynamic programming language for numerical computing. It provides a sophisticated compiler, distributed parallel execution, numerical accuracy, and an extensive mathematical function library. Julia’s Base library, largely written in Julia itself, also integrates mature, best-of-breed open source C and Fortran libraries for linear algebra, random number generation, signal processing, and string processing. Basically, if you care about your future and call yourself a decent programmer, you should learn Julia.
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"> </script> # Introduction to Julia *** ## Printing Strings and Things If you are here, you probably already know what Julia is. So, let's jump straight into it and begin with the hardest problem known to a beginner programmer, "Hello World!" julia println("Hello World!")  Hello World! Holy guacomole! We just coded in Julia! Forget the explanation, let's keep going. How about we try our hand at pasting some strings together to form a word we all know very well. julia a = "Con" b = "cat" c = "enate" println(a*b*c) println(uppercase(a*b*c))  Concatenate CONCATENATE ## Arrays I never knew the importance of linear algebra until I started programming. Here are a few examples to kickstart our array-making career in Julia. julia you = [1, 2, 3, 4, 5] are = collect(1:5) learning = [2^i for i in 1:5] hopefully = hcat(you, are, learning)  5×3 Array{Int64,2}: 1 1 2 2 2 4 3 3 8 4 4 16 5 5 32 ## Functions Say we want to define a function that squares a number. Example. $$12^2 = 144$$ Here is how we do that in Julia. julia function number_sqr(x) return x^2 end  number_sqr (generic function with 1 method) julia num_sqr(12)  144 How about we try coding up a function to find the volume of a sphere. Formula. $$\dfrac{4}{3} \pi r^3$$ Notice how we are able to simply write "pi." Julia can interpret Unicode names and symbols. Thus, if we really want to, we could use $\pi$. julia function sphere_volume(r) return 4/3 * pi * r^3 end  sphere_volume (generic function with 1 method) julia sphere_volume(6)  904.7786842338603 ## Loops and Fruits I bought a bunch of fruits today so I decided to use fruits for this example. Let's be honest, nobody wants to loop over boring numbers. julia fruits = ["strawberry", "apple", "blueberry", "cantaloupe", "banana"] for fruit in sort(fruits) print(fruit * " ") end  apple banana blueberry cantaloupe strawberry ## Forget the Basics! # Time to Import Data *** julia using RDatasets iris = dataset("datasets","iris")  <table class="data-frame"><thead><tr><th></th><th>SepalLength</th><th>SepalWidth</th><th>PetalLength</th><th>PetalWidth</th><th>Species</th></tr></thead><tbody><tr><th>1</th><td>5.1</td><td>3.5</td><td>1.4</td><td>0.2</td><td>setosa</td></tr><tr><th>2</th><td>4.9</td><td>3.0</td><td>1.4</td><td>0.2</td><td>setosa</td></tr><tr><th>3</th><td>4.7</td><td>3.2</td><td>1.3</td><td>0.2</td><td>setosa</td></tr><tr><th>4</th><td>4.6</td><td>3.1</td><td>1.5</td><td>0.2</td><td>setosa</td></tr><tr><th>5</th><td>5.0</td><td>3.6</td><td>1.4</td><td>0.2</td><td>setosa</td></tr><tr><th>6</th><td>5.4</td><td>3.9</td><td>1.7</td><td>0.4</td><td>setosa</td></tr><tr><th>7</th><td>4.6</td><td>3.4</td><td>1.4</td><td>0.3</td><td>setosa</td></tr><tr><th>8</th><td>5.0</td><td>3.4</td><td>1.5</td><td>0.2</td><td>setosa</td></tr><tr><th>9</th><td>4.4</td><td>2.9</td><td>1.4</td><td>0.2</td><td>setosa</td></tr><tr><th>10</th><td>4.9</td><td>3.1</td><td>1.5</td><td>0.1</td><td>setosa</td></tr><tr><th>11</th><td>5.4</td><td>3.7</td><td>1.5</td><td>0.2</td><td>setosa</td></tr><tr><th>12</th><td>4.8</td><td>3.4</td><td>1.6</td><td>0.2</td><td>setosa</td></tr><tr><th>13</th><td>4.8</td><td>3.0</td><td>1.4</td><td>0.1</td><td>setosa</td></tr><tr><th>14</th><td>4.3</td><td>3.0</td><td>1.1</td><td>0.1</td><td>setosa</td></tr><tr><th>15</th><td>5.8</td><td>4.0</td><td>1.2</td><td>0.2</td><td>setosa</td></tr><tr><th>16</th><td>5.7</td><td>4.4</td><td>1.5</td><td>0.4</td><td>setosa</td></tr><tr><th>17</th><td>5.4</td><td>3.9</td><td>1.3</td><td>0.4</td><td>setosa</td></tr><tr><th>18</th><td>5.1</td><td>3.5</td><td>1.4</td><td>0.3</td><td>setosa</td></tr><tr><th>19</th><td>5.7</td><td>3.8</td><td>1.7</td><td>0.3</td><td>setosa</td></tr><tr><th>20</th><td>5.1</td><td>3.8</td><td>1.5</td><td>0.3</td><td>setosa</td></tr><tr><th>21</th><td>5.4</td><td>3.4</td><td>1.7</td><td>0.2</td><td>setosa</td></tr><tr><th>22</th><td>5.1</td><td>3.7</td><td>1.5</td><td>0.4</td><td>setosa</td></tr><tr><th>23</th><td>4.6</td><td>3.6</td><td>1.0</td><td>0.2</td><td>setosa</td></tr><tr><th>24</th><td>5.1</td><td>3.3</td><td>1.7</td><td>0.5</td><td>setosa</td></tr><tr><th>25</th><td>4.8</td><td>3.4</td><td>1.9</td><td>0.2</td><td>setosa</td></tr><tr><th>26</th><td>5.0</td><td>3.0</td><td>1.6</td><td>0.2</td><td>setosa</td></tr><tr><th>27</th><td>5.0</td><td>3.4</td><td>1.6</td><td>0.4</td><td>setosa</td></tr><tr><th>28</th><td>5.2</td><td>3.5</td><td>1.5</td><td>0.2</td><td>setosa</td></tr><tr><th>29</th><td>5.2</td><td>3.4</td><td>1.4</td><td>0.2</td><td>setosa</td></tr><tr><th>30</th><td>4.7</td><td>3.2</td><td>1.6</td><td>0.2</td><td>setosa</td></tr><tr><th>&vellip;</th><td>&vellip;</td><td>&vellip;</td><td>&vellip;</td><td>&vellip;</td><td>&vellip;</td></tr></tbody></table> Now we will actually read in our own data using readtable. I have used this a few times simply to test out performance and I can say pandas might be a bit more optimized. But, definitely faster than R. julia df = readtable("/Users/Macbook/Downloads/conf_spurswars.csv")  <table class="data-frame"><thead><tr><th></th><th>Players</th><th>MIN</th><th>_</th><th>OFF</th><th>DEF</th><th>REB</th><th>AST</th><th>STL</th><th>BLK</th><th>TO</th><th>PF</th><th>PTS</th><th>Team</th></tr></thead><tbody><tr><th>1</th><td>Aldridge</td><td>40</td><td>-14</td><td>2</td><td>6</td><td>8</td><td>3</td><td>3</td><td>1</td><td>6</td><td>4</td><td>28</td><td>Spurs</td></tr><tr><th>2</th><td>Mills</td><td>37</td><td>-15</td><td>1</td><td>1</td><td>2</td><td>3</td><td>2</td><td>0</td><td>1</td><td>3</td><td>5</td><td>Spurs</td></tr><tr><th>3</th><td>Green</td><td>33</td><td>-10</td><td>1</td><td>1</td><td>2</td><td>2</td><td>1</td><td>1</td><td>3</td><td>3</td><td>8</td><td>Spurs</td></tr><tr><th>4</th><td>Leonard</td><td>24</td><td>21</td><td>4</td><td>4</td><td>8</td><td>3</td><td>1</td><td>0</td><td>1</td><td>2</td><td>26</td><td>Spurs</td></tr><tr><th>5</th><td>Gasol</td><td>16</td><td>-1</td><td>0</td><td>2</td><td>2</td><td>1</td><td>1</td><td>1</td><td>1</td><td>5</td><td>5</td><td>Spurs</td></tr><tr><th>6</th><td>Ginobili</td><td>26</td><td>4</td><td>0</td><td>1</td><td>1</td><td>1</td><td>3</td><td>0</td><td>2</td><td>2</td><td>17</td><td>Spurs</td></tr><tr><th>7</th><td>Simmons</td><td>26</td><td>-17</td><td>1</td><td>0</td><td>1</td><td>1</td><td>0</td><td>0</td><td>1</td><td>4</td><td>12</td><td>Spurs</td></tr><tr><th>8</th><td>Lee</td><td>16</td><td>15</td><td>3</td><td>4</td><td>7</td><td>1</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>Spurs</td></tr><tr><th>9</th><td>Murray</td><td>13</td><td>7</td><td>1</td><td>1</td><td>2</td><td>2</td><td>1</td><td>1</td><td>1</td><td>1</td><td>6</td><td>Spurs</td></tr><tr><th>10</th><td>Anderson</td><td>9</td><td>-3</td><td>1</td><td>3</td><td>4</td><td>2</td><td>1</td><td>0</td><td>0</td><td>0</td><td>4</td><td>Spurs</td></tr><tr><th>11</th><td>Curry</td><td>39</td><td>8</td><td>2</td><td>5</td><td>7</td><td>3</td><td>3</td><td>0</td><td>4</td><td>0</td><td>40</td><td>Warriors</td></tr><tr><th>12</th><td>Thompson</td><td>39</td><td>5</td><td>1</td><td>3</td><td>4</td><td>3</td><td>3</td><td>2</td><td>2</td><td>5</td><td>6</td><td>Warriors</td></tr><tr><th>13</th><td>Durant</td><td>39</td><td>14</td><td>2</td><td>3</td><td>5</td><td>4</td><td>1</td><td>4</td><td>3</td><td>4</td><td>34</td><td>Warriors</td></tr><tr><th>14</th><td>Green</td><td>37</td><td>3</td><td>3</td><td>4</td><td>7</td><td>7</td><td>2</td><td>0</td><td>3</td><td>5</td><td>9</td><td>Warriors</td></tr><tr><th>15</th><td>Pachulia</td><td>26</td><td>11</td><td>5</td><td>4</td><td>9</td><td>3</td><td>1</td><td>1</td><td>1</td><td>3</td><td>11</td><td>Warriors</td></tr><tr><th>16</th><td>Livingston</td><td>23</td><td>4</td><td>4</td><td>2</td><td>6</td><td>1</td><td>1</td><td>0</td><td>1</td><td>1</td><td>4</td><td>Warriors</td></tr><tr><th>17</th><td>Iguodala</td><td>10</td><td>-19</td><td>0</td><td>0</td><td>0</td><td>1</td><td>1</td><td>0</td><td>1</td><td>0</td><td>2</td><td>Warriors</td></tr><tr><th>18</th><td>Barnes</td><td>10</td><td>1</td><td>0</td><td>2</td><td>2</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>2</td><td>Warriors</td></tr><tr><th>19</th><td>West</td><td>8</td><td>-11</td><td>0</td><td>1</td><td>1</td><td>0</td><td>1</td><td>1</td><td>2</td><td>3</td><td>1</td><td>Warriors</td></tr><tr><th>20</th><td>McGee</td><td>5</td><td>-11</td><td>0</td><td>1</td><td>1</td><td>0</td><td>0</td><td>0</td><td>1</td><td>2</td><td>1</td><td>Warriors</td></tr><tr><th>21</th><td>Clark</td><td>5</td><td>5</td><td>0</td><td>1</td><td>1</td><td>0</td><td>0</td><td>0</td><td>1</td><td>0</td><td>3</td><td>Warriors</td></tr></tbody></table> <h1> Proper Visualizations </h1> julia using DataFrames, JSON  <script>(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var VNode = require('vtree/vnode'); var svg = require('virtual-hyperscript/svg'); var VText = require('vtree/vtext'); var VPatch = require('vtree/vpatch'); var diff = require('virtual-dom/diff'); var patch = require('virtual-dom/patch'); var createElement = require('virtual-dom/create-element'); var nodeIndex = require('./node-index'); var patchVNode = require('./patch-vnode'); var isArray = require('x-is-array'); var isVPatch = require('./is-vpatch'); var P = Patchwork = { nodes: {}, debug: false, Node: function (id, jlNode, el, renderOpts) { if (typeof(el) === "undefined") { el = document.getElementById(id) } this.id = id this.renderOptions = renderOpts if (jlNode) { // Note: makes this.root var vnode = P.makeVNode(jlNode) P.log("makeVNode: ", jlNode, "=>", vnode) this.mount(vnode, el, renderOpts) } P.nodes[id] = this }, NAMESPACES: { "xhtml": null, "svg": "http://www.w3.org/2000/svg", null: null, undefined: null }, refDiff: function (a, b, p) { var a = P.makeVNode(a) b = P.makeVNode(b) p = P.makeVPatches(a, p) console.log(p, diff(a, b)); }, massageProps: function (props) { if ("attributes" in props) { // we can't send undefined over JSON, so we turn nulls into undefs // so that VDom calls removeAttribute on the DOM node. //console.log("attributes ", props.attributes) for (var attr in props.attributes) { if (!props.attributes.hasOwnProperty(attr)) { continue } if (props.attributes[attr] === null) { //console.log("remove ", attr, props.attributes[attr]); props.attributes[attr] = undefined } } } return P.setupHooks(props); }, hooks: {}, register_hook: function (hook, f) { P.hooks[hook] = f; }, setupHooks: function (props) { if (typeof props !== "object" || props == null) { return props; } else if (props && "_hook" in props) { if (props._hook in P.hooks) { v = P.hooks[props._hook](P.setupHooks(props.val)); return v } else { console.warn("Unknown hook " + props._hook + "use Patchwork.register_hook to set it up") return undefined } } else { for (var k in props) { props[k] = P.setupHooks(props[k]); } return props; } }, makeVNode: function (jlNode) { if ('txt' in jlNode) return new VText(jlNode.txt); var children = [], props = P.massageProps(jlNode.p || {}) if (jlNode.c) { for (var i = 0, l = jlNode.c.length; i < l; i++) { children[i] = P.makeVNode(jlNode.c[i]) } } if (jlNode.n === "svg") { return svg(jlNode.t, props, children) } else { var key = null if (props && props.key) { key = props.key delete props.key } return new VNode(jlNode.t, props, children, key, P.NAMESPACES[jlNode.n]); } }, makeVPatches: function (root, jlPatches) { var indices = []; var vpatches = {a: root} for (var idx in jlPatches) { if (!jlPatches.hasOwnProperty(idx)) { continue } indices.push(Number(idx)) } nodes = nodeIndex(root, indices) for (var idx in jlPatches) { vpatches[idx] = P.makeVPatch(nodes[idx], jlPatches[idx]); } return vpatches }, makeVPatch: function (vnode, jlPatch) { if (isArray(jlPatch)) { // multiple patches to the same VNode var ps = []; for (var i=0, l=jlPatch.length; i < l; i++) { ps[i] = P.makeVPatch(vnode, jlPatch[i]) } return ps } var type, patch; for (var k in jlPatch) { type = k; patch = jlPatch[k]; break; // inorite? } function vpatch(p) { return new VPatch(type, vnode, p); } switch (Number(type)) { case VPatch.VTEXT: return vpatch(new VText(patch)); case VPatch.VNODE: return vpatch(P.makeVNode(patch)); case VPatch.PROPS: patch = P.massageProps(patch) if (vnode.namespace === P.NAMESPACES["svg"]) { patch = svg('dummy', patch, []).properties } return vpatch(patch); case VPatch.ORDER: return vpatch(patch); case VPatch.INSERT: return vpatch(P.makeVNode(patch)); case VPatch.REMOVE: return vpatch(null); default: return null; } }, log: function () { if (console && P.debug) { console.log.apply(console, arguments); } } } Patchwork.Node.prototype = { mount: function (vnode, outer, renderOpts) { var el = createElement(vnode, renderOpts); P.log("createElement: ", vnode, "=>", el) outer.appendChild(el) this.element = el this.root = vnode; return el; }, applyPatch: function (vpatches) { // apply patch to DOM nodes if (!isVPatch(vpatches)) { vpatches = P.makeVPatches(this.root, vpatches) } this.element = patch(this.element, vpatches, this.renderOptions) this.root = patchVNode(this.root, vpatches) } } function init(nb, cue) { if (!Patchwork.inited) { try { console.log("attempting Patchwork setup, cue:", cue) var commMgr = nb.kernel.comm_manager; commMgr.register_target("PatchStream", function (comm, msg) { var nodeId = msg.content.data.pwid; comm.on_msg(function (msg) { var node = P.nodes[nodeId], patches = msg.content.data node.applyPatch(patches) P.log("received patches", patches) }); }); Patchwork.inited = true; } catch (e) { Patchwork.inited = false; console.log("ERROR initializing patchwork: ", e); console.log("attempting failed, cue:", cue) } } } // IJulia setup if (typeof(window.IPython) !== "undefined") { init(IPython.notebook, "immediate"); $(document).ready(function () { init(IPython.notebook, "document ready"); });$([IPython.events]).on("kernel_ready.Kernel kernel_created.Kernel", function (evt, nb) { init(nb, "kernel start") }) } window.Patchwork = Patchwork; },{"./is-vpatch":2,"./node-index":3,"./patch-vnode":58,"virtual-dom/create-element":5,"virtual-dom/diff":6,"virtual-dom/patch":23,"virtual-hyperscript/svg":47,"vtree/vnode":53,"vtree/vpatch":54,"vtree/vtext":55,"x-is-array":56}],2:[function(require,module,exports){ var version = require("vtree/version") module.exports = isVirtualPatch function isVirtualPatch(x) { return x && x.type === "VirtualPatch" && x.version === version } },{"vtree/version":52}],3:[function(require,module,exports){ module.exports = nodeIndex function nodeIndex(tree, indices, nodes) { if (!indices || indices.length === 0) { return {} } else { indices.sort(ascending) return recurse(tree, indices, nodes, 0) } } function recurse(tree, indices, nodes, rootIndex) { nodes = nodes || {} if (tree) { if (indexInRange(indices, rootIndex, rootIndex)) { nodes[rootIndex] = tree } var vChildren = tree.children if (vChildren) { for (var i = 0; i < vChildren.length; i++) { rootIndex += 1 var vChild = vChildren[i] var nextIndex = rootIndex + (vChild.count || 0) // skip recursion down the tree if there are no nodes down here if (indexInRange(indices, rootIndex, nextIndex)) { recurse(vChild, indices, nodes, rootIndex) } rootIndex = nextIndex } } } else { rootIndex } return nodes } // Binary search for an index in the interval [left, right] function indexInRange(indices, left, right) { if (indices.length === 0) { return false } var minIndex = 0 var maxIndex = indices.length - 1 var currentIndex var currentItem while (minIndex <= maxIndex) { currentIndex = ((maxIndex + minIndex) / 2) >> 0 currentItem = indices[currentIndex] if (minIndex === maxIndex) { return currentItem >= left && currentItem <= right } else if (currentItem < left) { minIndex = currentIndex + 1 } else if (currentItem > right) { maxIndex = currentIndex - 1 } else { return true } } return false; } function ascending(a, b) { return a > b ? 1 : -1 } },{}],4:[function(require,module,exports){ module.exports = isObject function isObject(x) { return typeof x === "object" && x !== null } },{}],5:[function(require,module,exports){ var createElement = require("vdom/create-element") module.exports = createElement },{"vdom/create-element":8}],6:[function(require,module,exports){ var diff = require("vtree/diff") module.exports = diff },{"vtree/diff":14}],7:[function(require,module,exports){ var isObject = require("is-object") var isHook = require("vtree/is-vhook") module.exports = applyProperties function applyProperties(node, props, previous, renderOptions) { var domNode = renderOptions && renderOptions.extractNode ? renderOptions.extractNode(node) : node for (var propName in props) { var propValue = props[propName] if (propValue === undefined) { removeProperty(domNode, props, previous, propName); } else if (isHook(propValue)) { propValue.hook(domNode, propName, previous ? previous[propName] : undefined) } else { if (isObject(propValue)) { patchObject(domNode, props, previous, propName, propValue); } else if (propValue !== undefined) { domNode[propName] = propValue } } } } function removeProperty(node, props, previous, propName) { if (previous) { var previousValue = previous[propName] if (!isHook(previousValue)) { if (propName === "attributes") { for (var attrName in previousValue) { node.removeAttribute(attrName) } } else if (propName === "style") { for (var i in previousValue) { node.style[i] = "" } } else if (typeof previousValue === "string") { node[propName] = "" } else { node[propName] = null } } } } function patchObject(node, props, previous, propName, propValue) { var previousValue = previous ? previous[propName] : undefined // Set attributes if (propName === "attributes") { for (var attrName in propValue) { var attrValue = propValue[attrName] if (attrValue === undefined) { node.removeAttribute(attrName) } else { node.setAttribute(attrName, attrValue) } } return } if(previousValue && isObject(previousValue) && getPrototype(previousValue) !== getPrototype(propValue)) { node[propName] = propValue return } if (!isObject(node[propName])) { node[propName] = {} } var replacer = propName === "style" ? "" : undefined for (var k in propValue) { var value = propValue[k] node[propName][k] = (value === undefined) ? replacer : value } } function getPrototype(value) { if (Object.getPrototypeOf) { return Object.getPrototypeOf(value) } else if (value.__proto__) { return value.__proto__ } else if (value.constructor) { return value.constructor.prototype } } },{"is-object":4,"vtree/is-vhook":17}],8:[function(require,module,exports){ var document = require("global/document") var applyProperties = require("./apply-properties") var isVNode = require("vtree/is-vnode") var isVText = require("vtree/is-vtext") var isWidget = require("vtree/is-widget") var handleThunk = require("vtree/handle-thunk") module.exports = createElement function id(x) { return x } function createElement(vnode, opts) { var doc = opts ? opts.document || document : document var warn = opts ? opts.warn : null vnode = handleThunk(vnode).a if (isWidget(vnode)) { return vnode.init() } else if (isVText(vnode)) { return doc.createTextNode(vnode.text) } else if (!isVNode(vnode)) { if (warn) { warn("Item is not a valid virtual dom node", vnode) } return null } var node = (vnode.namespace === null) ? doc.createElement(vnode.tagName, vnode.properties.is) : doc.createElementNS(vnode.namespace, vnode.tagName) var props = vnode.properties applyProperties(node, props, null, opts) var children = vnode.children for (var i = 0; i < children.length; i++) { var childNode = createElement(children[i], opts) if (childNode) { node.appendChild(childNode) } } return node } },{"./apply-properties":7,"global/document":10,"vtree/handle-thunk":15,"vtree/is-vnode":18,"vtree/is-vtext":19,"vtree/is-widget":20}],9:[function(require,module,exports){ // Maps a virtual DOM tree onto a real DOM tree in an efficient manner. // We don't want to read all of the DOM nodes in the tree so we use // the in-order tree indexing to eliminate recursion down certain branches. // We only recurse into a DOM node if we know that it contains a child of // interest. var noChild = {} module.exports = domIndex function domIndex(rootNode, tree, indices, nodes) { if (!indices || indices.length === 0) { return {} } else { indices.sort(ascending) return recurse(rootNode, tree, indices, nodes, 0) } } function recurse(rootNode, tree, indices, nodes, rootIndex) { nodes = nodes || {} if (rootNode) { if (indexInRange(indices, rootIndex, rootIndex)) { nodes[rootIndex] = rootNode } var vChildren = tree.children if (vChildren) { var childNodes = rootNode.childNodes for (var i = 0; i < tree.children.length; i++) { rootIndex += 1 var vChild = vChildren[i] || noChild var nextIndex = rootIndex + (vChild.count || 0) // skip recursion down the tree if there are no nodes down here if (indexInRange(indices, rootIndex, nextIndex)) { recurse(childNodes[i], vChild, indices, nodes, rootIndex) } rootIndex = nextIndex } } } return nodes } // Binary search for an index in the interval [left, right] function indexInRange(indices, left, right) { if (indices.length === 0) { return false } var minIndex = 0 var maxIndex = indices.length - 1 var currentIndex var currentItem while (minIndex <= maxIndex) { currentIndex = ((maxIndex + minIndex) / 2) >> 0 currentItem = indices[currentIndex] if (minIndex === maxIndex) { return currentItem >= left && currentItem <= right } else if (currentItem < left) { minIndex = currentIndex + 1 } else if (currentItem > right) { maxIndex = currentIndex - 1 } else { return true } } return false; } function ascending(a, b) { return a > b ? 1 : -1 } },{}],10:[function(require,module,exports){ (function (global){ var topLevel = typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : {} var minDoc = require('min-document'); if (typeof document !== 'undefined') { module.exports = document; } else { var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; if (!doccy) { doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; } module.exports = doccy; } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"min-document":60}],11:[function(require,module,exports){ var applyProperties = require("./apply-properties") var isWidget = require("vtree/is-widget") var VPatch = require("vtree/vpatch") var render = require("./create-element") var updateWidget = require("./update-widget") module.exports = applyPatch function applyPatch(vpatch, domNode, renderOptions) { var type = vpatch.type var vNode = vpatch.vNode var patch = vpatch.patch switch (type) { case VPatch.REMOVE: return removeNode(domNode, vNode) case VPatch.INSERT: return insertNode(domNode, patch, renderOptions) case VPatch.VTEXT: return stringPatch(domNode, vNode, patch, renderOptions) case VPatch.WIDGET: return widgetPatch(domNode, vNode, patch, renderOptions) case VPatch.VNODE: return vNodePatch(domNode, vNode, patch, renderOptions) case VPatch.ORDER: reorderChildren(domNode, patch) return domNode case VPatch.PROPS: applyProperties(domNode, patch, vNode.properties, renderOptions) return domNode case VPatch.THUNK: return replaceRoot(domNode, renderOptions.patch(domNode, patch, renderOptions)) default: return domNode } } function removeNode(domNode, vNode) { var parentNode = domNode.parentNode if (parentNode) { parentNode.removeChild(domNode) } destroyWidget(domNode, vNode); return null } function insertNode(parentNode, vNode, renderOptions) { var newNode = render(vNode, renderOptions) if (parentNode) { parentNode.appendChild(newNode) } return parentNode } function stringPatch(domNode, leftVNode, vText, renderOptions) { var newNode if (domNode.nodeType === 3) { domNode.replaceData(0, domNode.length, vText.text) newNode = domNode } else { var parentNode = domNode.parentNode newNode = render(vText, renderOptions) if (parentNode) { parentNode.replaceChild(newNode, domNode) } } destroyWidget(domNode, leftVNode) return newNode } function widgetPatch(domNode, leftVNode, widget, renderOptions) { if (updateWidget(leftVNode, widget)) { return widget.update(leftVNode, domNode) || domNode } var parentNode = domNode.parentNode var newWidget = render(widget, renderOptions) if (parentNode) { parentNode.replaceChild(newWidget, domNode) } destroyWidget(domNode, leftVNode) return newWidget } function vNodePatch(domNode, leftVNode, vNode, renderOptions) { var parentNode = domNode.parentNode var newNode = render(vNode, renderOptions) if (parentNode) { parentNode.replaceChild(newNode, domNode) } destroyWidget(domNode, leftVNode) return newNode } function destroyWidget(domNode, w) { if (typeof w.destroy === "function" && isWidget(w)) { w.destroy(domNode) } } function reorderChildren(domNode, bIndex) { var children = [] var childNodes = domNode.childNodes var len = childNodes.length var i var reverseIndex = bIndex.reverse for (i = 0; i < len; i++) { children.push(domNode.childNodes[i]) } var insertOffset = 0 var move var node var insertNode for (i = 0; i < len; i++) { move = bIndex[i] if (move !== undefined && move !== i) { // the element currently at this index will be moved later so increase the insert offset if (reverseIndex[i] > i) { insertOffset++ } node = children[move] insertNode = childNodes[i + insertOffset] || null if (node !== insertNode) { domNode.insertBefore(node, insertNode) } // the moved element came from the front of the array so reduce the insert offset if (move < i) { insertOffset-- } } // element at this index is scheduled to be removed so increase insert offset if (i in bIndex.removes) { insertOffset++ } } } function replaceRoot(oldRoot, newRoot) { if (oldRoot && newRoot && oldRoot !== newRoot && oldRoot.parentNode) { console.log(oldRoot) oldRoot.parentNode.replaceChild(newRoot, oldRoot) } return newRoot; } },{"./apply-properties":7,"./create-element":8,"./update-widget":13,"vtree/is-widget":20,"vtree/vpatch":22}],12:[function(require,module,exports){ var document = require("global/document") var isArray = require("x-is-array") var domIndex = require("./dom-index") var patchOp = require("./patch-op") module.exports = patch function patch(rootNode, patches, renderOptions) { return patchRecursive(rootNode, patches, renderOptions) } function patchRecursive(rootNode, patches, renderOptions) { var indices = patchIndices(patches) if (indices.length === 0) { return rootNode } var index = domIndex(rootNode, patches.a, indices) var ownerDocument = rootNode.ownerDocument if (!renderOptions) { renderOptions = {} if (ownerDocument !== document) { renderOptions.document = ownerDocument } } if (!renderOptions.patch) { renderOptions.patch = patchRecursive } for (var i = 0; i < indices.length; i++) { var nodeIndex = indices[i] rootNode = applyPatch(rootNode, index[nodeIndex], patches[nodeIndex], renderOptions) } return rootNode } function applyPatch(rootNode, domNode, patchList, renderOptions) { if (!domNode) { return rootNode } var newNode if (isArray(patchList)) { for (var i = 0; i < patchList.length; i++) { newNode = patchOp(patchList[i], domNode, renderOptions) if (domNode === rootNode) { rootNode = newNode } } } else { newNode = patchOp(patchList, domNode, renderOptions) if (domNode === rootNode) { rootNode = newNode } } return rootNode } function patchIndices(patches) { var indices = [] for (var key in patches) { if (key !== "a") { indices.push(Number(key)) } } return indices } },{"./dom-index":9,"./patch-op":11,"global/document":10,"x-is-array":56}],13:[function(require,module,exports){ var isWidget = require("vtree/is-widget") module.exports = updateWidget function updateWidget(a, b) { if (isWidget(a) && isWidget(b)) { if ("name" in a && "name" in b) { return a.id === b.id } else { return a.init === b.init } } return false } },{"vtree/is-widget":20}],14:[function(require,module,exports){ var isArray = require("x-is-array") var isObject = require("is-object") var VPatch = require("./vpatch") var isVNode = require("./is-vnode") var isVText = require("./is-vtext") var isWidget = require("./is-widget") var isThunk = require("./is-thunk") var handleThunk = require("./handle-thunk") module.exports = diff function diff(a, b) { var patch = { a: a } walk(a, b, patch, 0) return patch } function walk(a, b, patch, index) { if (a === b) { if (isThunk(a) || isThunk(b)) { thunks(a, b, patch, index) } else { hooks(b, patch, index) } return } var apply = patch[index] if (b == null) { apply = appendPatch(apply, new VPatch(VPatch.REMOVE, a, b)) destroyWidgets(a, patch, index) } else if (isThunk(a) || isThunk(b)) { thunks(a, b, patch, index) } else if (isVNode(b)) { if (isVNode(a)) { if (a.tagName === b.tagName && a.namespace === b.namespace && a.key === b.key) { var propsPatch = diffProps(a.properties, b.properties, b.hooks) if (propsPatch) { apply = appendPatch(apply, new VPatch(VPatch.PROPS, a, propsPatch)) } apply = diffChildren(a, b, patch, apply, index) } else { apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b)) destroyWidgets(a, patch, index) } } else { apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b)) destroyWidgets(a, patch, index) } } else if (isVText(b)) { if (!isVText(a)) { apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b)) destroyWidgets(a, patch, index) } else if (a.text !== b.text) { apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b)) } } else if (isWidget(b)) { apply = appendPatch(apply, new VPatch(VPatch.WIDGET, a, b)) if (!isWidget(a)) { destroyWidgets(a, patch, index) } } if (apply) { patch[index] = apply } } function diffProps(a, b, hooks) { var diff for (var aKey in a) { if (!(aKey in b)) { diff = diff || {} diff[aKey] = undefined } var aValue = a[aKey] var bValue = b[aKey] if (hooks && aKey in hooks) { diff = diff || {} diff[aKey] = bValue } else { if (isObject(aValue) && isObject(bValue)) { if (getPrototype(bValue) !== getPrototype(aValue)) { diff = diff || {} diff[aKey] = bValue } else { var objectDiff = diffProps(aValue, bValue) if (objectDiff) { diff = diff || {} diff[aKey] = objectDiff } } } else if (aValue !== bValue) { diff = diff || {} diff[aKey] = bValue } } } for (var bKey in b) { if (!(bKey in a)) { diff = diff || {} diff[bKey] = b[bKey] } } return diff } function getPrototype(value) { if (Object.getPrototypeOf) { return Object.getPrototypeOf(value) } else if (value.__proto__) { return value.__proto__ } else if (value.constructor) { return value.constructor.prototype } } function diffChildren(a, b, patch, apply, index) { var aChildren = a.children var bChildren = reorder(aChildren, b.children) var aLen = aChildren.length var bLen = bChildren.length var len = aLen > bLen ? aLen : bLen for (var i = 0; i < len; i++) { var leftNode = aChildren[i] var rightNode = bChildren[i] index += 1 if (!leftNode) { if (rightNode) { // Excess nodes in b need to be added apply = appendPatch(apply, new VPatch(VPatch.INSERT, null, rightNode)) } } else if (!rightNode) { if (leftNode) { // Excess nodes in a need to be removed patch[index] = new VPatch(VPatch.REMOVE, leftNode, null) destroyWidgets(leftNode, patch, index) } } else { walk(leftNode, rightNode, patch, index) } if (isVNode(leftNode) && leftNode.count) { index += leftNode.count } } if (bChildren.moves) { // Reorder nodes last apply = appendPatch(apply, new VPatch(VPatch.ORDER, a, bChildren.moves)) } return apply } // Patch records for all destroyed widgets must be added because we need // a DOM node reference for the destroy function function destroyWidgets(vNode, patch, index) { if (isWidget(vNode)) { if (typeof vNode.destroy === "function") { patch[index] = new VPatch(VPatch.REMOVE, vNode, null) } } else if (isVNode(vNode) && vNode.hasWidgets) { var children = vNode.children var len = children.length for (var i = 0; i < len; i++) { var child = children[i] index += 1 destroyWidgets(child, patch, index) if (isVNode(child) && child.count) { index += child.count } } } } // Create a sub-patch for thunks function thunks(a, b, patch, index) { var nodes = handleThunk(a, b); var thunkPatch = diff(nodes.a, nodes.b) if (hasPatches(thunkPatch)) { patch[index] = new VPatch(VPatch.THUNK, null, thunkPatch) } } function hasPatches(patch) { for (var index in patch) { if (index !== "a") { return true; } } return false; } // Execute hooks when two nodes are identical function hooks(vNode, patch, index) { if (isVNode(vNode)) { if (vNode.hooks) { patch[index] = new VPatch(VPatch.PROPS, vNode.hooks, vNode.hooks) } if (vNode.descendantHooks) { var children = vNode.children var len = children.length for (var i = 0; i < len; i++) { var child = children[i] index += 1 hooks(child, patch, index) if (isVNode(child) && child.count) { index += child.count } } } } } // List diff, naive left to right reordering function reorder(aChildren, bChildren) { var bKeys = keyIndex(bChildren) if (!bKeys) { return bChildren } var aKeys = keyIndex(aChildren) if (!aKeys) { return bChildren } var bMatch = {}, aMatch = {} for (var key in bKeys) { bMatch[bKeys[key]] = aKeys[key] } for (var key in aKeys) { aMatch[aKeys[key]] = bKeys[key] } var aLen = aChildren.length var bLen = bChildren.length var len = aLen > bLen ? aLen : bLen var shuffle = [] var freeIndex = 0 var i = 0 var moveIndex = 0 var moves = {} var removes = moves.removes = {} var reverse = moves.reverse = {} var hasMoves = false while (freeIndex < len) { var move = aMatch[i] if (move !== undefined) { shuffle[i] = bChildren[move] if (move !== moveIndex) { moves[move] = moveIndex reverse[moveIndex] = move hasMoves = true } moveIndex++ } else if (i in aMatch) { shuffle[i] = undefined removes[i] = moveIndex++ hasMoves = true } else { while (bMatch[freeIndex] !== undefined) { freeIndex++ } if (freeIndex < len) { var freeChild = bChildren[freeIndex] if (freeChild) { shuffle[i] = freeChild if (freeIndex !== moveIndex) { hasMoves = true moves[freeIndex] = moveIndex reverse[moveIndex] = freeIndex } moveIndex++ } freeIndex++ } } i++ } if (hasMoves) { shuffle.moves = moves } return shuffle } function keyIndex(children) { var i, keys for (i = 0; i < children.length; i++) { var child = children[i] if (child.key !== undefined) { keys = keys || {} keys[child.key] = i } } return keys } function appendPatch(apply, patch) { if (apply) { if (isArray(apply)) { apply.push(patch) } else { apply = [apply, patch] } return apply } else { return patch } } },{"./handle-thunk":15,"./is-thunk":16,"./is-vnode":18,"./is-vtext":19,"./is-widget":20,"./vpatch":22,"is-object":4,"x-is-array":56}],15:[function(require,module,exports){ var isVNode = require("./is-vnode") var isVText = require("./is-vtext") var isWidget = require("./is-widget") var isThunk = require("./is-thunk") module.exports = handleThunk function handleThunk(a, b) { var renderedA = a var renderedB = b if (isThunk(b)) { renderedB = renderThunk(b, a) } if (isThunk(a)) { renderedA = renderThunk(a, null) } return { a: renderedA, b: renderedB } } function renderThunk(thunk, previous) { var renderedThunk = thunk.vnode if (!renderedThunk) { renderedThunk = thunk.vnode = thunk.render(previous) } if (!(isVNode(renderedThunk) || isVText(renderedThunk) || isWidget(renderedThunk))) { throw new Error("thunk did not return a valid node"); } return renderedThunk } },{"./is-thunk":16,"./is-vnode":18,"./is-vtext":19,"./is-widget":20}],16:[function(require,module,exports){ module.exports = isThunk function isThunk(t) { return t && t.type === "Thunk" } },{}],17:[function(require,module,exports){ module.exports = isHook function isHook(hook) { return hook && typeof hook.hook === "function" && !hook.hasOwnProperty("hook") } },{}],18:[function(require,module,exports){ var version = require("./version") module.exports = isVirtualNode function isVirtualNode(x) { return x && x.type === "VirtualNode" && x.version === version } },{"./version":21}],19:[function(require,module,exports){ var version = require("./version") module.exports = isVirtualText function isVirtualText(x) { return x && x.type === "VirtualText" && x.version === version } },{"./version":21}],20:[function(require,module,exports){ module.exports = isWidget function isWidget(w) { return w && w.type === "Widget" } },{}],21:[function(require,module,exports){ module.exports = "1" },{}],22:[function(require,module,exports){ var version = require("./version") VirtualPatch.NONE = 0 VirtualPatch.VTEXT = 1 VirtualPatch.VNODE = 2 VirtualPatch.WIDGET = 3 VirtualPatch.PROPS = 4 VirtualPatch.ORDER = 5 VirtualPatch.INSERT = 6 VirtualPatch.REMOVE = 7 VirtualPatch.THUNK = 8 module.exports = VirtualPatch function VirtualPatch(type, vNode, patch) { this.type = Number(type) this.vNode = vNode this.patch = patch } VirtualPatch.prototype.version = version VirtualPatch.prototype.type = "VirtualPatch" },{"./version":21}],23:[function(require,module,exports){ var patch = require("vdom/patch") module.exports = patch },{"vdom/patch":12}],24:[function(require,module,exports){ module.exports = AttributeHook; function AttributeHook(value) { if (!(this instanceof AttributeHook)) { return new AttributeHook(value); } this.value = value; } AttributeHook.prototype.hook = function (node, prop, prev) { if (prev && prev.value === this.value) { return; } node.setAttributeNS(null, prop, this.value) } },{}],25:[function(require,module,exports){ var DataSet = require("data-set") module.exports = DataSetHook; function DataSetHook(value) { if (!(this instanceof DataSetHook)) { return new DataSetHook(value); } this.value = value; } DataSetHook.prototype.hook = function (node, propertyName) { var ds = DataSet(node) var propName = propertyName.substr(5) ds[propName] = this.value; }; },{"data-set":30}],26:[function(require,module,exports){ var DataSet = require("data-set") module.exports = DataSetHook; function DataSetHook(value) { if (!(this instanceof DataSetHook)) { return new DataSetHook(value); } this.value = value; } DataSetHook.prototype.hook = function (node, propertyName) { var ds = DataSet(node) var propName = propertyName.substr(3) ds[propName] = this.value; }; },{"data-set":30}],27:[function(require,module,exports){ module.exports = SoftSetHook; function SoftSetHook(value) { if (!(this instanceof SoftSetHook)) { return new SoftSetHook(value); } this.value = value; } SoftSetHook.prototype.hook = function (node, propertyName) { if (node[propertyName] !== this.value) { node[propertyName] = this.value; } }; },{}],28:[function(require,module,exports){ var VNode = require("vtree/vnode.js") var VText = require("vtree/vtext.js") var isVNode = require("vtree/is-vnode") var isVText = require("vtree/is-vtext") var isWidget = require("vtree/is-widget") var isHook = require("vtree/is-vhook") var isVThunk = require("vtree/is-thunk") var TypedError = require("error/typed") var parseTag = require("./parse-tag.js") var softSetHook = require("./hooks/soft-set-hook.js") var dataSetHook = require("./hooks/data-set-hook.js") var evHook = require("./hooks/ev-hook.js") var UnexpectedVirtualElement = TypedError({ type: "virtual-hyperscript.unexpected.virtual-element", message: "Unexpected virtual child passed to h().\n" + "Expected a VNode / Vthunk / VWidget / string but:\n" + "got a {foreignObjectStr}.\n" + "The parent vnode is {parentVnodeStr}.\n" + "Suggested fix: change your h(..., [ ... ]) callsite.", foreignObjectStr: null, parentVnodeStr: null, foreignObject: null, parentVnode: null }) module.exports = h function h(tagName, properties, children) { var childNodes = [] var tag, props, key, namespace if (!children && isChildren(properties)) { children = properties props = {} } props = props || properties || {} tag = parseTag(tagName, props) // support keys if ("key" in props) { key = props.key props.key = undefined } // support namespace if ("namespace" in props) { namespace = props.namespace props.namespace = undefined } // fix cursor bug if (tag === "input" && "value" in props && props.value !== undefined && !isHook(props.value) ) { props.value = softSetHook(props.value) } var keys = Object.keys(props) var propName, value for (var j = 0; j < keys.length; j++) { propName = keys[j] value = props[propName] if (isHook(value)) { continue } // add data-foo support if (propName.substr(0, 5) === "data-") { props[propName] = dataSetHook(value) } // add ev-foo support if (propName.substr(0, 3) === "ev-") { props[propName] = evHook(value) } } if (children !== undefined && children !== null) { addChild(children, childNodes, tag, props) } var node = new VNode(tag, props, childNodes, key, namespace) return node } function addChild(c, childNodes, tag, props) { if (typeof c === "string") { childNodes.push(new VText(c)) } else if (isChild(c)) { childNodes.push(c) } else if (Array.isArray(c)) { for (var i = 0; i < c.length; i++) { addChild(c[i], childNodes, tag, props) } } else if (c === null || c === undefined) { return } else { throw UnexpectedVirtualElement({ foreignObjectStr: JSON.stringify(c), foreignObject: c, parentVnodeStr: JSON.stringify({ tagName: tag, properties: props }), parentVnode: { tagName: tag, properties: props } }) } } function isChild(x) { return isVNode(x) || isVText(x) || isWidget(x) || isVThunk(x) } function isChildren(x) { return typeof x === "string" || Array.isArray(x) || isChild(x) } },{"./hooks/data-set-hook.js":25,"./hooks/ev-hook.js":26,"./hooks/soft-set-hook.js":27,"./parse-tag.js":46,"error/typed":37,"vtree/is-thunk":38,"vtree/is-vhook":39,"vtree/is-vnode":40,"vtree/is-vtext":41,"vtree/is-widget":42,"vtree/vnode.js":44,"vtree/vtext.js":45}],29:[function(require,module,exports){ module.exports = createHash function createHash(elem) { var attributes = elem.attributes var hash = {} if (attributes === null || attributes === undefined) { return hash } for (var i = 0; i < attributes.length; i++) { var attr = attributes[i] if (attr.name.substr(0,5) !== "data-") { continue } hash[attr.name.substr(5)] = attr.value } return hash } },{}],30:[function(require,module,exports){ var createStore = require("weakmap-shim/create-store") var Individual = require("individual") var createHash = require("./create-hash.js") var hashStore = Individual("__DATA_SET_WEAKMAP@3", createStore()) module.exports = DataSet function DataSet(elem) { var store = hashStore(elem) if (!store.hash) { store.hash = createHash(elem) } return store.hash } },{"./create-hash.js":29,"individual":31,"weakmap-shim/create-store":32}],31:[function(require,module,exports){ (function (global){ var root = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : {}; module.exports = Individual function Individual(key, value) { if (root[key]) { return root[key] } Object.defineProperty(root, key, { value: value , configurable: true }) return value } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],32:[function(require,module,exports){ var hiddenStore = require('./hidden-store.js'); module.exports = createStore; function createStore() { var key = {}; return function (obj) { if (typeof obj !== 'object' || obj === null) { throw new Error('Weakmap-shim: Key must be object') } var store = obj.valueOf(key); return store && store.identity === key ? store : hiddenStore(obj, key); }; } },{"./hidden-store.js":33}],33:[function(require,module,exports){ module.exports = hiddenStore; function hiddenStore(obj, key) { var store = { identity: key }; var valueOf = obj.valueOf; Object.defineProperty(obj, "valueOf", { value: function (value) { return value !== key ? valueOf.apply(this, arguments) : store; }, writable: true }); return store; } },{}],34:[function(require,module,exports){ module.exports = function(obj) { if (typeof obj === 'string') return camelCase(obj); return walk(obj); }; function walk (obj) { if (!obj || typeof obj !== 'object') return obj; if (isDate(obj) || isRegex(obj)) return obj; if (isArray(obj)) return map(obj, walk); return reduce(objectKeys(obj), function (acc, key) { var camel = camelCase(key); acc[camel] = walk(obj[key]); return acc; }, {}); } function camelCase(str) { return str.replace(/[_.-](\w|\$)/g, function (_,x) { return x.toUpperCase(); }); } var isArray = Array.isArray || function (obj) { return Object.prototype.toString.call(obj) === '[object Array]'; }; var isDate = function (obj) { return Object.prototype.toString.call(obj) === '[object Date]'; }; var isRegex = function (obj) { return Object.prototype.toString.call(obj) === '[object RegExp]'; }; var has = Object.prototype.hasOwnProperty; var objectKeys = Object.keys || function (obj) { var keys = []; for (var key in obj) { if (has.call(obj, key)) keys.push(key); } return keys; }; function map (xs, f) { if (xs.map) return xs.map(f); var res = []; for (var i = 0; i < xs.length; i++) { res.push(f(xs[i], i)); } return res; } function reduce (xs, f, acc) { if (xs.reduce) return xs.reduce(f, acc); for (var i = 0; i < xs.length; i++) { acc = f(acc, xs[i], i); } return acc; } },{}],35:[function(require,module,exports){ var nargs = /\{([0-9a-zA-Z]+)\}/g var slice = Array.prototype.slice module.exports = template function template(string) { var args if (arguments.length === 2 && typeof arguments[1] === "object") { args = arguments[1] } else { args = slice.call(arguments, 1) } if (!args || !args.hasOwnProperty) { args = {} } return string.replace(nargs, function replaceArg(match, i, index) { var result if (string[index - 1] === "{" && string[index + match.length] === "}") { return i } else { result = args.hasOwnProperty(i) ? args[i] : null if (result === null || result === undefined) { return "" } return result } }) } },{}],36:[function(require,module,exports){ module.exports = extend function extend(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] for (var key in source) { if (source.hasOwnProperty(key)) { target[key] = source[key] } } } return target } },{}],37:[function(require,module,exports){ var camelize = require("camelize") var template = require("string-template") var extend = require("xtend/mutable") module.exports = TypedError function TypedError(args) { if (!args) { throw new Error("args is required"); } if (!args.type) { throw new Error("args.type is required"); } if (!args.message) { throw new Error("args.message is required"); } var message = args.message if (args.type && !args.name) { var errorName = camelize(args.type) + "Error" args.name = errorName[0].toUpperCase() + errorName.substr(1) } createError.type = args.type; createError._name = args.name; return createError; function createError(opts) { var result = new Error() Object.defineProperty(result, "type", { value: result.type, enumerable: true, writable: true, configurable: true }) var options = extend({}, args, opts) extend(result, options) result.message = template(message, options) return result } } },{"camelize":34,"string-template":35,"xtend/mutable":36}],38:[function(require,module,exports){ module.exports=require(16) },{"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-thunk.js":16}],39:[function(require,module,exports){ module.exports=require(17) },{"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-vhook.js":17}],40:[function(require,module,exports){ module.exports=require(18) },{"./version":43,"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-vnode.js":18}],41:[function(require,module,exports){ module.exports=require(19) },{"./version":43,"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-vtext.js":19}],42:[function(require,module,exports){ module.exports=require(20) },{"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-widget.js":20}],43:[function(require,module,exports){ module.exports=require(21) },{"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/version.js":21}],44:[function(require,module,exports){ var version = require("./version") var isVNode = require("./is-vnode") var isWidget = require("./is-widget") var isVHook = require("./is-vhook") module.exports = VirtualNode var noProperties = {} var noChildren = [] function VirtualNode(tagName, properties, children, key, namespace) { this.tagName = tagName this.properties = properties || noProperties this.children = children || noChildren this.key = key != null ? String(key) : undefined this.namespace = (typeof namespace === "string") ? namespace : null var count = (children && children.length) || 0 var descendants = 0 var hasWidgets = false var descendantHooks = false var hooks for (var propName in properties) { if (properties.hasOwnProperty(propName)) { var property = properties[propName] if (isVHook(property)) { if (!hooks) { hooks = {} } hooks[propName] = property } } } for (var i = 0; i < count; i++) { var child = children[i] if (isVNode(child)) { descendants += child.count || 0 if (!hasWidgets && child.hasWidgets) { hasWidgets = true } if (!descendantHooks && (child.hooks || child.descendantHooks)) { descendantHooks = true } } else if (!hasWidgets && isWidget(child)) { if (typeof child.destroy === "function") { hasWidgets = true } } } this.count = count + descendants this.hasWidgets = hasWidgets this.hooks = hooks this.descendantHooks = descendantHooks } VirtualNode.prototype.version = version VirtualNode.prototype.type = "VirtualNode" },{"./is-vhook":39,"./is-vnode":40,"./is-widget":42,"./version":43}],45:[function(require,module,exports){ var version = require("./version") module.exports = VirtualText function VirtualText(text) { this.text = String(text) } VirtualText.prototype.version = version VirtualText.prototype.type = "VirtualText" },{"./version":43}],46:[function(require,module,exports){ var classIdSplit = /([\.#]?[a-zA-Z0-9_:-]+)/ var notClassId = /^\.|#/ module.exports = parseTag function parseTag(tag, props) { if (!tag) { return "div" } var noId = !("id" in props) var tagParts = tag.split(classIdSplit) var tagName = null if (notClassId.test(tagParts[1])) { tagName = "div" } var classes, part, type, i for (i = 0; i < tagParts.length; i++) { part = tagParts[i] if (!part) { continue } type = part.charAt(0) if (!tagName) { tagName = part } else if (type === ".") { classes = classes || [] classes.push(part.substring(1, part.length)) } else if (type === "#" && noId) { props.id = part.substring(1, part.length) } } if (classes) { if (props.className) { classes.push(props.className) } props.className = classes.join(" ") } return tagName ? tagName.toLowerCase() : "div" } },{}],47:[function(require,module,exports){ var attributeHook = require("./hooks/attribute-hook.js") var h = require("./index.js") var BLACKLISTED_KEYS = { "style": true, "namespace": true, "key": true } var SVG_NAMESPACE = "http://www.w3.org/2000/svg" module.exports = svg function svg(tagName, properties, children) { if (!children && isChildren(properties)) { children = properties properties = {} } properties = properties || {} // set namespace for svg properties.namespace = SVG_NAMESPACE // for each key, if attribute & string, bool or number then // convert it into a setAttribute hook for (var key in properties) { if (!properties.hasOwnProperty(key)) { continue } if (BLACKLISTED_KEYS[key]) { continue } var value = properties[key] if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean" ) { continue } properties[key] = attributeHook(value) } return h(tagName, properties, children) } function isChildren(x) { return typeof x === "string" || Array.isArray(x) } },{"./hooks/attribute-hook.js":24,"./index.js":28}],48:[function(require,module,exports){ module.exports=require(17) },{"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-vhook.js":17}],49:[function(require,module,exports){ module.exports=require(18) },{"./version":52,"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-vnode.js":18}],50:[function(require,module,exports){ module.exports=require(19) },{"./version":52,"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-vtext.js":19}],51:[function(require,module,exports){ module.exports=require(20) },{"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/is-widget.js":20}],52:[function(require,module,exports){ module.exports=require(21) },{"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/version.js":21}],53:[function(require,module,exports){ module.exports=require(44) },{"./is-vhook":48,"./is-vnode":49,"./is-widget":51,"./version":52,"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-hyperscript/node_modules/vtree/vnode.js":44}],54:[function(require,module,exports){ module.exports=require(22) },{"./version":52,"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-dom/node_modules/vtree/vpatch.js":22}],55:[function(require,module,exports){ module.exports=require(45) },{"./version":52,"/home/shashi/.julia/v0.3/Patchwork/runtime/node_modules/virtual-hyperscript/node_modules/vtree/vtext.js":45}],56:[function(require,module,exports){ var nativeIsArray = Array.isArray var toString = Object.prototype.toString module.exports = nativeIsArray || isArray function isArray(obj) { return toString.call(obj) === "[object Array]" } },{}],57:[function(require,module,exports){ isObject = require('is-object') module.exports = {reorder: reorder, patchObject: patchObject} function reorder(array, moves) { if (!arr) { return } var copy = array.slice(0) for (var i=0, l=array.length; i < l; i++) { var move = moves[i] if (move !== undefined) { array[move] = copy[i] } } return array } function patchObject(obj, patch) { for (var key in patch) { if (patch[key] && typeof patch[key].hook == "function") { obj[key] = patch[key] } else if (isObject(patch[key]) && isObject(obj[key])) { obj[key] = patchObject(obj[key], patch[key]); } else { obj[key] = patch[key] } } } },{"is-object":4}],58:[function(require,module,exports){ var mutateNode = require("./vnode-patch-op") var isArray = require('x-is-array') module.exports = patchVNode function patchVNode(root, patches) { linkParents(root) for (var key in patches) { if (key === "a") continue patch = patches[key] if (isArray(patch)) { for (var i=0, l=patch.length; i < l; i++) { mutateNode(patch[i].type, patch[i].vNode, patch[i].patch) } } else { mutateNode(patch.type, patch.vNode, patch.patch) } } return root } function linkParents(vNode) { if (!vNode || !vNode.children) { return } var children = vNode.children for (var i=0, l=children.length; i < l; i++) { children[i].up = vNode linkParents(children[i]) } } },{"./vnode-patch-op":59,"x-is-array":56}],59:[function(require,module,exports){ var isWidget = require("vtree/is-widget") var isVText = require("vtree/is-vtext") var VPatch = require("vtree/vpatch") var patchUtil = require("./patch-util.js") module.exports = applyPatch function applyPatch(type, vNode, patch) { switch (type) { case VPatch.REMOVE: return removeNode(vNode) case VPatch.INSERT: return insertNode(vNode, patch) case VPatch.VTEXT: return stringPatch(vNode, patch) case VPatch.VNODE: return vNodePatch(vNode, patch) case VPatch.ORDER: patchUtil.reorder(vNode.children, patch) return vNode case VPatch.PROPS: patchUtil.patchObject(vNode.properties, patch) return vNode default: return vNode } } function offsetCount(node, count) { if (!node) { return } if (node.count !== undefined) { node.count = node.count + count offsetCount(node.up, count) } else { node.count = count } } function removeNode(node) { if (!node) { return } var count = node.count, up = node.up var idx = up.children.indexOf(node) if (idx > -1) { up.children.splice(idx, 1) var count = 0 if (isVText(node)) { count = -1 } else { count = -node.count - 1 } offsetCount(up, count) } delete node return null } function insertNode(node, child) { node.children.push(child) var count = 0 if (isVText(child)) { count = 1 } else { count = child.count + 1 } offsetCount(node, count) child.up = node return node } function stringPatch(node, patch) { node.text = patch.text return node } function vNodePatch(node, patch) { var up = node.up if (!up) { // copy over the patch to the root node for (key in patch) { if (!patch.hasOwnProperty(key)) continue node[key] = patch[key] } return } var idx = up.children.indexOf(node), count = patch.count || 0 if (idx > -1) { up.children[idx] = patch if (node.count != count) { offsetCount(up, count - node.count) } } return node } },{"./patch-util.js":57,"vtree/is-vtext":50,"vtree/is-widget":51,"vtree/vpatch":54}],60:[function(require,module,exports){ },{}]},{},[1]); </script> I will be using the visualization package Plotly because it is the best I found so far. My measure of best is quality of the graphics and the ability to customize. Dear ggplot, Please come to Julia. But seriously, these visualizations produced by Plotly are not bad. They definitely took some time to produce, though. julia using Plotly, Colors  In this example, I will be using the Iris dataset to create a scatter plot. Arguably the most useful and used graph around, having this in our knowledge toolbox for visualizing data will serve us immediately if we are deciding whether to do some machine learning. In every honesty, Plotly documentation kind of sucks. But, if you stick with it long enough, you will notice a small pattern. I will attempt to comment as much as I know/understood. julia # similar to ggplot wherein you can define your own theme layout = Layout(;title="Iris Dataset Colored by Species", legend_y=0.5, legend_yref="paper", hovermode="closest", legend=attr(family="Arial, sans-serif", size=20, color="grey"), :paper_bgcolor => "rgb(217, 232, 245)", :plot_bgcolor => "rgb(217, 232, 245)", xaxis=attr(showgrid=false, showline=false), yaxis=attr(showgrid=true, showline=false)) # Once again, similar to ggplot # Plot(dataframe, x, y, circles, circle size, THEME/LAYOUT(if applicable), and other args. ) p = Plot(iris, x=:SepalLength, y=:SepalWidth, mode="markers", marker_size=8, layout, group=:Species, text=:Species) # Make sure you call "plot" plot(p)  <div id="3346a420-234d-498e-9a63-354e3d77bc7b" class="plotly-graph-div"></div> <script> window.PLOTLYENV=window.PLOTLYENV || {}; window.PLOTLYENV.BASE_URL="https://plot.ly"; require(['plotly'], function(Plotly) { Plotly.newPlot('3346a420-234d-498e-9a63-354e3d77bc7b', [{"y":[3.5,3.0,3.2,3.1,3.6,3.9,3.4,3.4,2.9,3.1,3.7,3.4,3.0,3.0,4.0,4.4,3.9,3.5,3.8,3.8,3.4,3.7,3.6,3.3,3.4,3.0,3.4,3.5,3.4,3.2,3.1,3.4,4.1,4.2,3.1,3.2,3.5,3.6,3.0,3.4,3.5,2.3,3.2,3.5,3.8,3.0,3.8,3.2,3.7,3.3],"text":["setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa"],"name":"setosa","type":"scatter","x":[5.1,4.9,4.7,4.6,5.0,5.4,4.6,5.0,4.4,4.9,5.4,4.8,4.8,4.3,5.8,5.7,5.4,5.1,5.7,5.1,5.4,5.1,4.6,5.1,4.8,5.0,5.0,5.2,5.2,4.7,4.8,5.4,5.2,5.5,4.9,5.0,5.5,4.9,4.4,5.1,5.0,4.5,4.4,5.0,5.1,4.8,5.1,4.6,5.3,5.0],"marker":{"size":8},"mode":"markers"},{"y":[3.2,3.2,3.1,2.3,2.8,2.8,3.3,2.4,2.9,2.7,2.0,3.0,2.2,2.9,2.9,3.1,3.0,2.7,2.2,2.5,3.2,2.8,2.5,2.8,2.9,3.0,2.8,3.0,2.9,2.6,2.4,2.4,2.7,2.7,3.0,3.4,3.1,2.3,3.0,2.5,2.6,3.0,2.6,2.3,2.7,3.0,2.9,2.9,2.5,2.8],"text":["versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor"],"name":"versicolor","type":"scatter","x":[7.0,6.4,6.9,5.5,6.5,5.7,6.3,4.9,6.6,5.2,5.0,5.9,6.0,6.1,5.6,6.7,5.6,5.8,6.2,5.6,5.9,6.1,6.3,6.1,6.4,6.6,6.8,6.7,6.0,5.7,5.5,5.5,5.8,6.0,5.4,6.0,6.7,6.3,5.6,5.5,5.5,6.1,5.8,5.0,5.6,5.7,5.7,6.2,5.1,5.7],"marker":{"size":8},"mode":"markers"},{"y":[3.3,2.7,3.0,2.9,3.0,3.0,2.5,2.9,2.5,3.6,3.2,2.7,3.0,2.5,2.8,3.2,3.0,3.8,2.6,2.2,3.2,2.8,2.8,2.7,3.3,3.2,2.8,3.0,2.8,3.0,2.8,3.8,2.8,2.8,2.6,3.0,3.4,3.1,3.0,3.1,3.1,3.1,2.7,3.2,3.3,3.0,2.5,3.0,3.4,3.0],"text":["virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica"],"name":"virginica","type":"scatter","x":[6.3,5.8,7.1,6.3,6.5,7.6,4.9,7.3,6.7,7.2,6.5,6.4,6.8,5.7,5.8,6.4,6.5,7.7,7.7,6.0,6.9,5.6,7.7,6.3,6.7,7.2,6.2,6.1,6.4,7.2,7.4,7.9,6.4,6.3,6.1,7.7,6.3,6.4,6.0,6.9,6.7,6.9,5.8,6.8,6.7,6.7,6.3,6.5,6.2,5.9],"marker":{"size":8},"mode":"markers"}], {"yaxis":{"showline":false,"showgrid":true},"plot_bgcolor":"rgb(217, 232, 245)","hovermode":"closest","legend":{"y":0.5,"size":20,"yref":"paper","color":"grey","family":"Arial, sans-serif"},"xaxis":{"showline":false,"showgrid":false},"paper_bgcolor":"rgb(217, 232, 245)","title":"Iris Dataset Colored by Species","margin":{"r":50,"l":50,"b":50,"t":60}}, {showLink: false}); }); </script> <iframe width="800" height="600" frameborder="0" scrolling="no" src="//plot.ly/~amilworks/82.embed"></iframe> *** Perfect. So let's extend our knowledge a tiny bit further. By further, I mean creating a 3D visualization. This one is a little out there in terms of coding it up, but again I did the best I could explaining away some of the ambiguity that would otherwise entail. So, I would say look at the Plotly documentation for more 3D examples. This is probably not the most efficent way. But, maybe you will pick up on a pattern. julia # names of the species nms = unique(iris[:Species]) colors = [RGB(0.89, 0.1, 0.1), RGB(0.21, 0.50, 0.72), RGB(0.28, 0.68, 0.3)] #traces = PlotlyJS.GenericTrace[] data = GenericTrace[] # for loop to help us create the 3D scatterplot AND the clustering mesh for (i, nm) in enumerate(nms) df = iris[iris[:Species] .== nm, :] x=df[:SepalLength] y=df[:SepalWidth] z=df[:PetalLength] # 3D scatterplot trace = scatter3d(;name=nm, mode="markers", marker_size=4, marker_color=colors[i], marker_line_width=0, text=df[:Species], x=x, y=y, z=z) push!(data, trace) # Clustering mesh cluster = mesh3d(;color=colors[i], opacity=0.3, x=x, y=y, z=z, text=df[:Species]) push!(data, cluster) # Dont forget to end your for loop !! end # Just like before, this is our theme. # Only difference is we colored the background, created labels, and defined a size layout = Layout(;:paper_bgcolor => "rgb(217, 232, 245)", :plot_bgcolor => "rgb(217, 232, 245)", width=1000, height=600, autosize=false, title="Clustering Iris Dataset in 3D", legend_y=0.5, legend_yref="paper", hovermode="closest", legend=attr(size=30, color="grey"), scene=attr(xaxis=attr(gridcolor="rgb(3, 5,38)", zerolinecolor="rgb(255, 255, 255)", showbackground=true, backgroundcolor="rgb(3, 5,38)", title="Sepal Length"), yaxis=attr(gridcolor="rgb(3, 5,38)", zerolinecolor="rgb(255, 255, 255)", showbackground=true, backgroundcolor="rgb(3, 5,38)", title="Sepal Width"), zaxis=attr(gridcolor="rgb(3, 5,38)", zerolinecolor="rgb(205, 222,230)", showbackground=true, backgroundcolor="rgb(3, 5,38)", title="Petal Length"), aspectratio=attr(x=1, y=1, z=0.7), aspectmode = "manual")) # Don't forget to call plot AND layout since we defined them separately here plot(data, layout)  <div id="75b5b0f4-4311-48e2-98df-252f366c2131" class="plotly-graph-div"></div> <script> window.PLOTLYENV=window.PLOTLYENV || {}; window.PLOTLYENV.BASE_URL="https://plot.ly"; require(['plotly'], function(Plotly) { Plotly.newPlot('75b5b0f4-4311-48e2-98df-252f366c2131', [{"text":["setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa"],"y":[3.5,3.0,3.2,3.1,3.6,3.9,3.4,3.4,2.9,3.1,3.7,3.4,3.0,3.0,4.0,4.4,3.9,3.5,3.8,3.8,3.4,3.7,3.6,3.3,3.4,3.0,3.4,3.5,3.4,3.2,3.1,3.4,4.1,4.2,3.1,3.2,3.5,3.6,3.0,3.4,3.5,2.3,3.2,3.5,3.8,3.0,3.8,3.2,3.7,3.3],"name":"setosa","type":"scatter3d","z":[1.4,1.4,1.3,1.5,1.4,1.7,1.4,1.5,1.4,1.5,1.5,1.6,1.4,1.1,1.2,1.5,1.3,1.4,1.7,1.5,1.7,1.5,1.0,1.7,1.9,1.6,1.6,1.5,1.4,1.6,1.6,1.5,1.5,1.4,1.5,1.2,1.3,1.4,1.3,1.5,1.3,1.3,1.3,1.6,1.9,1.4,1.6,1.4,1.5,1.4],"x":[5.1,4.9,4.7,4.6,5.0,5.4,4.6,5.0,4.4,4.9,5.4,4.8,4.8,4.3,5.8,5.7,5.4,5.1,5.7,5.1,5.4,5.1,4.6,5.1,4.8,5.0,5.0,5.2,5.2,4.7,4.8,5.4,5.2,5.5,4.9,5.0,5.5,4.9,4.4,5.1,5.0,4.5,4.4,5.0,5.1,4.8,5.1,4.6,5.3,5.0],"mode":"markers","marker":{"line":{"width":0},"size":4,"color":"#E31A1A"}},{"opacity":0.3,"y":[3.5,3.0,3.2,3.1,3.6,3.9,3.4,3.4,2.9,3.1,3.7,3.4,3.0,3.0,4.0,4.4,3.9,3.5,3.8,3.8,3.4,3.7,3.6,3.3,3.4,3.0,3.4,3.5,3.4,3.2,3.1,3.4,4.1,4.2,3.1,3.2,3.5,3.6,3.0,3.4,3.5,2.3,3.2,3.5,3.8,3.0,3.8,3.2,3.7,3.3],"text":["setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa","setosa"],"type":"mesh3d","z":[1.4,1.4,1.3,1.5,1.4,1.7,1.4,1.5,1.4,1.5,1.5,1.6,1.4,1.1,1.2,1.5,1.3,1.4,1.7,1.5,1.7,1.5,1.0,1.7,1.9,1.6,1.6,1.5,1.4,1.6,1.6,1.5,1.5,1.4,1.5,1.2,1.3,1.4,1.3,1.5,1.3,1.3,1.3,1.6,1.9,1.4,1.6,1.4,1.5,1.4],"x":[5.1,4.9,4.7,4.6,5.0,5.4,4.6,5.0,4.4,4.9,5.4,4.8,4.8,4.3,5.8,5.7,5.4,5.1,5.7,5.1,5.4,5.1,4.6,5.1,4.8,5.0,5.0,5.2,5.2,4.7,4.8,5.4,5.2,5.5,4.9,5.0,5.5,4.9,4.4,5.1,5.0,4.5,4.4,5.0,5.1,4.8,5.1,4.6,5.3,5.0],"color":"#E31A1A"},{"text":["versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor"],"y":[3.2,3.2,3.1,2.3,2.8,2.8,3.3,2.4,2.9,2.7,2.0,3.0,2.2,2.9,2.9,3.1,3.0,2.7,2.2,2.5,3.2,2.8,2.5,2.8,2.9,3.0,2.8,3.0,2.9,2.6,2.4,2.4,2.7,2.7,3.0,3.4,3.1,2.3,3.0,2.5,2.6,3.0,2.6,2.3,2.7,3.0,2.9,2.9,2.5,2.8],"name":"versicolor","type":"scatter3d","z":[4.7,4.5,4.9,4.0,4.6,4.5,4.7,3.3,4.6,3.9,3.5,4.2,4.0,4.7,3.6,4.4,4.5,4.1,4.5,3.9,4.8,4.0,4.9,4.7,4.3,4.4,4.8,5.0,4.5,3.5,3.8,3.7,3.9,5.1,4.5,4.5,4.7,4.4,4.1,4.0,4.4,4.6,4.0,3.3,4.2,4.2,4.2,4.3,3.0,4.1],"x":[7.0,6.4,6.9,5.5,6.5,5.7,6.3,4.9,6.6,5.2,5.0,5.9,6.0,6.1,5.6,6.7,5.6,5.8,6.2,5.6,5.9,6.1,6.3,6.1,6.4,6.6,6.8,6.7,6.0,5.7,5.5,5.5,5.8,6.0,5.4,6.0,6.7,6.3,5.6,5.5,5.5,6.1,5.8,5.0,5.6,5.7,5.7,6.2,5.1,5.7],"mode":"markers","marker":{"line":{"width":0},"size":4,"color":"#3680B8"}},{"opacity":0.3,"y":[3.2,3.2,3.1,2.3,2.8,2.8,3.3,2.4,2.9,2.7,2.0,3.0,2.2,2.9,2.9,3.1,3.0,2.7,2.2,2.5,3.2,2.8,2.5,2.8,2.9,3.0,2.8,3.0,2.9,2.6,2.4,2.4,2.7,2.7,3.0,3.4,3.1,2.3,3.0,2.5,2.6,3.0,2.6,2.3,2.7,3.0,2.9,2.9,2.5,2.8],"text":["versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor","versicolor"],"type":"mesh3d","z":[4.7,4.5,4.9,4.0,4.6,4.5,4.7,3.3,4.6,3.9,3.5,4.2,4.0,4.7,3.6,4.4,4.5,4.1,4.5,3.9,4.8,4.0,4.9,4.7,4.3,4.4,4.8,5.0,4.5,3.5,3.8,3.7,3.9,5.1,4.5,4.5,4.7,4.4,4.1,4.0,4.4,4.6,4.0,3.3,4.2,4.2,4.2,4.3,3.0,4.1],"x":[7.0,6.4,6.9,5.5,6.5,5.7,6.3,4.9,6.6,5.2,5.0,5.9,6.0,6.1,5.6,6.7,5.6,5.8,6.2,5.6,5.9,6.1,6.3,6.1,6.4,6.6,6.8,6.7,6.0,5.7,5.5,5.5,5.8,6.0,5.4,6.0,6.7,6.3,5.6,5.5,5.5,6.1,5.8,5.0,5.6,5.7,5.7,6.2,5.1,5.7],"color":"#3680B8"},{"text":["virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica"],"y":[3.3,2.7,3.0,2.9,3.0,3.0,2.5,2.9,2.5,3.6,3.2,2.7,3.0,2.5,2.8,3.2,3.0,3.8,2.6,2.2,3.2,2.8,2.8,2.7,3.3,3.2,2.8,3.0,2.8,3.0,2.8,3.8,2.8,2.8,2.6,3.0,3.4,3.1,3.0,3.1,3.1,3.1,2.7,3.2,3.3,3.0,2.5,3.0,3.4,3.0],"name":"virginica","type":"scatter3d","z":[6.0,5.1,5.9,5.6,5.8,6.6,4.5,6.3,5.8,6.1,5.1,5.3,5.5,5.0,5.1,5.3,5.5,6.7,6.9,5.0,5.7,4.9,6.7,4.9,5.7,6.0,4.8,4.9,5.6,5.8,6.1,6.4,5.6,5.1,5.6,6.1,5.6,5.5,4.8,5.4,5.6,5.1,5.1,5.9,5.7,5.2,5.0,5.2,5.4,5.1],"x":[6.3,5.8,7.1,6.3,6.5,7.6,4.9,7.3,6.7,7.2,6.5,6.4,6.8,5.7,5.8,6.4,6.5,7.7,7.7,6.0,6.9,5.6,7.7,6.3,6.7,7.2,6.2,6.1,6.4,7.2,7.4,7.9,6.4,6.3,6.1,7.7,6.3,6.4,6.0,6.9,6.7,6.9,5.8,6.8,6.7,6.7,6.3,6.5,6.2,5.9],"mode":"markers","marker":{"line":{"width":0},"size":4,"color":"#47AD4C"}},{"opacity":0.3,"y":[3.3,2.7,3.0,2.9,3.0,3.0,2.5,2.9,2.5,3.6,3.2,2.7,3.0,2.5,2.8,3.2,3.0,3.8,2.6,2.2,3.2,2.8,2.8,2.7,3.3,3.2,2.8,3.0,2.8,3.0,2.8,3.8,2.8,2.8,2.6,3.0,3.4,3.1,3.0,3.1,3.1,3.1,2.7,3.2,3.3,3.0,2.5,3.0,3.4,3.0],"text":["virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica","virginica"],"type":"mesh3d","z":[6.0,5.1,5.9,5.6,5.8,6.6,4.5,6.3,5.8,6.1,5.1,5.3,5.5,5.0,5.1,5.3,5.5,6.7,6.9,5.0,5.7,4.9,6.7,4.9,5.7,6.0,4.8,4.9,5.6,5.8,6.1,6.4,5.6,5.1,5.6,6.1,5.6,5.5,4.8,5.4,5.6,5.1,5.1,5.9,5.7,5.2,5.0,5.2,5.4,5.1],"x":[6.3,5.8,7.1,6.3,6.5,7.6,4.9,7.3,6.7,7.2,6.5,6.4,6.8,5.7,5.8,6.4,6.5,7.7,7.7,6.0,6.9,5.6,7.7,6.3,6.7,7.2,6.2,6.1,6.4,7.2,7.4,7.9,6.4,6.3,6.1,7.7,6.3,6.4,6.0,6.9,6.7,6.9,5.8,6.8,6.7,6.7,6.3,6.5,6.2,5.9],"color":"#47AD4C"}], {"width":1000,"hovermode":"closest","scene":{"yaxis":{"backgroundcolor":"rgb(3, 5,38)","zerolinecolor":"rgb(255, 255, 255)","showbackground":true,"title":"Sepal Width","gridcolor":"rgb(3, 5,38)"},"aspectmode":"manual","xaxis":{"backgroundcolor":"rgb(3, 5,38)","zerolinecolor":"rgb(255, 255, 255)","showbackground":true,"title":"Sepal Length","gridcolor":"rgb(3, 5,38)"},"aspectratio":{"y":1,"z":0.7,"x":1},"zaxis":{"backgroundcolor":"rgb(3, 5,38)","zerolinecolor":"rgb(205, 222,230)","showbackground":true,"title":"Petal Length","gridcolor":"rgb(3, 5,38)"}},"legend":{"y":0.5,"size":30,"yref":"paper","color":"grey"},"plot_bgcolor":"rgb(217, 232, 245)","paper_bgcolor":"rgb(217, 232, 245)","autosize":false,"title":"Clustering Iris Dataset in 3D","margin":{"r":50,"l":50,"b":50,"t":60},"height":600}, {showLink: false}); }); </script> <iframe width="800" height="700" frameborder="0" scrolling="no" src="//plot.ly/~amilworks/80.embed"></iframe> *** # Congratulations! You made it to the end! ## Go out there and replicate this if you have not already. ***