Transforming a rectangle in Python - python

I have any transformation matrix, for example:
sig =[[2,1],[1,1]]
With this code, I could transform a circle with r=1:
import numpy as np
import math as mt
from matplotlib.pyplot import *
sig =[[2,1],[1,1]]
ndiv=100
r=1.0
theta=np.linspace(0,2*np.pi,ndiv)
x=r*np.cos(theta)
y=r*np.sin(theta)
fig = figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot(x,y,'b.')
x_transf=np.zeros(ndiv)
y_transf=np.zeros(ndiv)
direc=np.zeros(ndiv)
N=np.zeros(ndiv)
v=[0.0,0.0]
w=[0.0,0.0]
for i in range(ndiv):
v[0]=x[i]
v[1]=y[i]
w=np.dot(sig,v)
x_transf[i]=w[0]
y_transf[i]=w[1]
N[i]=mt.sqrt(x_transf[i]**2+y_transf[i]**2)
ax.plot(x_transf,y_transf,'g+')
axis('equal')
grid('on')
Now I need to transform a rectangle (square) using this tranformation matrix:
M = [[sqrt(th), -1.5*th],[2*sin(th),cos(th)]] #th is an angle between 0 and 2pi
Also find the angle that produces the biggest area. How can I do this?

Here's an example of how to apply the transformation. As an example and a check I also applied a normal rotation (in red):
import matplotlib.pyplot as plt
import numpy as np
from numpy import sin, cos, sqrt, pi
r0 = np.array([[.5, .2], [1.5,.2], [1.5,1.2], [.5,1.2], [.5,.2]])
th = .05*pi
R = np.array([[cos(th), -sin(th)], [sin(th), cos(th)]])
M = np.array([[sqrt(th), -1.5*th],[2*sin(th),cos(th)]])
r1 = R.dot(r0.T).T
r2 = M.dot(r0.T).T
plt.plot(r0[:,0], r0[:,1], "bo-")
plt.plot(r1[:,0], r1[:,1], "ro-")
plt.plot(r2[:,0], r2[:,1], "go-")
plt.xlim(-0.2, 1.8)
plt.ylim(-0., 2.)
plt.show()
As for finding the largest area, you could either derive this analytically, or numerically calculate the area of the rotated rectangle and maximize it, using, say, scipy.optimize.

Related

interpolate, derivate and integrate a function -- some math fun

I have a problem. I have three lists. The list_umf are the x values and list list_kf are the y values, while list_kfm are y values, too. kfm is the integral of kf. The values are the output of my code.
To show that kfm is the integral of kf, I want to calculate the derivative of kfm, which shuold be the same as kf. But the re calculated kfm (list_kf_re) is just 101.0 every time.
Whats wrong with my code?
import numpy as np
from scipy import integrate, interpolate
from scipy.misc import derivative as deriv
import matplotlib.pyplot as plt
list_kfm = [15.348748494618041, 26.240336614039776, 37.76846357985518, 49.80068952374503, 62.25356792292074, 75.0692188764684, 88.20491343740369, 101.6276911997135,
115.31128207665246, 129.2342114999071, 143.37856687640036, 157.72915825067278, 172.27292637703843, 186.9985127198004, 201.89593919604192, 216.95636451973587]
list_kf = [168.08871431597626, 179.78615963605742, 188.728883379148, 196.0371678709251, 202.25334207341422, 207.68364358717665, 212.51893919883966, 216.88670040685466,
220.87653440371076, 224.55397301446894, 227.96847485999652, 231.15833919688876, 234.1538643061246, 236.97945558527186, 239.65507793294745, 242.19728380107006]
list_umf = [0.1, 0.15000000000000002, 0.20000000000000004, 0.25000000000000006, 0.30000000000000004, 0.3500000000000001, 0.40000000000000013, 0.45000000000000007,
0.5000000000000001, 0.5500000000000002, 0.6000000000000002, 0.6500000000000001, 0.7000000000000002, 0.7500000000000002, 0.8000000000000002, 0.8500000000000002]
f = interpolate.interp1d(
list_umf, list_kfm, bounds_error=False, fill_value=(15, 217))
list_kf_re = [deriv(f, x) for x in list_umf]
plt.plot(list_umf, list_kfm, label='kfm')
plt.plot(list_umf, list_kf, label='kf')
plt.plot(list_umf, list_kf_re, label='kfre')
print(list_kf_re)
print(list_kf)
Use UnivariateSpline to create an interpolator that you can later apply integral or derivative functions (see this post)
Sample:
import numpy as np
#from scipy import integrate, interpolate
from scipy.interpolate import UnivariateSpline as US, InterpolatedUnivariateSpline as IUS
#from scipy.misc import derivative as deriv
import matplotlib.pyplot as plt
list_kfm = [15.348748494618041, 26.240336614039776, 37.76846357985518, 49.80068952374503, 62.25356792292074, 75.0692188764684, 88.20491343740369, 101.6276911997135,
115.31128207665246, 129.2342114999071, 143.37856687640036, 157.72915825067278, 172.27292637703843, 186.9985127198004, 201.89593919604192, 216.95636451973587]
list_kf = [168.08871431597626, 179.78615963605742, 188.728883379148, 196.0371678709251, 202.25334207341422, 207.68364358717665, 212.51893919883966, 216.88670040685466,
220.87653440371076, 224.55397301446894, 227.96847485999652, 231.15833919688876, 234.1538643061246, 236.97945558527186, 239.65507793294745, 242.19728380107006]
list_umf = [0.1, 0.15000000000000002, 0.20000000000000004, 0.25000000000000006, 0.30000000000000004, 0.3500000000000001, 0.40000000000000013, 0.45000000000000007,
0.5000000000000001, 0.5500000000000002, 0.6000000000000002, 0.6500000000000001, 0.7000000000000002, 0.7500000000000002, 0.8000000000000002, 0.8500000000000002]
f = US(list_umf, list_kfm)
list_kf_re = [f.derivative()(x) for x in list_umf]
plt.plot(list_umf, list_kfm, label='kfm')
plt.plot(list_umf, list_kf, label='kf')
plt.plot(list_umf, list_kf_re, label='kfre')
plt.plot(list_umf, list_kf, 'o', label='kfre_2')
print(list_kf_re)
print(list_kf)

How to generate a 3D contour plot using data for torsion angles as numpy arrays

I am trying to generate a 3D contour plot using data stored as lists for two angles phi2 and theta in degrees. I have in total 88 datapoints. I am trying to generate the joint multivariate normal DPF using the scipy stats multivariate_normal and then plot the graph. But the attached code does not work it gives me errors refered to that z is 1D and has to be 2D.
Could anybody be so kind of direct me on how to get a decent density surface and/or contour with the data I have and fix this code? Thank you in advance
This is my code:
phi2 = [68.74428813, 73.81435267, 66.13791645, 178.54309657, 179.52273055, 161.05564169,
157.29079181, 191.92405566, 91.49774385, 96.19566795, 70.59561195, 119.9603657,
120.22305924, 98.52577754, 102.37894512, 100.12088791, 150.21004667, 139.18249739,
139.09246089, 89.51031839, 88.39689092, 136.47397506, 286.26056406, 283.74464006,
290.17913953, 286.74459786, 284.86706369, 328.13937238, 275.44219073, 303.47499211,
260.52134486, 259.35788745, 306.90146741, 11.20622691, 10.78220574, 19.15446087,
12.15462016, 13.58160662, 3.83673279, 0.12494051, 17.73139875, 8.53784067, 16.50118845,
2.53838974, 233.88019465, 234.93195189, 229.57996459, 233.07447083, 233.59862002,
231.18392245, 207.88397566, 237.31741345, 183.95293031, 179.42872881, 213.32271268,
140.7533708, 150.16895446, 130.61256041, 130.89734197, 128.63260154, 12.06830893,
200.28087782, 189.90378416, 62.39275508, 58.30936802, 205.64840358, 277.30394295,
287.76441089, 284.93518941, 265.89041707, 265.04884345, 343.86712163, 9.14315768,
341.43239609, 259.68283323, 260.00152679, 319.65245694, 341.08153124, 328.45596486,
336.02665804, 334.51276135, 334.8480636, 14.23480894, 12.53212715, 326.89899848,
42.62591188, 45.9396189, 335.39967741]
theta = [162.30883091334002, 162.38681345640427, 159.9615814653753, 174.16782637794842,
174.2151437560705, 176.40150466571572, 172.99139904772483, 175.92043493594562,
170.54952038009057, 172.72436078059172, 157.8929621077973, 168.98842698365024,
171.98480108104968, 157.1025039563731, 158.00939405227624, 157.85195861050553,
171.7970456599733, 173.88542939027778, 174.13060483554227, 157.06302225640127,
156.68490146086768, 174.10583004433656, 12.057892850177469, 22.707446760473047,
10.351988334104147, 10.029845365897357, 9.685493520484972, 7.903767103756965,
2.4881977395826027, 5.95349444674959, 30.507921155263, 30.63344201861564,
12.408566633469452, 3.9720259901877712, 4.65662142520097, 4.638183341072918,
4.106777084823232, 4.080743212101051, 4.747614837690929, 5.50356343278645,
3.5832926179292923, 3.495358074328152, 2.980060059242138, 5.785575733164003,
172.46901133841854, 172.2062576963548, 173.0410300278859, 174.06303865166896,
174.21162725364357, 170.0470319897294, 174.10752252682713, 171.23903792872886,
172.86412623832285, 174.4850965754363, 172.82274147050111, 176.9008741019669,
177.0080169547876, 171.90883294152246, 173.22247813491, 173.4304905772758,
89.63634206258786, 175.70086864635368, 175.71009499829492, 162.5980851129683,
162.16583875715634, 175.35616287818408, 4.416907543506939, 4.249480386717373,
5.265265803392446, 21.091392446454336, 21.573883985068303, 7.135649687137961,
5.332884425609576, 1.4184699545284118, 24.487533963462965, 25.63021267148377,
5.005913657707176, 7.562769691801299, 7.52664594699765, 7.898159135060811,
7.167861631741688, 7.018092266267269, 5.939275995893341, 5.975608665369072,
7.138904478798905, 9.93153808410636, 9.415946863231648, 7.154298332687937]
import sys, os
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from numpy import loadtxt
import matplotlib
from matplotlib.mlab import bivariate_normal
import math
from scipy.stats import multivariate_normal
from astropy.stats import circcorrcoef
from astropy import units as u
from scipy.stats import circvar
from scipy.stats import circmean
phi2_vacuum = np.array(phi2_vacuum)
theta_vacuum = np.array(theta_vacuum)
angle1 = np.radians(phi2_vacuum)
angle2 = np.radians(theta_vacuum)
# Obtain the circular variance
var_angle1 = circvar(angle1)
var_angle2 = circvar(angle2)
# Obtain circular mean from scipy
mean_angle1 = circmean(angle1)
mean_angle2 = circmean(angle2)
# Obtain circular covar between both angles in degrees
corr = circcorrcoef(angle1, angle2)
covar = corr * np.sqrt(var_angle1*var_angle2)
# Create the covar matrix
covar_matrix = np.array([[var_angle1, covar], [covar, var_angle2]])
# Obtain circular prob
delta = covar / (var_angle1 * var_angle2)
S = ((angle1-mean_angle1)/var_angle1) + ((angle2-mean_angle2)/var_angle2) - ((2*delta*
(angle1-mean_angle1)*(angle2-mean_angle2))/(var_angle1*var_angle2))
# Obtain exponential of PDF
exp = -1 * S / (2 * (1 - delta**2))
# Calculate the PDF
#prob = (1/(2*np.pi*var_angle1*var_angle2*np.sqrt(1-(delta**2)))) * np.e**exp
prob = multivariate_normal([mean_angle1, mean_angle2], covar_matrix)
# Create the stacking
pos = np.dstack((angle1, angle2))
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.contourf(angle1, angle2, pdf.pdf(pos))

how to replicate scipy.stats.fit using optimization function?

I am trying to fit a distribution to some values. This is my code
from __future__ import print_function
import pandas as pd
import numpy as np
import scipy as sp
import scipy.optimize as opt
import scipy.stats
import matplotlib.pyplot as plt
values = np.random.pareto(1.5, 10000)
loc = values.min()
scale = 1
def cost_function(alpha):
cost = -sp.stats.pareto(alpha, loc=loc, scale=scale).pdf(values)
return cost.sum()
opt_res = opt.fmin(cost_function, 1.5)
alpha_fit_v = sp.stats.pareto.fit(values, floc=loc, fscale=scale)
print('opt_res = ', opt_res,
' alpha_fit_v = ', alpha_fit_v)
I was expecting alpha_fit_v to be equivalent to opt_res but it is not. What's wrong?.
What's wrong?.
The cost function is wrong.
np.random.pareto has a different distribution than sp.stats.pareto
1. The cost function is wrong
It does not make sense to sum inverse probabilities. You need to use the logarithm:
def cost_function(alpha):
cost = -sp.stats.pareto(alpha, loc=loc, scale=scale).logpdf(values)
return cost.sum()
2. np.random.pareto has a different distribution than sp.stats.pareto
This one is tricky, but you may have noticed that not even sp.stats.pareto.fit returns the correct result. This is because scipy's Pareto distribution cannot fit the data generated by numpy.
import matplpotlib.pyplot as plt
import scipys as sp
import numpy as np
plt.subplot(2, 1, 1)
plt.hist(np.random.pareto(1.5, 10000), 1000) # This is a Lomax or Pareto II distribution
plt.xlim(0, 10)
plt.subplot(2, 1, 2)
plt.hist(sp.stats.pareto.rvs(1.5, size=1000), 1000) # This is a Pareto distribution
plt.xlim(0, 10)
That said, this will work as expected:
values = sp.stats.pareto.rvs(1.5, size=1000)
loc = 0
scale = 1
def cost_function(alpha):
cost = -sp.stats.pareto(alpha, loc=loc, scale=scale).logpdf(values)
return cost.sum()
opt_res = opt.fmin(cost_function, 1.5)
alpha_fit_v = sp.stats.pareto.fit(values, floc=loc, fscale=scale)
print('opt_res = ', opt_res,
' alpha_fit_v = ', alpha_fit_v)
# opt_res = [ 1.49611816] alpha_fit_v = (1.4960937500000013, 0, 1)
According to the documentation numpy.random.pareto does not quite draw from the Pareto distribution:
Draw samples from a Pareto II or Lomax distribution with specified shape.
The Lomax or Pareto II distribution is a shifted Pareto distribution. The classical Pareto distribution can be obtained from the Lomax distribution by adding 1 and multiplying by the scale parameter m (see Notes).
So you have two alternatives if using numpy to generate the data:
You can set loc=-1 for the scipy distribution.
You can do values = np.random.pareto(1.5, 10000) + 1 and set loc=0.

Is that the expected result on ndimage.gaussian_filter?

I'm trying to calculate the discrete derivative using gaussian_filter from scipy.ndimage and so the output is presenting some strange behavior with boundary conditions. The code is below:
from scipy import ndimage
import numpy as np
import matplotlib.pyplot as plt
y = np.linspace(0.2*np.pi,0.7*np.pi,100)
U = np.sin(y)
sg = 1
Uy = ndimage.gaussian_filter1d(U, sigma=sg,order=1,mode='constant',cval=0)
Uy2 = ndimage.gaussian_filter1d(U, sigma=sg,order=1,mode='nearest')
Uy3 = ndimage.gaussian_filter1d(U, sigma=sg,order=1,mode='reflect')
Uy4 = ndimage.gaussian_filter1d(U, sigma=sg,order=1,mode='mirror')
Uy5 = ndimage.gaussian_filter1d(U, sigma=sg,order=1,mode='wrap')
fig,(a1,a2) = plt.subplots(1,2)
a1.plot(U , y,label='data')
a2.plot(Uy, y,label='constant')
a2.plot(Uy2,y,label='nearest')
a2.plot(Uy3,y,label='reflect')
a2.plot(Uy4,y,label='mirror')
a2.plot(Uy5,y,label='wrap')
a1.legend(loc='best')
a2.legend(loc='best')
What happened? Constant mode should result cval on boudary? Is that the expected result?

Finding the intersection of a curve from polyfit

This seems simple but I can't quite figure it out. I have a curve calculated from x,y data. Then I have a line. I want to find the x, y values for where the two intersect.
Here is what I've got so far. It's super confusing and doesn't give the correct result. I can look at the graph and find the intersection x value and calculate the correct y value. I'd like to remove this human step.
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
from scipy import linalg
import sys
import scipy.interpolate as interpolate
import scipy.optimize as optimize
w = np.array([0.0, 11.11111111111111, 22.22222222222222, 33.333333333333336, 44.44444444444444, 55.55555555555556, 66.66666666666667, 77.77777777777777, 88.88888888888889, 100.0])
v = np.array([0.0, 8.333333333333332, 16.666666666666664, 25.0, 36.11111111111111, 47.22222222222222, 58.333333333333336, 72.22222222222221, 86.11111111111111, 100.0])
z = np.polyfit(w, v, 2)
print (z)
p=np.poly1d(z)
g = np.polyval(z,w)
print (g)
N=100
a=arange(N)
b=(w,v)
b=np.array(b)
c=(w,g)
c=np.array(c)
print(c)
d=-a+99
e=(a,d)
print (e)
p1=interpolate.PiecewisePolynomial(w,v[:,np.newaxis])
p2=interpolate.PiecewisePolynomial(w,d[:,np.newaxis])
def pdiff(x):
return p1(x)-p2(x)
xs=np.r_[w,w]
xs.sort()
x_min=xs.min()
x_max=xs.max()
x_mid=xs[:-1]+np.diff(xs)/2
roots=set()
for val in x_mid:
root,infodict,ier,mesg = optimize.fsolve(pdiff,val,full_output=True)
# ier==1 indicates a root has been found
if ier==1 and x_min<root<x_max:
roots.add(root[0])
roots=list(roots)
print(np.column_stack((roots,p1(roots),p2(roots))))
plt.plot(w,v, 'r', a, -a+99, 'b-')
plt.show()
q=input("what is the intersection value? ")
print (p(q))
Any ideas to get this to work?
Thanks
I don't think I fully understand what you are trying to do in your code, but what you described in English can be done with
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
w = np.array([0.0, 11.11111111111111, 22.22222222222222, 33.333333333333336,
44.44444444444444, 55.55555555555556, 66.66666666666667,
77.77777777777777, 88.88888888888889, 100.0])
v = np.array([0.0, 8.333333333333332, 16.666666666666664, 25.0,
36.11111111111111, 47.22222222222222, 58.333333333333336,
72.22222222222221, 86.11111111111111, 100.0])
poly_coeff = np.polynomial.polynomial.polyfit(w, v, 2)
poly = np.polynomial.polynomial.Polynomial(poly_coeff)
roots = np.polynomial.polynomial.polyroots(poly_coeff - [99, -1, 0])
x = np.linspace(np.min(roots) - 50, np.max(roots) + 50, num=1000)
plt.plot(x, poly(x), 'r-')
plt.plot(x, 99 - x, 'b-')
for root in roots:
plt.plot(root, 99 - root, 'ro')

Categories