Connect all 2D Points from NumPy 2D Arrays as a triangular meshgrid - python

I am pretty new to Python and I am trying to plot a triangular grid like this:
import matplotlib.pyplot as plt
import numpy as np
r = 0.25
d = 2*r
s = 0
l1 = np.array([[s,0], [s+d,0], [s+2*d,0], [s+3*d,0]])
l2 = np.array([[s-r,d], [s+r,d], [s+r+d,d], [s+r+2*d,d]])
l3 = np.array([[s,2*d], [s+d,2*d], [s+2*d,2*d], [s+3*d,2*d]])
l4 = np.array([[s-r,3*d], [s+r,3*d], [s+r+d,3*d], [s+r+2*d,3*d]])
l5 = np.array([[s,4*d], [s+d,4*d], [s+2*d,4*d], [s+3*d,4*d]])
plt.scatter(*zip(*l1))
plt.scatter(*zip(*l2))
plt.scatter(*zip(*l3))
plt.scatter(*zip(*l4))
plt.scatter(*zip(*l5))
plt.show
My problem is, that I have no real clue how to connect all points. I have added horizontal lines with plt.plot(*zip(*l1)) for all l but I have no idea how to draw the 'vertical' zigzag lines... Has anybody a 'simple' solution?
Many thanks in advance!

triplot is made for that purpose: plotting triangles.
You can either pass only x and y coordinates (in this case a Delaunay triangulation will be computed), or a full Triangulation object to which you can specify your own triangles.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.tri as mtri
r = 0.25
d = 2*r
s = 0
def meshgrid_triangles(n, m):
""" Returns triangles to mesh a np.meshgrid of n x m points """
tri = []
for i in range(n-1):
for j in range(m-1):
a = i + j*(n)
b = (i+1) + j*n
d = i + (j+1)*n
c = (i+1) + (j+1)*n
if j%2 == 1:
tri += [[a, b, d], [b, c, d]]
else:
tri += [[a, b, c], [a, c, d]]
return np.array(tri, dtype=np.int32)
x0 = np.arange(4) * d
y0 = np.arange(5) * d
x, y = np.meshgrid(x0, y0)
x[1::2] -= r
triangles = meshgrid_triangles(4, 5)
triangulation = mtri.Triangulation(x.ravel(), y.ravel(), triangles)
plt.scatter(x, y, color='red')
plt.triplot(triangulation, 'g-h')
plt.show()

Using the code the way you have (otherwise look at triplot_demo depending on what you want, as mentioned by #GBy), you can extract or rotate each array so that you just plot the line downwards:
import matplotlib.pyplot as plt
import numpy as np
r = 0.25
d = 2*r
s = 0
l1 = np.array([[s,0], [s+d,0], [s+2*d,0], [s+3*d,0]])
l2 = np.array([[s-r,d], [s+r,d], [s+r+d,d], [s+r+2*d,d]])
l3 = np.array([[s,2*d], [s+d,2*d], [s+2*d,2*d], [s+3*d,2*d]])
l4 = np.array([[s-r,3*d], [s+r,3*d], [s+r+d,3*d], [s+r+2*d,3*d]])
l5 = np.array([[s,4*d], [s+d,4*d], [s+2*d,4*d], [s+3*d,4*d]])
fig = plt.figure(0)
ax = fig.add_subplot(111)
larr = [l1,l2,l3,l4,l5]
# Plot horizontally
for l in larr:
# same as your *zip(*l1), but you can select on a column-wise basis
ax.errorbar(l[:,0], l[:,1], fmt="o", ls="-", color="black")
# Plot zig-zag-horizontally
for i in range(len(larr[0])):
lxtmp = np.array([x[:,0][i] for x in larr])
lytmp = np.array([x[:,1][i] for x in larr])
ax.errorbar(lxtmp, lytmp, fmt="o", ls="-", color="black")
ax.set_ylim([-0.1,2.1])
ax.set_xlim([-0.6,1.6])
plt.show()
EDIT:
lxtmp = np.array([x[:,0][i] for x in larr])
So, x[:,0] means take all of the rows ":" but only the first column "0". For l1 it will return:
l1[:,0]
array([ 0. , 0.5, 1. , 1.5])
which are the x-values for l1. Doing l1[:,1] will return all of the rows from column "1", the y-values. To draw the vertical lines, you want to take all the x and y values from each i-th array, and hence you loop over all the arrays, taking out the i-th element. For example, the 3rd vertical zig-zag line, would be:
lxtmp = [l1[:,0][2], l2[:,0][2], l3[:,0][2], l4[:,0][2], l5[:,0][2]]
lytmp = [l1[:,1][2], l2[:,1][2], l3[:,1][2], l4[:,1][2], l5[:,1][2]]
To simplify and run over each element, I created 'larr' to loop over and 'build' then in a normal python fashion, e.g.,
[i for i in range(1,10)]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Related

How to count a peak that drops to 0? Python Find Peaks

I am using Scipy's find_peaks to count the number of peaks in a time series.
I need to count the number of peaks with the requirement that it starts at 0 and falls to 0. The second peak from the right (indicated by a vertical line) is counted here, but it shouldn't be since it doesn't fall to 0 before the last peak. Is there a way to specify this in find_peaks?
peaks1 = find_peaks(array, height=(1,1.5),prominence=1)
peaks1_5 = find_peaks(array, height=(1.5,2),prominence=1.5)
peaks2 = find_peaks(array, height=2,prominence=2)
fig, ax = plt.subplots(figsize=(30, 10), dpi=80)
plt.plot(spi_neg['date'],spi["SPI-12"])
[plt.axvline(spi_neg.date.iloc[p],c='red',linewidth=0.3) for p in peaks1[0]]
[plt.axvline(spi_neg.date.iloc[p],c='green',linewidth=0.3) for p in peaks1_5[0]]
[plt.axvline(spi_neg.date.iloc[p],c='purple',linewidth=0.3) for p in peaks2[0]]
plt.axhline(2,linestyle='dashed',linewidth=1)
plt.axhline(1.5,linestyle='dashed',linewidth=1)
plt.axhline(1,linestyle='dashed',linewidth=1)
Peaks chart
A running code with the question would be helpful, and a more precise definition of the countable peaks too ;-)
First we generate some data:
import numpy as np
import matplotlib.pyplot as plt
#---- generate data
mp = 200
freq = 20
t = np.linspace(0,freq*np.pi,mp)
signal = np.sin(t)
noise = np.random.rand(mp)
X = 0.5*signal + noise
#---- scale X
def scale01(a):
return (a-a.min())/(a.max()-a.min())
X = scale01(X) - 0.5
X = np.maximum(X,0.0)
#---- grafics
with plt.style.context('ggplot'):
fig = plt.figure(figsize=(15,3))
plt.plot(t, X)
plt.plot(t, X, 'o')
Now we identify the zero lakes and the non-zero islands
a = np.array(np.where(X<=0))[0] # extract the indices with X<=0
b = np.array(np.where(X>0) )[0] # extract the indices with X>0
with plt.style.context('ggplot'):
fig = plt.figure(figsize=(15,3))
plt.plot(t[b], X[b], 'or', label=">0")
plt.vlines(t[b], 0, X[b], colors='k')
plt.plot(t[a], -X[a], 'og', label="<=0")
plt.legend(); plt.show()
Next we fill the non-zero islands in a list with numpy arrays. Each numpy array contains a non-zero island.
X_ = X[b]
m = len(X_)
list_y = list()
list_Y = list()
for j in range(1,m):
if b[j]-b[j-1]>1 :
list_Y.append(list_y)
list_y = list()
#print("------------------------------------------------------ new list")
#print(j, b[j], X_[j])
list_y.append(X_[j])
list_Y.append(list_y)
print("list_Y");
n = len(list_Y)
for j in range(n):
print(list_Y[j])
With each numpy array in the list you can evaluate the peaks according to your definition (which I could not capture fully).
list_Y
[0.22062475371241386, 0.29207471279008657, 0.35072832015294586, 0.1251594602284437, 0.24379282278250836, 0.06896727821692716]
[0.06271739133976328]
[0.2689504650818615, 0.011887999386713255, 0.055442917743508624, 0.2876317343278316, 0.24084993011027578, 0.12097014134978235]
[0.1907699022464584]
[0.08249052680941726]
[0.10205561805376617]
[0.18903867830269638, 0.26990334850384257, 0.5, 0.3288200602696131, 0.05036869827824486, 0.040381419904307436]
[0.08618838642790339]
[0.0053279353208096625, 0.3468189863146819, 0.05644254569326557, 0.3985674171686334, 0.14897985190026097, 0.0025548308606182513, 0.32765453143333545, 0.3328107320769136, 0.1838328219774621, 0.21123652127176762]
[0.18870251894797663]
[0.13453490446867422, 0.25258744200608363, 0.4981866504733391, 0.35180043079867795, 0.08425183513691303, 0.3376976620831299, 0.22348609066402825]
[0.0716155758184146]
[0.052227024152749935, 0.08639499278421903]
[0.1581304564482665, 0.2273016493144655, 0.26721741895716056, 0.33665669827299305, 0.19255497112246478, 0.16227876457894175]
[0.10236622631923908, 0.06039140456773806, 0.053391261130168344]
[0.21170561257978093, 0.11669466945342633, 0.2479665749659119, 0.25792206298341824, 0.19579440295962314, 0.15210847528158666, 0.23531008247873408]
[0.05340116678342899]
[0.2088166123161308, 0.26031072203571415, 0.2786317264092839, 0.289871721166855, 0.25460661866030165, 0.3214937091565473, 0.36293451974436275]
[0.04525610202919361, 0.1740374143631349, 0.17258947174880612]
[0.14217066607610684, 0.03435965315335088, 0.09996473411377804, 0.48290831305140514, 0.09407783896892297]
[0.03224632110920911, 0.08787466747977346, 0.20032938280871493, 0.23646809723694695, 0.13380244841935984, 0.05305696510866664, 0.2657761536751757, 0.34514204517200975]
[0.17123014194168007, 0.2397521290598289]

Three nested loop over a 2D array

I have a 2D array, which is basically representing a function F that depends on two variables: F(V,T).
F(V,T) is a 2D array, represented as F_VT:
F_VT = [[F(V1), F(V2), F3(V3), ..., F(V11)], -> values for T1
[F(V1), F(V2), F(V3)], ..., F(V11)], -> values for T2
...
[F(V1), F(V2), F(V3)], ..., F(V11)] -> values for T4
V is a 1D array, V = [V1, V2, V3 ... V11]
T is a 1D array, T = [T1, T2, T3, T4]
P is a 1D array, P = [P1, P2, P3, P4]
For a given F(V,T), a new function Fb(V,T) can be calculated:
Fb(V,T) = F(V,T) + P*V
For a fixed value of T and P, I would like to plot Fb, and sort out the V coordinates where Fb reaches the minimum. e.g. for that fixed T and P, Fb reaches the minimum at V = ...
I have come out with the following three nested loop:
for index_T, Ts in enumerate(T):
for Ps in P:
aux_P = []
for Vs in V:
Fb_VT = F_VT[index_T][:] + (2.293710449E+17)*(1E-21) * Ps * Vs
p1 = plt.scatter(V, Fb_VT, color='red', marker="^", s=100)
plt.pause(0.05)
But the curves are not considering the loop over P.
Any help is much appreciated.
Code:
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
F_VT = [np.array([-941.57370763, -941.57401198, -941.57415914, -941.5741743 ,
-941.57418547, -941.57409029, -941.57384471, -941.57349143,
-941.57299666, -941.57242367, -941.57172351]), np.array([-941.59428621, -941.59452901, -941.59467455, -941.59470002,
-941.59475968, -941.59472847, -941.59457033, -941.59432064,
-941.5939331 , -941.59347988, -941.59293092]), np.array([-941.64179308, -941.64203825, -941.64223508, -941.642278 ,
-941.64245276, -941.64254897, -941.6425414 , -941.64245835,
-941.64223967, -941.64196782, -941.641634 ]), np.array([-941.70391106, -941.70416543, -941.70441939, -941.70448022,
-941.70477693, -941.70500704, -941.70515626, -941.70524589,
-941.70520195, -941.70511723, -941.70500381])]
V = np.array([ 60.208589, 60.8721745, 61.4382305, 61.515143, 62.2128025, 62.888581,
63.567809, 64.250832, 64.937775, 65.6287725, 66.3238705])
T = np.linspace(10.00, 2000.00, 4)
P = np.linspace(1., 10., 4)
plt.figure()
for index_T, Ts in enumerate(T):
for Ps in P:
aux_P = []
for Vs in V:
Fb_VT = F_VT[index_T][:] + (2.293710449E+17)*(1E-21) * Ps * Vs
p1 = plt.scatter(V, Fb_VT, color='red', marker="^", label='Calcite I', s=100)
plt.pause(0.05)
plt.show()
You have a math problem
You don't have a code problem, you have a math problem. You can get the complete set of your P*V values with the following array operation:
((2.293710449E+17)*(1E-21) * P * V[:,None]).reshape(-1)
Output:
[0.01381011 0.05524043 0.09667075 0.13810107 0.01396231 0.05584926
0.0977362 0.13962314 0.01409215 0.0563686 0.09864506 0.14092151
0.01410979 0.05643917 0.09876855 0.14109793 0.01426982 0.05707926
0.09988871 0.14269816 0.01442482 0.05769928 0.10097374 0.1442482
0.01458061 0.05832246 0.1020643 0.14580615 0.01473728 0.05894912
0.10316096 0.1473728 0.01489485 0.05957938 0.10426392 0.14894845
0.01505334 0.06021336 0.10537338 0.1505334 0.01521278 0.0608511
0.10648943 0.15212775]
Notice how small all of these values are. Now compare these to the values you have in F_VT. The values of P * V are all in fact roughly 4 orders of magnitude smaller than the values in F_VT. This makes sense, since you're multiplying all of your P * V values by a constant factor that's on the order of 1e-4.
The only thing I can suggest is increasing either your V or P values. Maybe something like P = np.linspace(1, 1000, 4)?
Remove loops and speedup your code through vectorization
This has basically nothing to do with the actual problem in your code, but you can speed things up by replacing your triple-loop with two vectorized operations:
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
F_VT = np.array([[-941.57370763, -941.57401198, -941.57415914, -941.5741743 , -941.57418547, -941.57409029, -941.57384471, -941.57349143, -941.57299666, -941.57242367, -941.57172351],
[-941.59428621, -941.59452901, -941.59467455, -941.59470002, -941.59475968, -941.59472847, -941.59457033, -941.59432064, -941.5939331 , -941.59347988, -941.59293092],
[-941.64179308, -941.64203825, -941.64223508, -941.642278 , -941.64245276, -941.64254897, -941.6425414 , -941.64245835, -941.64223967, -941.64196782, -941.641634 ],
[-941.70391106, -941.70416543, -941.70441939, -941.70448022, -941.70477693, -941.70500704, -941.70515626, -941.70524589, -941.70520195, -941.70511723, -941.70500381]])
V = np.array([ 60.208589, 60.8721745, 61.4382305, 61.515143, 62.2128025, 62.888581, 63.567809, 64.250832, 64.937775, 65.6287725, 66.3238705])
T = np.linspace(10.00, 2000.00, 4)
P = np.linspace(1., 10., 4)
fig = plt.figure()
ax = fig.gca()
PV = ((2.293710449E+17)*(1E-21) * P * V[:,None]).reshape(-1)
Fb_VT = (F_VT[..., None, :] + PV[None, ..., None]).reshape(-1, F_VT.shape[1])
# looping over the rows of Fb_VT will give results equivalent to the triple loop in the old code
for fbvt in Fb_VT:
ax.scatter(V, fbvt, color='red', marker="^", label='Calcite I', s=100)
fig.show()
This will produce the same output as your old code (though for brevity's sake I've plotted all on the output on a single figure):

Q1: IndexError: index 1 is out of bounds for axis 1 with size 1

I'm trying to estimate the steady state distribution of piecewise probability density function using the look ahead estimator. But getting the error
z[condition1] = (1/(sigma*np.sqrt(2*np.pi) ))*np.e**(-0.5*((x[condition1]-y[condition1]+Q1-u)/sigma)**2.
IndexError: index 1 is out of bounds for axis 1 with size 1.
could anyone tell why that first conditional is not working?
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import sympy as sp
from sympy import *
import numpy as np
from scipy.stats import lognorm, beta
from quantecon import LAE
from sympy import symbols
q= symbols('q')
## == Define parameters == #
a_sigma = 0.4
psi_0 = beta(5, 5, scale=0.5) # Initial distribution
phi = lognorm(a_sigma)
def p(x,y):
u=80
sigma=30
b=0.2
Q=80
Q1=Q*(1-b)
Q2=Q*(1+b)
z = np.zeros_like(x, dtype=float)
# Condition 1 indexes all elements where subformula 1 is valid
condition1 = np.logical_and(y>0.0, x >=y-Q1)
z[condition1] = (1/(sigma*np.sqrt(2*np.pi) ))*np.e**(-0.5*((x[condition1]-y[condition1]+Q1-u)/sigma)**2)
condition2 = np.logical_and(y<0.0, x >=y-Q2)
z[condition2] = (1/(sigma*np.sqrt(2*np.pi) ))*np.e**(-0.5*((x[condition2]-y[condition2]+Q2-u)/sigma)**2)
condition3 = np.logical_and(y==0.0, x >=-Q1)
#print(-0.5*((k_prime[condition3] + q - u))**2)
j=-0.5*((x[condition3] + q - u))**2
K=[]
for elem in j:
print(elem)
K.append(1/(sigma*sqrt(2*pi) )*sp.integrate(sp.exp(elem),(q,Q1,Q2)))
#z[condition3] = K
return z
n = 10000 # Number of observations at each date t
T = 30 # Compute density of k_t at 1,...,T+1
# == Generate matrix s.t. t-th column is n observations of k_t == #
k = np.empty((n, T))
A = phi.rvs((n, T))
k[:, 0] = psi_0.rvs(n) # Draw first column from initial distribution
for t in range(T-1):
k[:, t+1] = k[:, t]+ A[:, t]
# == Generate T instances of LAE using this data, one for each date t == #
laes = [LAE(p, k[:, t]) for t in range(T)]
# == Plot == #
fig, ax = plt.subplots()
ygrid = np.linspace(0.01, 4.0, 200)
greys = [str(g) for g in np.linspace(0.0, 0.8, T)]
greys.reverse()
for psi, g in zip(laes, greys):
ax.plot(ygrid, psi(ygrid), color=g, lw=2, alpha=0.6)
ax.set_xlabel('capital')
title = r'Density of $k_1$ (lighter) to $k_T$ (darker) for $T={}$'
ax.set_title(title.format(T))
plt.show()
What I'd do is check the values of condition1 and the shape of all items indexed with it, x,y,z. As you give it, the error message doesn't indicate which indexing is the problem.
I don't know anything about LAE. It looks like it takes a function (here p), and some argument(s). Here you are passing an n element array (k[:,t]). But there's no indication as to how that maps on to the x,y arguments of p.
Here's a simple example that produces this error:
In [204]: x=np.arange(10).reshape(10,1)
In [205]: x[:,1]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-205-9bea3f5be5f1> in <module>()
----> 1 x[:,1]
IndexError: index 1 is out of bounds for axis 1 with size 1
If the index is an array, it may make a difference as to whether it is integer or boolean:
In [212]: idx=np.array([1])
In [213]: x[:,idx]
...
IndexError: index 1 is out of bounds for axis 1 with size 1
In [214]: idx=np.array([1],bool)
In [215]: x[:,idx]
Out[215]:
array([[0],
[1],
[2],
[3],
[4],
[5],
[6],
[7],
[8],
[9]])

Matplotlib plot with multiple colors based on values on x-axis

I want to get a plot similar to the following plot that has different colors based on values for x-axis. Ignore the u and f letters and also the blue curve and gray lines. I only need the green and red lines. So, if you use my code, you will get a plot that is all one color. What I want is to have different color when x is between 0 and the turning point (in this case it is x=50%) and then a different color for the rest.
Code:
import matplotlib.pyplot as plt
def GRLC(values):
n = len(values)
assert(n > 0), 'Empty list of values'
sortedValues = sorted(values) #Sort smallest to largest
#Find cumulative totals
cumm = [0]
for i in range(n):
cumm.append(sum(sortedValues[0:(i + 1)]))
#Calculate Lorenz points
LorenzPoints = [[], []]
sumYs = 0 #Some of all y values
robinHoodIdx = -1 #Robin Hood index max(x_i, y_i)
for i in range(1, n + 2):
x = 100.0 * (i - 1)/n
y = 100.0 * (cumm[i - 1]/float(cumm[n]))
LorenzPoints[0].append(x)
LorenzPoints[1].append(y)
sumYs += y
maxX_Y = x - y
if maxX_Y > robinHoodIdx: robinHoodIdx = maxX_Y
giniIdx = 100 + (100 - 2 * sumYs)/n #Gini index
return [giniIdx, giniIdx/100, robinHoodIdx, LorenzPoints]
reg=[400,200]
result_reg = GRLC(reg)
print 'Gini Index Reg', result_reg[0]
print 'Gini Coefficient Reg', result_reg[1]
print 'Robin Hood Index Reg', result_reg[2]
#Plot
plt.plot(result_reg[3][0], result_reg[3][1], [0, 100], [0, 100], '--')
plt.legend(['Reg-ALSRank#10','Equity-Line'], loc='upper left',prop={'size':16})
plt.xlabel('% of items ')
plt.ylabel('% of times being recommended')
plt.show()
This is how you would plot two lines of different colors, knowing the index in the array at which the color should change.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,49, num=50)
y = x**2
x0 = 23
plt.plot(x[:x0+1], y[:x0+1])
plt.plot(x[x0:], y[x0:])
plt.show()
This works because by default, subsequent line plots have a different color, but you could of course set the color yourself,
plt.plot(x[:x0+1], y[:x0+1], color="cornflowerblue")

Graph Customization in python

currently I have a program that takes data and makes a histogram out of it, I know how to change the labels and stuff, but is there a way to make x-axis display the number range more frequently (badly worded I'll just give an example):so right now on the x-axis is shows the number values in increments of 5, but how can I make it show up in like increments of 2 or 1 or 3.
Current code:
#!/usr/bin/python
import operator
import matplotlib.pyplot as plt
import numpy as np
l=[]
with open("testdata") as f:
line = f.next()
f.next()# skip headers
nat = int(line.split()[
print nat
for line in f:
if line.strip():
l.append(map(float,line.split()[1:]))
b = 0
a = 1
distances = []
for b in range(53):
for a in range(b+1,54):
vector1 = (l[b][0],l[b][1],l[b][2])
vector2 = (l[a][0],l[a][1],l[a][2])
x = vector1
y = vector2
vector3 = list(np.array(x) - np.array(y))
dotProduct = reduce( operator.add, map( operator.mul, vector3, vector3))
dp = dotProduct**.5
distances.append(dp)
num_bins = 200 # <- number of bins for the histogram
(n, bins, patches) = plt.hist(distances, num_bins)
plt.title('Histogram')
plt.xlabel('Distance')
plt.ylabel('Frequency')
plt.show()
label_positions = np.arange(start, end, step, endpoint=True)
plt.xticks(label_positions)

Categories

Resources