How to create a 2D mesh with refinement? Python - python

How can I create a mesh with refinement, lets say x and y go from 0 to 1 and between 0.4 and 0.6 in both directions I want the points to be closer.
I have been reading about numpy.logspace, but it doesnt allow much freedom.
Any ideas?

There isn't one specific command with this functionality, but you can build arrays up with numpy.concatenate this way:
import numpy
start = 0
end = 1
bigstep = 0.1
refinedstart = 0.4
refinedend = 0.6
smallstep = 0.01
x = numpy.concatenate([numpy.arange(start, refinedstart, bigstep),
numpy.arange(refinedstart, refinedend, smallstep),
numpy.arange(refinedend, end, bigstep)])

It depends on how you want to "squash" the middle values. But say you want to do it quadratically, using an 11-by-11 grid spanning from -10 to 10 on each axis:
a = np.linspace(-np.sqrt(10), np.sqrt(10), 11)
b = np.sign(a)*a**2
x, y = np.meshgrid(b, b)
To see what this grid looks like:
import matplotlib.pyplot as plt
plt.plot(x.flatten(), y.flatten(), '*')
plt.show()

Related

How to split data into two graphs with mat plot lib

I would be so thankful if someone would be able to help me with this. I am creating a graph in matplotib however I would to love to split up the 14 lines created from the while loop into the x and y values of P, so instead of plt.plot(t,P) it would be plt.plot(t,((P[1])[0]))) and
plt.plot(t,((P[1])[1]))). I would love if someone could help me very quick, it should be easy but i am just getting errors with the arrays
`
#Altering Alpha in Tumor Cells vs PACCs
#What is alpha? α = Rate of conversion of cancer cells to PACCs
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from google.colab import files
value = -6
counter = -1
array = []
pac = []
while value <= 0:
def modelP(x,t):
P, C = x
λc = 0.0601
K = 2000
α = 1 * (10**value)
ν = 1 * (10**-6)
λp = 0.1
γ = 2
#returning odes
dPdt = ((λp))*P*(1-(C+(γ*P))/K)+ (α*C)
dCdt = ((λc)*C)*(1-(C+(γ*P))/K)-(α*C) + (ν***P)
return dPdt, dCdt
#initial
C0= 256
P0 = 0
Pinit = [P0,C0]
#time points
t = np.linspace(0,730)
#solve odes
P = odeint(modelP,Pinit,t)
plt.plot(t,P)
value += 1
#plot results
plt.xlabel('Time [days]')
plt.ylabel('Number of PACCs')
plt.show()
`
You can use subplots() to create two subplots and then plot the individual line into the plot you need. To do this, firstly add the subplots at the start (before the while loop) by adding this line...
fig, ax = plt.subplots(2,1) ## Plot will 2 rows, 1 column... change if required
Then... within the while loop, replace the plotting line...
plt.plot(t,P)
with (do take care of the space so that the lines are within while loop)
if value < -3: ## I am using value = -3 as the point of split, change as needed
ax[0].plot(t,P)#, ax=ax[0]) ## Add to first plot
else:
ax[1].plot(t,P)#,ax=ax[1]) ## Add to second plot
This will give a plot like this.

Fit a time series in python with a mean value as boundary condition

I have the following boundary conditions for a time series in python.
The notation I use here is t_x, where x describe the time in milliseconds (this is not my code, I just thought this notation is good to explain my issue).
t_0 = 0
t_440 = -1.6
t_830 = 0
mean_value = -0.6
I want to create a list that contains 83 values (so the spacing is 10ms for each value).
The list should descibe a "curve" that starts at zero, has the minimum value of -1.6 at 440ms (so 44 in the list), ends with 0 at 880ms (so 83 in the list) and the overall mean value of the list should be -0.6.
I absolutely could not come up with an idea how to "fit" the boundaries to create such a list.
I would really appreciate help.
It is a quick and dirty approach, but it works:
X = list(range(0, 830 +1, 10))
Y = [0.0 for x in X]
Y[44] = -1.6
b = 12.3486
for x in range(44):
Y[x] = -1.6*(b*x+x**2)/(b*44+44**2)
for x in range(83, 44, -1):
Y[x] = -1.6*(b*(83-x)+(83-x)**2)/(b*38+38**2)
print(f'{sum(Y)/len(Y)=:8.6f}, {Y[0]=}, {Y[44]=}, {Y[83]=}')
from matplotlib import pyplot as plt
plt.plot(X,Y)
plt.show()
With the code giving following output:
sum(Y)/len(Y)=-0.600000, Y[0]=-0.0, Y[44]=-1.6, Y[83]=-0.0
And showing following diagram:
The first step in coming up with the above approach was to create a linear sloping 'curve' from the minimum to the zeroes. I turned out that linear approach gives here too large mean Y value what means that the 'curve' must have a sharp peak at its minimum and need to be approached with a polynomial. To make things simple I decided to use quadratic polynomial and approach the minimum from left and right side separately as the curve isn't symmetric. The b-value was found by trial and error and its precision can be increased manually or by writing a small function finding it in an iterative way.
Update providing a generic solution as requested in a comment
The code below provides a
meanYboundaryXY(lbc = [(0,0), (440,-1.6), (830,0), -0.6], shape='saw')
function returning the X and Y lists of the time series data calculated from the passed parameter with the boundary values:
def meanYboundaryXY(lbc = [(0,0), (440,-1.6), (830,0), -0.6]):
lbcXY = lbc[0:3] ; meanY_boundary = lbc[3]
minX = min(x for x,y in lbcXY)
maxX = max(x for x,y in lbcXY)
minY = lbc[1][1]
step = 10
X = list(range(minX, maxX + 1, step))
lenX = len(X)
Y = [None for x in X]
sumY = 0
for x, y in lbcXY:
Y[x//step] = y
sumY += y
target_sumY = meanY_boundary*lenX
if shape == 'rect':
subY = (target_sumY-sumY)/(lenX-3)
for i, y in enumerate(Y):
if y is None:
Y[i] = subY
elif shape == 'saw':
peakNextY = 2*(target_sumY-sumY)/(lenX-1)
iYleft = lbc[1][0]//step-1
iYrght = iYleft+2
iYstart = lbc[0][0] // step
iYend = lbc[2][0] // step
for i in range(iYstart, iYleft+1, 1):
Y[i] = peakNextY * i / iYleft
for i in range(iYend, iYrght-1, -1):
Y[i] = peakNextY * (iYend-i)/(iYend-iYrght)
else:
raise ValueError( str(f'meanYboundaryXY() EXIT, {shape=} not in ["saw","rect"]') )
return (X, Y)
X, Y = meanYboundaryXY()
print(f'{sum(Y)/len(Y)=:8.6f}, {Y[0]=}, {Y[44]=}, {Y[83]=}')
from matplotlib import pyplot as plt
plt.plot(X,Y)
plt.show()
The code outputs:
sum(Y)/len(Y)=-0.600000, Y[0]=0, Y[44]=-1.6, Y[83]=0
and creates following two diagrams for shape='rect' and shape='saw':
As an old geek, i try to solve the question with a simple algorithm.
First calculate points as two symmetric lines from 0 to 44 and 44 to 89 (orange on the graph).
Calculate sum except middle point and its ratio with sum of points when mean is -0.6, except middle point.
Apply ratio to previous points except middle point. (blue curve on the graph)
Obtain curve which was called "saw" by Claudio.
For my own, i think quadratic interpolation of Claudio is a better curve, but needs trial and error loops.
import matplotlib
# define goals
nbPoints = 89
msPerPoint = 10
midPoint = nbPoints//2
valueMidPoint = -1.6
meanGoal = -0.6
def createSerieLinear():
# two lines 0 up to 44, 44 down to 88 (89 values centered on 44)
serie=[0 for i in range(0,nbPoints)]
interval =valueMidPoint/midPoint
for i in range(0,midPoint+1):
serie[i]=i*interval
serie[nbPoints-1-i]=i*interval
return serie
# keep an original to plot
orange = createSerieLinear()
# work on a base
base = createSerieLinear()
# total except midPoint
totalBase = (sum(base)-valueMidPoint)
#total goal except 44
totalGoal = meanGoal*nbPoints - valueMidPoint
# apply ratio to reduce
reduceRatio = totalGoal/totalBase
for i in range(0,midPoint):
base[i] *= reduceRatio
base[nbPoints-1-i] *= reduceRatio
# verify
meanBase = sum(base)/nbPoints
print("new mean:",meanBase)
# draw
from matplotlib import pyplot as plt
X =[i*msPerPoint for i in range(0,nbPoints)]
plt.plot(X,base)
plt.plot(X,orange)
plt.show()
new mean: -0.5999999999999998
Hope you enjoy simple things :)

Combining Arrays within an Array

I am currently trying to generate a random dataset based on a choice of k, the number of clusters, and xlim and ylim as the boundaries to be inputted. I want my output to be as follows:
[array([11.7282981 , 6.89656728],
[ 9.88391172, 5.83611126],
[7.45631652, 7.88674093],
[8.38232831, 7.82884638])
This code is for k means project
Here is my attempt. First I create a cluster center, which is randomly generated within a range between 0 and xlimit and ylimit inputted. Then I create 2 (in this case 2 but I will be doing 100) random points around the cluster center with noise:
k = 2
xlim = 12
ylim = 12
f = []
for x in range(0,k):
clusterCenter = [random.randint(0,xlim),random.randint(0,ylim)]
cluster = np.random.randn(2, 2) + clusterCenter
f.append(cluster)
f
unfortunately the output comes out to be:
[array([[11.7282981 , 6.89656728],
[ 9.88391172, 5.83611126]]),
array([[7.45631652, 7.88674093],
[8.38232831, 7.82884638]])]
which is not what I want as I would like to put this into a pandas dataframe. can anyone help?
the numbers will be a lot greater, I have made it such that the cluster generated would be a set of 2 x and y co-ordinates, but would ideally want:
cluster = np.random.randn(100, 2) + clusterCenter
So keep that in consideration! any help would be greatly appreciated!
Replace f.append(cluster) with:
f = None # instead of []
...
if f is None:
f = cluster
else:
f = np.concatenate( (f, cluster) )

How to index List/ numpy array in order to plot the data with matplotlib

I have a function f(x,t) = cos(t)*t + x and i want to display the change of the result over the width x and time t at discretised time steps t_i and discretised width steps x_j.
Now I am a while here on SX and feel really embarrassed to only can post such little code or in other words nothing (since nothing worked I have done...):
Nevertheless if someone has the time to help, I`d appreciate it.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as pyplot
from astropy.io.ascii.latex import AASTex
def func(xi, ti):
res = np.cos(ti)*ti + xi
return res
timeSpacing = 100
timeStart = 0
timeEnd = 1
time = np.linspace(timeStart, timeEnd, timeSpacing)
widthSpacing = 300
widthStart = 0
widthEnd = 3
width = np.linspace(widthStart, widthEnd, widthSpacing)
resultList = [None]*timeSpacing
resultListInner = [None]*widthSpacing
for i, ithTime in enumerate(time):
for j, jthWidth in enumerate(width):
aas = np.zeros_like(width)
aas.fill(ithTime)
resultListInner[j] = ithTime, jthWidth, func(jthWidth, aas)
resultList[i] = resultListInner
So how do I correctly index the list and array and plot my data using matplotlib?
My plot should look like this:
where in my case the aperature should be the width x, the sky annulus is my time t and the RMS is my func(x,t).
A couple of points:
Numpy provides a very nice function for doing differences of array elements: diff
Matplotlib uses plot_wireframe for creating a plot that you would want (also using Numpy's meshgrid)
Now, combining these into what you may want would look something like this.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
def func(xi, ti):
res = np.cos(ti)*np.sin(xi)
return res
timeSpacing = 20
timeStart = 0
timeEnd = 1
time = np.linspace(timeStart, timeEnd, timeSpacing)
widthSpacing = 50
widthStart = 0
widthEnd = 3
width = np.linspace(widthStart, widthEnd, widthSpacing)
X,T = np.meshgrid(width,time)
F = func(X,T)
DF = np.diff(np.diff(F,axis=0),axis=1)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_wireframe(X[:-1,:-1],T[:-1,:-1],DF)
plt.show()
Note that diff is applied twice: once in each dimension axis= . I have also changed the toy function you provided to something that actually looks decent in this case.
For your more general use, it seems that you would want to just collect all of your F data into a 2D array, then proceed from the DF = line.

python program bezier function

So I am trying to program a bezier curve using python, and unlike previously posts I have been able to find, I need to program It in such a way, that the summation adjust for how many splines there is, since I need to be able to remove or add splines.
I am basing my programming on this wiki http://en.wikipedia.org/wiki/B%C3%A9zier_curve right after the headline "Explicit definition"
so far this is what I have made
from __future__ import division
import math
import numpy as np
from pylab import*
fact = math.factorial
def binormal(n,i):
koef = fact(n)/float((fact(i)*fact(n-i)))
return koef
def bernstein(n,i,t):
bern = binormal(n,i)*(1-t)**(n-i)*(t**i)
return bern
f = open('polaerekoordinator.txt','r')
whole_thing = f.read().splitlines()
f.close() #these are the coordinates I'm am trying to use for now
#0.000 49.3719597
#9.0141211 49.6065178
#20.2151089 50.9161568
#32.8510895 51.3330612
#44.5151596 45.5941772
#50.7609444 35.3062477
#51.4409332 23.4890251
#49.9188042 11.8336229
#49.5664711 0.000
alle = []
for entry in whole_thing:
alle.append(entry.split(" "))
def bezier(t): #where t is how many points there is on the bezier curve
n = len(alle)
x = y = 0
for i,entry in enumerate(alle):
x +=float(entry[0])*bernstein(n,i,t)+x
for i,entry in enumerate(alle):
y +=float(entry[1])*bernstein(n,i,t)+y
return x,y
bezier(np.arange(0,1,0.01))
my problem right now is that I need to do a summation of the x and y coordinates, so they become something like this
y = [y0, y0+y1, y0+y1+y2, y0+y1+y2+...+yn]
and the same for x
any pointers?
I think you can use np.cumsum http://docs.scipy.org/doc/numpy/reference/generated/numpy.cumsum.html:
>>>y = np.arange(0,1,0.1)
>>>[ 0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
>>>y_cum = np.cumsum(y)
>>>[ 0. 0.1 0.3 0.6 1. 1.5 2.1 2.8 3.6 4.5]
Edit:
Using your example coordinates I get the following outputs:
x,y = bezier(np.arange(0,1,0.01))
plot(x,y)
plot(np.cumsum(x),np.cumsum(y))
Assuming this is what you are looking for!
I'm not very clear on what're you trying to accomplish, but it's probably something like this:
for i, v in enumerate(y):
y2.append(sum(y[:i+1]))
Demo:
>>> y = [1, 2, 3]
>>> y2 = []
>>> for i, v in enumerate(y):
y2.append(sum(y[:i+1]))
>>> y2
[1, 3, 6]
>>>
Or, the shortcut using list comprehension:
y2 = [sum(y[:i+1]) for i,_ in enumerate(y)]
Well, hope it helps!

Categories

Resources