#!/usr/bin/env python # coding: utf-8 # > This is one of the 100 recipes of the [IPython Cookbook](http://ipython-books.github.io/), the definitive guide to high-performance scientific computing and data science in Python. # # 5.12. Trying the Julia language in the notebook # For this recipe, you need to install Julia and IJulia. You'll find the installation instructions in the book. # 1. We can't avoid the customary *Hello World* example. The `println()` function displays a string and adds a line break at the end. # In[ ]: println("Hello world!") # 2. We create a polymorphic function `f` that computes the expression $z*z+c$. We will notably evaluate this function on arrays, so we use elementwise operators with a dot (`.`) prefix. # In[ ]: f(z, c) = z.*z .+ c # 3. Let's evaluate `f` on scalar complex numbers (the imaginary number $i$ is `1im`). # In[ ]: f(2.0 + 1.0im, 1.0) # 4. Now, we create a `(2, 2)` matrix. Components are separated by a space, rows are separated by a semicolon (`;`). The type of this `Array` is automatically inferred from its components. The `Array` type is a built-in data type in Julia, similar, but not identical, to NumPy's `ndarray` type. # In[ ]: z = [-1.0 - 1.0im 1.0 - 1.0im; -1.0 + 1.0im 1.0 + 1.0im] # 5. We can index arrays with brackets `[]`. A notable difference with Python is that indexing starts from 1 instead of 0. MATLAB has the same convention. Besides, the keyword `end` refers to the last item in that dimension. # In[ ]: z[1,end] # 6. We can evaluate `f` on the matrix `z` and a scalar `c` (polymorphism). # In[ ]: f(z, 0) # 7. Now, we create a function `julia` that computes a Julia set. Optional named arguments are separated from positional arguments by a semicolon (`;`). Julia's syntax for flow control is close from Python's, except that colons are dropped, indentation doesn't count, and block `end` keywords are mandatory. # In[ ]: function julia(z, c; maxiter=200) for n = 1:maxiter if abs2(z) > 4.0 return n-1 end z = f(z, c) end return maxiter end # 8. We can use Python packages from Julia. First, we have to install the `PyCall` package by using Julia's built-in package manager (`Pkg`). Once the package is installed, we can use it in the interactive session with `using PyCall`. # In[ ]: Pkg.add("PyCall") using PyCall # 9. We can import Python packages with the `@pyimport` **macro** (a metaprogramming feature in Julia). This macro is the equivalent of Python's `import` command. # In[ ]: @pyimport numpy as np # 10. The `np` namespace is now available in the Julia interactive session. NumPy arrays are automatically converted to Julia `Array`s. # In[ ]: z = np.linspace(-1., 1., 100) # 11. We can use list comprehensions to evaluate the function `julia` on many arguments. # In[ ]: m = [julia(z[i], 0.5) for i=1:100] # 12. Let's try the Gadfly plotting package. This library offers a high-level plotting interface inspired by Grammar of Graphics. In the notebook, plots are interactive thanks to the **d3.js** library. # In[ ]: Pkg.add("Gadfly") using Gadfly # In[ ]: plot(x=1:100, y=m, Geom.point, Geom.line) # 13. Now, we compute a Julia set by using two nested loops. In general, and unlike Python, there is no significant performance penalty using `for` loops instead of vectorized operations in Julia. High-performance code can be written either with vectorized operations or `for` loops. # In[ ]: @time m = [julia(complex(r, i), complex(-0.06, 0.67)) for i = 1:-.001:-1, r = -1.5:.001:1.5]; # 14. Finally, we use the `PyPlot` package to draw matplotlib figures in Julia. # In[ ]: Pkg.add("PyPlot") using PyPlot # In[ ]: imshow(m, cmap="RdGy", extent=[-1.5, 1.5, -1, 1]); # > You'll find all the explanations, figures, references, and much more in the book (to be released later this summer). # # > [IPython Cookbook](http://ipython-books.github.io/), by [Cyrille Rossant](http://cyrille.rossant.net), Packt Publishing, 2014 (500 pages).