I defined both of my functions but it doesn't plot - python

Hi guys im trying to plot these two functions x(x2) vs y(x2). x(x2) being equal to log10(x_2) and y(x_2) being equal to gam(x2) which was then equal also equal to (gam0 - 0.0187 * temp * math.log10(1+628.1455.556x_2)). It seems like the code for y(x_2) works fine but i can't seem to get the code for x(x_2) to work. When it does plot it should look like this 1
import matplotlib.pyplot as plt
import numpy as np
import math
import pylab
%matplotlib inline
gam0 = 72.8
temp = 293.15
#x = range(0, 10000)
#x_2= range(0, 10000)
def gam(x_2):
returns = []
for x_i in x_2:
returns.append(gam0 - 0.0187 * temp * math.log10(1+628.14*55.556*x_i))
return returns
def x(x_2):
returns = math.log10(x_2)
x()
plt.plot(gam(x_2), x(x_2))
plt.xlabel('Log_10x_2')
plt.ylabel('gamma (erg cm^2)')
plt.show()
These are the errors im getting
NameError Traceback (most recent call last)
<ipython-input-13-ac6002d962a0> in <module>
25
26
---> 27 plt.plot(gam(x_2), x(x_2))
28
29 plt.xlabel('Log_10x_2')
<ipython-input-13-ac6002d962a0> in x(x_2)
19 return returns
20 def x(x_2):
---> 21 returns = numpy.log10(x_2)
22
23 return returns

I found a number of issues with your code:
Your function x(x_2) is not return anything. Instead it keeps calling itself recursively.
You are calling math.log10, which only acts on a single number, not an array. You can either wrap that in a loop, or call the numpy version.
In your function gam(x_2) you are using log10, but log is needed.
Your plot range is of, you need much smaller values on the x-axis.
I added two variants, because the spacing of the grid points is different on the linear and logarithmic scales. Also, with np.linspace() you can specify the number of grid points, instead of the step size. (For details see https://numpy.org/doc/1.18/reference/generated/numpy.linspace.html)
Here is the overall code
import matplotlib.pyplot as plt
import numpy as np
gam0 = 72.8
temp = 293.15
x_2 = np.linspace(1e-7, 1e-1, 1000) # evenly spaced on linear scale
x_2 = 10**np.linspace(-7, -1, 1000) # evenly spaced on logarithmic scale
def gam(x_2):
return gam0 - 0.0187 * temp * np.log(1+628.14*55.556*x_2)
def x(x_2):
return np.log10(x_2)
plt.plot(x(x_2), gam(x_2))
plt.xlabel('Log_10x_2')
plt.ylabel('gamma (erg cm^2)')
It is also possible, to let matplotlib deal with the log scale on the x-axis:
plt.plot(x_2, gam(x_2))
plt.xlabel('x_2')
plt.ylabel('gamma (erg cm^2)')
plt.gca().set_xscale('log')

Related

How to plot a branched sin(x) function

I'm a noob practicing how to use pylab, matplot lib etc.
Somehow I'm not able to plot this simple branched sin(x) function in pylab/matplotlib.
from math import sin
import pylab as plb
def f(x):
if sin(x) > 0:
return sin(x)
else:
return 0
x = plb.linspace(-4,4,10000)
plb.plot(x,f(x))
plb.show()
The following error outputs when I run the program:
Traceback (most recent call last):
File "C:/Users/...plot.py", line 12, in <module>
plb.plot(x,f(x))
File "C:/Users/......plot.py", line 5, in f
if sin(x) > 0:
TypeError: only size-1 arrays can be converted to Python scalars
Is there anyone who can help me out?
The inbuilt sine function inside math module accepts only a scalar value. You can use numpy sine instead to accomplish your plot as it accepts an array.
import numpy as np
import pylab as plb
def f(x):
sine_ = np.sin(x)
sine_[sine_< 0] = 0
return sine_
x = plb.linspace(-4,4,10000)
plb.plot(x,f(x))
plb.show()
The output is as shown below:
[]
However, as pointed out by Trenton McKinney, this answer states the use of pylab is no longer recommended. So, the alternate solution using matplotlib.pyplot is shown below:
import numpy as np
import matplotlib.pyplot as plt
def f(x):
sine_ = np.sin(x)
sine_[sine_< 0] = 0
return sine_
x = np.linspace(-4,4,10000)
plt.plot(x,f(x))
plt.show()
The output is the same as the image above.

QuantLib Python Hull White Model - RuntimeError: time (20) is past max curve time (19)

I tried using QuantLib-python to run several iterations of a Hull-White model. I followed along with the code and blog here:
http://gouthamanbalaraman.com/blog/hull-white-simulation-quantlib-python.html
I made some edits from Balaraman's code on the site. Namely, I changed the spot_curve from being a FlatForward to a ZeroCurve. Now I keep getting an error. I am trying to model the zero curve data as seen in my code below.
Does anyone know how to fix this and implement the zero curve in QuantLib-python?
from QuantLib import *
import utils
import numpy as np
%matplotlib inline
##Assign all variables
sigma = 0.015
a = 0.1
timestep = 30
length = 30 # in years
day_count = Thirty360()
start_date = Date(19, 11, 1989)
calendar = UnitedStates()
interpolation = Linear()
compounding = Compounded
compoundingFrequency = Annual
dates = [Date(19,11,1990), Date(19,11,1991), Date(19,11,1992),
Date(19,11,1993), Date(19,11,1994), Date(19,11,1995),
Date(19,11,1996), Date(19,11,1997), Date(19,11,1998),
Date(19,11,1999), Date(19,11,2000), Date(19,11,2001),
Date(19,11,2002), Date(19,11,2003), Date(19,11,2004),
Date(19,11,2005), Date(19,11,2006), Date(19,11,2007),
Date(19,11,2008), Date(19,11,2009)]
zeros = [0.115974,0.118913,0.120676,0.121751,0.122455,0.122988,
0.12347,0.123972,0.124527,0.125147,0.125831,0.126573,
0.127359,0.128178,0.129016,0.129863,0.130708,0.131544,
0.132364,0.133162]
#setup spot curve. Notable difference is the ZeroCurve instead of FlatForward
spot_curve = ZeroCurve(dates, zeros, day_count, calendar, interpolation, compounding, compoundingFrequency)
spot_curve_handle = YieldTermStructureHandle(spot_curve)
#The Hull-White process is constructed by passing the term-structure, a and sigma.
#To create the path generator, one has to provide a random sequence generator along
#with other simulation inputs such as timestep and `length.
hw_process = HullWhiteProcess(spot_curve_handle, a, sigma)
rng = GaussianRandomSequenceGenerator(
UniformRandomSequenceGenerator(timestep, UniformRandomGenerator()))
seq = GaussianPathGenerator(hw_process, length, timestep, rng, False)
#define generate paths function
def generate_paths(num_paths, timestep):
arr = np.zeros((num_paths, timestep+1))
for i in range(num_paths):
sample_path = seq.next()
path = sample_path.value()
time = [path.time(j) for j in range(len(path))]
value = [path[j] for j in range(len(path))]
arr[i, :] = np.array(value)
return np.array(time), arr
#plotting short rates
num_paths = 100
paths = generate_paths(num_paths, timestep)
fig, ax = utils.plot()
for i in range(num_paths):
ax.plot(time, paths[i, :], lw=0.8, alpha=0.6)
ax.set_title("Hull-White Short Rate Simulation");
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-3-366fe665a669> in <module>
62 #plotting short rates
63 num_paths = 100
---> 64 paths = generate_paths(num_paths, timestep)
65 fig, ax = utils.plot()
66 for i in range(num_paths):
<ipython-input-3-366fe665a669> in generate_paths(num_paths, timestep)
52 arr = np.zeros((num_paths, timestep+1))
53 for i in range(num_paths):
---> 54 sample_path = seq.next()
55 path = sample_path.value()
56 time = [path.time(j) for j in range(len(path))]
~/opt/anaconda3/lib/python3.7/site-packages/QuantLib/QuantLib.py in next(self)
22328
22329 def next(self):
> 22330 return _QuantLib.GaussianPathGenerator_next(self)
22331
22332 def antithetic(self):
RuntimeError: time (20) is past max curve time (19)
That error means you are trying to get a point (date) from your yield curve that is past the maximum maturity. Your yield curve has a maximum maturity of 19 years and your simulation is for 30 years...
To avoid that error, either build your curve with extra maturities, or enable extrapolation:
spot_curve.enableExtrapolation()

Cannot sample values of a trigonometric function

I have a problem with my code.
So i try to represent the sampled values of a function 'sin(t^3)/2^tan(t)' for
t between 0 and 1.5 and frequency fs=50Hz.
I have created a function 'sampleFunction' which takes as parameters the string which represents the trigonometric function,beginning of the interval,end of interval and the frequency.
I create tVector(0,0.02,0.04,..,1.48)
Then I take the elements of tVector and use them to evaluate the string and put the result in another vector y
I return both y and tVector
But I encounter a problem when i run it saying 'y' is not defined
This is the code:
import numpy as np
import matplotlib.pyplot as plt
import math
def sampleFunction(functionString,t0,t1,fs):
tVector=np.arange(start=t0, stop=t1, step=1/fs, dtype='float')
t=t0
for i in range(0,len(tVector)):
t=tVector[i]
y[i]=eval(functionString)
return y,tVector
t0=0
t1 =1.5
fs=50
thold=.1
functionString='math.sin(t**3)/2**math.tan(t)'
y,t=sampleFunction(functionString,t0,t1,fs)
plt.plot(t,y)
plt.xlabel('time')
plt.ylabel('Amplitude')
You can change your code in the following way:
def sampleFunction(functionString,t0,t1,fs):
tVector=np.arange(start=t0, stop=t1, step=1/fs, dtype='float')
t=t0
y = np.zeros( tVector.shape )
for i in range(0,len(tVector)):
t=tVector[i]
y[i]=eval(functionString)
return y,tVector
However, this is not good python. There are a couple of issues:
You should use vectorized operations.
You should avoid eval like the plague. This has security implications.
For vectorized operations, simply do:
def sampleFunction(functionString,t0,t1,fs):
t = np.arange(start=t0, stop=t1, step=1/fs, dtype='float')
y = eval(functionString)
return y, t
and call it as:
sampleFunction('np.sin(t**3)/2**np.tan(t)', 0, 10, 100)
This is much faster (especially for large arrays)
Finally, the vectorized form is only a single line long. You probably don't need the extra function.
You have a problem with the allocation of the 'y' variable as Harold is saying.
However, there are multiple ways of achieving what you are doing and the eval function is, unless you have a very good reason, the absolute worst. Maybe consider one of the possible examples below:
import numpy as np
import matplotlib.pyplot as plt
import math
def sampleFunction(functionString,t0,t1,fs):
tVector=np.arange(start=t0, stop=t1, step=1/fs, dtype='float')
t=t0
y = [float]*len(tVector) # <------------------- Allocate 'y' variable
for i in range(0,len(tVector)):
t = tVector[i]
y[i]=eval(functionString)
return y,tVector
t0=0
t1 =1.5
fs=50
thold=.1
# Your code
functionString = 'math.sin(t**3)/2**math.tan(t)'
y, t = sampleFunction(functionString,t0,t1,fs)
plt.plot(t, y, color='cyan')
# Using the 'map' built-in function
t = np.arange(start=t0, stop=t1, step=1./fs, dtype='float')
y = map(lambda ti: 0.9*math.sin(ti**3)/2**math.tan(ti), t)
plt.plot(t, y, color='magenta')
# Using Numpy's 'sin' and 'tan'
t = np.arange(start=t0, stop=t1, step=1./fs, dtype='float')
y = 0.8*np.sin(t**3)/2**np.tan(t)
plt.plot(t, y, color='darkorange')
# Using 'list comprehensions'
t = np.arange(start=t0, stop=t1, step=1./fs, dtype='float')
y = [ 0.7*math.sin(ti**3)/2**math.tan(ti) for ti in t]
plt.plot(t, y, color='darkgreen')
plt.xlabel('time')
plt.ylabel('Amplitude')
plt.show()
The result is:
When running the above code, you should have gotten an error message saying, in the end, "name 'y' is not defined". If you look at your function definition, you will see that it really isn't. You cannot passing a value to y[i] without defining y first! The following line before the "for" loop fixes that particular problem:
y = [None] * len(tVector)
The code will run fine after that correction.
But: why do you want to pass a function string when you can pass a function? Functions, in Python, are first-class-objects!

Use savefig in Python with string and iterative index in the name

I need to use the "savefig" in Python to save the plot of each iteration of a while loop, and I want that the name i give to the figure contains a literal part and a numerical part. This one comes out from an array or is the number associated to the index of iteration. I make a simple example:
# index.py
from numpy import *
from pylab import *
from matplotlib import *
from matplotlib.pyplot import *
import os
x=arange(0.12,60,0.12).reshape(100,5)
y=sin(x)
i=0
while i<99
figure()
a=x[:,i]
b=y[:,i]
c=a[0]
plot(x,y,label='%s%d'%('x=',c))
savefig(#???#) #I want the name is: x='a[0]'.png
#where 'a[0]' is the value of a[0]
thanks a lot.
Well, it should be simply this:
savefig(str(a[0]))
This is a toy example. Works for me.
import pylab as pl
import numpy as np
# some data
x = np.arange(10)
pl.figure()
pl.plot(x)
pl.savefig('x=' + str(10) + '.png')
I had the same demand recently and figured out the solution. I modify the given code and correct several explicit errors.
from pylab import *
import matplotlib.pyplot as plt
x = arange(0.12, 60, 0.12).reshape(100, 5)
y = sin(x)
i = 0
while i < 99:
figure()
a = x[i, :] # change each row instead of column
b = y[i, :]
i += 1 # make sure to exit the while loop
flag = 'x=%s' % str(a[0]) # use the first element of list a as the name
plot(a, b, label=flag)
plt.savefig("%s.png" % flag)
Hope it helps.
Since python 3.6 you can use f-strings to format strings dynamically:
import matplotlib.pyplot as plt
for i in range(99):
plt.figure()
a = x[:, i]
b = y[:, i]
c = a[0]
plt.plot(a, b, label=f'x={c}')
plt.savefig(f'x={c}.png')

Plot really big file in python (5GB) with x axis offset

I am trying to plot a very big file (~5 GB) using python and matplotlib. I am able to load the whole file in memory (the total available in the machine is 16 GB) but when I plot it using simple imshow I get a segmentation fault. This is most probable to the ulimit which I have set to 15000 but I cannot set higher. I have come to the conclusion that I need to plot my array in batches and therefore made a simple code to do that. My main isue is that when I plot a batch of the big array the x coordinates start always from 0 and there is no way I can overlay the images to create a final big one. If you have any suggestion please let me know. Also I am not able to install new packages like "Image" on this machine due to administrative rights. Here is a sample of the code that reads the first 12 lines of my array and make 3 plots.
import os
import sys
import scipy
import numpy as np
import pylab as pl
import matplotlib as mpl
import matplotlib.cm as cm
from optparse import OptionParser
from scipy import fftpack
from scipy.fftpack import *
from cmath import *
from pylab import *
import pp
import fileinput
import matplotlib.pylab as plt
import pickle
def readalllines(file1,rows,freqs):
file = open(file1,'r')
sizer = int(rows*freqs)
i = 0
q = np.zeros(sizer,'float')
for i in range(rows*freqs):
s =file.readline()
s = s.split()
#print s[4],q[i]
q[i] = float(s[4])
if i%262144 == 0:
print '\r ',int(i*100.0/(337*262144)),' percent complete',
i += 1
file.close()
return q
parser = OptionParser()
parser.add_option('-f',dest="filename",help="Read dynamic spectrum from FILE",metavar="FILE")
parser.add_option('-t',dest="dtime",help="The time integration used in seconds, default 10",default=10)
parser.add_option('-n',dest="dfreq",help="The bandwidth of each frequency channel in Hz",default=11.92092896)
parser.add_option('-w',dest="reduce",help="The chuncker divider in frequency channels, integer default 16",default=16)
(opts,args) = parser.parse_args()
rows=12
freqs = 262144
file1 = opts.filename
s = readalllines(file1,rows,freqs)
s = np.reshape(s,(rows,freqs))
s = s.T
print s.shape
#raw_input()
#s_shift = scipy.fftpack.fftshift(s)
#fig = plt.figure()
#fig.patch.set_alpha(0.0)
#axes = plt.axes()
#axes.patch.set_alpha(0.0)
###plt.ylim(0,8)
plt.ion()
i = 0
for o in range(0,rows,4):
fig = plt.figure()
#plt.clf()
plt.imshow(s[:,o:o+4],interpolation='nearest',aspect='auto', cmap=cm.gray_r, origin='lower')
if o == 0:
axis([0,rows,0,freqs])
fdf, fdff = xticks()
print fdf
xticks(fdf+o)
print xticks()
#axis([o,o+4,0,freqs])
plt.draw()
#w, h = fig.canvas.get_width_height()
#buf = np.fromstring(fig.canvas.tostring_argb(), dtype=np.uint8)
#buf.shape = (w,h,4)
#buf = np.rol(buf, 3, axis=2)
#w,h,_ = buf.shape
#img = Image.fromstring("RGBA", (w,h),buf.tostring())
#if prev:
# prev.paste(img)
# del prev
#prev = img
i += 1
pl.colorbar()
pl.show()
If you plot any array with more than ~2k pixels across something in your graphics chain will down sample the image in some way to display it on your monitor. I would recommend down sampling in a controlled way, something like
data = convert_raw_data_to_fft(args) # make sure data is row major
def ds_decimate(row,step = 100):
return row[::step]
def ds_sum(row,step):
return np.sum(row[:step*(len(row)//step)].reshape(-1,step),1)
# as per suggestion from tom10 in comments
def ds_max(row,step):
return np.max(row[:step*(len(row)//step)].reshape(-1,step),1)
data_plotable = [ds_sum(d) for d in data] # plug in which ever function you want
or interpolation.
Matplotlib is pretty memory-inefficient when plotting images. It creates several full-resolution intermediate arrays, which is probably why your program is crashing.
One solution is to downsample the image before feeding it into matplotlib, as #tcaswell suggests.
I also wrote some wrapper code to do this downsampling automatically, based on your screen resolution. It's at https://github.com/ChrisBeaumont/mpl-modest-image, if it's useful. It also has the advantage that the image is resampled on the fly, so you can still pan and zoom without sacrificing resolution where you need it.
I think you're just missing the extent=(left, right, bottom, top) keyword argument in plt.imshow.
x = np.random.randn(2, 10)
y = np.ones((4, 10))
x[0] = 0 # To make it clear which side is up, etc
y[0] = -1
plt.imshow(x, extent=(0, 10, 0, 2))
plt.imshow(y, extent=(0, 10, 2, 6))
# This is necessary, else the plot gets scaled and only shows the last array
plt.ylim(0, 6)
plt.colorbar()
plt.show()

Categories