Related
Aim
I would like to create a 3D Streamtube Plot with Plotly.
Here is a cross-section of the vector field in the middle of the plot to give you an idea of how it looks like:
The final vector field should have rotational symmetry.
My Attempt
Download the data here: https://filebin.net/x6ywfuo6v4851v74
Run the code bellow:
Code:
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
import plotly.io as pio
pio.renderers.default='browser'
# Import data to pandas
df = pd.read_csv("data.csv")
# Plot
X = np.linspace(0,1,101)
Y = np.linspace(0,1,10)
Z = np.linspace(0,1,101)
# Points from which the streamtubes should originate
xpos,ypos = np.meshgrid(X[::5],Y, indexing="xy")
xpos = xpos.reshape(1,-1)[0]
ypos = ypos.reshape(1,-1)[0]
starting_points = px.scatter_3d(
x=xpos,
y=ypos,
z=[-500]*len(xpos)
)
starting_points.show()
# Streamtube Plot
data_plot = [go.Streamtube(
x = df['x'],
y = df['y'],
z = df['z'],
u = df['u'],
v = df['v'],
w = df['w'],
starts = dict( #Determines the streamtubes starting position.
x=xpos,
y=ypos,
z=[-500]*len(xpos)
),
#sizeref = 0.3,
colorscale = 'jet',
showscale = True,
maxdisplayed = 300 #Determines the maximum segments displayed in a streamtube.
)]
fig = go.Figure(data=data_plot)
fig.show()
The initial points (starting points) of the streamtubes seem to be nicely defined:
...but the resulting 3D streamtube plot is very weird:
Edit
I tried normalizing the field plot, but the result is still not satisfactory:
import plotly.graph_objs as go
import pandas as pd
import numpy as np
import plotly.io as pio
pio.renderers.default='browser'
# Import data to pandas
df = pd.read_csv("data.csv")
# NORMALIZE VECTOR FIELD -> between [0,1]
df["u"] = (df["u"]-df["u"].min()) / (df["u"].max()-df["u"].min())
df["v"] = (df["v"]-df["v"].min()) / (df["v"].max()-df["v"].min())
df["w"] = (df["w"]-df["w"].min()) / (df["w"].max()-df["w"].min())
# Plot
X = np.linspace(0,1,101)
Y = np.linspace(0,1,10)
Z = np.linspace(0,1,101)
# Points from which the streamtubes should originate
xpos,ypos = np.meshgrid(X[::5],Y, indexing="xy")
xpos = xpos.reshape(1,-1)[0]
ypos = ypos.reshape(1,-1)[0]
# Streamtube Plot
data_plot = [go.Streamtube(
x = df['x'],
y = df['y'],
z = df['z'],
u = df['u'],
v = df['v'],
w = df['w'],
starts = dict( #Determines the streamtubes starting position.
x=xpos,
y=ypos,
z=[0]*len(xpos)
),
#sizeref = 0.3,
colorscale = 'jet',
showscale = True,
maxdisplayed = 300 #Determines the maximum segments displayed in a streamtube.
)]
fig = go.Figure(data=data_plot)
fig.show()
Data
As for the data itself:
It is created from 10 slices (y-direction). For each slice (y), [u,v,w] on a regular xz mesh (101x101) was computed. The whole was then assembled into the dataframe which you can download, and which has 101x101x10 data points.
Edit 2
It may be that I am wrongly converting my original data (download here: https://filebin.net/tlgkz3fy1h3j6h5o) into the format suitable for plotly, hence I was wondering if you know how this can be done correctly?
Here some code to visualize the data in a 3D vector plot correctly:
# %%
import pickle
import numpy as np
import matplotlib.pyplot as plt
# Import Full Data
with open("full_data.pickle", 'rb') as handle:
full_data = pickle.load(handle)
# Axis
X = np.linspace(0,1,101)
Y = np.linspace(0,1,10)
Z = np.linspace(-500,200,101)
# Initialize List of all fiels
DX = []
DY = []
DZ = []
for cross_section in list(full_data["cross_sections"].keys()):
# extract field components in x, y, and z
dx,dy,dz = full_data["cross_sections"][cross_section]
# Make them numpy imediatley
dx = np.array(dx)
dy = np.array(dy)
dz = np.array(dz)
# Apppend
DX.append(dx)
DY.append(dy)
DZ.append(dz)
#Convert to numpy
DX = np.array(DX)
DY = np.array(DY)
DZ = np.array(DZ)
# Create 3D Quiver Plot with color gradient
# Source: https://stackoverflow.com/questions/65254887/how-to-plot-with-matplotlib-a-3d-quiver-plot-with-color-gradient-for-length-giv
def plot_3d_quiver(x, y, z, u, v, w):
# COMPUTE LENGTH OF VECTOR -> MAGNITUDE
c = np.sqrt(np.abs(v) ** 2 + np.abs(u) ** 2 + np.abs(w) ** 2)
c = (c.ravel() - c.min()) / c.ptp()
# Repeat for each body line and two head lines
c = np.concatenate((c, np.repeat(c, 2)))
# Colormap
c = plt.cm.jet(c)
fig = plt.figure(dpi =300)
ax = fig.gca(projection='3d')
ax.quiver(x, y, z, u, v, w, colors=c, length=0.2, arrow_length_ratio=0.7)
plt.gca().invert_zaxis()
plt.show()
# Create Mesh !
xi, yi, zi = np.meshgrid(X, Y, Z, indexing='xy')
skip_every = 5
skip_slice = 2
skip3D=(slice(None,None,skip_slice),slice(None,None,skip_every),slice(None,None,skip_every))
# Source: https://stackoverflow.com/questions/68690442/python-plotting-3d-vector-field
plot_3d_quiver(xi[skip3D], yi[skip3D], zi[skip3D]/1000, DX[skip3D], DY[skip3D],
np.moveaxis(DZ[skip3D],2,1))
As you can see there are some long downward vectors in the middle of the 3D space, which is not shown in the plotly tubes.
Edit 3
Using the code from the answer, I get this:
This is a huge improvement. This looks almost perfect and is in accordance to what I expect.
A few more questions:
Is there a way to also show some tubes at the lower part of the plot?
Is there a way to flip the z-axis, such that the tubes are coming down from -z to +z (like shown in the cross-section streamline plot) ?
How does the data need to be structured to be organized correctly for the plotly plot? I ask that because of the use of np.moveaxis()?
I have rewritten my answer to reflect the history of conversation but in a disciplined manner.
The situation is:
len(np.unique(df['x']))
>>> 101
that when compared with:
len(np.unique(df['y']))
>>> 10
Seems data in y-direction are much coarser than that of x-direction!
But in z-direction the situation is even worse because the range of data are way more than that of x and y:
df.min()
>>> x 0.000000
y 0.000000
z -500.000000
u -0.369106
v -0.259156
w -0.517652
df.max()
>>> x 1.000000
y 1.000000
z 200.000000
u 0.368312
v 0.238271
w 1.257869
The solution to the ill formed data-set comprises of three steps:
Normalize the vector field and sample points in each direction
Either reduce data density in x and z direction or increase density of data on y-axis.(This step is optional but generally recommended)
After making a plot based on the new data, change axis ticks to the real values.
To normalize a vector-field in this situation which apparently is an engineering one, it's important to maintain the relative length of vectors on every spacial point by doing it this way:
# NORMALIZE VECTOR FIELD -> between [0,1]
np_df = np.array([u, v, w])
vecf_norm = np.linalg.norm(np_df, 2, axis=0)
max_norm = np.max(vecf_norm)
min_norm = np.min(vecf_norm)
u = u * (vecf_norm - min_norm) / (max_norm - min_norm)
v = v * (vecf_norm - min_norm) / (max_norm - min_norm)
w = w * (vecf_norm - min_norm) / (max_norm - min_norm)
As you will see at the end, this formulation will be used to enhance the resulting tube-plot.
Please let me add some important details about using dimensionless data for engineering data visualisation:
First of all if this vector field is resulted from any sort of differential equations, it is highly recommended to reformulate your P.D.F. to a dimensionless equation before attempting to solve it numerically.
If the vector field is result of an already dimensionless differential equation, you need to plot it using dimensionless data (including geometry and u,v,w values).
Please consider plotly uses the local divergence values to determine the local diameter of the tubes. When changing the vector field (and the geometry) we are changing the divergence as well.
I tried to mix your initial and second codes to get this:
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
import plotly.io as pio
import pickle
pio.renderers.default='browser'
# Import Full Data
with open("full_data.pickle", 'rb') as handle:
full_data = pickle.load(handle)
# Axis
X = np.linspace(0,1,101)
Y = np.linspace(0,1,10)
Z = np.linspace(-0.5,0.2,101)
xpos,ypos = np.meshgrid(X[::5],Y, indexing="ij")
#xpos = xpos.reshape(1,-1)[0]
#ypos = ypos.reshape(1,-1)[0]
xpos = np.ravel(xpos)
ypos = np.ravel(ypos)
# Initialize List of all fields
DX = []
DY = []
DZ = []
for cross_section in list(full_data["cross_sections"]):
# extract field components in x, y, and z
dx,dy,dz = full_data["cross_sections"][cross_section]
# Make them numpy imediatley
dx = np.array(dx)
dy = np.array(dy)
dz = np.array(dz)
# Apppend
DX.append(dx)
DY.append(dy)
DZ.append(dz)
#Convert to numpy
move_i = [0, 1, 2]
move_e = [1, 2, 0]
DX = np.moveaxis(np.array(DX), move_i, move_e)
DY = np.moveaxis(np.array(DY), move_i, move_e)
DZ = np.moveaxis(np.array(DZ), move_i, move_e)
# Create Mesh !
xi, yi, zi = np.meshgrid(X, Y, Z, indexing="ij")
data_plot = [go.Streamtube(
x = np.ravel(xi),
y = np.ravel(yi),
z = np.ravel(zi),
u = np.ravel(DX),
v = np.ravel(DY),
w = np.ravel(DZ),
starts = dict( #Determines the streamtubes starting position.
x=xpos,
y=ypos,
z=np.array([-0.5]*len(xpos)
)),
#sizeref = 0.3,
colorscale = 'jet',
showscale = True,
maxdisplayed = 300 #Determines the maximum segments displayed in a streamtube.
)]
fig = go.Figure(data=data_plot)
fig.show()
In this code I have removed the skipping thing, because I suspect the evil is happening there. The resulting plot which you have added to your question, seems similar to the 2D plot of your question, but it requires more work to have better result.
So using what have been told already in addition to the info below:
Yes, Tubes are started from the start points, so you need to define start points where you expect to see tubes there! but, the start points need to be geometrically inside the space defined by sample points, otherwise maybe plotly be forced to extrapolate data (I'm not sure about this) and it results in distorted and unexpected results. This means you can define start points both in upper and lower planes of the field to ensure that you have vectors which emit on both planes. Sometime the vectors are there but you can not see them because they are drawn too thin to see. It's because their local divergences are too low, may be if you normalize this vector field by the rules mentioned earlier, it gives you a better result.
According to plotly documentation:
You can tell plotly's automatic axis range calculation logic to reverse the direction of an axis by setting the autorange axis property to "reversed"
plotly reads data point-by-point, so the order of points doesn't really matter but in case of your problem, the issue happens when data became corrupted and disturbed during omitting of some of sample points. i.e. some of x,y,z and some of u,v,w data loosed their correct location which resulted in an entirely different unexpected data set.
I have tried to normalize the (u,v,w) vector-field(using the formulation provided earlier):
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
import plotly.io as pio
import pickle
pio.renderers.default='browser'
# Import Full Data
with open("full_data.pickle", 'rb') as handle:
full_data = pickle.load(handle)
# Axis
X = np.linspace(0,1,101)
Y = np.linspace(0,1,10)
Z = np.linspace(-0.5,0.2,101)
xpos,ypos = np.meshgrid(X[::5],Y, indexing="ij")
#xpos = xpos.reshape(1,-1)[0]
#ypos = ypos.reshape(1,-1)[0]
xpos = np.ravel(xpos)
ypos = np.ravel(ypos)
# Initialize List of all fields
DX = []
DY = []
DZ = []
for cross_section in list(full_data["cross_sections"]):
# extract field components in x, y, and z
dx,dy,dz = full_data["cross_sections"][cross_section]
# Make them numpy imediatley
dx = np.array(dx)
dy = np.array(dy)
dz = np.array(dz)
# Apppend
DX.append(dx)
DY.append(dy)
DZ.append(dz)
#Convert to numpy
move_i = [0, 1, 2]
move_e = [1, 2, 0]
DX = np.moveaxis(np.array(DX), move_i, move_e)
DY = np.moveaxis(np.array(DY), move_i, move_e)
DZ = np.moveaxis(np.array(DZ), move_i, move_e)
u1 = np.ravel(DX)
v1 = np.ravel(DY)
w1 = np.ravel(DZ)
np_df = np.array([u1, v1, w1])
vecf_norm = np.linalg.norm(np_df, 2, axis=0)
max_norm = np.max(vecf_norm)
min_norm = np.min(vecf_norm)
u2 = u1 * (vecf_norm - min_norm) / (max_norm - min_norm)
v2 = v1 * (vecf_norm - min_norm) / (max_norm - min_norm)
w2 = w1 * (vecf_norm - min_norm) / (max_norm - min_norm)
# Create Mesh !
xi, yi, zi = np.meshgrid(X, Y, Z, indexing="ij")
data_plot = [go.Streamtube(
x = np.ravel(xi),
y = np.ravel(yi),
z = np.ravel(zi),
u = u2,
v = v2,
w = w2,
starts = dict( #Determines the streamtubes starting position.
x=xpos,
y=ypos,
z=np.array([-0.5]*len(xpos)
)),
#sizeref = 0.3,
colorscale = 'jet',
showscale = True,
maxdisplayed = 300 #Determines the maximum segments displayed in a streamtube.
)]
fig = go.Figure(data=data_plot)
fig.show()
and get a better plot:
I have a dataframe like this:
import pandas as pd
import numpy as np
time = pd.date_range('2018-05-14 00:00:00','2018-05-14 01:00:00',freq='5T')
mile = np.linspace(0,100,10)
x = list(time)*len(mile)
y = np.repeat(mile,len(time))
z = []
for i in range(0,10,1):
z.extend(np.random.normal(loc=i*5, scale=5, size=13))
origin_data = pd.DataFrame({'x':x, 'y':y ,'z':z})
origin_data contains original points' positions(x and y) and their values(z). I want to interpolate the z values at these new positions: x = pd.date_range('2018-05-14 00:00:00','2018-05-14 01:00:00',freq='1T') with y = np.linspace(0,91,1) just using bilinear interpolation.
I learned about the official document about scipy.interpolate.interp2d. But its x type is numeric, mine is datetime. Also, the tutorial's z values are calculated while mine are already given so I don't know how to handle the order of input z value. Could anyone give me an example that contains an interpolation result plot based on the dataframe I provided above? Thank you for your attention!
This is the way I found to this question:
import pandas as pd
import numpy as np
from scipy import interpolate
import itertools
time = pd.date_range('2018-05-14 00:00:00','2018-05-14 01:00:00',freq='5T')
mile = np.arange(0,100,10)
x = list(time)*len(mile)
y = np.repeat(mile,len(time))
z = []
for i in range(0,10,1):
z.extend(np.random.normal(loc=i*5, scale=5, size=13))
origin_data = pd.DataFrame({'x':x, 'y':y ,'z':z})
from ggplot import *
ggplot(aes(x = 'x', y = 'y', colour = 'z'), data = origin_data) +\
geom_point(size = 100) +\
scale_x_date(labels = date_format("%Y-%m-%d %H:%M:S"))
x_numeric = [x.timestamp() for x in origin_data['x']]
x_cors = pd.unique(x_numeric)
y_cors = pd.unique(origin_data['y'])
cors = list(itertools.product(x_cors,y_cors))
interp_func = interpolate.LinearNDInterpolator(cors, z)
interp_func = interpolate.CloughTocher2DInterpolator(cors, z)
new_x = [x.timestamp() for x in pd.date_range('2018-05-14 00:00:00','2018-05-14 01:00:00',freq='1T')]
new_y = np.arange(0,91,1)
new_cors = list(itertools.product(new_x,new_y))
new_z = interp_func(new_cors)
new_data = pd.DataFrame({'x':[x[0] for x in new_cors],
'y':[x[1] for x in new_cors],
'z':new_z})
import datetime
new_data['x'] = [pd.Timestamp(x,unit = 's') for x in new_data['x']]
ggplot(aes(x='x',y='y',colour='z'),data=new_data) +\
geom_point(size=100) +\
scale_x_date(labels = date_format("%Y-%m-%d %H:%M:S"))
I have created a vector (v) and would like to perform the rotMatrix function on it. I cannot figure out how to call the function rotMatrix with a degree of 30 on the vector (v). I am also plotting the vectors.
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("white")
import math
def rotMatrix(angle):
return np.array([[np.cos(np.degrees(angle)), np.arcsin(np.degrees(angle))], [np.sin(np.degrees(angle)), np.cos(np.degrees(angle))]])
v = np.array([3,7])
v30 = rotMatrix(np.degrees(30)).dot(v)
plt.arrow(0,0,v[0],v[1], head_width=0.8, head_length=0.8)
plt.arrow(0,0,v30[0],v30[1],head_width=0.8, head_length=0.8)
plt.axis([-5,5,0,10])
plt.show()
In your rotMatrix function you have used the arcsin() function. You want to use -sin() You should also convert your degrees value to radians
return np.array([[np.cos(np.radians(angle)),
-np.sin(np.radians(angle))],
[np.sin(np.radians(angle)),
np.cos(np.radians(angle))]])
Or slightly improve efficiently and readability by
c = np.cos(np.radians(angle))
s = np.sin(np.radians(angle))
return np.array([[c, -s], [s, c]])
and the call with
rotMatrix(30).dot(v)
-sin and arcsin are very different.
When in doubt, play around with the calculations in an interactive Python/numpy session.
In [23]: 30/180*np.pi # do it yourself convsion - easy
Out[23]: 0.5235987755982988
In [24]: np.radians(30) # degrees to radians - samething
Out[24]: 0.52359877559829882
In [25]: np.sin(np.radians(30)) # sin(30deg)
Out[25]: 0.49999999999999994
enter image description here import numpy as np
import matplotlib.pyplot as plt
A = np.array([[3],[-3]])
n = np.linspace(0,2*np.pi,100)
def rotate_me(A,n):
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols = 2, figsize=(18, 16))
buf1 = []
buf11 = []
buf12 = []
buf13 = []
buf1p = []
buf2 = []
# t = []
for theta in n:
x=2
x1=3
x2=2
x3=3
# xp=3
# theta = 1/p
origin = [0],[0]
R = np.array([[x*np.cos(theta),-np.sin(theta)],
[np.sin(theta),np.cos(theta)]])
R1 = np.array([[np.cos(theta),-np.sin(theta)],
[np.sin(theta),np.cos(theta)*x1]])
R2 = np.array([[np.cos(theta),-np.sin(theta)],
[x2*np.sin(theta),np.cos(theta)]])
R3 = np.array([[np.cos(theta),-np.sin(theta)*x3],
[np.sin(theta),np.cos(theta)]])
Rp = np.array([[np.cos(theta),-np.sin(theta)],
[np.sin(theta),np.cos(theta)]])
V = R.dot(A)
V1 = R1.dot(A)
V2 = R2.dot(A)
V3 = R3.dot(A)
Vp = Rp.dot(A)
buf1.append(np.linalg.norm(V))
buf11.append(np.linalg.norm(V1))
buf12.append(np.linalg.norm(V2))
buf13.append(np.linalg.norm(V3))
buf1p.append(np.linalg.norm(Vp))
# buf2.append(np.linalg.norm(A))
ax1.quiver(*origin,V[0,:],V[1,:], scale=21,color ='r',label='cos')
ax1.quiver(*origin,V1[0,:],V1[1,:], scale=21,color ='g',label='cos')
ax1.quiver(*origin,V2[0,:],V2[1,:], scale=21,color ='m',label='sin')
ax1.quiver(*origin,V3[0,:],V3[1,:], scale=21,color ='b',label='-sin')
ax1.quiver(*origin,Vp[0,:],Vp[1,:], scale=21,color ='k',label='pure')
# print(theta)
# ax1.legend()
ax2.plot(n,buf1,color ='r')
ax2.plot(n,buf11,color ='g')
ax2.plot(n,buf12,color ='m')
ax2.plot(n,buf13,color ='b')
ax2.plot(n,buf1p,color ='k')
# ax2.plot(n,buf2,color ='b')
ax2.set_xlabel('angle')
ax2.set_ylabel('magnitude')
plt.show()
# return buf1,buf2
rotate_me(A,n)
I am trying to map surface curvature (mean, gaussian and principle curvature) values to surface faces. I have computed the curvature values for an artificially generated 3D surface (eg. cylinder). The resulting 3D surface that I am trying to get is something like this mean curvature mapped to surface. Can somebody guide me in how to get this?
The code for the surface I am creating is:
import math
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
xindex = []
yindex = []
zindex = []
x = []
y = []
z = []
count = 1
surfaceSt = []
import numpy
numpy.set_printoptions(threshold=numpy.nan)
#surfaceStX = numpy.empty((10,36))
#surfaceStY = numpy.empty((10,36))
#surfaceStZ = numpy.empty((10,36))
surfaceStZ = []
surfaceStX = []
surfaceStY = []
for i in range(1,21):
if i < 11:
x = []
y = []
z = []
pt = []
ptX = []
ptY = []
ptZ = []
for t in range(0,360,10):
x = i*math.sin(math.radians(t))
y = i*math.cos(math.radians(t))
z = i-1
ptX.append(x)
ptY.append(y)
ptZ.append(z)
pt.append([x,y,z])
ptX.append(ptX[0])
ptY.append(ptY[0])
ptZ.append(ptZ[0])
surfaceStX.append(ptX)
surfaceStY.append(ptY)
surfaceStZ.append(ptZ)
# numpy.append(surfaceStX,ptX)
# numpy.append(surfaceStY,ptY)
# numpy.append(surfaceStZ,ptZ)
#ax.scatter(x,y,z)
elif i >= 11:
x = []
y = []
z = []
pt = []
ptX = []
ptY = []
ptZ = []
for t in range(0,360,10):
x = (i-count)*math.sin(math.radians(t))
y = (i-count)*math.cos(math.radians(t))
z = i-1
ptX.append(x)
ptY.append(y)
ptZ.append(z)
pt.append([x,y,z])
ptX.append(ptX[0])
ptY.append(ptY[0])
ptZ.append(ptZ[0])
surfaceStX.append(ptX)
surfaceStY.append(ptY)
surfaceStZ.append(ptZ)
count +=2
X = numpy.array(surfaceStX)
Y = numpy.array(surfaceStY)
Z = numpy.array(surfaceStZ)
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,shade = 'True' )
from surfaceCurvature import surface_curvature
Pcurvature,Gcurvature,Mcurvature = surface_curvature(X,Y,Z)
plt.show()
My surface curvature computation is given below (courtesy: https://github.com/sujithTSR/surface-curvature):
def surface_curvature(X,Y,Z):
(lr,lb)=X.shape
#print lr
#print "awfshss-------------"
#print lb
#First Derivatives
Xv,Xu=np.gradient(X)
Yv,Yu=np.gradient(Y)
Zv,Zu=np.gradient(Z)
#Second Derivatives
Xuv,Xuu=np.gradient(Xu)
Yuv,Yuu=np.gradient(Yu)
Zuv,Zuu=np.gradient(Zu)
Xvv,Xuv=np.gradient(Xv)
Yvv,Yuv=np.gradient(Yv)
Zvv,Zuv=np.gradient(Zv)
#2D to 1D conversion
#Reshape to 1D vectors
Xu=np.reshape(Xu,lr*lb)
Yu=np.reshape(Yu,lr*lb)
Zu=np.reshape(Zu,lr*lb)
Xv=np.reshape(Xv,lr*lb)
Yv=np.reshape(Yv,lr*lb)
Zv=np.reshape(Zv,lr*lb)
Xuu=np.reshape(Xuu,lr*lb)
Yuu=np.reshape(Yuu,lr*lb)
Zuu=np.reshape(Zuu,lr*lb)
Xuv=np.reshape(Xuv,lr*lb)
Yuv=np.reshape(Yuv,lr*lb)
Zuv=np.reshape(Zuv,lr*lb)
Xvv=np.reshape(Xvv,lr*lb)
Yvv=np.reshape(Yvv,lr*lb)
Zvv=np.reshape(Zvv,lr*lb)
Xu=np.c_[Xu, Yu, Zu]
Xv=np.c_[Xv, Yv, Zv]
Xuu=np.c_[Xuu, Yuu, Zuu]
Xuv=np.c_[Xuv, Yuv, Zuv]
Xvv=np.c_[Xvv, Yvv, Zvv]
# First fundamental Coeffecients of the surface (E,F,G)
E=np.einsum('ij,ij->i', Xu, Xu)
F=np.einsum('ij,ij->i', Xu, Xv)
G=np.einsum('ij,ij->i', Xv, Xv)
m=np.cross(Xu,Xv,axisa=1, axisb=1)
p=np.sqrt(np.einsum('ij,ij->i', m, m))
n=m/np.c_[p,p,p]
# Second fundamental Coeffecients of the surface (L,M,N), (e,f,g)
L= np.einsum('ij,ij->i', Xuu, n) #e
M= np.einsum('ij,ij->i', Xuv, n) #f
N= np.einsum('ij,ij->i', Xvv, n) #g
# Gaussian Curvature
K=(L*N-M**2)/(E*G-F**2)
K=np.reshape(K,lr*lb)
# Mean Curvature
H = (E*N + G*L - 2*F*M)/((E*G - F**2))
H = np.reshape(H,lr*lb)
# Principle Curvatures
Pmax = H + np.sqrt(H**2 - K)
Pmin = H - np.sqrt(H**2 - K)
#[Pmax, Pmin]
Principle = [Pmax,Pmin]
return Principle,K,H
EDIT 1:
I tried a few things based on the link provided by armatita. Following is my code:
'''
Creat half cylinder
'''
import numpy
import matplotlib.pyplot as plt
import math
ptX= []
ptY = []
ptZ = []
ptX1 = []
ptY1 = []
ptZ1 = []
for i in range(0,10):
x = []
y = []
z = []
for t in range(0,200,20):
x.append(10*math.cos(math.radians(t)))
y.append(10*math.sin(math.radians(t)))
z.append(i)
x1= 5*math.cos(math.radians(t))
y1 = 5*math.sin(math.radians(t))
z1 = i
ptX1.append(x1)
ptY1.append(y1)
ptZ1.append(z1)
ptX.append(x)
ptY.append(y)
ptZ.append(z)
X = numpy.array(ptX)
Y = numpy.array(ptY)
Z = numpy.array(ptZ)
fig = plt.figure()
ax = fig.add_subplot(111,projection = '3d')
from surfaceCurvature import surface_curvature
p,g,m= surface_curvature(X,Y,Z)
n = numpy.reshape(m,numpy.shape(X))
ax.plot_surface(X,Y,Z, rstride=1, cstride=1)
plt.show()
'''
Map mean curvature to color
'''
import numpy as np
X1 = X.ravel()
Y1 = Y.ravel()
Z1 = Z.ravel()
from scipy.interpolate import RectBivariateSpline
# Define the points at the centers of the faces:
y_coords, x_coords = np.unique(Y1), np.unique(X1)
y_centers, x_centers = [ arr[:-1] + np.diff(arr)/2 for arr in (y_coords, x_coords)]
# Convert back to a 2D grid, required for plot_surface:
#Y1 = Y.reshape(y_coords.size, -1)
#X1 = X.reshape(-1, x_coords.size)
#Z1 = Z.reshape(X.shape)
C = m.reshape(X.shape)
C -= C.min()
C /= C.max()
interp_func = RectBivariateSpline(x_coords, y_coords, C.T, kx=1, ky=1)
I get the following error:
raise TypeError('y dimension of z must have same number of y')
TypeError: y dimension of z must have same number of elements as y
All the dimensions are same. Can anybody tell what's going wrong with my implementation?
I think you need to figure out exactly what you need. Looking at your code I notice you are producing variables that have no use. Also you seem to have a function to calculate the surface curvature but than you try to make some calculations using the np.unique function for which I cannot see the purpose here (and that is why that error appears).
So let's assume this:
You have a function that returns the curvature value for each cell.
You have the X,Y and Z meshes to plot that surface.
Using your code, and assuming you m variable is the curvature (again this is in your code), if I do this:
import numpy
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import math
# Here would be the surface_curvature function
X = numpy.array(ptX)
Y = numpy.array(ptY)
Z = numpy.array(ptZ)
p,g,m= surface_curvature(X,Y,Z)
C = m.reshape(X.shape)
C -= C.min()
C /= C.max()
fig = plt.figure()
ax = fig.add_subplot(111,projection = '3d')
n = numpy.reshape(m,numpy.shape(X))
ax.plot_surface(X,Y,Z,facecolors = cm.jet(C), rstride=1, cstride=1)
plt.show()
, I obtain this:
Which is a value mapped to color in a matplotlib surface. If that C you've built is not the actual curvature you need to replace it by the one that is.
I'm trying to do a polynomial regression of csv file I have (or any other csv file). I am not sure how to build a matrix that contains the data set I have. Here is the current code I have.
from matplotlib.pyplot import *
import numpy as np
import csv
from math import *
f=open("data_setshort.csv", "r")
csv_f = csv.reader(f)
xval = []
yval = []
polyreg = []
for row in csv_f:
xval.append(row[0])
yval.append(row[1])
f.close()
x = np.array(xval)
y = np.array(yval)
xlist = [float(i) for i in x]
ylist = [float(i) for i in y]
print xlist
print ylist
def poly_fit(x,y):
for i in range(1, len(x)):
M = np.matrix(x[i],y[i])
return M
Matrix = poly_fit(xlist,ylist)
print Matrix
The poly_fit(x,y) is the function I am trying to build to do the polynomial regression.
Maybe I misunderstood exactly what you're trying to do, but if it's fitting a polynomial from continuous x and y values, then this will do it:
import numpy as np
xi = np.random.uniform(-3, 3, 30)
ni = np.random.uniform(0, .4, 30)
coefficients = np.polyfit(xi, ni, 3)
print coefficients
Then, to use it to generate y values given new x values:
new_x = 2.5
polynomial = np.poly1d(coefficients)
new_y = polynomial(new_x)