# -*- coding: utf-8 -*-
"""
Created on Fri Sep 25 14:09:12 2020

@author: jbobowsk
"""

# The tutorial basic_plots.m discussed how to plot data using 'plot' and
# 'errorbar' and then how to format those plots.  In this tutorial we plot
# functions.  Actually, we will give Python a function f(x) and then evaluate
# that function at a bunch of x-values.  You actually have to create a list of x 
# data and then evaluate the function  at all those values of x (thus creating 
# a list of y data) and then plot y vs x as in basic_plots.m.  At first, this 
# might seem odd, but it's actually not too bad.  In fact, it gives you full 
#control of the density of points to be used in the plots, whereas other prorams 
# will try to guess for you what might be a good number of points to use.

# I will first import the module numpy and 'matplotlib' which we will use
# for ploting.  Matplotlib provides a MATLAB-like interface.  Many of the 
# options used for plotting in MATLAB are the same in Matplotlib.
import math
import numpy as np
import matplotlib.pyplot as plt

# Here's a simple example of ploting sin x vs x.  First, create some x
# data.
xx = np.array(np.arange(0, 2*math.pi, 0.1))
print(xx)

# Next, create the y data
yy = np.sin(xx)

# Finally, create the plot.
plt.plot(xx, yy, 'ro-', markersize = 8, linewidth = 2,  fillstyle = 'none')
plt.xlabel(r'$x$')
plt.ylabel(r'$\sin x$')
plt.axis((0, 2*math.pi, -1, 1))

# Here's another example.  The function plotted below is the frequency
# derivative of a Lorentzian.  We first define a Python function.
def dlorentz(f, f0, Q0):
    return (Q0**2/f)*((f0/f)**2 - (f/f0)**2)/((1 + Q0**2*(f/f0 - f0/f)**2)**(3/2))

# The derivative of the Lorentzian has sharp features near the resonance
# frequency.  First, we show what the plot looks like if we use too few
# points.
f0 = 1e9
Q0 = 500
ff = np.arange(960e6, 1040e6, 2e6)
plt.figure()
plt.plot(ff, dlorentz(ff, f0, Q0), 'bo-', linewidth = 2, fillstyle = 'none')
plt.xlabel('Frequency (Hz)')
plt.ylabel(r'$dL/df$')

# For this second curve we'll use a varying density of points (high density
# near the sharp resonant freatures).  This results in a much smoother
# curve that better represents the true features of the function.
ff = np.concatenate((np.arange(960e6, 990e6, 2e6), np.arange(990e6, 997e6, 1e6),\
  np.arange(997e6, 1003e6, 0.1e6), np.arange(1003e6, 1010e6, 1e6),\
  np.arange(1010e6, 1040e6, 2e6)))
plt.plot(ff, dlorentz(ff, f0, Q0), 'r-', linewidth = 2)