I have been puzzled about this issue for some time now, regarding the creation of streamplot given what I would consider limited data compared to the examples I've seen.
I am attempting to plot streamlines of particles in a flow field given the following information on each particle: x coordinate, y coordinate, x-component velocity, y-component velocity. Each of these data sets is in the form of a one-dimensional array. Based on the documentation of the streamplot function in matplotlib, the first two input arguments should be one-dimensional arrays, and the third and fourth should be two-dimensional.
So, my question is: what is the most accurate way to create a streamplot based on the data I have? I have tried using the griddata function in scipy to create grids out of the velocity data, but I'm not quite sure how to decide on appropriate xi values (or from doc: "Points at which to interpolate data") when using this function.
Please excuse the generality of this question, as it might be more about the theory behind a streamplot than python syntax itself.
Any help would be much appreciated!
Related
I am doing some computational fluid dynamics (CFD) simulations for some research, and I have come across a paper that I would like to build upon.
In principle, I am trying to simulate flows and viscosities etc inside a triangular shaped container. Now, some of the cavity-flow and Navier-Stokes equations are quite long. Therefore, some these equations have kindly been publicly written and available in python format here. The code for these equations uses numpy.meshgrid() and numpy.linspace() extensively to produce some rectangular plots in the link. There is nothing wrong with the equations and they are mathematically sound.
However, I would like to replicate these results by simulating them instead inside a triangular container. The plots for these would therefore look like the plots provided on page 28 of this paper. Note here that this is not the rectangular plots with only a triangular subsection plotted, rather the "grid" in this simulation is triangular itself.
My question is whether numpy has a specific feature that would allow for these triangular grids? My evidence of research into this question has led me to scour the documentation regarding non-rectangular arrays, however the closest that I could find was numpy.tril() and numpy.triu(), which still give me rectangular arrays with zeros in the lower and upper triangles of the array respectively. I was wondering if there was any numpy method that allows for the creation of these triangular containers to simulate fluids in.
My last hope would be to create some kind of dictionary, with keys as row numbers, and values as lists which store the column. That way I could create a triangular dictionary. But this would not integrate with the mathematical equations that have written for numpy mentioned previously.
TLDR
How can I use the existing numpy libraries to create triangular grids so that I can have plots that look like this
to then look like this
I am plotting the result of an interpolation in a periodic domain, namely, the earth mercator projection map, [0,2*pi] or [0,360] is the domain for longitude. As you can see on the picture below, I'm plotting a groundtrack.
I am getting first r, i.e. position, and then I'm projecting that right onto earth. Since the coordinate transformations involves trigonometric functions, the results that I obtain are certainly restricted to a domain, where the inverse is bijective. To obtain this plot I've used atan2 in order to obtain a non bijective inverse function, as well as manipulating arccos in order to extend the domain of the inverse function.
All good up to now. The fact is that when I interpolate the resulting points, naturally, the function that returns does not interpret the domain folding property.
I just wanted to know if there is any way around this, apart from manipulating my data and representing it in a non periodic domain, interpolate it, and after that applying %(2*np.pi). These option, even if is doable, implies touching even more those inverse functions. The other option I thought was interpolating in chunks of only increasing values, i.e. and concatenating them.
Nothing found on the scipy documentation.
Solved the issue implementing something like the following. Notice that I am using astropy units module.
adder = 2*np.pi*u.rad
for i in range(1,len(lons)):
if lons[i].value-lons[i-1].value > 1:
sgn=np.sign(lons[i].value-lons[i-1].value)
lons[i:] -= sgn*adder
after doing this, apply the %
f_lons = interp1d(t,lons)
lons = f_lons(new_t) % (2*np.pi)
I've been tasked to develop an algorithm that, given a set of sparse points representing measurements of an existing surface, would allow us to compute the z coordinate of any point on the surface. The challenge is to find a suitable interpolation method that can recreate the 3D surface given only a few points and extrapolate values also outside of the range containing the initial measurements (a notorious problem for many interpolation methods).
After trying to fit many analytic curves to the points I've decided to use RBF interpolation as I thought this will better reproduce the surface given that the points should all lie on it (I'm assuming the measurements have a negligible error).
The first results are quite impressive considering the few points that I'm using.
Interpolation results
In the picture that I'm showing the blue points are the ones used for the RBF interpolation which produces the shape represented in gray scale. The red points are instead additional measurements of the same shape that I'm trying to reproduce with my interpolation algorithm.
Unfortunately there are some outliers, especially when I'm trying to extrapolate points outside of the area where the initial measurements were taken (you can see this in the upper right and lower center insets in the picture). This is to be expected, especially in RBF methods, as I'm trying to extract information from an area that initially does not have any.
Apparently the RBF interpolation is trying to flatten out the surface while I would just need to continue with the curvature of the shape. Of course the method does not know anything about that given how it is defined. However this causes a large discrepancy from the measurements that I'm trying to fit.
That's why I'm asking if there is any way to constrain the interpolation method to keep the curvature or use a different radial basis function that doesn't smooth out so quickly only on the border of the interpolation range. I've tried different combination of the epsilon parameters and distance functions without luck. This is what I'm using right now:
from scipy import interpolate
import numpy as np
spline = interpolate.Rbf(df.X.values, df.Y.values, df.Z.values,
function='thin_plate')
X,Y = np.meshgrid(np.linspace(xmin.round(), xmax.round(), precision),
np.linspace(ymin.round(), ymax.round(), precision))
Z = spline(X, Y)
I was also thinking of creating some additional dummy points outside of the interpolation range to constrain the model even more, but that would be quite complicated.
I'm also attaching an animation to give a better idea of the surface.
Animation
Just wanted to post my solution in case someone has the same problem. The issue was indeed with scipy implementation of the RBF interpolation. I tried instead to adopt a more flexible library, https://rbf.readthedocs.io/en/latest/index.html#.
The results are pretty cool! Using the following options
from rbf.interpolate import RBFInterpolant
spline = RBFInterpolant(X_obs, U_obs, phi='phs5', order=1, sigma=0.0, eps=1.)
I was able to get the right shape even at the edge.
Surface interpolation
I've played around with the different phi functions and here is the boxplot of the spread between the interpolated surface and the points that I'm testing the interpolation against (the red points in the picture).
Boxplot
With phs5 I get the best result with an average spread of about 0.5 mm on the upper surface and 0.8 on the lower surface. Before I was getting a similar average but with many outliers > 15 mm. Definitely a success :)
I have unstructured (taken in no regular order) point cloud data (x,y,z) for a surface. This surface has bulges (+z) and depressions (-z) scattered around in an irregular fashion. I would like to generate some surface that is a function of the original data points and then be able to input a specific (x,y) and get the surface roughness value from it (z value). How would I go about doing this?
I've looked at scipy's interpolation functions, but I don't know if creating a single function for the entire surface is the correct approach? Is there a technical name for what I am trying to do? I would appreciate any suggestions/direction.
I don't know if creating a single function for the entire surface is the correct approach?
I guess this depends on your data. Let's assume the base form of your surface is spherical. Then you can model it as such.
If your surface is more complex then a sphere you might can still model the neighborhood of (x,y) as such. Maybe you could even consider your surface as plain in the near neighborhood of (x,y).
What you are trying to do, can be called surface fitting, or two-dimensional curve fitting. You would be able to find lots of available algorithms by searching for those terms. Now, the choice of the particular algorithm/method should be dictated:
by the origin of your data (there are specialized algorithms or variations of more common ones that are tailored for certain application areas)
by the future use of your data (depending on what you are going to do with it, maybe you need to be able to calculate derivatives easily, etc)
It is not easy to represent complicated data (especially the noisy one) using a single function. Thus there is a lot of research about it. However, in a lot of applications curve-fitting is very successful and very widely used.
I'm referencing this question and this documentation in trying to turn a set of points (the purple dots in the image below) into an interpolated grid.
As you can see, the image has missing spots where dots should be. I'd like to figure out where those are.
import numpy as np
from scipy import interpolate
CIRCLES_X = 25 # There should be 25 circles going across
CIRCLES_Y = 10 # There should be 10 circles going down
points = []
values = []
# Points range from 0-800 ish X, 0-300 ish Y
for point in points:
points.append([points.x, points.y])
values.append(1) # Not sure what this should be
grid_x, grid_y = np.mgrid[0:CIRCLES_Y, 0:CIRCLES_X]
grid = interpolate.griddata(points, values, (grid_x, grid_y), method='linear')
print(grid)
Whenever I print out the result of the grid, I get nan for all of my values.
Where am I going wrong? Is my problem even the correct use case for interpolate.grid?
First, your uncertain points are mainly at an edge, so it's actually extrapolation. Second, interpolation methods built into scipy deal with continuous functions defined on the entire plane and approximate it as a polynomial. While yours is discrete (1 or 0), somewhat periodic rather than polynomial and only defined in a discrete "grid" of points.
So you have to invent some algorithm to inter/extrapolate your specific kind of function. Whether you'll be able to reuse an existing one - from scipy or elsewhere - is up to you.
One possible way is to replace it with some function (continuous or not) defined everywhere, then calculate that approximation in the missing points - whether as one step as scipy.interpolate non-class functions do or as two separate steps.
e.g. you can use a 3-D parabola with peaks in your dots and troughs exactly between them. Or just with ones in the dots and 0's in the blanks and hope the resulting approximation in the grid's points is good enough to give a meaningful result (random overswings are likely). Then you can use scipy.interpolate.RegularGridInterpolator for both inter- and extrapolation.
or as a harmonic function - then what you're seeking is Fourier transformation
Another possible way is to go straight for a discrete solution rather than try to shoehorn the continual mathanalysis' methods into your case: design a (probably entirely custom) algorithm that'll try to figure out the "shape" and "dimensions" of your "grids of dots" and then simply fill in the blanks. I'm not sure if it is possible to add it into the scipy.interpolate's harness as a selectable algorithm in addition to the built-in ones.
And last but not the least. You didn't specify whether the "missing" points are points where the value is unknown or are actual part of the data - i.e. are incorrect data. If it's the latter, simple interpolation is not applicable at all as it assumes that all the data are strictly correct. Then it's a related but different problem: you can approximate the data but then have to somehow "throw away irregularities" (higher order of smallness entities after some point).