In [ ]:
from numpy import *
In [ ]:
def dummy_func(x=0, y=0):
"""This function takes two optional arguments (x and y) with default values of zero and adds them together
to create a new variable z, then prints it."""
z=x+y
z
In [ ]:
dummy_func()
There are a few things to note here. First that the function did not print out z, even though in an ordinary notebook cell (without a function definition) typing the variable name alone usually prints the value stored in it. That's not the case with functions because functions will only return to output what you tell them to. If you want to print the value of something within a function, then you must use a print statement. For example:
In [ ]:
def dummy_func(x=0, y=0):
"""This function takes two optional arguments (x and y) with default values of zero and adds them together
to create a new variable z, then prints it."""
print("x is", x)
print("y is", y)
z=x+y
print("z is", z)
In [ ]:
dummy_func(2,3)
This brings up another subtelty that it's worth reemphasizing here - optional arguments can be specified in a function call in any order but if you don't specify which variable is which in the function call, it will assume that you are specifying them in the order that you defined them in the function. For example, as I've written the function, you should be able to specify none, one or two arguments in any order.
Make sure you understand what each of the following cells are doing before moving on
In [ ]:
dummy_func(1)
In [ ]:
dummy_func(y=1)
In [ ]:
dummy_func(y=3,x=2)
In [ ]:
dummy_func(3,2)
OK back to the function dummy_func and the idea of return statements. Note that we did not include a return statement in the definition cell. A return statement is not necessary to delimit the end of a function, though it can be visually useful in that way.
In fact, a function will consist of any code that is indented beneath it. If you remove the indentation, any code that you write is no longer considered part of the function. For example:
In [ ]:
def dummy_func(x=0, y=0):
"""This function takes two optional arguments (x and y) with default values of zero and adds them together
to create a new variable z, then prints it."""
print("x is", x)
print("y is", y)
z=x+y
print("z is", z)
print('This is not part of the function and will not be printed when I call it. It will print when I execute this cell')
In [ ]:
dummy_func()
In [ ]:
def dummy_func(x=0, y=0):
"""This function takes two optional arguments (x and y) with default values of zero and adds them together
to create a new variable z, then prints it."""
print("x is", x)
print("y is", y)
z=x+y
print("z is", z)
return
In [ ]:
dummy_func()
Note that nothing changed about the output when we added a return to dummy_func. Regardless of where it is embedded in a function, a return statement always tells Python that the function is complete and it should stop execution and return to a command prompt. In this way, it can sometimes be useful inside a function. For example, consider the following function (from Lab 3 solutions)
In [ ]:
def temp_convert(system="C"):
"""
Description:
Asks user to input a temperature, and prints it in C, F and K.
Required Inputs: none
Optional Inputs:
system - string variable that allows the user to specify the temperature system.
Default is C, but F and K are also options.
"""
#ask the user to enter a temperature
input_temp = input("enter a temperature (set system keyword if not Celsius):")
# default input type is string. Convert it to a Float
input_temp=float(input_temp)
#Convert all input temperatures to Celsius
if system == "C":
input_temp = input_temp
elif system == "F":
input_temp = (input_temp-32)*5/9
elif system == "K":
input_temp = input_temp - 273
else:
#if system keyword is not C, F or K, exit without any output and print a warning
print("unrecognized system - please specify C, F or K")
return
#Convert and print the temperatures
print('Temperature in Celsius is ', str(input_temp))
temp_f = input_temp*9/5 + 32
print('Temperature in Farenheit is ', str(temp_f))
temp_k = input_temp + 273
print('Temperature in Kelvin is ', str(temp_k))
return
In [ ]:
temp_convert(system="B")
In the example above, a return statement was used mid-function in order to break out of it when a bad temperature system is specified. This returns the prompt to the user BEFORE reaching the print functions below, which are bound to fail.
In this way, the return statement acts a bit like a "break" statement but break is only useable inside of loops (for, while) and it does not exit the entire function, but only the loop. For example, consider the following function (also from Lab #4 solutions).
In [ ]:
def order_please(names):
orders=''
foods=''
names.sort(key=len)
for a in names:
negg = input(a +": How many eggs would you like?")
spam = input(a +": Would you like Spam (yes or no)?")
if spam == "yes":
spam = ""
spam_print = "SPAM!"
elif spam == "no":
spam_print = "NO SPAM!"
else:
print('unrecognized answer. Please specify yes or no')
break
order =a +" wants "+negg + " eggs, and " + spam + " Spam"
food = a+": "+"egg "*int(negg)+"and "+spam_print
orders = orders+'\n\n'+order
foods = foods+'\n'+food
print(orders)
print(foods)
Like the return statement in the temperature conversion function, break is used here to handle unrecognized input, but here it functions only to end the for loop and not to exit the function. It will still reach the two print statements at the bottom and print any orders that were collected before the bad input. To verify this, exectute the cell below. For Rowan's order, enter 2 for eggs and no for spam. For Tasha's order, enter 3 eggs and yuck for spam. At the end, the function will still print Rowan's order, and skip Tasha's.
In [ ]:
order_please(['Rowan','Tasha'])
Note though that break will break you out of the for loop entirely. If you enter an unrecognized answer for spam in Rowan's order, it will not then ask Tasha for hers. Verify this by reexecuting the cell above and entering a bad value for spam in Rowan's order.
Note too that entering return in place of break in the function above would have stopped the code entirely at that point, and would not have printed the good order before exiting. Try swapping it out in the function definition to verify this.
Return statements are not only useful as code breaks, however. Their main purpose is to return calculated values, arrays, etc. to the user so that they can be referenced in future code cells. So far our code has mostly involved printing things, but sometimes we want to use and manupulate the output of a function and so it needs to be passed back to the user. For example:
In [ ]:
def dummy_func(x=0, y=0):
"""This function takes two optional arguments (x and y) with default values of zero and adds them together
to create a new variable z, then prints it."""
print("x is", x)
print("y is", y)
z=x+y
print("z is", z)
return z
In [ ]:
dummy_func()
Note in executing the cell above, you now have output (z in this case). Nice, but stil not that useful since it just tells you what it is. The function returns z as output, but does not store anything in a variable called z. So even though you defined z within the function and returned it, python will not recognize the variable. You can see this by executing the cell below, which will return an error.
In [ ]:
z
This is an important higher-order thing to note about functions - variables only have meaning within them, not outside them. If I want the function to return whatever I've told it to return (z) and store it in a variable, I have to tell it so via the following syntax:
In [ ]:
z = dummy_func()
This time, I've told python that it should take the output of dummy_func and store it in the variable z.
Functions can return arbitrary numbers of things as well
In [ ]:
def dummy_func(x=0, y=0):
"""This function takes two optional arguments (x and y) with default values of zero and adds them together
to create a new variable z, then prints it."""
print("x is", x)
print("y is", y)
z=x+y
print("z is", z)
return x, y, z
In [ ]:
dummy_func()
And when you want to assign them to variables, you use a similar syntax, though it seems a bit funny.
In [ ]:
x, y, z = dummy_func()
In [ ]:
x
In [ ]:
y
In [ ]:
z
Note that when you define a function with multiple return variables and you assign those returned variables into stored variables with = you must have an equal number of assigned variables as returned variables. For example, the following will return an error.
In [ ]:
x, y = dummy_func()
You've already made some plots for this course, however we have not yet manipulated their appearance in any way. For example, in Homework #2, you wrote functions that returned double slit interference patterns that looked like this:
As you can see, python (unlike many languages) generally does a lovely job with coloring, line thickness etc. with simple plot commands. It does not, however, add titles, axis labels, legends, etc. and these are very important things to include. From now on, any plots that you make in Labs or homeworks should always, at a minimum, include: axis labels (including units), a plot title and a legend in any case where there's more than one line on the same plot.
There are many useful optional inputs to the plot command that allow you to tweak the appearance of the plot, including: linestyle, color, placement of the legend, etc.
So let's learn the basics by plotting some things.
So far we have been using the command %pylab inline to allow jupyter to insert inline plots in our notebooks. Now we are going to do this more properly by importing the matplotlib library's plotting module pyplot an then telling the notebook that you still want it to display any plots inline (inside the notebook) with the magic function %matplotlib inline with the following lines
In [ ]:
import matplotlib.pyplot as plt
%matplotlib inline
This gives you access to all of pyplot's functions in the usual way of calling modules (plt.functionname). For example:
In [ ]:
x=arange(-10,10,0.01)
y=x**2
plt.plot(x, y)
Here are some especially useful pyplot functions, called with plt.functionname(input(s)):
Line properties are controlled with optional keywords to the plot function, namely the commands color, linestyle and linewidth. The first two have required string arguments (lists of the options are available here), and the third (linewidth) requires a numerical argument in multiples of the default linewidth (1).
These can be specified either in the call to the function or separately before or after the plot call.
See the cell below for an example of all of these at play
In [ ]:
plt.xlim(-5,5)
plt.ylim(0,20)
plt.xlabel("the independent variable (no units)")
plt.ylabel("the dependent variable (no units)")
plt.title("The Quadratic Function")
plt.plot(x, y, color='red',linestyle='--', linewidth=2.5)
Note these functions can be set before or after the plot command as long as they're within the same cell.
In [ ]:
plt.plot(x, y, color='red',linestyle='--', linewidth=2.5)
plt.xlim(-5,5)
plt.ylim(0,20)
plt.xlabel("the independent variable (no units)")
plt.ylabel("the dependent variable (no units)")
plt.title("The Quadratic Function")
As you have already encountered in your labs and homeworks, it is often useful to overplot functions on top of one another, which we do with multiple plot commands. In this case, what you need to make a quality graphic is a legend to label which is which. For example, let's plot the cubic function on top of the quadratic. In doing so below, note that we don't actually have to specify a separate variable, but that the arguments to a plot command can be combinations of variables
In [ ]:
plt.plot(x,x**2)
plt.plot(x,x**3)
To add a legend to a plot, you use the pyplot function legend. Perhaps the simplest way to use this function is to assign labels to each line plot with the label keyword, as below, and then call legend with no input. Note that the label keyword requires string input and that you can use LaTeX syntax within those labels
In [ ]:
plt.plot(x,x**2, label='$x^2$')
plt.plot(x,x**3, label='$x^3$')
plt.legend()
As you can see above, the default for a legend is to place it at the upper right of the plot, even when it obscures the underlying lines and to draw a solid line around it (bounding box). Generally speaking, bounding boxes are rather ugly, so you should nearly always (unless you really want to set the legend apart) use the optional Boolean (True or False) keyword "frameon" to turn this off. Legend also takes the optional keyword loc to set the location of the legend. Loc should be a string, and you can see the full list of options by accessing help for the legend function by hitting shift+tab+tab inside of the plt.legend parentheses below.
In [ ]:
plt.plot(x,x**2, label='$x^2$')
plt.plot(x,x**3, label='$x^3$')
plt.legend(loc="lower right", frameon=False)
Make a plot that meets the following criteria:
In [ ]:
# plotting code here
Insert Planck's Law here
Now, code a function with one required input (temperature) that will return a numpy array called Planck with two columns and 100000 rows. The first column should contain wavelength values between 0 and 100000 nanometers, and the second column should contain the corresponding $B_\lambda$ values. The output flux column should be in units of $W/m^2/nm$. The cell below will import all of the constants that you need to accomplish this.
In [ ]:
import astropy.units as u
from astropy.constants import G, h, c, k_B
In [ ]:
#the cell below should include your planck_func function definition
In [ ]:
# insert test statements here
In [ ]:
x = planck_func(1000)
x.shape
Use the output of the function to make a plot with appropriate labels (including units) and legend that shows the difference between a 6000K (sun-like) star's blackbody curve and those of stars that are slightly warmer (7000K) and cooler (5000K). Manipulate the x and/or y range of the plot to zoom in on the curves as much as you can while showing all three.
Reminder/Hint: Since the function returns a 2 x 10000 element matrix you will need to use array indices in your plot command. Remember that python array indices start from 0.
In [ ]:
#define your variables to be plotted (outputs from the function you defined) here
In [ ]:
#insert your plot commands here
Insert your description here
In [ ]:
##new normalized Planck function definition
In [ ]:
#define your variables to be plotted (outputs from the function you defined) here
In [ ]:
#insert your plot commands here
insert normalization paragraph
In [ ]:
#you should insert some code here to find the peak wavelength for each star
insert description of peak wavelengths here
In [1]:
from IPython.core.display import HTML
def css_styling():
styles = open("../custom.css", "r").read()
return HTML(styles)
css_styling()
Out[1]: