# Getting Visual With It

### Time to Get Vizzy With It!

Like Will says:

Gettin vizzy wit it Na na na na na na na nana Na na na na nana Gettin vizzy wit it…

### Plot thickens

Time to turn on the lights and see what our data objects look like when we turn them
into visualized plots. Sure, we can use the `print`

function to see the *numbers* within
our **numpy** objects. Better yet, let’s turn our objects into pretty graphical images. To do so, we turn to
the `matplotlib`

library. An extensive library of plotting routines that easily allows us to render
image plots into many different formats (png, jpg, pdf, etc…) - both onto the screen for quick visual inspection, or written
to a file for general use.

### Mandelbrot

To demonstrate the use of **numpy** and **matplotlib** let’s look at computing the complex numbers
found in the Mandelbrot set. A quick review here of complex numbers and the Mandelbrot fractal
generated by performing a calculation across a range of complex numbers.

A complex number is a number that can be expressed in the form $a + bi$, where $a$ and $b$ are real numbers, and $i$ is a solution of the equation $x^{2} = −1$.

The Mandelbrot set is the set of complex numbers, c for which the function $f_{c}(z)=z^{2}+c$ does not diverge when iterated from $z=0$.

Fortunatly, **numpy** can represent complex numbers just as easily as it represents integers or floats. We can create an array of complex
numbers like:

```
a = np.array([[1+2j, 2+3j], [3+4j, 4+5j]])
>>> a
array([[ 1.+2.j, 2.+3.j],
[ 3.+4.j, 4.+5.j]])
```

You may notice, we use $j$ and not $i$. Why you ask? Engineering convention uses $j$ whereas mathematicians use $i$. They both represent $\sqrt{-1}$.

### Compute and Plot a classical Mandelbrot set

We’ll **numpy** and **maplotlib** to generate and plot the classical **Mandelbrot**.

Here is a basic gist of code that imports our libraries, defines a Mandelbrot function, and plots the calculated points.

```
import numpy as np
import matplotlib.pyplot as plt
def mandelbrot(h,w, maxIterations=25):
y,x = np.ogrid[ -1.4:1.4:h*1j, -2:0.8:w*1j ]
c = x+y*1j
z = c
divtime = maxIterations + np.zeros(z.shape, dtype=int)
for i in range(maxIterations):
z = z**2 + c
diverge = z*np.conj(z) > 2**2
div_now = diverge & (divtime==maxIterations)
divtime[div_now] = i
z[diverge] = 2
return divtime
plt.figure(figsize=(10,10))
plt.imshow(mandelbrot(1024, 1024, 50))
plt.axis('off')
plt.show()
```

Let’s break down our code above into three sections:

- library imports
`mandelbrot()`

function- plotting

The first section is straight-forward - but notice that we import the **pyplot** sublibrary and name is **plt**.

Next we define the **mandelbrot** function. The **numpy** functions that we need to understand here are **ogrid**, **conj**, and
**zeros**.

Lastly, we take the return value from the **mandelbrot** function, our array of complex values representing divergence times, and pass
this into the **matplotlib** **pyplot.imshow()** function. But before we do that, we want to set up our plot. We first use **figure**
to establish the size of our plot. and we use **axis** to turn off the $x$, and $y$ axis which are on by default. Lastly, we call
the **show()** function to render our plot onto the screen.

Pretty cool! and very straight-forwad. Let’s modify our function to pass the exponent of the function, $z=z^{exp}+c$ and modify our plotting to put multiple subplots into one plot. Rather than plot the classical function $z=z^{2}+c$, let’s examine what happens when we plot the following for exponents: $1.2, 1.4, 1.6$, and $1.8$.

### Subplotting along

Instead of creating one plot of the classical Mandelbrot, let’s create one plot containing four subplots with the list of exponents above.

In order to create a subplot within our plot we need to specify a grid of rows and columns. We can then incrementally select each subplot, starting with the first row amd column, and proceeding left to right across the columns, and top to bottom across the rows, beginning with $1$ and ending with the $n^{th}$ row and $n^{th}$ column.

Modifying our code above, we can create a plot containing four subplots:

```
import numpy as np
import matplotlib.pyplot as plt
def mandelbrot( h,w, exp, maxIterations=20 ):
y,x = np.ogrid[ -1.4:1.4:h*1j, -2:0.8:w*1j ]
c = x+y*1j
z = c
divtime = maxit + np.zeros(z.shape, dtype=int)
for i in range(maxIterations):
z = z**exp + c
diverge = z*np.conj(z) > 2**2
div_now = diverge & (divtime==maxIterations)
divtime[div_now] = i
z[diverge] = 2
return divtime
def makeplot(exps, h, w, iterations):
plt.figure(figsize=(10,10))
for e in range(len(exps)):
plt.subplot(2,2,e+1)
plt.imshow(mandelbrot(h,w,exps[e], iterations))
plt.axis('off')
plt.title('Fractal with exp = ' + str(exps[e]))
plt.show()
exps = [1, 1.2, 1.5, 1.8]
makeplot(exps, 1024, 1024, 50)
```

Running our program would produce the plot below.

Disecting the code above, we see a few mods to the previous version that generated the classic Mandelbrot.
We’ve added a function, **makeplot()** that we will call for each element in our array, **exps**, of exponents. Looking inside
**makeplot** notice we first call **plt.subplot(2,2,e+1)**. Here we are telling plot that we want a 2x2 grid of subplots, and we
start with 1 (e+1 since e ranges from 0 to 4). Next we place the generated image into the plot with **imshow**. We turn off the axis,
and lastly set a title. That’s it! There are many many more sophisticated things that you can do with **matplotlib**. As a noob, this
just scratches the surface, but gives you a real-world feel of what can be accomplished. Look at the gallery
of samples to see more elaborate examples.