## Histogram

**Histograms** are one of the heavily used plots across functions as it gives a very good view of the distribution of data.

## Line

Single line:

## Several Lines

How do we add multiple lines in the same chart? Let us take it a bit further to plot multiple lines in the same chart.

# Bar Plot

Bar plots are one of the most popular charts used in any type of visualization as it shows the relative data points in an emphasized manner like a line chart.

**Scatter Plot**

**Fractals** – a subset of Euclidean space with a fractal dimension that strictly exceeds its topological dimension – are one of my fondest topics in mathematics. I have always been fascinated by fractals, and the first piece of code I ever wrote was to create fractals.

The Julia set is one of the most beautiful fractals to have been discovered. Named after the esteemed French mathematician Gaston Julia, the Julia set expresses a complex and rich set of dynamics, giving rise to a wide range of breathtaking visuals.

In this article, we will explore how to use `Python`

to create the Julia set.

**Complex Numbers**

The Julia set lies on the complex plane, which is a space populated by complex numbers. Each point you see in the image above corresponds to a specific complex number on the complex plane with value: *z* = *x* + *yi*,

where *i* = √-1 is the imaginary unit.

Complex numbers have very interesting dynamics which is what gives the Julia set its complex dynamics, but for now let us take a look at real numbers, the numbers that we encounter in everyday life.

If you take the square of the real number 10, you get 100. Taking the square of 100 leads to 10,000. If we keep taking the square of the result, we get 100,000,000 in the next iteration, an astronomically large number in the next, and an even larger number in the next. Doing this enough times, we eventually tend to infinity, and we can say that the operation described is not bounded.

On the other hand, if you take the square of the real number 0.1, you get 0.01. Taking the square of 0.01 leads to 0.0001, and as with above if we keep taking the square of the result, we get 0.00000001 in the next number, a microscopically small number in the next and an even smaller number in the next. Doing this enough times we eventually tend to zero, and we can say that the operation described is bounded.

It turns out that complex numbers also behave similarly. If we take the square of the complex number 1 + *i*, we get 2*i*. If we square that we get -4. Repeating this we end up with 16, 256, 65536, 4294967296 and so on until we tend to infinity. This is similar to what happens if we iteratively square the result of the square of 10.

Likewise, if we take the square of 0.5 + 0.5*i*, we get 0.5*i*, -0.25, 0.0625, 0.00390625 and so on until we tend to 0. This is similar to what happens if we iteratively square the result of the square of 0.1.

**Iterative Operations on the Complex Plane**

Now instead of doing this iterative squaring operation on a single complex number, we can do this for an grid of complex numbers ** z** lying on the complex plane. In addition to the squaring operation, we also add an arbitrary complex number

*c*after the squaring operation to get the operation

**:=**

*z***+**

*z*

*c.*

After multiple iterations of ** z** :=

**+**

*z*

*c*, most complex numbers in

**will blow up to infinity, while some will remain bounded. During the iterative process we track how many iterations it takes for a complex number in**

*z***to blow up to infinity. It is this number of iterations measurement for each complex number in the grid that contains the image of the fractal in the image above.**

*z***Creating the Julia Set with Python**

The Python code to create the Julia set is given below. The function `julia_set`

takes the arguments `c`

an arbitrary complex number, `num_iter`

the number of iterations to perform, `N`

the number of grid points on each axis in the grid, and `X0`

the limits of the grid.

```
import numpy as np
import matplotlib.pyplot as plt
def julia_set(c = -0.835 - 0.2321 * 1j, num_iter = 50,
N = 1000, X0 = np.array([-2, 2, -2, 2])):
# Limits of the complex grid.
x0 = X0[0]
x1 = X0[1]
y0 = X0[2]
y1 = X0[3]
# Set up the complex grid. Each element in the grid
# is a complex number x + yi.
x, y = np.meshgrid(np.linspace(x0, x1, N),
np.linspace(y0, y1, N) * 1j)
z = x + y
# F keeps track of which grid points are bounded
# even after many iterations of z := z**2 + c.
F = np.zeros([N, N])
# Iterate through the operation z := z**2 + c.
for j in range(num_iter):
z = z ** 2 + c
index = np.abs(z) < np.inf
F[index] = F[index] + 1
return np.linspace(x0, x1, N), np.linspace(y0, y1, N), F
```

During each step in the `for`

loop, after `z = z ** 2 + c`

we check which points in `z`

are still smaller than `np.inf`

. The number of iterations taken by each point to blow up to infinity is recorded in `F`

. By plotting `F`

as a 2 dimensional image, the Julia set finally reveals itself. For example, the code below results in the image shown at the top of this post!

The light areas in the image correspond to points in the complex plane `z`

that blow up to infinity very quickly after only several iterations, while the dark areas correspond to points that are bounded even after many iterations!

```
x, y, F = julia_set(c = 0.285 + 0.01 * 1j, num_iter = 200,
N = 1000, X0 = np.array([-1.5, 1.5, -1.5, 1.5]))
plt.figure(figsize = (10, 10))
plt.pcolormesh(x, y, F, cmap = "gist_heat")
plt.axis('equal')
plt.axis('off')
plt.show()
```

As mentioned earlier, the Julia set has a rich and complex set of dynamics. This can be explored by changing the value of *c*! For example if we use the value *c* = -0.835–0.2321*i*, we get the visualization below, which is completely different from the previous one.

```
x, y, F = julia_set(c = -0.835 - 0.231 * 1j, num_iter = 200,
N = 1000, X0 = np.array([-1.5, 1.5, -1.5, 1.5]))
plt.figure(figsize = (10, 10))
plt.pcolormesh(x, y, F, cmap = "gist_heat")
plt.axis('equal')
plt.axis('off')
plt.show()
```

In fact, we can take things one step further, and define *c* to be the entire complex grid, by using `c = x + y`

instead using the value of the input argument in the code above. In this case, the resulting fractal is so famous that it has its own name — the Mandelbrot set.

Un uomo libero, quando è sconfitto, non dà la colpa a nessuno.

*Iosif Brodskij*

Here, we will discuss about image transformation: geometrical, color, point some image thresholding, image enhancement buy applying filters, editing GIF, drawing on an image, image conversion and modification in bulk and rolling image using `PIL`

.`Pillow`

is a fork of `PIL- Python Imaging Library`

that will support Python 3.x.

Installing `pillow`

library:

`pip install PIL`

**The important class of the library: Image**

Opening the image and getting details about it.

```
from PIL import Image
im = Image.open('simpson.png')
print(im.size, im.mode, im.format)
#(1600, 1200) RGBA PNG
im.show()
#To open the image
```

As you can see from the comand:

```
print(im.size, im.mode, im.format)
#(1600, 1200) RGBA PNG
```

the image has a RGBA color profile. We can convert it to jpeg **only** after converting it to RGB:

```
rgb_im = im.convert('RGB')
rgb_im.save('simpson_new.jpg')
```

Rotate an image:

```
from PIL import Image
import os
im = Image.open('simpson.png')
im = im.rotate(45) # rotate the object im 45 degrees
rgb_im = im.convert('RGB')
rgb_im.save('simpson_45.jpg')
im.close()
```

You can resize the image through the `resize`

command:

```
from PIL import Image
import os
im = Image.open('simpson.png')
rx = int(im.width/10)
ry = int(im.height/10)
im=im.resize((rx,ry)) #rx and ry are new pixel of image
rgb_im = im.convert('RGB')
rgb_im.save('simpson_resized.jpg')
im.close()
```

Add a text to immage:

```
from PIL import Image, ImageDraw, ImageFont
import os
im = Image.open('simpson.png')
d1 = ImageDraw.Draw(im)
myFont = ImageFont.truetype('Monofur/monofur bold Nerd Font Complete Mono Windows Compatible.ttf', 140)
d1.text((650,700), 'Hello World', font=myFont, fill=(255,255,0))
im.save('simpson_hello.png')
im.close()
```

Crop and paste the parts of the image:

```
from PIL import Image
import os
#path = # path of the image that you won't to open
#os.chdir(path)
im = Image.open('simpson.png')
print(im.size, im.mode, im.format)
#(1600, 1200) RGBA PNG
box = (531,38,957,434) #Two points of a rectangle to be cropped
cropped_part = im.crop(box)
cropped_part = cropped_part.transpose(Image.ROTATE_180)
im.paste(cropped_part,box)
im.show()
#To open the image
```

Che a restare incinte siamo noi donne, che a partorire siamo noi donne, che a morire partorendo, o abortendo, siamo noi. E che la scelta tocca dunque a noi. A noi donne. E dobbiamo essere noi donne a prenderla, di volta in volta, di caso in caso, che a voi piaccia o meno.

*Oriana Fallac*i