simple keras nn does not predict well - neural-network

the code:
x1 = np.array([1, 10])
x2 = np.array([7, 4])
x3 = np.array([8, 7])
x4 = np.array([1, 15])
x5 = np.array([4, 4])
X = np.array([x1, x2, x3, x4, x5])
X = X / 100
Y = np.array([4, 8, 7, 5, 1])
Y = Y / 100
model = Sequential()
model.add(Dense(4, input_dim=2, activation='sigmoid', kernel_initializer="uniform"))
model.add(Dense(2, activation='sigmoid', kernel_initializer="uniform"))
model.add(Dense(1, activation='sigmoid', kernel_initializer="uniform"))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(X, Y, epochs=500, batch_size=3)
toPred = np.array([x1]) / 100
print(model.predict(toPred) * 100)
For everything I predict I get a strange result, all the predictions are almost the same and are not close to the real value.
Suggestions?

Try this sample instead, I didn't change much just a different approach to scaling, and a longer training time.
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
x1 = np.array([1, 10])
x2 = np.array([7, 4])
x3 = np.array([8, 7])
x4 = np.array([1, 15])
x5 = np.array([4, 4])
X = np.array([x1, x2, x3, x4, x5])
# Scale to range 0-1 since input activation is a sigmoid
X = (X - X.std()) / X.mean()
#Dont need to scale Y, leaves us with one less unnecessary operation
Y = np.array([4, 8, 7, 5, 1])
model = Sequential()
model.add(Dense(4, input_dim=2, activation='sigmoid', kernel_initializer="uniform"))
model.add(Dense(2, activation='sigmoid', kernel_initializer="uniform"))
#Set output activation to linear
model.add(Dense(1, activation='linear', kernel_initializer="uniform"))
model.compile(loss='mean_squared_error', optimizer='adam')
#Train for 5k epochs, since the loss keeps decreasing
model.fit(X, Y, epochs=5000, batch_size=5)
print(model.predict(X))
gives me
[[ 3.50988507]
[ 7.0278182 ]
[ 7.61787605]
[ 5.38016272]
[ 1.63140726]]
Sometimes you just need to tinker with the hyper-parameters. You could probably eliminate the second dense layer since this data is small and I also get better results using the 'SGD' (stochastic gradient descent) optimizer. You can also get good results faster by turning up the learning rate (may only work well for this snippet). So just play around until you get result your looking for. Hope this helps :)
from keras.optimizers import SGD
opt = SGD(lr=.05)
model.compile(loss='mean_squared_error', optimizer=opt)
model.fit(X, Y, epochs=1000, batch_size=5)

Related

How to do nonlinear data-fitting a function on the experiment data

I have some experiment data. Hereby, I need to fit the following function to determine one of the variable. A Levenberg–Marquardt least-squares algorithm was used in this procedure.
I have used curve fitting option in Igor Pro software. I defined new fit function and tried to define independent and dependent variable.
Nevertheless, I don't know what is the reason that I got the this error:
"The fitting function returned INF for at least one X variable"
My function is :
sin(theta) = -1+2*sqrt(alpha/x)*exp(-beta*(x-alpha)^2)
beta = 1.135e-4;
sin(theta) = [-0.81704 -0.67649 -0.83137 -0.73468 -0.66744 -0.43602 0.45368 0.75802 0.96705 0.99717 ]
x = [72.01 59.99 51.13 45.53 36.15 31.66 30.16 29.01 25.62 23.47 ]
Is there any suggestion to find alpha variable here?
Is there any handy software or program for nonlinear curve fitting?
In gnuplot, it would look like this. The fit is not great, but that's not the "fault" of gnuplot, but apparently this data cannot be fitted with this function very well.
Code:
### nonlinear curve fitting
reset session
$Data <<EOD
72.01 -0.81704
59.99 -0.67649
51.13 -0.83137
45.53 -0.73468
36.15 -0.66744
31.66 -0.43602
30.16 0.45368
29.01 0.75802
25.62 0.96705
23.47 0.99717
EOD
f(x) = -1+2*sqrt(alpha/x)*exp(-beta*(x-alpha)**2)
# initial guessed values
alpha = 25
beta = 1
set fit nolog results
fit f(x) $Data u 1:2 via alpha,beta
plot $Data u 1:2 w lp pt 7, \
f(x) lc rgb "red"
print sprintf("alpha=%g, beta=%g",alpha,beta)
### end of code
Result:
alpha=25.818, beta=0.0195229
If it might be of some use, my equation search on your data turned up a good fit to a standard 4-parameter logistic equation "y = d + (a - d) / (1.0 + pow(x / c, b))" with parameters a = 0.96207949, b = 44.14292256, c = 30.67324939, and d = -0.74830947 yielding RMSE = 0.0565 and R-squared = 0.9943, and I have included code for a Python graphical fitter using this equation.
import numpy, scipy, matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
theta = [-0.81704, -0.67649, -0.83137, -0.73468, -0.66744, -0.43602, 0.45368, 0.75802, 0.96705, 0.99717]
x = [72.01, 59.99, 51.13, 45.53, 36.15, 31.66, 30.16, 29.01, 25.62, 23.47]
# rename to match previous example code
xData = numpy.array(x)
yData = numpy.array(theta)
# StandardLogistic4Parameter equation from zunzun.com
def func(x, a, b, c, d):
return d + (a - d) / (1.0 + numpy.power(x / c, b))
# these are the same as the scipy defaults
initialParameters = numpy.array([1.0, 1.0, 1.0, 1.0])
# curve fit the test data
fittedParameters, pcov = curve_fit(func, xData, yData, initialParameters)
modelPredictions = func(xData, *fittedParameters)
absError = modelPredictions - yData
SE = numpy.square(absError) # squared errors
MSE = numpy.mean(SE) # mean squared errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(yData))
print('Parameters:', fittedParameters)
print('RMSE:', RMSE)
print('R-squared:', Rsquared)
print()
##########################################################
# graphics output section
def ModelAndScatterPlot(graphWidth, graphHeight):
f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
axes = f.add_subplot(111)
# first the raw data as a scatter plot
axes.plot(xData, yData, 'D')
# create data for the fitted equation plot
xModel = numpy.linspace(min(xData), max(xData))
yModel = func(xModel, *fittedParameters)
# now the model as a line plot
axes.plot(xModel, yModel)
axes.set_xlabel('X Data') # X axis data label
axes.set_ylabel('Y Data') # Y axis data label
plt.show()
plt.close('all') # clean up after using pyplot
graphWidth = 800
graphHeight = 600
ModelAndScatterPlot(graphWidth, graphHeight)
Matlab
I slightly changed the function, -1 changed to -gamma and optimize to find gamma
The code is as follow
ydata = [-0.81704 -0.67649 -0.83137 -0.73468 -0.66744 -0.43602 0.45368...
0.75802 0.96705 0.99717 ];
xdata = [72.01 59.99 51.13 45.53 36.15 31.66 30.16 29.01 25.62 23.47 ];
sin_theta = #(alpha, beta, gamma, xdata) -gamma+2.*sqrt(alpha./xdata).*exp(beta.*(xdata-alpha).^2);
%Fitting function as function of array(x) required by lsqcurvefit
f = #(x,xdata) sin_theta(x(1),x(2), x(3),xdata);
% [alpha, beta, gamma]
x0 = [25, 0, 1] ;
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt', 'FunctionTolerance', 1e-30);
[x,resnorm,residual,exitflag,output] = lsqcurvefit(f,x0,xdata,ydata,[], [], options);
% Accuracy
RMSE = sqrt(sum(residual.^2)/length(residual));
alpha = x(1); beta = x(2); gamma = x(3);
%Plotting data
data = linspace(xdata(1),xdata(end));
plot(xdata,ydata,'ro',data,f(x,data),'b-', 'linewidth', 3)
legend('Data','Fitted exponential')
title('Data and Fitted Curve')
set(gca,'FontSize',20)
Result
alpha = 26.0582, beta = -0.0329, gamma = 0.7881 instead of 1, RMSE = 0.1498
Graph

How to achieve 0 training error when using one-hidden-layer neural network with random inputs?

In theory, one-hidden-layer neural network with m hidden nodes can be trained by gradient descent to fit n data points with 0 training error, where m >= n.
I have 100 data points (x, y), x in R and y in R, no specific pattern, just random. And I was using one-hidden-layer neural network with 1000/2000/10000/... hidden nodes to fit those points (with stochastic gradient descent and ReLU).
But I can't achieve that. Any idea what's the problem here?
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Activation
from keras.optimizers import SGD
from keras import initializers
## initializing x_train and y_train randomly ##
def f1(x):
if x < 3:
return np.abs(x-1)
else:
return -np.abs(x-1)+4
n = 100
x_train = np.random.uniform(-4+1, 4+1, size = n)
e = np.random.normal(0, 0.5, size = n)
y_train = np.vectorize(f1)(x_train) + e
np.random.shuffle(y_train)
k = 10000 # number of hidden nodes
ep = 5
loss = []
model = Sequential()
model.add(Dense(k, kernel_initializer = 'random_normal', input_shape = (1,), use_bias=True))
model.add(Activation('relu'))
model.add(Dense(1, kernel_initializer = 'random_normal', use_bias=True))
#sgd = SGD(lr=0.00005, decay=1e-6, momentum=0.9)
sgd = SGD(lr=0.00008)
model.compile(loss='mse', optimizer=sgd, metrics = ['mse'])
for i in range(5000):
H = model.fit(x_train, y_train, epochs=ep, verbose=False)
wt = model.get_weights()
temp = H.history['mean_squared_error'][-1]
print(temp)
loss.append(temp)
image
What is your loss function? Can you show your code and perhaps some printouts of the loss per training epoch? How are you initializing the parameters of those hidden nodes (also do the nnn/nnnn/nnnn in your description mean those are different experimental settings?)?

TensorFlow XOR code works fine with two dimensional target but not without?

Trying to implement a very basic XOR FFNN in TensorFlow. I may just be misunderstanding the code but can anyone see an obvious reason why this won't work-- blows up to NaNs and starts with loss of $0$.
Toggles are on works/ doesn't work if you want to mess around with it.
Thanks!
import math
import tensorflow as tf
import numpy as np
HIDDEN_NODES = 10
x = tf.placeholder(tf.float32, [None, 2])
W_hidden = tf.Variable(tf.truncated_normal([2, HIDDEN_NODES]))
b_hidden = tf.Variable(tf.zeros([HIDDEN_NODES]))
hidden = tf.nn.relu(tf.matmul(x, W_hidden) + b_hidden)
#-----------------
#DOESN"T WORK
W_logits = tf.Variable(tf.truncated_normal([HIDDEN_NODES, 1]))
b_logits = tf.Variable(tf.zeros([1]))
logits = tf.add(tf.matmul(hidden, W_logits),b_logits)
#WORKS
# W_logits = tf.Variable(tf.truncated_normal([HIDDEN_NODES, 2]))
# b_logits = tf.Variable(tf.zeros([2]))
# logits = tf.add(tf.matmul(hidden, W_logits),b_logits)
#-----------------
y = tf.nn.softmax(logits)
#-----------------
#DOESN"T WORK
y_input = tf.placeholder(tf.float32, [None, 1])
#WORKS
#y_input = tf.placeholder(tf.float32, [None, 2])
#-----------------
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits, y_input)
loss = tf.reduce_mean(cross_entropy)
loss = cross_entropy
train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init_op = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init_op)
xTrain = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
#-----------------
#DOESN"T WORK
yTrain = np.array([[0], [1], [1], [0]])
# WORKS
#yTrain = np.array([[1, 0], [0, 1], [0, 1], [1, 0]])
#-----------------
for i in xrange(500):
_, loss_val,logitsval = sess.run([train_op, loss,logits], feed_dict={x: xTrain, y_input: yTrain})
if i % 10 == 0:
print "Step:", i, "Current loss:", loss_val,"logits",logitsval
print sess.run(y,feed_dict={x: xTrain})
TL;DR: For this to work, you should use
loss = tf.nn.l2_loss(logits - y_input)
...instead of tf.nn.softmax_cross_entropy_with_logits.
The tf.nn.softmax_cross_entropy_with_logits operator expects the logits and labels inputs to be a matrix of size batch_size by num_classes. Each row of logits is an unscaled probability distribution across the classes; and each row of labels is a one-hot encoding of the true class for each example in the batch. If the inputs do not match these assumptions, the training process may diverge.
In this code, the logits are batch_size by 1, which means that there is only a single class, and the softmax outputs a prediction of class 0 for all of the examples; the labels are not one-hot. If you look at the implementation of the operator, the backprop value for tf.nn.softmax_cross_entropy_with_logits is:
// backprop: prob - labels, where
// prob = exp(logits - max_logits) / sum(exp(logits - max_logits))
This will be [[1], [1], [1], [1]] - [[0], [1], [1], [0]] in every step, which clearly does not converge.

Matlab to Python code conversion: Binary phase-shift keying (BPSK)

I have this MATLAB code:
d=[1 0 1 1 0]; % Data sequence
b=2*d-1; % Convert unipolar to bipolar
T=1; % Bit duration
Eb=T/2; % This will result in unit amplitude waveforms
fc=3/T; % Carrier frequency
t=linspace(0,5,1000); % discrete time sequence between 0 and 5*T (1000 samples)
N=length(t); % Number of samples
Nsb=N/length(d); % Number of samples per bit
dd=repmat(d',1,Nsb); % replicate each bit Nsb times
bb=repmat(b',1,Nsb); dw=dd'; % Transpose the rows and columns
dw=dw(:)';
% Convert dw to a column vector (colum by column) and convert to a row vector
bw=bb';
bw=bw(:)'; % Data sequence samples
w=sqrt(2*Eb/T)*cos(2*pi*fc*t); % carrier waveform
bpsk_w=bw.*w; % modulated waveform
% plotting commands follow
subplot(4,1,1);
plot(t,dw); axis([0 5 -1.5 1.5])
subplot(4,1,2);
plot(t,bw); axis([0 5 -1.5 1.5])
subplot(4,1,3);
plot(t,w); axis([0 5 -1.5 1.5])
subplot(4,1,4);
plot(t,bpsk_w,'.'); axis([0 5 -1.5 1.5])
xlabel('time')
Which gives me the graphs shown below:
Below is my converted Python Code using Numpy / Scipy
import numpy as np
import scipy
import matplotlib.pylab as plt
plt.clf()
plt.close('all')
d = np.array(np.hstack((1, 0, 1, 1, 0)))
b = 2*d-1.
T = 1
Eb = T/2
fc = 3/T
t = np.linspace(0, 5, 1000)
N = t.shape
Nsb = np.divide(N, d.shape)
dd = np.tile(d.conj().T, Nsb)
bb = np.tile(b.conj().T, Nsb)
dw = dd.conj().T
dw = dw.flatten(0).conj()
bw = bb.conj().T
bw = bw.flatten(0).conj()
w = np.dot(np.sqrt(np.divide(2*Eb, T)), np.cos(np.dot(np.dot(2*np.pi, fc), t)))
bpsk_w = bw*w
plt.subplot(4, 1, 1)
plt.plot(t, dw)
plt.axis(np.array(np.hstack((0, 5, -1.5, 1.5))))
plt.subplot(4, 1, 2)
plt.plot(t, bw)
plt.axis(np.array(np.hstack((0, 5, -1.5, 1.5))))
plt.subplot(4, 1, 3)
plt.plot(t, w)
plt.axis(np.array(np.hstack((0, 5, -1.5, 1.5))))
plt.subplot(4, 1, 4)
plt.plot(t, bpsk_w, '.')
plt.axis(np.array(np.hstack((0, 5, -1.5, 1.5))))
plt.xlabel('time')
plt.show()
But I neither get an error nor the proper output:
Please let me know where is my error in migrating this code?
=====UPDATE======
When I change the Python code to use the following lines, I get some better output:
..............
b = 2.*d-1.
T = 1.
Eb = T/2.
fc = 3./T
...............
w = np.dot(np.sqrt(np.divide(2.*Eb, T)), np.cos(np.dot(np.dot(2.*np.pi, fc), t)))
.............
Your problem stems from using np.tile rather than np.repeat.
To give a simple example of the difference between both:
>>> a = np.arange(3)
>>> a
array([0, 1, 2])
>>> np.repeat(a, 4)
array([0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2])
>>> np.tile(a, 4)
array([0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2])
So basically tile takes a "tiling array" and concatenates it, similar to the way you would tile a kitchen floor, whereas repeat repeats each element in the vector a specified number of times before it takes the next element of that vector.
Now, using that knowledge you could rewrite the matlab sample and wind up with the following:
from __future__ import division
import numpy as np
import scipy
import matplotlib.pylab as plt
unipolar_arr = np.array([1, 0, 1, 1, 0])
bipolar = 2*unipolar_arr - 1
bit_duration = 1
amplitude_scaling_factor = bit_duration/2 # This will result in unit amplitude waveforms
freq = 3/bit_duration # carrier frequency
n_samples = 1000
time = np.linspace(0, 5, n_samples)
samples_per_bit = n_samples/unipolar_arr.size # no need for np.divide. Also, use size rather than shape if you want something similar to Matlab's "length"
# 1. Use repeat rather than tile (read the docs)
# 2. No need for conjugate transpose
dd = np.repeat(unipolar_arr, samples_per_bit) # replicate each bit Nsb times
bb = np.repeat(bipolar, samples_per_bit) # Transpose the rows and columns
dw = dd
# no idea why this is here
#dw = dw.flatten(0).conj()
bw = bb # one again, no need for conjugate transpose
# no idea why this is here
#bw = bw.flatten(0).conj()
waveform = np.sqrt(2*amplitude_scaling_factor/bit_duration) * np.cos(2*np.pi * freq * time) # no need for np.dot to perform scalar-scalar multiplication or scalar-array multiplication
bpsk_w = bw*waveform
f, ax = plt.subplots(4,1, sharex=True, sharey=True, squeeze=True)
ax[0].plot(time, dw)
ax[1].plot(time, bw)
ax[2].plot(time, waveform)
ax[3].plot(time, bpsk_w, '.')
ax[0].axis([0, 5, -1.5, 1.5])
ax[0].set_xlabel('time')
plt.show()
I've added more comments to show what is not needed at all (so much clutter, was the code you showed us somehow produced by a conversion program?) and taken the liberty to change most of your 1-2 character variable names into something more readable, that's just one of my pet peeves.
Also, in Python2.x, integer division is the default, so 5/2 will evaluate as 2, rather than 2.5. In Python3.x, this was changed for the better and by using the line from __future__ import division you can get that behaviour in Python2.x as well.

Plot a plane based on a normal vector and a point in Matlab or matplotlib

How would one go plotting a plane in matlab or matplotlib from a normal vector and a point?
For all the copy/pasters out there, here is similar code for Python using matplotlib:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
point = np.array([1, 2, 3])
normal = np.array([1, 1, 2])
# a plane is a*x+b*y+c*z+d=0
# [a,b,c] is the normal. Thus, we have to calculate
# d and we're set
d = -point.dot(normal)
# create x,y
xx, yy = np.meshgrid(range(10), range(10))
# calculate corresponding z
z = (-normal[0] * xx - normal[1] * yy - d) * 1. /normal[2]
# plot the surface
plt3d = plt.figure().gca(projection='3d')
plt3d.plot_surface(xx, yy, z)
plt.show()
For Matlab:
point = [1,2,3];
normal = [1,1,2];
%# a plane is a*x+b*y+c*z+d=0
%# [a,b,c] is the normal. Thus, we have to calculate
%# d and we're set
d = -point*normal'; %'# dot product for less typing
%# create x,y
[xx,yy]=ndgrid(1:10,1:10);
%# calculate corresponding z
z = (-normal(1)*xx - normal(2)*yy - d)/normal(3);
%# plot the surface
figure
surf(xx,yy,z)
Note: this solution only works as long as normal(3) is not 0. If the plane is parallel to the z-axis, you can rotate the dimensions to keep the same approach:
z = (-normal(3)*xx - normal(1)*yy - d)/normal(2); %% assuming normal(3)==0 and normal(2)~=0
%% plot the surface
figure
surf(xx,yy,z)
%% label the axis to avoid confusion
xlabel('z')
ylabel('x')
zlabel('y')
For copy-pasters wanting a gradient on the surface:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import numpy as np
import matplotlib.pyplot as plt
point = np.array([1, 2, 3])
normal = np.array([1, 1, 2])
# a plane is a*x+b*y+c*z+d=0
# [a,b,c] is the normal. Thus, we have to calculate
# d and we're set
d = -point.dot(normal)
# create x,y
xx, yy = np.meshgrid(range(10), range(10))
# calculate corresponding z
z = (-normal[0] * xx - normal[1] * yy - d) * 1. / normal[2]
# plot the surface
plt3d = plt.figure().gca(projection='3d')
Gx, Gy = np.gradient(xx * yy) # gradients with respect to x and y
G = (Gx ** 2 + Gy ** 2) ** .5 # gradient magnitude
N = G / G.max() # normalize 0..1
plt3d.plot_surface(xx, yy, z, rstride=1, cstride=1,
facecolors=cm.jet(N),
linewidth=0, antialiased=False, shade=False
)
plt.show()
The above answers are good enough. One thing to mention is, they are using the same method that calculate the z value for given (x,y). The draw back comes that they meshgrid the plane and the plane in space may vary (only keeping its projection the same). For example, you cannot get a square in 3D space (but a distorted one).
To avoid this, there is a different way by using the rotation. If you first generate data in x-y plane (can be any shape), then rotate it by equal amount ([0 0 1] to your vector) , then you will get what you want. Simply run below code for your reference.
point = [1,2,3];
normal = [1,2,2];
t=(0:10:360)';
circle0=[cosd(t) sind(t) zeros(length(t),1)];
r=vrrotvec2mat(vrrotvec([0 0 1],normal));
circle=circle0*r'+repmat(point,length(circle0),1);
patch(circle(:,1),circle(:,2),circle(:,3),.5);
axis square; grid on;
%add line
line=[point;point+normr(normal)]
hold on;plot3(line(:,1),line(:,2),line(:,3),'LineWidth',5)
It get a circle in 3D:
A cleaner Python example that also works for tricky $z,y,z$ situations,
from mpl_toolkits.mplot3d import axes3d
from matplotlib.patches import Circle, PathPatch
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
from mpl_toolkits.mplot3d import art3d
import numpy as np
def plot_vector(fig, orig, v, color='blue'):
ax = fig.gca(projection='3d')
orig = np.array(orig); v=np.array(v)
ax.quiver(orig[0], orig[1], orig[2], v[0], v[1], v[2],color=color)
ax.set_xlim(0,10);ax.set_ylim(0,10);ax.set_zlim(0,10)
ax = fig.gca(projection='3d')
return fig
def rotation_matrix(d):
sin_angle = np.linalg.norm(d)
if sin_angle == 0:return np.identity(3)
d /= sin_angle
eye = np.eye(3)
ddt = np.outer(d, d)
skew = np.array([[ 0, d[2], -d[1]],
[-d[2], 0, d[0]],
[d[1], -d[0], 0]], dtype=np.float64)
M = ddt + np.sqrt(1 - sin_angle**2) * (eye - ddt) + sin_angle * skew
return M
def pathpatch_2d_to_3d(pathpatch, z, normal):
if type(normal) is str: #Translate strings to normal vectors
index = "xyz".index(normal)
normal = np.roll((1.0,0,0), index)
normal /= np.linalg.norm(normal) #Make sure the vector is normalised
path = pathpatch.get_path() #Get the path and the associated transform
trans = pathpatch.get_patch_transform()
path = trans.transform_path(path) #Apply the transform
pathpatch.__class__ = art3d.PathPatch3D #Change the class
pathpatch._code3d = path.codes #Copy the codes
pathpatch._facecolor3d = pathpatch.get_facecolor #Get the face color
verts = path.vertices #Get the vertices in 2D
d = np.cross(normal, (0, 0, 1)) #Obtain the rotation vector
M = rotation_matrix(d) #Get the rotation matrix
pathpatch._segment3d = np.array([np.dot(M, (x, y, 0)) + (0, 0, z) for x, y in verts])
def pathpatch_translate(pathpatch, delta):
pathpatch._segment3d += delta
def plot_plane(ax, point, normal, size=10, color='y'):
p = Circle((0, 0), size, facecolor = color, alpha = .2)
ax.add_patch(p)
pathpatch_2d_to_3d(p, z=0, normal=normal)
pathpatch_translate(p, (point[0], point[1], point[2]))
o = np.array([5,5,5])
v = np.array([3,3,3])
n = [0.5, 0.5, 0.5]
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.gca(projection='3d')
plot_plane(ax, o, n, size=3)
ax.set_xlim(0,10);ax.set_ylim(0,10);ax.set_zlim(0,10)
plt.show()