Weeks 3 & 4: Beta Edition

Picking up from the last two weeks of the internship; the first modules of LancAstro had been created and seemed to be working. Now it was time to create the more complex scripts envisioned, such as 3D plotting, scripts to fit functions to data, regression etc.

To give me a better chance of doing this, my supervisor David decided that it would be best to go through example scripts he had to make specific figures, like those for papers he had wrote. My task would be to go through them and organise each one to have the same generic structure.

Firstly a ‘pre-amble’. This sets out the name of the script, the date it was last edited, its author and version number, plus a short description of what it does. Lets use the Ionisation_n_Excitations.py script as an example of this standard format:

# ============================================================================
# ======================= Ionisation_n_Excitations ===========================
#
# Author: Dr David Sobral
# Version: 
# Date: 22.07.2019
#
# Script to demonstrate the Boltzmann and Saha functions with ionised hydrogen
#
# Edited by Harry Baker as part of the LancAstro Example Library
# for the XGAL Internships 2019 
#

Next comes the imports where packages are imported into Python and named. These were corrected for Python 3.7 use and removed any instances of

from numpy import *

to

import numpy as np

or anything similar as using * means methods are called without designating which package they are from which can lead to errors if two packages share methods with the same names.

# ============================================================================
# 							  IMPORTS	
# ============================================================================

from astropy.io import fits as pyfits	# Import pyfits to handle FITS files
import matplotlib as mpl 				# Import matplotlib for various stuff
import matplotlib.pyplot as plt 		# Import pyplot for plotting
import numpy as np 						# Import numpy for maths functions
mpl.rc('text', usetex = True) 			# Set to use LaTeX font formatting

Now follows the functions or methods. Each one has a ‘docstring’ which is a comment section under the definition of the method which gives a description of its function, then lays out the arguments it takes and what it should return.

# ============================================================================
#							FUNCTIONS
# ============================================================================

def Boltzmann(T,g1=2.,g2=8.,DE=10.2):
	""" Creates the Boltzmann distribution

	Args:
		T: Temperature
		
		g1: 

		g2:

		DE:

	Returns:
		The Boltzmann distribution
	"""
	Kb = 1.38*10.**(-23.)
	Ev_to_J = 1.6*10.**(-19.)
	return (g2/g1)*np.e**(-(DE*Ev_to_J)/(T*Kb))

As you can see, I didn’t fully understand the arguements for each method well enough to put down their descriptions in the docstring but hopefully people could see the general idea of how to lay one out.

Python does allow for some pretty cool use of docstrings. If written correctly, a user can type

help(methodname) 

into the terminal and it will return the docstring for that method, so you can see what arguments it should have etc.

All the parameters or settings that are used come next. This mainly consists of a series of commands which update the Matplotlib.rcParams which set out all the default settings of how Matplotlib outputs figures. These include axis tick sizes, label sizes, font sizes, etc.

By standardising these across all scripts, figures can always be produced which have the same style, lets say XGAL style!

# ============================================================================
# 							PARAMETERS
# ============================================================================
# FIGURE AND AXIS SIZES ======================================================
mpl.rcParams['xtick.labelsize'] = 14		# Size of x-tick labels
mpl.rcParams['ytick.labelsize'] = 14		# Size of y-tick labels
mpl.rcParams['axes.labelsize'] = 14			# Size of axes labels
mpl.rcParams['image.origin'] = 'lower'		# 

mpl.rcParams['axes.linewidth'] = 2.5		# Size of axes line width
mpl.rcParams['xtick.major.size'] = 14		# Size of major x-ticks	
mpl.rcParams['xtick.minor.size'] = 6		# Size of minor x-ticks
mpl.rcParams['xtick.major.width'] = 2.5		# Width of major x-ticks  
mpl.rcParams['xtick.minor.width'] = 1.5		# Width of minor x-ticks
mpl.rcParams['ytick.major.size'] = 14		# Size of major y-ticks
mpl.rcParams['ytick.minor.size'] = 6		# Size of minor y-ticks
mpl.rcParams['ytick.major.width'] = 2.5		# Width of major y-ticks
mpl.rcParams['ytick.minor.width'] = 1.5		# Width of minor y-ticks

# Sets font style and size
mpl.rcParams.update({'font.size': 18, 'font.weight': 'bold'})

# FIGURE =====================================================================
filename = 'Excited_H_demo.pdf'
figsize = (14.7,6)

# AXIS DIMENSIONS ============================================================
x_min = 0.0                				# Minimum x-axis value to plot
x_max = 20900            				# Maximum x-axis value to plot
y_min = -0.01           				# Minimum y-axis value to plot
y_max = 1.08        					# Maximum y-axis value to plot

axis_ranges = [x_min,x_max,y_min,y_max] # Dimensions of axes

# AXIS TICKS =================================================================
# Positions of x-ticks
x_ticks = np.arange(0,21000,2000)

# Positions of y-ticks        		  
y_ticks = np.round(np.arange(0,1.1,0.2),1)

You can see how this section also defines the axis-tick positions and labels and the range of the plot so that in the main, the commands to set these are always the same for every script, thereby making it much clearer to the user how a figure is actually set up and created.

The final part is the ‘main’. This is where the actual program is executed, mainly consisting of creating/ loading data, processing it to be ready to plot, then plotting it and producing and customising the figure ready to be saved.

# ============================================================================
#								MAIN PROGRAM
# ============================================================================
# PLOTTING ===================================================================

# SETUP PLOT:
f, ax1 = plt.subplots(1,1, sharey=True, figsize=figsize)

# Adjust spacing between sub-figures
plt.subplots_adjust(wspace = 0.02)

# Create a range of temperatures from 0K-30000K in increments of 100K
x = np.arange(1.0,30000.,100)

# Create the Boltzmann distribution with given temperature range
y = Boltzmann(x)

# Produces tbe Saha partition function with given temperature range
y2,y3 = Saha(x)

# Plot Boltzmann distribution
Boltz = ax1.plot(x,y*1000.,color = 'b', linestyle = '-',linewidth = 3.9,
				 alpha=0.7,zorder=-10)

At first, editing scripts was quite laborious. Many were written in Python 2.7. That’s fine, fairly easy to convert over to Python 3.7 by removing/ editing the print statements for example of a classic difference between the languages:

print "Hello world!"        # Python 2.x
print("Hello world!")       # Python 3.x

However, the script may run then but there will be a few subtle differences between the original figure and the new one. Small things like ticks missing on the top and right axis, or labels a few points to the side of where they were etc. These often-required hours of tinkering to find a small piece of syntax that may fix it or having to adjust the co-ordinates of a label several times till it lined up again, such as the example of Fig 1.

Fig 1: Figure to demonstrate Wien’s Law. Converting over from Python 2 to 3, all the labels for each band of the EM spectrum were mis-aligned so their co-ordinates had to be manually redefined

After the first few days though I managed to get into the rhythm of it by finding the common commands to convert over to Python 3 that would often mean the new figure was identical to the original first time. The larger task was re-organising the code into the format I spoke of earlier. This required me to scour through the code to find where each bit should belong. Also tricky was attempting to write the docstrings for functions that I couldn’t understand the meaning of. At least though the main purpose of this exercise was to produce example code of how to make different python figures so how the data was created/ handled didn’t really matter. And, as I endeavoured to find out how these different scripts worked, I was learning more Python skills which was also the point of doing this.

Fig 2: Example of a fairly complicated figure with subplots and different x-axis made from a script updated to Python 3 taken from Sobral et. al 2018 paper

By the end of the 4th week of the internship, I had fully re-organised and updated 11 scripts, 2 of which are for figures in a 2018 paper by Sobral et. al concerning SC4K data.

Now I had to compile these into some documentation that would show the example figure and which script made it, and explain how these are laid out and work. So, I produced a document in LaTeX with some cool boxes to highlight how to say make a legend or multiple plots. I put the XGAL logo I made in the last blog in there too on the front cover for good measure and hey presto!

Also during the fortnight, I’ve been improving and tinkering with the existing modules of LancAstro.py. Heather and Amaia have been working on outreach projects (check out their XGAL from Lancaster to the World blog), one of which required a gif showing how a spectrum changes with increasing redshift with filter profiles plotted on the same figure too. This seemed like a perfect job for ScatterPlot! With a bit of fettling, and script that executed ScatterPlot in a for loop with increasing redshift, outputting the figure to an iterate-able filename, a series of frames were created!

ScatterPlot had done its job. It had gone once more into the breach and survived with some new options and parameters to show for it!

My reward for its outstanding performance? ScatterPlot being reorganised into Plot2D, for a safe and secure LancAstro!

This could now plot any array of data, line, scatter etc with different point styles, colours, labels, errorbars. You name it, Plot2D could *probably* do it!

And that rounds up the fortnight’s work. Stay tuned for LancAstro: Release Edition which will detail the final week of my internship as LancAstro gets new modules and ventures into the 3rd dimension!  

-Harry

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s