I have a scatter curved data in 3D z=f(x,y), I want to fit it a smoothed curve. The fitted curve needs to be able to be extracted points from.
I don't have a model for it and I don't bother to make a model. I was thinking use polyfit but it seems only to work for 2D data. I have seen an answer that suggests to make one variable as independent and generate the other two w.r.t it, let's say x. I don't think it is a good idea as the relation between y and z is ignored.
I tried using scipy.interpolate.splprep. I later realised it was spline not fitting.
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
from mpl_toolkits.mplot3d import Axes3D
tck, u = interpolate.splprep([xdata,ydata,zdata], s=2)
x,y,z = interpolate.splev(u,tck)
fig1 = plt.figure(1)
ax3d = fig1.add_subplot(111, projection='3d')
ax3d.plot(xdata,ydata,zdata, 'bo')
ax3d.plot(x,y,z, 'r-')
Is there a way to make interpolate.splprep smoother? Or any other method to fit a 3D curve?
Edit
I have managed to make the curve smoother by increase quite a bit of s.
The x,y,z given by splev are distributed unevenly like the original data. How can I extract a even spread data from the smoothed curve.
Or I mean how I can get the smoothed spline model by splprep, I can np.linspace x and y then sub to the model and get a smoothed data set.
This is my data.
A curve
Fitting a polynomial using np.polyfit in 3 dimensions
Follow the second answer of this question, I managed to get a coefficient result by sklearn. But I don't know how to use it. How can I used it to get the smoothed data?
I am frustrating not able to find a way plot or extract data from it.
Related
Here's the least-square quadratic fitting result of my data: y = 0.06(+/- 0.16)x**2-0.65(+/-0.04)x+1.2(+/-0.001). I wonder is there a direct way to plot the fit as well as the error band? I found a similar example which used plt.fill_between method. However, in that example the boundaries are known, while in my case I'm not quite sure about the exact parameters which correspond to the boundaries. I don't know if I could use plt.fill_between or a different approach. Thanks!
You can use seaborn.regplot to calculate the fit and plot it directly (order=2 is second order fit):
Here is a dummy example:
import seaborn as sns
import numpy as np
xs = np.linspace(0, 10, 50)
ys = xs**2+xs+1+np.random.normal(scale=20, size=50)
sns.regplot(x=xs, y=ys, order=2)
I believe the fix to this will be relatively simple, but I can't seem to figure out how to convolve a scatter plot that I've plotted in python.
I have 2 data arrays, one of galactic latitudes and one of galactic longitudes, and I've plotted them with a hammer projection to represent a distribution of stars in galactic coordinates.
Now, I want to use boxcar smoothing to smooth the plot with 15 degree boxes.
I have tried using astropy.convolution with convolve and Box2DKernel, but I can't seem to make it work.
I've also looked at examples from http://docs.astropy.org/en/stable/convolution/kernels.html
but I don't understand how to translate their examples to what I need to do. They seem to be plotting a 2D function and smoothing that. Can I not convolve a plot and bin up the points by where they are on the graph? The only thing that I've gotten to display anything produces a straight line and I don't understand why. I'm very new to python so this has been giving me a lot of trouble.
This is the code that I have so far:
This plots the two arrays into a hammer projection:
from astropy import units as u
import astropy.coordinates as coord
glat = coord.Angle(pos_data['GLAT']*u.degree)
glon = coord.Angle(pos_data['GLON']*u.degree)
glon= glon.wrap_at(180*u.degree)
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,12))
ax = fig.add_subplot(211, projection="hammer")
ax.scatter(glon.radian, glat.radian)
ax.grid(True)
This is my attempt at convolving the data:
from astropy.convolution import convolve, Box2DKernel
data = [glon, glat]
kernel = Box2DKernel(10)
smoothed = convolve(data, kernel)
ax = fig.add_subplot(212, projection="hammer")
ax.scatter(smoothed[0]*u.radian, smoothed[1]*u.radian)
ax.grid(True)
Like I said, it's just one of many attempts that ended up giving something instead of an error, but I'm not sure that I'm using the function correctly at all. I'm not sure (or I don't think) that I can create "data" the way that I did, but any other combination of arrays or convolving each as a 1D array didn't work either.
Any ideas would be really helpful, thanks.
It seems like you're looking for Kernel Density Estimation, which is a way of turning individual measurements of spatial point patterns into a continuous distribution. I happen to prefer the scikit-learn implementation. You can then use the basemap package to do your plotting. The following code should be adaptable to your situation, where ra and dec are arrays of your stars' Right Ascension and Declination (you'll have to be careful about radians vs degrees here):
from sklearn.neighbors import KernelDensity
from sklearn.grid_search import GridSearchCV
data = np.column_stack((ra, dec))
# use a tophat/boxcar kernel and a haversine (spherical) metric
p = {'bandwidth': np.logspace(-1, 1, 20), 'kernel'='tophat',
'metric'='haversine'}
grid = GridSearchCV(KernelDensity(), params)
grid.fit(data)
Then you should be able to define a meshgrid over which to evaluate your KDE, and then plot it using imshow/pcolormesh/something else over a Hammer projection (see here or here)
cI previously posted this over at code review, but moved it over here as I was told it is more fitting.
Basically, I want to create a colorplot of some irregularly sampled data. I've had some success with the interpolation using matplotlib.mlab.griddata. When I plot the interpolated data (using matplotlib.pyplot.imshow) however, the edges of the domain appear to be left blank. This gets better if I increase the grid density (increase N in the code) but doesn't solve the problem.
I've attached my code and would like to upload an image of the plot I can generate, but am still lacking the reputation to post an image ;)
edit: That has changed now, uploaded the plot after the changes proposed by Ajean:
. Can someone help me out as to what is going wrong?
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.mlab import griddata
# Generate Data
X=np.random.random(100)
Y=2*np.random.random(100)-1
Z=X*Y
# Interpolation
N=100j
extent=(0,1,-1,1)
xs,ys = np.mgrid[extent[0]:extent[1]:N, extent[2]:extent[3]:N]
resampled=griddata(X,Y,Z,xs,ys,interp='nn')
#Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlabel('X')
ax.set_ylabel('Y')
cplot=ax.imshow(resampled.T,extent=extent)
ticks=np.linspace(-1,1,11)
cbar=fig.colorbar(magplot,ticks=ticks,orientation='vertical')
cbar.set_label('Value', labelpad=20,rotation=270,size=16)
ax.scatter(X,Y,c='r')
It is because your calls to random don't provide you with any values at the boundary corners, therefore there is nothing to interpolate with. If you change X and Y definitions to
# Just include the four corners
X=np.concatenate([np.random.random(100),[0,0,1,1]])
Y=np.concatenate([2*np.random.random(100)-1,[-1,1,1,-1]])
You'll fill in the whole thing.
My Question:
How can i draw a curve though this data, thus describing an equation for this plot..
I generated this scatter plot by following code, but I am not able to figure out how to generate an equation for this data and draw the corresponding curve on this plot simultaneously. Please Help.!
def draw(data,xlabel,ylabel):
print('length of data : ',len(data))
x,y = [],[]
for i in data:
x.append((i[1]))
y.append((i[0]))
plt.scatter(x, y,marker=r'o',color='b')
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.show()
Basically I want something like this:
You have to perform a curve fitting procedure, which is called a regression problem in mathematics. In your case it seems that data is more or less exponential, but you can fit arbitrary function through scipy.optimize.curve_fit
http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html
I'm trying to reproduce this plot in python with little luck:
It's a simple number density contour currently done in SuperMongo. I'd like to drop it in favor of Python but the closest I can get is:
which is by using hexbin(). How could I go about getting the python plot to resemble the SuperMongo one? I don't have enough rep to post images, sorry for the links. Thanks for your time!
Example simple contour plot from a fellow SuperMongo => python sufferer:
import numpy as np
from matplotlib.colors import LogNorm
from matplotlib import pyplot as plt
plt.interactive(True)
fig=plt.figure(1)
plt.clf()
# generate input data; you already have that
x1 = np.random.normal(0,10,100000)
y1 = np.random.normal(0,7,100000)/10.
x2 = np.random.normal(-15,7,100000)
y2 = np.random.normal(-10,10,100000)/10.
x=np.concatenate([x1,x2])
y=np.concatenate([y1,y2])
# calculate the 2D density of the data given
counts,xbins,ybins=np.histogram2d(x,y,bins=100,normed=LogNorm())
# make the contour plot
plt.contour(counts.transpose(),extent=[xbins.min(),xbins.max(),
ybins.min(),ybins.max()],linewidths=3,colors='black',
linestyles='solid')
plt.show()
produces a nice contour plot.
The contour function offers a lot of fancy adjustments, for example let's set the levels by hand:
plt.clf()
mylevels=[1.e-4, 1.e-3, 1.e-2]
plt.contour(counts.transpose(),mylevels,extent=[xbins.min(),xbins.max(),
ybins.min(),ybins.max()],linewidths=3,colors='black',
linestyles='solid')
plt.show()
producing this plot:
And finally, in SM one can do contour plots on linear and log scales, so I spent a little time trying to figure out how to do this in matplotlib. Here is an example when the y points need to be plotted on the log scale and the x points still on the linear scale:
plt.clf()
# this is our new data which ought to be plotted on the log scale
ynew=10**y
# but the binning needs to be done in linear space
counts,xbins,ybins=np.histogram2d(x,y,bins=100,normed=LogNorm())
mylevels=[1.e-4,1.e-3,1.e-2]
# and the plotting needs to be done in the data (i.e., exponential) space
plt.contour(xbins[:-1],10**ybins[:-1],counts.transpose(),mylevels,
extent=[xbins.min(),xbins.max(),ybins.min(),ybins.max()],
linewidths=3,colors='black',linestyles='solid')
plt.yscale('log')
plt.show()
This produces a plot which looks very similar to the linear one, but with a nice vertical log axis, which is what was intended:
Have you checked out matplotlib's contour plot?
Unfortunately I couldn't view yours images. Do you mean something like this? It was done by MathGL -- GPL plotting library, which have Python interface too. And you can use arbitrary data arrays as input (including numpy's one).
You can use numpy.histogram2d to get a number density distribution of your array.
Try this example:
http://micropore.wordpress.com/2011/10/01/2d-density-plot-or-2d-histogram/