{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Binder is an open-source project and Julia support is early in development. If you'd like to improve Julia support in Binder, see our issue on adding Julia support here: https://github.com/jupyter/repo2docker/issues/23. We'd love to hear from you!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# An IJulia Demo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook uses **IJulia**: a [Julia-language](http://julialang.org/) backend combined with the [IPython](http://ipython.org/) interactive environment. This combination allows you to interact with the Julia language using IPython's powerful [graphical notebook](http://ipython.org/notebook.html), which combines code, formatted text, math, and multimedia in a single document." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic Julia interaction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Basic mathematical expressions work like you expect:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.1411200080598671" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 + sin(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can define variables, write loops, and execute arbitrary multiline code blocks. Here is an example of an alternating harmonic series $\\sum_{n=1}^\\infty \\frac{(-1)^n}{n}$ from a [Julia tutorial by Homer Reid](http://homerreid.ath.cx/teaching/18.330/JuliaProgramming.shtml#SimplePrograms):" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.6930971830599458" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = 0.0\n", "for n = 1:2:10000\n", " s += 1/n - 1/(n+1)\n", "end\n", "s # an expression on the last line (if it doesn't end with \";\") is printed as \"Out\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Previous outputs can be referred to via `Out[`*n*`]`, following the IPython, for example `Out[2]` for the result above. You can also use the shorthand `_2`, or `_` for the previous result, as in IPython. Like in Matlab, `ans` can also be used to refer to the previous result, *even if it was not printed* (when the command ended with `;`).\n", "\n", "For example, the harmonic series above should be converging (slowly) to $\\ln 2$, and we can check this:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-4.9997499999454575e-5" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Out[2] - log(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like Matlab or Scipy + Numpy, Julia has lots of mathematical functions and linear algebra built in. For example, we can define a $500\\times500$ random matrix $R$ and form the positive-definite matrix $R^* R$:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "500×500 Matrix{Float64}:\n", " 157.086 125.405 118.942 118.733 … 117.178 123.108 122.162 117.716\n", " 125.405 173.866 123.271 128.494 125.963 133.41 134.021 126.669\n", " 118.942 123.271 164.226 124.741 115.388 124.413 124.559 121.537\n", " 118.733 128.494 124.741 172.028 120.07 132.452 130.219 124.989\n", " 117.854 124.889 118.002 121.872 113.562 128.753 120.994 120.3\n", " 117.883 127.353 120.785 123.513 … 116.297 124.635 122.531 122.652\n", " 115.686 131.518 122.198 122.745 120.083 129.317 126.648 122.29\n", " 116.221 122.986 117.507 124.981 116.987 126.97 124.202 119.834\n", " 123.159 132.421 122.964 127.201 119.728 132.898 131.866 127.199\n", " 123.811 135.27 129.507 127.765 124.031 130.567 135.025 129.98\n", " 119.078 129.342 120.877 128.224 … 117.447 128.78 127.715 124.812\n", " 122.518 132.505 124.904 127.682 121.978 133.272 130.274 126.781\n", " 123.486 128.846 121.908 127.604 122.377 130.09 131.613 126.676\n", " ⋮ ⋱ \n", " 119.693 130.541 123.739 127.712 121.312 131.16 128.154 124.676\n", " 131.872 135.59 131.746 134.505 130.822 135.926 133.603 130.854\n", " 118.757 125.092 119.031 124.342 … 114.532 128.658 126.616 122.564\n", " 121.568 131.177 125.89 128.342 123.977 133.799 131.53 128.369\n", " 120.815 130.618 121.841 124.483 117.978 130.369 127.911 125.013\n", " 122.4 130.523 124.284 128.061 121.082 131.908 128.22 127.261\n", " 129.042 136.992 128.067 131.556 127.416 137.022 134.724 129.579\n", " 124.725 131.668 126.848 132.483 … 121.312 129.146 129.876 126.526\n", " 117.178 125.963 115.388 120.07 154.73 123.11 125.081 117.828\n", " 123.108 133.41 124.413 132.452 123.11 171.529 131.11 129.629\n", " 122.162 134.021 124.559 130.219 125.081 131.11 172.845 127.886\n", " 117.716 126.669 121.537 124.989 117.828 129.629 127.886 162.92" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R = rand(500,500)\n", "R' * R" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(Notice that, by default, only a portion of a large matrix is shown. You didn't really want to read $500^2 = 250,000$ numbers, did you?)\n", "\n", "Standard output from Julia is also captured and sent to the IJulia notebook as you'd expect:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello world!\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "Börk börk börk, some unicode output on stderr...\n", "\n" ] } ], "source": [ "println(\"Hello world!\\n\")\n", "println(stderr, \"Börk börk börk, some unicode output on stderr...\\n\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "IJulia even captures output from external C libraries (and notice how easy it is using Julia's `@ccall` macro):" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello from C!!\n" ] }, { "data": { "text/plain": [ "15" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@ccall printf(\"Hello from C!!\\n\"::Cstring)::Cint" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can define functions, of course, and use them in later input cells:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "f (generic function with 1 method)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f(x) = x .+ 1" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4\n" ] }, { "data": { "text/plain": [ "6-element Vector{Int64}:\n", " 2\n", " 2\n", " 3\n", " 4\n", " 6\n", " 9" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "println(f(3))\n", "f([1,1,2,3,5,8])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the input above both printed an scalar to `stdout` and also returned a vector, the latter using Julia's ability to write polymorphic functions and built-in array operations.\n", "\n", "On the other hand adding a string to a number is not defined (there is no `+` method defined for those types, although we could easily add one), and attempting to do so will throw an exception:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "MethodError: no method matching +(::String, ::Int64)\nThe function `+` exists, but no method is defined for this combination of argument types.\n\n\u001b[0mClosest candidates are:\n\u001b[0m +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m\u001b[4moperators.jl:642\u001b[24m\u001b[39m\n\u001b[0m +(\u001b[91m::BigFloat\u001b[39m, ::Union{Int16, Int32, Int64, Int8})\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m\u001b[4mmpfr.jl:592\u001b[24m\u001b[39m\n\u001b[0m +(\u001b[91m::Complex{Bool}\u001b[39m, ::Real)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m\u001b[4mcomplex.jl:323\u001b[24m\u001b[39m\n\u001b[0m ...\n", "output_type": "error", "traceback": [ "MethodError: no method matching +(::String, ::Int64)\nThe function `+` exists, but no method is defined for this combination of argument types.\n\n\u001b[0mClosest candidates are:\n\u001b[0m +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m\u001b[4moperators.jl:642\u001b[24m\u001b[39m\n\u001b[0m +(\u001b[91m::BigFloat\u001b[39m, ::Union{Int16, Int32, Int64, Int8})\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m\u001b[4mmpfr.jl:592\u001b[24m\u001b[39m\n\u001b[0m +(\u001b[91m::Complex{Bool}\u001b[39m, ::Real)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m\u001b[4mcomplex.jl:323\u001b[24m\u001b[39m\n\u001b[0m ...\n", "", "Stacktrace:", " [1] \u001b[0m\u001b[1m_broadcast_getindex_evalf\u001b[22m", "\u001b[90m @\u001b[39m \u001b[90m./\u001b[39m\u001b[90m\u001b[4mbroadcast.jl:699\u001b[24m\u001b[39m\u001b[90m [inlined]\u001b[39m", " [2] \u001b[0m\u001b[1m_broadcast_getindex\u001b[22m", "\u001b[90m @\u001b[39m \u001b[90m./\u001b[39m\u001b[90m\u001b[4mbroadcast.jl:672\u001b[24m\u001b[39m\u001b[90m [inlined]\u001b[39m", " [3] \u001b[0m\u001b[1m_getindex\u001b[22m", "\u001b[90m @\u001b[39m \u001b[90m./\u001b[39m\u001b[90m\u001b[4mbroadcast.jl:620\u001b[24m\u001b[39m\u001b[90m [inlined]\u001b[39m", " [4] \u001b[0m\u001b[1mgetindex\u001b[22m", "\u001b[90m @\u001b[39m \u001b[90m./\u001b[39m\u001b[90m\u001b[4mbroadcast.jl:616\u001b[24m\u001b[39m\u001b[90m [inlined]\u001b[39m", " [5] \u001b[0m\u001b[1mcopy\u001b[22m", "\u001b[90m @\u001b[39m \u001b[90m./\u001b[39m\u001b[90m\u001b[4mbroadcast.jl:909\u001b[24m\u001b[39m\u001b[90m [inlined]\u001b[39m", " [6] \u001b[0m\u001b[1mmaterialize\u001b[22m", "\u001b[90m @\u001b[39m \u001b[90m./\u001b[39m\u001b[90m\u001b[4mbroadcast.jl:894\u001b[24m\u001b[39m\u001b[90m [inlined]\u001b[39m", " [7] \u001b[0m\u001b[1mf\u001b[22m\u001b[0m\u001b[1m(\u001b[22m\u001b[90mx\u001b[39m::\u001b[0mString\u001b[0m\u001b[1m)\u001b[22m", "\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m./\u001b[39m\u001b[90m\u001b[4mIn[7]:1\u001b[24m\u001b[39m", " [8] top-level scope", "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[9]:1\u001b[24m\u001b[39m", " [9] \u001b[0m\u001b[1meval\u001b[22m\u001b[0m\u001b[1m(\u001b[22m\u001b[90mm\u001b[39m::\u001b[0mModule, \u001b[90me\u001b[39m::\u001b[0mAny\u001b[0m\u001b[1m)\u001b[22m", "\u001b[90m @\u001b[39m \u001b[90mCore\u001b[39m \u001b[90m./\u001b[39m\u001b[90m\u001b[4mboot.jl:489\u001b[24m\u001b[39m" ] } ], "source": [ "f(\"Hello?\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Interactive Plotting in IJulia\n", "\n", "Below we'll show off some plotting using the excellent [Plots.jl](https://docs.juliaplots.org/stable/) package. The plots are heavily inspired by [this blog post](http://int8.io/basic-visualization-in-julia-gadfly/)." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| Row | Reaction | Days | Subject |
|---|---|---|---|
| Float64 | Int32 | Cat… | |
| 1 | 249.56 | 0 | 308 |
| 2 | 258.705 | 1 | 308 |
| 3 | 250.801 | 2 | 308 |
| 4 | 321.44 | 3 | 308 |
| 5 | 356.852 | 4 | 308 |
| 6 | 414.69 | 5 | 308 |
| 7 | 382.204 | 6 | 308 |
| 8 | 290.149 | 7 | 308 |
| 9 | 430.585 | 8 | 308 |
| 10 | 466.353 | 9 | 308 |
| 11 | 222.734 | 0 | 309 |
| 12 | 205.266 | 1 | 309 |
| 13 | 202.978 | 2 | 309 |
| ⋮ | ⋮ | ⋮ | ⋮ |
| 169 | 350.781 | 8 | 371 |
| 170 | 369.469 | 9 | 371 |
| 171 | 269.412 | 0 | 372 |
| 172 | 273.474 | 1 | 372 |
| 173 | 297.597 | 2 | 372 |
| 174 | 310.632 | 3 | 372 |
| 175 | 287.173 | 4 | 372 |
| 176 | 329.608 | 5 | 372 |
| 177 | 334.482 | 6 | 372 |
| 178 | 343.22 | 7 | 372 |
| 179 | 369.142 | 8 | 372 |
| 180 | 364.124 | 9 | 372 |