plot multivariate function based on max - python

I would like to create a multivariate function that takes the max value of 2 functions and then to plot it. However by using the max function there is an error when applying the function on the meshgrid. I have tried this on other multivariate function without the max function and it worked.
import numpy as np
import pandas as pd
import plotly.graph_objects as go
def f(x,y):
return max(np.cos(x),np.sin(y))
x=np.linspace(0,5,20)
y=np.linspace(-3,2,20)
X, Y = np.meshgrid(x, y)
Z=f(X,Y)
fig = go.Figure(data=[go.Surface(x=X, y=Y, z=Z)])
fig.show()
The error I get is : The truth value of an array with more than one element is ambiguous. Use a.any() or a.all(). However, I don't think that the suggestion is adapted to my case. I also tried by defining the max function with if statement but as I expected I get the same error. Does anyone could help?

The np.sin and np.cos functions work with arrays and the max function would produce an ambiguous answer (do you want the maximum of both functions or a comparison - numpy doesn't know). I recommend doing the built-in math.sin, math.cos on each of the values in the arrays and compare to get the desired max value .
def f(x,y):
max_values = []
for x_value, y_value in zip(x,y): #(iterate both together)
max_values.append(max(math.cos(x_value), math.sin(y_value)))
This may run slower than before, but does this help?

try using ax.scatter3D with
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
x=np.linspace(0,5,20)
y=np.linspace(-3,2,20)
def f(x,y):
max_values = []
for x_value, y_value in zip(x,y): #(iterate both together)
max_values.append(max(math.cos(x_value), math.sin(y_value)))
X, Y = np.meshgrid(x, y)
max_values = []
for x_value, y_value in zip(X,Y):
Z=zip([math.cos(item) for item in x_value],[math.sin(item) for item in y_value])
max_values.append([max(x,y) for x,y in Z])
fig = plt.figure()
ax = plt.axes(projection="3d")
ax.scatter3D(X, Y,max_values, c=max_values, cmap='Greens');
plt.show()

I have found a very simple alternative without using np.meshgrid, and put it here in case it could help someone later.
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
x=np.linspace(0,5,20)
y=np.linspace(-3,2,20)
S=np.zeros([x.shape[0],y.shape[0]])
for i in range(x.shape[0]):
for j in range(y.shape[0]):
S[i,j]=f(x[i],y[j])
fig = go.Figure(data=[go.Surface(x=x, y=y, z=S, colorscale='Temps')])
fig.show()

Related

python mathplotlib: 3D plots error: "ValueError: Argument Z must be 2-dimensional."

I'm new at coding but i was wondring why this piece of code isn't working. I get the error: "ValueError: Argument Z must be 2-dimensional."
Can someone help solving my problem?
Thx
S.B.
from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits import mplot3d
ax = plt.axes(projection= '3d')
def z_function(x,y):
return m/(4*np.pi*r**3)*(3*m*r**2-m)
x = np.linspace(-10,10,100)
y = np.linspace(-10,10,100)
r = x**2+y**2
m = 10
X, Y = np.meshgrid(x,y)
Z = z_function(X,Y)
ax.plot_surface(X,Y,Z)
plt.show()
The reason your code failed is that you generate r as a 1-D array.
To generate it as a 2-D array, run:
r = x**2 + y[:, np.newaxis]**2
The rest of your code is OK.
Consider also such detail: Your z_function uses neither x nor y.
Why did you include these parameters?

Strange output in matplotlib

Can someone explain why I get this strange output when running this code:
import matplotlib.pyplot as plt
import numpy as np
def x_y():
return np.random.randint(9999, size=1000), np.random.randint(9999, size=1000)
plt.plot(x_y())
plt.show()
The output:
Your data is a tuple of two 1000 length arrays.
def x_y():
return np.random.randint(9999, size=1000), np.random.randint(9999, size=1000)
xy = x_y()
print(len(xy))
# > 2
print(xy[0].shape)
# > (1000,)
Let's read pyplot's documentation:
plot(y) # plot y using x as index array 0..N-1
Thus pyplot will plot a line between (0, xy[0][i]) and (1, xy[1][i]), for i in range(1000).
You probably try to do this:
plt.plot(*x_y())
This time, it will plot 1000 points joined by lines: (xy[0][i], xy[1][i]) for i in range 1000.
Yet, the lines don't represent anything here. Therefore you probably want to see individual points:
plt.scatter(*x_y())
Your function x_y is returning a tuple, assigning each element to a variable gives the correct output.
import matplotlib.pyplot as plt
import numpy as np
def x_y():
return np.random.randint(9999, size=1000), np.random.randint(9999, size=1000)
x, y = x_y()
plt.plot(x, y)
plt.show()

Plot shows wrong points in Jupyter

I'm doing a Python test to draw some functions.
The problem is that the points that both functions intersect at the same X are not correct.
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
x = np.arange(-10,10,1)
def f(x):
return x+30
def z(x):
return x*x
plt.figure(figsize=(5,5))
plt.plot(x, f(x).astype(np.int))
plt.plot(x, z(x).astype(np.int))
plt.title("Gráfico de función" )
plt.xlabel("X")
plt.ylabel("Y")
idx = np.argwhere(np.diff(np.sign(f(x) - z(x)))).flatten()
plt.plot(x[idx], f(x[idx]), 'ro')
plt.legend(["F","Z"])
plt.show()
I expect only two points, but in the plot appeared four. Two of them are incorrect.
This error is not with the plot itself but with your methods of getting the points for this case when the intersection is an integer value. When taking np.diff of np.sign you go from -1 to 0 to 1 at the intersection points giving you 1 at 4 locations. If the intersection was not an int, you would get -1 to 1 and get the correct answer. If you try this instead you can find the integer intersection points:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
x = np.arange(-10,10,1)
def f(x):
return x+30.
def z(x):
return x*x
plt.figure(figsize=(5,5))
plt.plot(x, f(x).astype(np.int))
plt.plot(x, z(x).astype(np.int))
plt.xlabel("X")
plt.ylabel("Y")
#Say only get args where there is no sign (i.e. zero).
idx = np.argwhere((np.sign(f(x) - z(x))==0))
plt.plot(x[idx], f(x[idx]), 'ro')
plt.legend(["F","Z"])
plt.show()
EDIT:
The above code only works if you have perfect integer intersections. To arbitrarily do both you need to check to see if a perfect integer intersection exists before deciding which method to use. I just used a simple for loop to do this but I am sure there are more elegant ways to do this.
for v in np.sign(f(x) - z(x)):
if v==0:
idx = np.argwhere(np.sign(f(x) - z(x))==0)
break
else:
idx = np.argwhere(np.diff(np.sign(f(x) - z(x))))

Tangent to curve interpolated from discrete data

I was wondering if there's a way to find tangents to curve from discrete data.
For example:
x = np.linespace(-100,100,100001)
y = sin(x)
so here x values are integers, but what if we want to find tangent at something like x = 67.875?
I've been trying to figure out if numpy.interp would work, but so far no luck.
I also found a couple of similar examples, such as this one, but haven't been able to apply the techniques to my case :(
I'm new to Python and don't entirely know how everything works yet, so any help would be appreciated...
this is what I get:
from scipy import interpolate
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-100,100,10000)
y = np.sin(x)
tck, u = interpolate.splprep([y])
ti = np.linspace(-100,100,10000)
dydx = interpolate.splev(ti,tck,der=1)
plt.plot(x,y)
plt.plot(ti,dydx[0])
plt.show()
There is a comment in this answer, which tells you that there is a difference between splrep and splprep. For the 1D case you have here, splrep is completely sufficient.
You may also want to limit your curve a but to be able to see the oscilations.
from scipy import interpolate
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-15,15,1000)
y = np.sin(x)
tck = interpolate.splrep(x,y)
dydx = interpolate.splev(x,tck,der=1)
plt.plot(x,y)
plt.plot(x,dydx, label="derivative")
plt.legend()
plt.show()
While this is how the code above would be made runnable, it does not provide a tangent. For the tangent you only need the derivative at a single point. However you need to have the equation of a tangent somewhere and actually use it; so this is more a math question.
from scipy import interpolate
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-15,15,1000)
y = np.sin(x)
tck = interpolate.splrep(x,y)
x0 = 7.3
y0 = interpolate.splev(x0,tck)
dydx = interpolate.splev(x0,tck,der=1)
tngnt = lambda x: dydx*x + (y0-dydx*x0)
plt.plot(x,y)
plt.plot(x0,y0, "or")
plt.plot(x,tngnt(x), label="tangent")
plt.legend()
plt.show()
It should be noted that you do not need to use splines at all if the points you have are dense enough. In that case obtaining the derivative is just taking the differences between the nearest points.
from scipy import interpolate
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-15,15,1000)
y = np.sin(x)
x0 = 7.3
i0 = np.argmin(np.abs(x-x0))
x1 = x[i0:i0+2]
y1 = y[i0:i0+2]
dydx, = np.diff(y1)/np.diff(x1)
tngnt = lambda x: dydx*x + (y1[0]-dydx*x1[0])
plt.plot(x,y)
plt.plot(x1[0],y1[0], "or")
plt.plot(x,tngnt(x), label="tangent")
plt.legend()
plt.show()
The result will be visually identical to the one above.

Plotting list of lists in a same graph in Python

I am trying to plot (x,y) where as y = [[1,2,3],[4,5,6],[7,8,9]].
Say, len(x) = len(y[1]) = len(y[2])..
The length of the y is decided by the User input. I want to plot multiple plots of y in the same graph i.e, (x, y[1],y[2],y[3],...). When I tried using loop it says dimension error.
I also tried: plt.plot(x,y[i] for i in range(1,len(y)))
How do I plot ? Please help.
for i in range(1,len(y)):
plt.plot(x,y[i],label = 'id %s'%i)
plt.legend()
plt.show()
Assuming some sample values for x, below is the code that could give you the desired output.
import matplotlib.pyplot as plt
x = [1,2,3]
y = [[1,2,3],[4,5,6],[7,8,9]]
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.title("A test graph")
for i in range(len(y[0])):
plt.plot(x,[pt[i] for pt in y],label = 'id %s'%i)
plt.legend()
plt.show()
Assumptions: x and any element in y are of the same length.
The idea is reading element by element so as to construct the list (x,y[0]'s), (x,y[1]'s) and (x,y[n]'s.
Edited: Adapt the code if y contains more lists.
Below is the plot I get for this case:
Use a for loop to generate the plots and use the .show() method after the for loop.
import matplotlib.pyplot as plt
for impacts in impactData:
timefilteredForce = plt.plot(impacts)
timefilteredForce = plt.xlabel('points')
timefilteredForce = plt.ylabel('Force')
plt.show()
impactData is a list of lists.

Categories

Resources