Python101/Session 4 - Plotting/Session 4 - Exercise Soluti...

552 KiB

<html> <head> </head>
In [1]:
import matplotlib.pyplot as plt

Exercise 1.1 - 1-5

In [2]:
# --- EXERCISE 1.1 ---
x = [1, 3, 6, 9, 16]
y = [7, 3, 7, 1, 5]

plt.plot(x, y, 'k.-', label='Original curve')


# --- EXERCISE 1.2 ---
plt.title('Title with random equation for showcase $c = \sqrt{a^2+b^2}$')


# --- EXERCISE 1.3 ---
plt.xlabel('This is the xlabel $x$')
plt.ylabel('This is the ylabel $y$')


# --- EXERCISE 1.4 ---
y2 = [9, 5, 5, 2, 6]
y3 = [4, 6, 2, 6, 8]
y4 = [1, 8, 1, 3, 2]

plt.plot(x, y2, label='Second curve')
plt.plot(x, y3, label='Third curve')
plt.plot(x, y4, label='Fourth curve')

# --- EXERCISE 1.5 ---
# The labels in the plot commands above were
# added as part of this exercise

plt.legend()
plt.show()

Some addtional info

Almost every aspect of the figure can be modified. For instance, the legend is located on top of the plot. It placed it in the location where there is least overlap, but still not ideal.

An explicit location can be specified as shown in the documentation: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.legend.html

It basically says that you can do:

plt.legend(loc='inset_location_string_or_code')

The available location strings/codes from the documentaion are shown in the table below. If not specified it will be set to loc='best'.

Location String Location Code
'best' 0
'upper right' 1
'upper left' 2
'lower left' 3
'lower right' 4
'right' 5
'center left' 6
'center right' 7
'lower center' 8
'upper center' 9
'center' 10

However, these locations are all inside the Axes (i.e. the actual plotting area). If we want the legend outside the plot, we could do it like this:

Note that I did not know how to do this before I made the exercise myself. I just googled for the solution.

In [3]:
x = [1, 3, 6, 9, 16]
y = [7, 3, 7, 1, 5]
y2 = [9, 5, 5, 2, 6]
y3 = [4, 6, 2, 6, 8]
y4 = [1, 8, 1, 3, 2]
plt.plot(x, y, 'k.-', label='Original curve')
plt.plot(x, y2, label='Second curve')
plt.plot(x, y3, label='Third curve')
plt.plot(x, y4, label='Fourth curve')

# Set legend location via 'bbox_to_anchor'
plt.legend(bbox_to_anchor=(1.0, 0.5), loc='center left')
# The numbers in paranthesis are in fractions of figure width and height

plt.show()

Exercise 1.6

Since we did not save the plot from Exercise 1.1-1.5 to a figure object, we need to repeat the code to create a new plot. This is becuase the plt.show() command shows and 'exhausts' the plot so it is inaccessible afterwards, unless it is saved in a figure object.

So, we repeat the code, this time saving the plots to a figure object.

In [4]:
# Create figure object to store plots inside
fig = plt.figure()

# ---REPEAT CODE FROM EXERCISE 1.1-1.5 ---
x = [1, 3, 6, 9, 16]
y = [7, 3, 7, 1, 5]
y2 = [9, 5, 5, 2, 6]
y3 = [4, 6, 2, 6, 8]
y4 = [1, 8, 1, 3, 2]
plt.plot(x, y, 'k.-', label='Original curve')
plt.title('Title with random equation for showcase $c = \sqrt{a^2+b^2}$')
plt.xlabel('This is the xlabel $x$')
plt.ylabel('This is the ylabel $y$')
plt.plot(x, y2, label='Second curve')
plt.plot(x, y3, label='Third curve')
plt.plot(x, y4, label='Fourth curve')
plt.legend(bbox_to_anchor=(1.0, 0.5), loc='center left')

# Save figure to a file 
fig.savefig('myfig.png')

In the saved png file, the legend appears to have been cut off. I dont' know why it cannot handle this. This would not have been a problem if it had stayed inside the plotting area.

A way to get it to show correctly could be to create a new Axes object to the right of the Axes object that contains the plots. Recall the Axes is the "plotting area".

So:

In [5]:
# Create figure object to store plots inside
fig2 = plt.figure(figsize=(14, 6))

# Create new axes object for putting legend
ax_leg = fig2.add_axes([0.1, 0.1, 0.6, 0.75])

# ---REPEAT CODE FROM EXERCISE 1.1-1.5 ---
x = [1, 3, 6, 9, 16]
y = [7, 3, 7, 1, 5]
y2 = [9, 5, 5, 2, 6]
y3 = [4, 6, 2, 6, 8]
y4 = [1, 8, 1, 3, 2]
plt.plot(x, y, 'k.-', label='Original curve')
plt.title('Title with random equation for showcase $c = \sqrt{a^2+b^2}$')
plt.xlabel('This is the xlabel $x$')
plt.ylabel('This is the ylabel $y$')
plt.plot(x, y2, label='Second curve')
plt.plot(x, y3, label='Third curve')
plt.plot(x, y4, label='Fourth curve')

# Add legend to new axes object
ax_leg.legend(bbox_to_anchor=(1.0, 0.5), loc='center left')

# Save figure to a file 
fig2.savefig('myfig2.png')

Exercise 2.1

In [6]:
plt.figure(figsize=(18, 5))
x = [1, 3, 6, 9, 16]
y = [7, 3, 7, 1, 5]
y2 = [9, 5, 5, 2, 6]
y3 = [4, 6, 2, 6, 8]
y4 = [1, 8, 1, 3, 2]

plt.subplot(141)
plt.plot(x, y)

plt.subplot(142)
plt.plot(x, y2)

plt.subplot(143)
plt.plot(x, y3)

plt.subplot(144)
plt.plot(x, y4)
plt.show()

Exercise 2.2

Only difference from the code in Exercise 2.1 is to change plt.plot() to plt.bar()

In [7]:
plt.figure(figsize=(18, 5))
x = [1, 3, 6, 9, 16]
y = [7, 3, 7, 1, 5]
y2 = [9, 5, 5, 2, 6]
y3 = [4, 6, 2, 6, 8]
y4 = [1, 8, 1, 3, 2]

plt.subplot(141)
plt.bar(x, y)

plt.subplot(142)
plt.bar(x, y2)

plt.subplot(143)
plt.bar(x, y3)

plt.subplot(144)
plt.bar(x, y4)
plt.show()

Exercise 3.1

In [8]:
import numpy as np
xx = np.linspace(-100, 100, 100)
yy = xx**2-3027
plt.plot(xx, yy)
plt.fill_between(xx, yy, where= yy<0, color='darkorchid',  alpha=.25)
plt.show()

Exercise 4.1

In [26]:
%%capture 
# %%capture prevent plots from showing after the cell
# ------------------------------------------------------

# Solution:

# Define x-values
x_arr = np.linspace(1, 10, 10)

# Copied y-values from exercise
y_arr1 = np.random.rand(10)
y_arr2 = np.random.rand(10)
y_arr3 = np.random.rand(10)
y_arr4 = np.random.rand(10)
y_arr5 = np.random.rand(10)

# Create list of the y-arrays
y_arrays = [y_arr1, y_arr2, y_arr3, y_arr4, y_arr5]

# Define names for the png files for each plot
names = ['plot1', 'plot2', 'plot3', 'plot4', 'plot5']

# Loop over all graphs and save as png file with their names 
for y_arr, name in zip(y_arrays, names):
    
    # Create a figure object
    plt.figure()
    
    # Create plot for current y-array
    plt.plot(x_arr, y_arr)
    
    # Save to figure and name file with current name
    plt.savefig(f'{name}.png')
    

Some notes to the solution

The zip() function puts two (or more) lists up beside eachother so it becomes easier to iterate over them:

for y_arr, name in zip(y_arrays, name):
    # Inside the loop, the i'th elements of the lists
    # can be referred to as 'y_arr' and 'name'

The same outcome could be obtained by creating a counter variable outside the loop and use that as index to refer to the i'th element of the lists:

i = 1  # Initial value for counter
for i in range(len(y_array)):
    # Inside the loop, the i'th elements of the lists 
    # can be referred to as 'y_array[i]' and 'names[i]' 

    i += 1 # Increase counter by 1

Choose whatever method you find the easiest.

If a new figure object is not created in each loop as plt.figure(), consecutive plots will be added to eachother. So, first png file will contain first plot, second png file will contain the first two and the last file will contain all the plots.

</html>