Plot arbitrary 2-D function in python/pyplot like Matlab's Ezplot - python

I'm looking for a way to generate a plot similar to how ezplot works in MATLAB in that I can type:
ezplot('x^2 + y^2 = y + 5')
and get a graph ready to go for any arbitrary function. I'm only worrying about the case where I have both a x and a y.
I only have the function, and I'd really rather not go about trying to calculate all the y values for some given x range if I didn't have to.
The few solutions I've seen suggested are either about decision boundaries (which this is not. There is no test data or anything, just an arbitrary function) or are all for functions already defined as y = some x equation which doesn't really help me.
I would somewhat accept if there was a good way to mimic Wolfram|Alpha in their solve functionality("solve x^2 + y^2 = y + 5 for y" will give me two functions I could then graph separately), but rather prefer the ezplot as that's more or less instant within MATLAB.

I think you could use sympy plotting and parse_expr for this For your example, this would work as follows
from sympy.plotting import plot_implicit
from sympy.parsing.sympy_parser import parse_expr
def ezplot(s):
#Parse doesn't parse = sign so split
lhs, rhs = s.replace("^","**").split("=")
eqn_lhs = parse_expr(lhs)
eqn_rhs = parse_expr(rhs)
plot_implicit(eqn_lhs-eqn_rhs)
ezplot('x^2 + y^2 = y + 5')
This can be made as general as needed

You could use sympy to solve the equation and then use the resulting functions for plotting y over x:
import sympy
x=sympy.Symbol('x')
y=sympy.Symbol('y')
f = sympy.solve(x**2 + y**2 - y - 5, [y])
print f
xpts = (numpy.arange(10.)-5)/10
ypts = sympy.lambdify(x, f, 'numpy')(xpts)
# then e.g.: pylab.scatter(xpts, ypts)

#EdSmith solution works fine. Nevertheless, I have another suggestion. You can use plot a contour. You can rewrite your function as f(x, y)=0, and then use this code
from numpy import mgrid, pi
import matplotlib.pyplot as plt
def ezplot(f):
x, y = mgrid[-2*pi:2*pi:51, -2*pi:2*pi:51]
z = f(x, y)
ezplt = plt.contour(x, y, f, 0, colors='k')
return ezplt
That's the main idea. Of course, you can generalize it as the function in MATLAB, like general intervals of x and y, passing the function as a string, etc.

Related

How can I find the x-corresponding value of a function?

I have a function (Moorse potential in case anybody cares), and I want to find the coordinates of the minimum value in X. I can very easily find the minimum value in y with min(y), but, how can I find the x value asociated witgh the minimum y coordinate?
Copy of my code:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import math
from math import e
#para niquel
D= 0.4205 #profundidad de pozo
f = 2.7540 #distancia de equilibrio
a = 1.4199 #ancho de potencial
x = np.arange(-100,100,0.01) #Distancia interatómica / eje X
y = -D + D*(1-e**(-a*(x-f)))**2
plt.xlabel('Distancia interatómica [$\AA$]')
plt.ylabel('Energía [eV]')
plt.plot(x, y, color = 'mediumturquoise')
plt.xlim(2,5.5)
plt.ylim(-0.5, 0.75)
#plt.annotate('a$_{0}$', xy = (X, min(y)) ) HERE'S WHERE I'D NEED THE X COORDINATE!!
plt.show()
Thanks in advance!
You can use an argmin to find the minimum index of y, then based on how you generated the range, you can work backwards to get the actual value. You can do something like
x[np.argmin(y)]
Note that this might not be equivalent to
np.argmin(y) * 0.01 + -100
due to floating point rounding issues.
With some algebra (or a graphing calculator...) you can resolve the Morse Potential equation in terms of y and get an accurate and quick answer.
I went ahead and did this (using symbolab, you can confirm here) given your constants, and then plotted the graphs here to confirm they looked right. There are two mathematical functions due to the two cases arising when taking the square root.
Here's some code that should compute the x value based off the y value:
import math
def getXfromY(y):
if(y <= 2.754):
return -(math.ln(-math.sqrt(y/0.4205) + 1))/1.4199
elif(y > 2.754):
return -(math.ln(math.sqrt(y/0.4205) + 1))/1.4199

System of First Order ODEs in Python

I have seen how to solve systems of ODEs in Python, but all of the examples I have seen were "standard" equations. What I mean by standard is that the equations do not say "derivative of one function = expression that contains derivative of another function".
Here is a sample system I am trying to solve numerically. Initial conditions are x(0) = 5, y(0) = 3, z(0) = 2, and all initial derivatives are 0:
x'(t) + 4y(t) = -3y'(t)
y'(t) + ty(t) = -2z'(t)
z'(t) = -2y(t) + x'(t)
I am not 100% sure how to code this. Here is what I have tried:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import math
def ODESystem(f,t):
x = f[0]
y = f[1]
z = f[2]
Now, what do I define first: dydt, dxdt or dzdt. Is there a way for me to define one expression that "hangs around" before I use it to define another expression?
You do not need to solve anything manually, you can just as well do
def ODESystem(f,t):
x,y,z = f
return np.linalg.solve([[1,3,0],[0,1,2],[-1,0,1]], [-4, -t, -2])*y
Nevermind; I am stupid. I can keep on substituting into the third equation until I get an equation for z'(t) that does not include any other derivatives.

Fitting two distinct equations to a function (curve_fit)

I have a problem: I have two distinct equations, one is a linear equation, the other one is an exponential equation. However not both equations should be valid at the same time, meaning that there are two distinct regimes.
Equation 1 (x < a): E*x
Equation 2 (x >=a): a+b*x+c*(1-np.exp(-d*np.array(x)))
Meaning the first part of the data should just be fit with a linear equation and the rest should be fit with the before mentioned equation 2.
The data I'm trying to fit looks like this (I have also added some sample data, if people wanna have a go):
I have tried several thing already, from just defining one fit function with a heaviside function:
def fit_fun(x,a,b,c,d,E):
funktion1=E*np.array(x)
funktion2=a+b*x+c*(1-np.exp(-d*np.array(x)))
return np.heaviside(x+a,0)*funktion2+(1-np.heaviside(x+a,0))*funktion1
defining a piecewise function:
def fit_fun(x,a,b,c,d,E):
return np.piecewise(x, [x <= a, x > a], [lambda x: E*np.array(x), lambda x: a+b*x+c*(1-np.exp(-d*np.array(x)))])
to lastly (which unforunattly yields me some form function error?):
def plast_fun(x,a,b,c,d,E):
out = E*x
out [np.where(x >= a)] = a+b*x+c*(1-np.exp(-d+x))
return out
Don't get me wrong I do get "some" fits, but they do seem to either take one or the other equation and not really use both. I also tried using several bounds and inital guesses, but it never changes.
Any input would be greatly appreciated!
Data:
0.000000 -1.570670
0.000434 83.292677
0.000867 108.909402
0.001301 124.121676
0.001734 138.187659
0.002168 151.278839
0.002601 163.160478
0.003035 174.255626
0.003468 185.035092
0.003902 195.629820
0.004336 205.887161
0.004769 215.611995
0.005203 224.752083
0.005636 233.436680
0.006070 241.897851
0.006503 250.352697
0.006937 258.915168
0.007370 267.569337
0.007804 276.199005
0.008237 284.646778
0.008671 292.772349
0.009105 300.489611
0.009538 307.776858
0.009972 314.666291
0.010405 321.224211
0.010839 327.531594
0.011272 333.669261
0.011706 339.706420
0.012139 345.689265
0.012573 351.628362
0.013007 357.488150
0.013440 363.185771
0.013874 368.606298
0.014307 373.635696
0.014741 378.203192
0.015174 382.315634
0.015608 386.064126
0.016041 389.592120
0.016475 393.033854
0.016908 396.454226
0.017342 399.831519
0.017776 403.107084
0.018209 406.277016
0.018643 409.441119
0.019076 412.710982
0.019510 415.987331
0.019943 418.873140
0.020377 421.178098
0.020810 423.756827
So far I have found these two questions, but I could't figure it out:
Fit of two different functions with boarder as fit parameter
Fit a curve for data made up of two distinct regimes
I suspect you are making a mistake in the second equation, where you do a+b*x+c*(1-np.exp(-d+x)). where a is the value of x where you change from one curve to the other. I think you should use the value of y instead which is a*E. Also it is very important to define initial parameters to the fit. I've ran the following code with your data in .txt file and the fit seems pretty good as you can see bellow:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import optimize, stats
def fit_fun(x,a,b,c,d,E):
return np.piecewise(x, [x <= a, x > a], [lambda x: E*x, lambda x: a*E+b*x+c*(1-np.exp(-d*x))])
df = pd.read_csv('teste.txt', delimiter='\s+', header=None)
df.columns = ['x','y']
xdata = df['x']
ydata = df['y']
p0 = [0.001,1,1,1,100000]
popt, pcov = optimize.curve_fit(fit_fun, xdata.values, ydata.values, p0=p0, maxfev=10000, absolute_sigma=True, method='trf')
print(popt)
plt.plot(xdata, ydata,'*')
plt.plot(xdata, fit_fun(xdata.values, *popt), 'r')
plt.show()

I am beginner, and have a question related to plotting in Python

I am new to python.
I wanted to know the syntax for a problem
Suppose I want to plot a quantity x = (constant with a fixed given value) * ln (1+z) versus z (which varies from c to d)
How do I define the variables x and z, how do I input an 'ln' function
I have imported numpy, scipy and matplotlib, but do not know how to proceed thereafter
Since you already imported numpy, here is just another answer:
import numpy as np
import matplotlib.pyplot as plt
x_coeff = 10
c = 0
d = 100
z = [i for i in range(c, d)]
x = [x_coeff * np.log(1+v) for i, v in enumerate(z)]
plt.plot(z, x)
plt.show()
It's always better to check the documents, and give out your first try:
https://docs.scipy.org/doc/numpy/reference/generated/numpy.log.html
You might also need to understand "list comprehension".
It's a beautiful and convenient way to create list in python.
For plotting a curve, you need two lists, one of them is domain on x axis and the other is range points on y-axis. first we take a constant as input,using python inbuilt input function and make sure that it is int, use math library and log function to do log as need.
import math
import matplotlib.pyplot as plt
a = int(input("enter a value for constant : "))
c,d = 0,100
xvals = list(range(c,d,1)) # start,end,step
print(xvals)
yvals = [a*math.log(1+x) for x in xvals]
print(yvals)
plt.plot(xvals,yvals)
plt.show()

Python: how is it possible to convert a symbolic expression into a function so that it can be numerically integrated?

I've been working with symbolic expressions in Python, and have arrived at one which I am wanting to integrate over a definite interval. The expression contains pi.
The trouble is that I have not been able to figure out how to convert this expression to a function which can be input as an argument to scipy.integrate.quad. The relevant parts of my code are as follows:
from sympy import *
import numpy as np
import scipy.integrate as integrate
from sympy.utilities.lambdify import lambdify
# this defines the symbols that
# we will be using in our computations:
x, y, g, y1, a0, a1, a2 = symbols('x y g y1 a0 a1 a2')
# this defines what a0 and a1,
# and what y and y' are:
a0 = 2
a1 = -((2/pi)+(pi*a2))
y = a0+a1*x+a2*x**2
y1 = y.diff(x)
# this defines the integrand that
# here represents the Lagrangian:
L=sqrt((1+y1**2)/(2*g*y))
# this differentiates the above with
# respect to a2, to define the integrand:
difL = L.diff(a2)
It is difL which I am wanting to integrate. I have tried defining it as a function in the following way:
def integrand(a2):
return difL
f = lambdify(x, integrand(a2))
to no avail. So my question is: how can I convert difL into a function which can then be integrated using scipy.integrate.quad?
And, as a disclaimer, I am new to Python, so if I've been employing terms incorrectly, let me know.
You do not need scipy, sympy is perfectly capable of numerical integration. Now, you have a lot of variables you are not defining (e.g. g) so I'll construct an easier example, and let you adapt to your question.
from sympy import *
from sympy.abc import x, a
# x is variable, a is parameter
y = x**2 + a
# integrate over x from 0 to 1; then evaluate with the value of the parameter
integrate(y, (x, 0, 1)).evalf(subs={a: -4})

Categories

Resources