An IJulia Demo

This notebook uses IJulia: a Julia-language backend combined with the IPython interactive environment. This combination allows you to interact with the Julia language using IPython's powerful graphical notebook, which combines code, formatted text, math, and multimedia in a single document.

Basic Julia interaction

Basic mathematical expressions work like you expect:

In [1]:
1 + sin(3)
Out[1]:
1.1411200080598671

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:

In [2]:
s = 0.0
for n = 1:2:10000
    s += 1/n - 1/(n+1)
end
s # an expression on the last line (if it doesn't end with ";") is printed as "Out"
Out[2]:
0.6930971830599458

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 ;).

For example, the harmonic series above should be converging (slowly) to $\ln 2$, and we can check this:

In [3]:
Out[2] - log(2)
Out[3]:
-4.9997499999454575e-5

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$:

In [4]:
R = rand(500,500)
R' * R
Out[4]:
500×500 Array{Float64,2}:
 163.997  119.989  123.258  122.417  …  123.598  124.586  126.629  122.147
 119.989  165.31   124.292  124.374     117.035  119.153  122.786  119.258
 123.258  124.292  167.951  125.519     123.505  126.095  127.652  120.941
 122.417  124.374  125.519  164.918     122.181  126.342  123.043  120.117
 127.785  124.018  127.959  129.493     120.899  124.241  122.532  124.211
 121.192  116.46   119.867  119.405  …  115.515  120.325  118.415  116.102
 130.641  125.334  129.166  126.353     128.142  128.794  128.912  126.152
 118.429  121.673  122.211  120.882     119.28   120.843  120.061  115.633
 114.759  116.719  117.559  118.914     115.986  111.788  116.589  111.718
 126.472  125.265  128.371  129.133     123.55   125.585  126.312  124.173
 119.794  122.89   121.815  121.749  …  118.439  119.945  120.698  118.216
 129.129  123.631  128.009  121.761     123.211  126.169  124.763  122.213
 125.867  125.239  130.308  126.008     123.634  123.635  122.633  123.519
   ⋮                                 ⋱                             
 126.251  124.15   124.044  125.863     121.515  120.809  124.746  121.935
 125.309  125.68   124.141  125.06      121.597  122.663  124.565  118.346
 123.473  122.476  129.296  123.392  …  127.251  124.75   125.145  120.303
 123.527  124.84   130.883  127.011     121.407  119.735  123.78   122.866
 126.463  126.522  127.294  124.359     124.548  127.588  126.791  122.264
 121.151  119.849  124.745  121.324     115.719  122.081  121.113  117.713
 123.211  121.858  123.66   123.795     118.055  126.116  123.354  119.606
 119.069  121.778  120.37   122.458  …  118.449  119.358  120.016  113.809
 123.598  117.035  123.505  122.181     160.443  123.832  121.902  119.567
 124.586  119.153  126.095  126.342     123.832  162.668  123.514  119.068
 126.629  122.786  127.652  123.043     121.902  123.514  165.55   123.263
 122.147  119.258  120.941  120.117     119.567  119.068  123.263  159.226

(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?) Standard output from Julia is also captured and sent to the IJulia notebook as you'd expect:

In [5]:
println("Hello world!\n")
println(stderr, "Börk börk börk, some unicode output on stderr...\n")
Hello world!

Börk börk börk, some unicode output on stderr...

IJulia even captures output from external C libraries (and notice how easy it is using Julia's ccall intrinsic):

In [6]:
ccall(:printf, Cint, (Ptr{UInt8},), "Hello from C!!\n");
Hello from C!!

We can define functions, of course, and use them in later input cells:

In [7]:
f(x) = x .+ 1
Out[7]:
f (generic function with 1 method)
In [8]:
println(f(3))
f([1,1,2,3,5,8])
4
Out[8]:
6-element Array{Int64,1}:
 2
 2
 3
 4
 6
 9

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.

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:

In [9]:
f("Hello?")
MethodError: no method matching +(::String, ::Int64)
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:538
  +(::Complex{Bool}, ::Real) at complex.jl:301
  +(::BigInt, ::Union{Int16, Int32, Int64, Int8}) at gmp.jl:530
  ...

Stacktrace:
 [1] _broadcast_getindex_evalf at ./broadcast.jl:648 [inlined]
 [2] _broadcast_getindex at ./broadcast.jl:621 [inlined]
 [3] getindex at ./broadcast.jl:575 [inlined]
 [4] copy at ./broadcast.jl:852 [inlined]
 [5] materialize at ./broadcast.jl:837 [inlined]
 [6] f(::String) at ./In[7]:1
 [7] top-level scope at In[9]:1
 [8] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091

Interactive Plotting in IJulia

Below we'll show off some plotting using the excellent Gadfly package. The plots are heavily inspired by this blog post.

In [10]:
import Pkg; Pkg.add("RDatasets")
import Pkg; Pkg.add("Gadfly")
   Updating registry at `/opt/julia/registries/General`
  Resolving package versions...
No Changes to `/opt/julia/environments/v1.5/Project.toml`
No Changes to `/opt/julia/environments/v1.5/Manifest.toml`
  Resolving package versions...
No Changes to `/opt/julia/environments/v1.5/Project.toml`
No Changes to `/opt/julia/environments/v1.5/Manifest.toml`
In [11]:
using RDatasets
sleep = dataset("lme4","sleepstudy")
Out[11]:

180 rows × 3 columns

ReactionDaysSubject
Float64Int32Cat…
1249.560308
2258.7051308
3250.8012308
4321.443308
5356.8524308
6414.695308
7382.2046308
8290.1497308
9430.5858308
10466.3539308
11222.7340309
12205.2661309
13202.9782309
14204.7073309
15207.7164309
16215.9625309
17213.636309
18217.7277309
19224.2968309
20237.3149309
21199.0540310
22194.3321310
23234.322310
24232.8423310
25229.3074310
26220.4585310
27235.4216310
28255.7517310
29261.0128310
30247.5159310
In [12]:
using Gadfly
plot(sleep, x = "Days", y = "Reaction", Geom.point)
Out[12]:
Days -12.5 -10.0 -7.5 -5.0 -2.5 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0 22.5 -10.0 -9.5 -9.0 -8.5 -8.0 -7.5 -7.0 -6.5 -6.0 -5.5 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 14.5 15.0 15.5 16.0 16.5 17.0 17.5 18.0 18.5 19.0 19.5 20.0 -10 0 10 20 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? -600 -500 -400 -300 -200 -100 0 100 200 300 400 500 600 700 800 900 1000 1100 -500 -480 -460 -440 -420 -400 -380 -360 -340 -320 -300 -280 -260 -240 -220 -200 -180 -160 -140 -120 -100 -80 -60 -40 -20 0 20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 320 340 360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680 700 720 740 760 780 800 820 840 860 880 900 920 940 960 980 1000 -500 0 500 1000 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 0 50 100 150 200 250 300 350 400 450 500 550 600 650 700 750 800 850 900 950 1000 Reaction
In [13]:
plot(sleep, x = "Reaction", Geom.density, color = "Subject", Scale.x_continuous(minvalue= 0, maxvalue= 500))
Out[13]:
Reaction -1000 -800 -600 -400 -200 0 200 400 600 800 1000 1200 1400 1600 1800 -800 -750 -700 -650 -600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 0 50 100 150 200 250 300 350 400 450 500 550 600 650 700 750 800 850 900 950 1000 1050 1100 1150 1200 1250 1300 1350 1400 1450 1500 1550 1600 -1000 0 1000 2000 -800 -750 -700 -650 -600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 0 50 100 150 200 250 300 350 400 450 500 550 600 650 700 750 800 850 900 950 1000 1050 1100 1150 1200 1250 1300 1350 1400 1450 1500 1550 1600 308 309 310 330 331 332 333 334 335 337 349 350 351 352 369 370 371 372 Subject h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? -0.05 -0.04 -0.03 -0.02 -0.01 0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 -0.040 -0.038 -0.036 -0.034 -0.032 -0.030 -0.028 -0.026 -0.024 -0.022 -0.020 -0.018 -0.016 -0.014 -0.012 -0.010 -0.008 -0.006 -0.004 -0.002 0.000 0.002 0.004 0.006 0.008 0.010 0.012 0.014 0.016 0.018 0.020 0.022 0.024 0.026 0.028 0.030 0.032 0.034 0.036 0.038 0.040 0.042 0.044 0.046 0.048 0.050 0.052 0.054 0.056 0.058 0.060 0.062 0.064 0.066 0.068 0.070 0.072 0.074 0.076 0.078 0.080 0.082 -0.05 0.00 0.05 0.10 -0.045 -0.040 -0.035 -0.030 -0.025 -0.020 -0.015 -0.010 -0.005 0.000 0.005 0.010 0.015 0.020 0.025 0.030 0.035 0.040 0.045 0.050 0.055 0.060 0.065 0.070 0.075 0.080
In [14]:
plot(x = sleep[!, :Reaction], Geom.histogram(bincount = 30), Scale.x_continuous(minvalue = 200), color = sleep[!, :Days])
Out[14]:
x -600 -500 -400 -300 -200 -100 0 100 200 300 400 500 600 700 800 900 1000 1100 -500 -480 -460 -440 -420 -400 -380 -360 -340 -320 -300 -280 -260 -240 -220 -200 -180 -160 -140 -120 -100 -80 -60 -40 -20 0 20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 320 340 360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680 700 720 740 760 780 800 820 840 860 880 900 920 940 960 980 1000 -500 0 500 1000 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 0 50 100 150 200 250 300 350 400 450 500 550 600 650 700 750 800 850 900 950 1000 5.0 10.0 0.0 2.5 7.5 Color h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? -25 -20 -15 -10 -5 0 5 10 15 20 25 30 35 40 45 -20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 -20 0 20 40 -20 -18 -16 -14 -12 -10 -8 -6 -4 -2 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40

Multimedia display in IJulia

Like most programming languages, Julia has a built-in print(x) function for outputting an object x as text, and you can override the resulting text representation of a user-defined type by overloading Julia's show function. The next version of Julia, however, will extend this to a more general mechanism to display arbitrary multimedia representations of objects, as defined by standard MIME types. More specifically, the Julia multimedia I/O API provides:

  • A display(x) function requests the richest available multimedia display of a Julia object x (with a text/plain fallback).
  • Overloading writemime allows one to indicate arbitrary multimedia representations (keyed by standard MIME types) of user-defined types.
  • Multimedia-capable display backends may be registered by subclassing a generic Display type. IJulia provides one such backend which, thanks to the IPython notebook, is capable of displaying HTML, LaTeX, SVG, PNG, and JPEG media formats. The last two points are critical, because they separate multimedia export (which is defined by functions associated with the originating Julia data) from multimedia display (defined by backends which know nothing about the source of the data). Precisely these mechanism were used to create the inline PyPlot plots above. To start with, the simplest thing is to provide the MIME type of the data when you call display, which allows you to pass "raw" data in the corresponding format:
In [15]:
display("text/html", """Hello <b>world</b> in <font color="red">HTML</font>!""")
Hello world in HTML!

However, it will be more common to attach this information to types, so that they display correctly automatically. For example, let's define a simple HTML type in Julia that contains a string and automatically displays as HTML (given an HTML-capable backend such as IJulia):

In [16]:
mutable struct HTML
   s::String
end

Base.show(io::IO, ::MIME"text/html", x::HTML) = print(io, x.s)

Here, Base.show is just a function that writes x in the corresponding format (text/html) to the I/O stream io.

This show definition is all that we need to make any object of type HTML display automatically as HTML text in IJulia:

In [17]:
x = HTML("<ul> <li> Hello from a bulleted list! </ul>")
Out[17]:
  • Hello from a bulleted list!
In [18]:
display(x)
println(x)
  • Hello from a bulleted list!
HTML("<ul> <li> Hello from a bulleted list! </ul>")