I have an xarray dataset of the dimensions time=350, xc=432, yc=432 that contains data on sea ice concentration (variable ice_conc). I want to calculate the linear trend in each grid cell and create a trend map. I have tried using numpy.polyfit:
x=np.linspace(1,350, num=350) #number of days in dataset
y=[ds.ice_conc] #ice concentration variable in the dataset
trend = np.polyfit(x, y, 1)
I keep getting this error:
TypeError: expected 1D or 2D array for y
The variable ice_conc is a 3D array with time, xc, yc.
Thank you in advance!
If you have a xarray.Dataset already, you could simply use xarray.Dataset.polyfit!
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
# Create some example data.
tsize = 10
xsize = 2
ysize = 2
data = np.ones((tsize, xsize, ysize)) * np.nan
data[:,0,0] = np.linspace(0, 10, tsize)
data[:,1,0] = np.logspace(0, 1, tsize)
data[:,0,1] = np.logspace(1.5, 0.5, tsize)
data[:,1,1] = np.linspace(40, 10, tsize)
# Put the data in a xarray.Dataset.
ds = xr.Dataset({"data": (["time", "x", "y"], data)})
# Apply polyfit.
result = ds.polyfit(dim = "time", deg = 1)
# The polyfit coefficients can be accessed like this.
a = result.data_polyfit_coefficients.sel(degree=1, x=0, y=0).values
b = result.data_polyfit_coefficients.sel(degree=0, x=0, y=0).values
The we could make a graph like this:
fig, axs = plt.subplots(xsize, ysize, sharex=True)
fig.set_size_inches(8, 8)
xs = np.arange(tsize)
for x in ds.x:
for y in ds.y:
ax = axs[y,x]
a = result.data_polyfit_coefficients.sel(degree=1, x=x, y=y).values
b = result.data_polyfit_coefficients.sel(degree=0, x=x, y=y).values
ax.scatter(xs, data[:, x, y], marker="*",
c="tab:blue", label="original data")
ax.plot(xs, a * xs + b, c="tab:orange", label=f"{a:.1f} * x + {b:.1f}")
ax.legend()
ax.grid()
ax.set_facecolor("lightgray")
ax.set_title(f"({x.values}, {y.values})")
Related
I am trying to Euclidean transform one plane to other plane. I have two equation of planes and they have different sizes. How can I align two planes in one coordinate system?
My two planes in form of ax+by+cz+d=0.
first plane => a = -5.297742252442251, b = 21.751836101364013, c = -2.470896764133499, d = -0.5601826186620921
Second plane => a = 45.42557999642176, b = -16.9433283673388, c = 2.5117971500097287, d = -8.528560240570203]
For plotting on the matplotlib, I used following code using matplotlib
import numpy as np
import pandas as pd
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from skimage import measure
import pandas as pd
# Data points 1 and 2
data1 = [[0.190133571624755, 0.146549582481384, 0.391435742378234, 'near'],
[0.0154470205307006, 0.0959569215774536, 0.484999418258667, 'near'],
[-0.119875073432922, 0.0414541959762573, 0.542818903923034, 'near'],
[0.104917883872985, 0.058539867401123, 0.171926498413085, 'far'],
[0.177520513534545, 0.130982756614685, 0.0330302715301513, 'far'],
[0.246979117393493, 0.173633933067321, 0.373323440551757, 'far']]
data2 = [[0.334545135498046, -0.0318257808685302, 0.282101511955261, 'near'],
[0.411889553070068, 0.0223467350006103, 0.183727979660034, 'near'],
[0.330880641937255, -0.00959080457687378, 0.178299665451049, 'near'],
[-0.00756144523620605, -0.07442307472229, -0.227764248847961, 'far'],
[-0.268512785434722, -0.309048891067504, 0.456292867660522, 'far'],
[-0.305409669876098, -0.304299354553222, 0.281461238861084, 'far']]
# Create the pandas DataFrame
df1 = pd.DataFrame(data1, columns=['A', 'B', 'C', 'NearOrFar'])
df2 = pd.DataFrame(data2, columns=['A', 'B', 'C', 'NearOrFar'])
# Data - 1
# Divide into X and y
X1 = df1.iloc[:,0:3]
Y1 = df1.iloc[:,3]
# Create scatter plot of data points for data 1
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection='3d')
for grp_name, grp_idx in df1.groupby('NearOrFar').groups.items():
x = df1.iloc[grp_idx, 0]
y = df1.iloc[grp_idx, 1]
z = df1.iloc[grp_idx, 2]
if (grp_name == 'near'):
ax.scatter(x, y, z, label=grp_name, c = 'red')
else:
ax.scatter(x, y, z, label=grp_name, c = 'blue')
# Train LDA model for data 1
lda_clf_1 = LDA(store_covariance=True)
lda_clf_1.fit(X1, Y1)
# Decision boundary Coefficient
a,b,c,d = lda_clf_1.coef_[0][0],lda_clf_1.coef_[0] [1],lda_clf_1.coef_[0][2],lda_clf_1.intercept_
# Find limit of each coordinates
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# Create meshgrid in xyz
xx = np.linspace(xlim[0], xlim[1], 50)
yy = np.linspace(ylim[0], ylim[1], 50)
X,Y = np.meshgrid(xx,yy)
Z = (-d - a*X - b*Y) / c
# plot decision boundary hyperplane
ax.plot_surface(X, Y, Z, alpha=0.45)
plt.show()
# Data - 2
# Divide into X and y
X2 = df2.iloc[:,0:3]
Y2 = df2.iloc[:,3]
# Create scatter plot of data points for data 2
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection='3d')
for grp_name, grp_idx in df2.groupby('NearOrFar').groups.items():
x = df2.iloc[grp_idx, 0]
y = df2.iloc[grp_idx, 1]
z = df2.iloc[grp_idx, 2]
if (grp_name == 'near'):
ax.scatter(x, y, z, label=grp_name, c = 'red')
else:
ax.scatter(x, y, z, label=grp_name, c = 'blue')
# Train LDA model for data 2
lda_clf_2 = LDA(store_covariance=True)
lda_clf_2.fit(X2, Y2)
# Decision boundary Coefficient
a,b,c,d = lda_clf_2.coef_[0][0],lda_clf_2.coef_[0][1],lda_clf_2.coef_[0][2],lda_clf_2.intercept_
# Find limit of each coordinates
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# Create meshgrid in xyz
xx = np.linspace(xlim[0], xlim[1], 50)
yy = np.linspace(ylim[0], ylim[1], 50)
X,Y = np.meshgrid(xx,yy)
Z = (-d - a*X - b*Y) / c
# plot decision boundary hyperplane
ax.plot_surface(X, Y, Z, alpha=0.45)
plt.show()
How can I align two planes and create 3d plot of two align planes in one graph with data points?
At the end, I want to transform(mostly roatation I think?) all the data points on data2 to coordinate system of data1 as data2 hyperplane align with data1 hyperplane
Each datapoints with hyperplane should looks like following
Data 1 =
enter image description here
and
Data 2 = enter image description here
If you simply want to plot the two planes on the same 3d axes, then you just need to compute two different values for Z and plot the two Zs relative to the same Xs and Ys, like so:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
# first plane:
a1 = -5.297742252442251
b1 = 21.751836101364013
c1 = -2.470896764133499
d1 = -0.5601826186620921
# second plane:
a2 = 45.42557999642176
b2 = -16.9433283673388
c2 = 2.5117971500097287
d2 = -8.528560240570203
x = np.linspace(-1, 1, 100)
y = np.linspace(-1, 1, 100)
X, Y = np.meshgrid(x, y)
Z1 = (-d1 - a1 * X - b1 * Y) / c1
Z2 = (-d2 - a2 * X - b2 * Y) / c2
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection="3d")
ax.plot_surface(X, Y, Z1, alpha=0.45)
ax.plot_surface(X, Y, Z2, alpha=0.45)
plt.show()
This produces the following figure:
As to "aligning" the two planes, it's not clear to me what you're asking...? Two planes will be coplanar if they have the same values of a, b, c and d in the equation you gave above - if they have different values of a, b, c and d, they won't be coplanar. They may intersect, they may not - and to ensure you graph them where they intersect (should they do so), you'd need to determine the values of x and y where they have equal values of z and set your xrange and yrange accordingly. If you can explain the meaning of "align" for your particular purposes, perhaps I could expand on this answer to accommodate.
I used the following code to try and plot a 3D plane of on its x axis the height (is also the momentum arm) and on its y axis the mass (in kg) which has a linear connection with the force used. The Z axis is the resulting momentum.
Unfortunately I get the following error:
ValueError: Argument Z must be 2-dimensional.
However I do believe that Z, thus the momentum is dependent on both the mass and the height, thus is Z 2d.
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits import mplot3d
g = 9.81
m = np.linspace(0, 1, 301)
H_1 = np.arange(100, 401, 1)
for i, kg in enumerate(m):
Fg = -m[i]*g
M = np.zeros(len(H_1))
for i, mm in enumerate(H_1):
F1 = np.array([0, Fg])
F2 = np.array([Fg * np.sin(np.arctan(200 / H_1[i])), Fg * np.cos(np.arctan(200 / H_1[i]))])
Fres = np.add(F1, F2)
M_arm = np.array([0, H_1[i]])
M[i] = np.cross(M_arm, Fres)/10e3
x,y = np.meshgrid(H_1,m)
z = M
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.plot_surface(x, y, z)
ax.set_xlabel('hoogte toren in (mm)')
ax.set_ylabel('massa')
ax.set_zlabel('momentum')
plt.show()
Check this out:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits import mplot3d
g = 9.81
m = np.linspace(0, 1, 301)
H_1 = np.arange(100, 401, 1)
Fg = -m * g
M = np.zeros(len(H_1))
for i, mm in enumerate(H_1):
F1 = np.array([0, Fg[i]])
F2 = np.array([Fg[i] * np.sin(np.arctan(200 / H_1[i])), Fg[i] * np.cos(np.arctan(200 / H_1[i]))])
Fres = np.add(F1, F2)
M_arm = np.array([0, H_1[i]])
M[i] = np.cross(M_arm, Fres) / 10e3
x, y = np.meshgrid(H_1, m)
z = M
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.plot_surface(x, y, z)
ax.set_xlabel('hoogte toren in (mm)')
ax.set_ylabel('massa')
ax.set_zlabel('momentum')
plt.show()
I made the following changes to your code:
Moved the calculation of Fg outside the loop.
Used the correct index i to access the elements of m and Fg in the loop.
Used the correct array index i to access the elements of H_1 in the loop.
Removed the unnecessary enumerate call in the inner loop.
Used the correct array index i to access the elements of M in the loop.
These changes should fix the errors in your code and produce the expected plot.
:)
I want to multiply two Kernel Density Estimates to get a composite likelihood ... The multiplication operator doesn't exist for sklearn.
I have KDR for data from 3 independent sources and I want multiply KDE from each sources. The below code is from https://scikit-learn.org/stable/auto_examples/neighbors/plot_species_kde.html#sphx-glr-auto-examples-neighbors-plot-species-kde-py and should run easily.
Although I made some small modification to get get two KDEs and then multiply them which fails.
Someone can help. Below code should run without error except the multiplication part.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_species_distributions
from sklearn.neighbors import KernelDensity
# if basemap is available, we'll use it.
# otherwise, we'll improvise later...
try:
from mpl_toolkits.basemap import Basemap
basemap = True
except ImportError:
basemap = False
def construct_grids(batch):
"""Construct the map grid from the batch object
Parameters
----------
batch : Batch object
The object returned by :func:`fetch_species_distributions`
Returns
-------
(xgrid, ygrid) : 1-D arrays
The grid corresponding to the values in batch.coverages
"""
# x,y coordinates for corner cells
xmin = batch.x_left_lower_corner + batch.grid_size
xmax = xmin + (batch.Nx * batch.grid_size)
ymin = batch.y_left_lower_corner + batch.grid_size
ymax = ymin + (batch.Ny * batch.grid_size)
# x coordinates of the grid cells
xgrid = np.arange(xmin, xmax, batch.grid_size)
# y coordinates of the grid cells
ygrid = np.arange(ymin, ymax, batch.grid_size)
return (xgrid, ygrid)
# Get matrices/arrays of species IDs and locations
data = fetch_species_distributions()
species_names = ['Bradypus Variegatus', 'Microryzomys Minutus']
Xtrain = np.vstack([data['train']['dd lat'], data['train']['dd long']]).T
ytrain = np.array([d.decode('ascii').startswith('micro')
for d in data['train']['species']], dtype='int')
Xtrain *= np.pi / 180. # Convert lat/long to radians
# Set up the data grid for the contour plot
xgrid, ygrid = construct_grids(data)
X, Y = np.meshgrid(xgrid[::5], ygrid[::5][::-1])
land_reference = data.coverages[6][::5, ::5]
land_mask = (land_reference > -9999).ravel()
xy = np.vstack([Y.ravel(), X.ravel()]).T
xy = xy[land_mask]
xy *= np.pi / 180.
# Plot map of South America with distributions of each species
fig = plt.figure()
fig.subplots_adjust(left=0.05, right=0.95, wspace=0.05)
kde0 = KernelDensity(bandwidth=0.04, metric='haversine',
kernel='gaussian', algorithm='ball_tree')
kde0.fit(Xtrain[ytrain == 0])
kde1 = KernelDensity(bandwidth=0.04, metric='haversine',
kernel='gaussian', algorithm='ball_tree')
kde1.fit(Xtrain[ytrain == 1])
kde01=kde0*kde1
plt.subplot(1, 1, 1)
# evaluate only on the land: -9999 indicates ocean
Z = np.full(land_mask.shape[0], -9999, dtype='int')
Z[land_mask] = np.exp(kde01.score_samples(xy))
Z = Z.reshape(X.shape)
# plot contours of the density
levels = np.linspace(0, Z.max(), 25)
plt.contourf(X, Y, Z, levels=levels, cmap=plt.cm.Reds)
plt.show()
I have two vectors that store my X, Y values than are lengths 81, 105 and then a (81,105) array (actually a list of lists) that stores my Z values for those X, Y. What would be the best way to plot this in 3d? This is what i've tried:
Z = np.load('Z.npy')
X = np.load('X.npy')
Y = np.linspace(0, 5, 105)
fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap= 'viridis')
plt.show()
I get the following error : ValueError: shape mismatch: objects cannot be broadcast to a single shape
OK, I got it running. There is some tricks here. I will mention them in the codes.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from random import shuffle
# produce some data.
x = np.linspace(0,1,81)
y = np.linspace(0,1,105)
z = [[i for i in range(81)] for x in range(105)]
array_z = np.array(z)
# Make them randomized.
shuffle(x)
shuffle(y)
shuffle(z)
# Match data in x and y.
data = []
for i in range(len(x)):
for j in range(len(y)):
data.append([x[i], y[j], array_z[j][i]])
# Be careful how you data is stored in your Z array.
# Stored in dataframe
results = pd.DataFrame(data, columns = ['x','y','z'])
# Plot the data.
fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(results.x, results.y, results.z, cmap= 'viridis')
The picture looks weird because I produced some data. Hope it helps.
The figure above is a great artwork showing the wind speed, wind direction and temperature simultaneously. detailedly:
The X axes represent the date
The Y axes shows the wind direction(Southern, western, etc)
The variant widths of the line were stand for the wind speed through timeseries
The variant colors of the line were stand for the atmospheric temperature
This simple figure visualized 3 different attribute without redundancy.
So, I really want to reproduce similar plot in matplotlib.
My attempt now
## Reference 1 http://stackoverflow.com/questions/19390895/matplotlib-plot-with-variable-line-width
## Reference 2 http://stackoverflow.com/questions/17240694/python-how-to-plot-one-line-in-different-colors
def plot_colourline(x,y,c):
c = plt.cm.jet((c-np.min(c))/(np.max(c)-np.min(c)))
lwidths=1+x[:-1]
ax = plt.gca()
for i in np.arange(len(x)-1):
ax.plot([x[i],x[i+1]], [y[i],y[i+1]], c=c[i],linewidth = lwidths[i])# = lwidths[i])
return
x=np.linspace(0,4*math.pi,100)
y=np.cos(x)
lwidths=1+x[:-1]
fig = plt.figure(1, figsize=(5,5))
ax = fig.add_subplot(111)
plot_colourline(x,y,prop)
ax.set_xlim(0,4*math.pi)
ax.set_ylim(-1.1,1.1)
Does someone has a more interested way to achieve this? Any advice would be appreciate!
Using as inspiration another question.
One option would be to use fill_between. But perhaps not in the way it was intended. Instead of using it to create your line, use it to mask everything that is not the line. Under it you can have a pcolormesh or contourf (for example) to map color any way you want.
Look, for instance, at this example:
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import interp1d
def windline(x,y,deviation,color):
y1 = y-deviation/2
y2 = y+deviation/2
tol = (y2.max()-y1.min())*0.05
X, Y = np.meshgrid(np.linspace(x.min(), x.max(), 100), np.linspace(y1.min()-tol, y2.max()+tol, 100))
Z = X.copy()
for i in range(Z.shape[0]):
Z[i,:] = c
#plt.pcolormesh(X, Y, Z)
plt.contourf(X, Y, Z, cmap='seismic')
plt.fill_between(x, y2, y2=np.ones(x.shape)*(y2.max()+tol), color='w')
plt.fill_between(x, np.ones(x.shape) * (y1.min() - tol), y2=y1, color='w')
plt.xlim(x.min(), x.max())
plt.ylim(y1.min()-tol, y2.max()+tol)
plt.show()
x = np.arange(100)
yo = np.random.randint(20, 60, 21)
y = interp1d(np.arange(0, 101, 5), yo, kind='cubic')(x)
dv = np.random.randint(2, 10, 21)
d = interp1d(np.arange(0, 101, 5), dv, kind='cubic')(x)
co = np.random.randint(20, 60, 21)
c = interp1d(np.arange(0, 101, 5), co, kind='cubic')(x)
windline(x, y, d, c)
, which results in this:
The function windline accepts as arguments numpy arrays with x, y , a deviation (like a thickness value per x value), and color array for color mapping. I think it can be greatly improved by messing around with other details but the principle, although not perfect, should be solid.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x = np.linspace(0,4*np.pi,10000) # x data
y = np.cos(x) # y data
r = np.piecewise(x, [x < 2*np.pi, x >= 2*np.pi], [lambda x: 1-x/(2*np.pi), 0]) # red
g = np.piecewise(x, [x < 2*np.pi, x >= 2*np.pi], [lambda x: x/(2*np.pi), lambda x: -x/(2*np.pi)+2]) # green
b = np.piecewise(x, [x < 2*np.pi, x >= 2*np.pi], [0, lambda x: x/(2*np.pi)-1]) # blue
a = np.ones(10000) # alpha
w = x # width
fig, ax = plt.subplots(2)
ax[0].plot(x, r, color='r')
ax[0].plot(x, g, color='g')
ax[0].plot(x, b, color='b')
# mysterious parts
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
# mysterious parts
rgba = list(zip(r,g,b,a))
lc = LineCollection(segments, linewidths=w, colors=rgba)
ax[1].add_collection(lc)
ax[1].set_xlim(0,4*np.pi)
ax[1].set_ylim(-1.1,1.1)
fig.show()
I notice this is what I suffered.