So I am having a problem plotting an if statement function. Could someone tell me where i am going wrong? The code follows:
import numpy as np
import matplotlib.pyplot as plt
#x-axis
x_1 = np.arange(-20,20,0.001)
#defining the function
def h(x):
"""
input: x \in R
oupit: h(x) defined above in R.
"""
if x == 0:
return 1
else:
return np.sin(x)/x
def g(x):
"""
input: x \in R
oupit: g(x) defined above in R.
"""
return np.cos(x)
#drawing the function
plt.plot(x_1,h(x_1),label = r"$\frac{\sin(x)}{x}$",color="red")
plt.legend()
plt.plot(x_1,g(x_1),label = r"$\cos(x)$",color="blue")
plt.legend()
plt.grid(linestyle="dotted")
plt.ylabel("$f(x)$")
#plt.savefig('img231.pdf')
plt.show()
The main problem is probably in the line with plt.plot(x_1,h(x_1)). Any answers are appreciated:)~ Thanks, Y
To write an if-test in numpy, you need np.where: np.where(x == 0, 1, np.sin(x)/x).
This still will write a warning for division by zero, which can be suppressed using with np.errstate(divide='ignore').
Also note that np.arange(-20, 20, 0.001) generates 40000 values, which is quite high compared to the number of pixels on a screen (an even compared to the dots on a printer). Using np.linspace() you have easier control over the number of points used. Using too many points can unnecessarily slow down calculations and plotting.
Calling plt.legend() twice can be a bit confusing. The second call will remove the first legend.
import numpy as np
import matplotlib.pyplot as plt
x_1 = np.linspace(-20, 20, 1000)
def h(x):
with np.errstate(divide='ignore'):
return np.where(x == 0, 1, np.sin(x) / x)
def g(x):
return np.cos(x)
plt.plot(x_1, h(x_1), label=r"$\frac{\sin(x)}{x}$", color="crimson")
plt.plot(x_1, g(x_1), label=r"$\cos(x)$", color="cornflowerblue")
plt.grid(linestyle="dotted")
plt.ylabel("$f(x)$")
plt.legend()
plt.show()
Related
I am trying to plot 3 different functions on a log-log scale in python for three intervals of the x-range. Attaching the image of the kind of plot that I want to create and which functions, y, for what intervals of x.
My code attempt is as follows. Maybe I am overcomplicating it.
import math as m
import numpy as np
import pylab as pl
import matplotlib.pyplot as plt
x = np.arange(100) # this gives `array([0, 1, 2, ..., 9])`
y = np.arange(100)
for i in range (-50,20):
if x[i] < -43:
y[i] = m.log10((10**x[i])/(10**-43))**(1/2)
if x[i] > -43 and x[i] < -40:
y[i] = m.log10(np.exp((10**36)((10**x[i])-(10**-43))))
if x[i] >-40:
y[i] = m.log10((np.exp((10**36)((10**-40) - (10**-43)))(((10**x[i])/(10**-43))**(1/2)))
#i+=1
pl.plot(x,y)
#pl.xlim([-100.,100.])
#pl.ylim([-100.,100.])
pl.xlabel('log x')
pl.ylabel('log y')
pl.show()
PLEASE NOTE:
updated code with help from #Sembei which works but there's further question on colours below:
import matplotlib.pyplot as plt
x = np.linspace(-50,23,500)
y = []
for xval in x:
if xval < -36:
y.append(m.log10(((10**xval)/(10**-36))**(1/2)))
elif -36 <= xval <= -34:
y.append(m.log10(np.exp((10**36)*((10**xval)-(10**-36)))))
else:
y.append(m.log10((np.exp((10**36)*((10**-34) - (10**-36)))*(((10**xval)/(10**-36))**(1/2)))))
plt.plot(x,y)
pl.xlim([-44.,-30.])
#pl.ylim([-10.,20.])
pl.xlabel('log x')
pl.ylabel('log y')
plt.show()
FURTHER QUESTION:
how to set 3 different colours for the different y functions for the 3 x-intervals?
Any help is appreciated. Thanks!
you can do something like this:
x = range(-50,23)
y = []
for xval in x:
if xval < -43:
y.append(-43) #your function in this interval
elif -43 <= xval <= -40:
y.append(xval) #your function in this interval)
else:
y.append(-40) #your function in this interval)
plt.plot(x,y, '.-')
plt.xlabel('log x')
plt.ylabel('log y')
plt.show()
You just need to fill the #your function in this interval with a correct syntax (note that in your syntax you are missing product operators *)
Here I have used y as a list and I'm appending values. You can also initialize y to all zeros and assign values based on indexes. For that you will need to include an enumerate in the loop that will give you the index of y where you have to put the value.
Note: here, range steps one by one. if you want more resolution you might want to use np.linspace so you can control the resolution of your function.
Edit: I put some toy definitions of the function so you can see how it works. Now just change my function definitions for your own
I have a really simple issue with my Python program -- which isn't finished at all. Right now it's doing everything I want, but not how I want.
There are three things I've been trying to change:
all functions are being plotted using the same color, and I'd like the program to automatically switch to a new color when a new function is added to the plot (it will be more than 2, all on the same plot).
f(x)'s range is 140. How can I decrease that? Maybe to 20/40.
(most important) My code isn't very efficient. f1 and derivative are not associated at all. I declare the function's model in f1, but I have to set up everything again in derivative. Every time I try to do otherwise I end up having some problem with the main function. I'll eventually add more features like integration and whatnot, and if I'm declaring everything from scratch everytime I want to do something with f1 the program will kinda lose its purpose.
Should I use x = Symbol('x') inside f1?
import numpy as np
import matplotlib.pyplot as plt
from sympy import *
x = Symbol('x')
def f1(a, b, c, d):
y = a*x**3 + b*x**2 + x*c + d
return y
###yprime = y.diff(x)
###return yprime
def derivative(a, b, c, d):
y = a*x**3 + b*x**2 + x*c + d
yprime = y.diff(x)
return yprime
def factorail(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
###colors = iter(cm.rainbow(np.linspace(0, 1, len(ys))))
###for y in ys:
###plt.scatter(x, y, color=next(colors))
def main():
###colors = itertools.cycle(["r", "b", "g"])
y = f1(0,1,2,1)
yp = derivative(0,1,2,1)
print(y)
plot(y, yp)
plot(yp)
plt.show()
if __name__ == '__main__':
main()
Vertical window is set by ylim option. I recommend to also use some explicit limits for x, the default -10 to 10 is not necessarily best for you. And I do recommend reading the page on SymPy plotting.
Color is set by line_color option. Different colors require different calls to plot, but those can be combined. Example:
p = plot(y, (x, -5, 5), ylim=(-20, 20), line_color='b', show=False)
p.extend(plot(yp, (x, -5, 5), ylim=(-20, 20), line_color='r', show=False))
p.show()
results in
The function reuse is easy:
def derivative(a, b, c, d):
y = f1(a, b, c, d)
yprime = y.diff(x)
return yprime
Aside: what happens if we try line_color=['b', 'r'], as in plot(y, yp, ylim=(-20, 20), line_color=['b', 'r'])? Funny stuff happens:
I use the following function to get colors that are "far" from each other in a general way. The 2396745 is pretty arbitrary, and defines how far apart the colors are. It seems to give me good results.
def cmap_ints(i):
return "#"+hex(((int(i)+1)*2396745)%(256**3))[2:].rjust(6,"0")
Usage:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,1,100)
y1 = 3*x + 4
y2 = 2*x - 5
plt.plot(x,y1,c=cmap_ints(1))
plt.plot(x,y2,c=cmap_ints(2))
I would like to plot implicit equations (of the form f(x, y)=g(x, y) eg. X^y=y^x) in Matplotlib. Is this possible?
Since you've tagged this question with sympy, I will give such an example.
From the documentation: http://docs.sympy.org/latest/modules/plotting.html.
from sympy import var, plot_implicit
var('x y')
plot_implicit(x*y**3 - y*x**3)
I don't believe there's very good support for this, but you could try something like
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
delta = 0.025
xrange = arange(-5.0, 20.0, delta)
yrange = arange(-5.0, 20.0, delta)
X, Y = meshgrid(xrange,yrange)
# F is one side of the equation, G is the other
F = Y**X
G = X**Y
matplotlib.pyplot.contour(X, Y, (F - G), [0])
matplotlib.pyplot.show()
See the API docs for contour: if the fourth argument is a sequence then it specifies which contour lines to plot. But the plot will only be as good as the resolution of your ranges, and there are certain features it may never get right, often at self-intersection points.
matplotlib does not plot equations; it plots serieses of points. You can use a tool like scipy.optimize to numerically calculate y points from x values (or vice versa) of implicit equations numerically or any number of other tools as appropriate.
For example, here is an example where I plot the implicit equation x ** 2 + x * y + y ** 2 = 10 in a certain region.
from functools import partial
import numpy
import scipy.optimize
import matplotlib.pyplot as pp
def z(x, y):
return x ** 2 + x * y + y ** 2 - 10
x_window = 0, 5
y_window = 0, 5
xs = []
ys = []
for x in numpy.linspace(*x_window, num=200):
try:
# A more efficient technique would use the last-found-y-value as a
# starting point
y = scipy.optimize.brentq(partial(z, x), *y_window)
except ValueError:
# Should we not be able to find a solution in this window.
pass
else:
xs.append(x)
ys.append(y)
pp.plot(xs, ys)
pp.xlim(*x_window)
pp.ylim(*y_window)
pp.show()
There is an implicit equation (and inequality) plotter in sympy. It is created as a part of GSoC and it produces the plots as matplotlib figure instances.
Docs at http://docs.sympy.org/latest/modules/plotting.html#sympy.plotting.plot_implicit.plot_implicit
Since sympy version 0.7.2 it is available as:
>>> from sympy.plotting import plot_implicit
>>> p = plot_implicit(x < sin(x)) # also creates a window with the plot
>>> the_matplotlib_axes_instance = p._backend._ax
Edit: If you plot a hyperbola using plt.plot() then you will get the undesired branching effect. plt.scatter() in its place should still work. Then there is no need to reverse the order of negative or positive values, but if you wanted to use this code for some reason (instead of using contour plot from scipy) it will work anyways with plt.scatter()
An implicit function in two dimensions in general can be written as:
f(x,y)=0
Since we cannot write this as f(x) = y, then we cannot compute y from an easily programmable set of discrete x. It is possible, however, to see how close a point generated from a grid is from the true function.
So make a grid of x and y to a custom point density and see how close each point is to satisfying the equation.
In other words, if we can't get f(x,y) =0, perhaps we can get close to 0. Instead of looking for f(x,y) =0 look for f(x,y) > -\epsilon and f(x,y) < \epsilon.
\epsilon is your tolerance and if this condition fits within your tolerance of 0 and tuning the grid appropriately you can get your function plotted.
The code below does just that for a circle of radius 1 (f(x,y)= x^2 + y^2 -1 = 0). I used the symbol dr for \epsilon.
Also, to make sure the plt.plot function connects the lines in the correct order, I use a reversed version of the x values for the negative y values. That way, the evaluation of f(x,y) is done in a clockwise loop so that the nearest values are one after another. Without this, lines from opposite sides of the function would connect and it would appear slightly filled in.
import numpy as np
import matplotlib.pyplot as plt
r = 1 #arbitrary radius to set up the span of points
points = 250
dr = r/points #epsilon window
x=list(np.linspace(-5*r,5*r,5*points+1)) #setting up the x,y grid
y=x
xreversed = reversed(x) #reversing the array
x_0=[] #placeholder arrays
y_0=[]
for i in x:
for j in y:
if i**2 + j**2 -1 < dr and i**2+j**2 -1 > -dr and j >= 0: #positive values of y
x_0.append(i)
y_0.append(j)
for i in xreversed:
for j in y:
if i**2+j**2 -1 < dr and i**2+j**2 -1 > -dr and j < 0: #negative values of y, using x reversed
x_0.append(i)
y_0.append(j)
plt.plot(x_0,y_0)
plt.show()
Many thanks Steve, Mike, Alex. I have gone along with Steve's solution (please see code below). My only remaining issue is that the contour plot appears behind my gridlines, as opposed to a regular plot, which I can force to the front with zorder. Any more halp greatly appreciated.
Cheers,
Geddes
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import numpy as np
fig = plt.figure(1)
ax = fig.add_subplot(111)
# set up axis
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# setup x and y ranges and precision
x = np.arange(-0.5,5.5,0.01)
y = np.arange(-0.5,5.5,0.01)
# draw a curve
line, = ax.plot(x, x**2,zorder=100)
# draw a contour
X,Y=np.meshgrid(x,y)
F=X**Y
G=Y**X
ax.contour(X,Y,(F-G),[0],zorder=100)
#set bounds
ax.set_xbound(-1,7)
ax.set_ybound(-1,7)
#produce gridlines of different colors/widths
ax.xaxis.set_minor_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.2))
ax.xaxis.grid(True,'minor',linestyle='-')
ax.yaxis.grid(True,'minor',linestyle='-')
minor_grid_lines = [tick.gridline for tick in ax.xaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.xaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
minor_grid_lines = [tick.gridline for tick in ax.yaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.yaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
plt.show()
I'm trying to find all the intersection points of two graphs and display them on the final plot. I've looked around and tried multiple things, but I haven't been able to obtain what l'm looking for.
Currently, I attempting to generate a list wherein the intersection points would be listed, though I keep getting the following error:
The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all().
import numpy as np
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
x = np.arange(-7.0, 7.0, 0.05)
def y(x):
return np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
def g(x):
return -10 * np.arctan(x)
def intersection(x):
if (y(x) - g(x)) == 0:
print y.all(x)
plt.plot(x, y(x), '-')
plt.plot(x, g(x), '-')
plt.show()
It's similar to:
Intersection of two graphs in Python, find the x value:
import numpy as np
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
x = np.arange(-7.0, 7.0, 0.05)
y = np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
g = -10 * np.arctan(x)
def intersection():
idx = np.argwhere(np.isclose(y, g, atol=10)).reshape(-1)
print idx
plt.plot(x, y, '-')
plt.plot(x, g, '-')
plt.show()
intersection()
edit: you don't use a function, but a list of values
For single solutions, this is answered in http://glowingpython.blogspot.de/2011/05/hot-to-find-intersection-of-two.html:
from scipy.optimize import fsolve
def findIntersection(fun1,fun2,x0):
return fsolve(lambda x : fun1(x) - fun2(x),x0)
result = findIntersection(y,g,0.0)
Now, you just need to iterate through your range to get all the roots. This gives some duplicates, which you might be able to remove by using mpmath, setting the precision low enough, and using a set.
from scipy.optimize import fsolve
import numpy as np
rng = np.arange(-7.0, 7.0, 0.05)
def y(x):
return np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
def g(x):
return -10 * np.arctan(x)
def findIntersection(fun1,fun2,x0):
return fsolve(lambda x : fun1(x) - fun2(x),x0)
result = []
for x in rng:
result.append(float(findIntersection(y,g,x)))
I would like to plot implicit equations (of the form f(x, y)=g(x, y) eg. X^y=y^x) in Matplotlib. Is this possible?
Since you've tagged this question with sympy, I will give such an example.
From the documentation: http://docs.sympy.org/latest/modules/plotting.html.
from sympy import var, plot_implicit
var('x y')
plot_implicit(x*y**3 - y*x**3)
I don't believe there's very good support for this, but you could try something like
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
delta = 0.025
xrange = arange(-5.0, 20.0, delta)
yrange = arange(-5.0, 20.0, delta)
X, Y = meshgrid(xrange,yrange)
# F is one side of the equation, G is the other
F = Y**X
G = X**Y
matplotlib.pyplot.contour(X, Y, (F - G), [0])
matplotlib.pyplot.show()
See the API docs for contour: if the fourth argument is a sequence then it specifies which contour lines to plot. But the plot will only be as good as the resolution of your ranges, and there are certain features it may never get right, often at self-intersection points.
matplotlib does not plot equations; it plots serieses of points. You can use a tool like scipy.optimize to numerically calculate y points from x values (or vice versa) of implicit equations numerically or any number of other tools as appropriate.
For example, here is an example where I plot the implicit equation x ** 2 + x * y + y ** 2 = 10 in a certain region.
from functools import partial
import numpy
import scipy.optimize
import matplotlib.pyplot as pp
def z(x, y):
return x ** 2 + x * y + y ** 2 - 10
x_window = 0, 5
y_window = 0, 5
xs = []
ys = []
for x in numpy.linspace(*x_window, num=200):
try:
# A more efficient technique would use the last-found-y-value as a
# starting point
y = scipy.optimize.brentq(partial(z, x), *y_window)
except ValueError:
# Should we not be able to find a solution in this window.
pass
else:
xs.append(x)
ys.append(y)
pp.plot(xs, ys)
pp.xlim(*x_window)
pp.ylim(*y_window)
pp.show()
There is an implicit equation (and inequality) plotter in sympy. It is created as a part of GSoC and it produces the plots as matplotlib figure instances.
Docs at http://docs.sympy.org/latest/modules/plotting.html#sympy.plotting.plot_implicit.plot_implicit
Since sympy version 0.7.2 it is available as:
>>> from sympy.plotting import plot_implicit
>>> p = plot_implicit(x < sin(x)) # also creates a window with the plot
>>> the_matplotlib_axes_instance = p._backend._ax
Edit: If you plot a hyperbola using plt.plot() then you will get the undesired branching effect. plt.scatter() in its place should still work. Then there is no need to reverse the order of negative or positive values, but if you wanted to use this code for some reason (instead of using contour plot from scipy) it will work anyways with plt.scatter()
An implicit function in two dimensions in general can be written as:
f(x,y)=0
Since we cannot write this as f(x) = y, then we cannot compute y from an easily programmable set of discrete x. It is possible, however, to see how close a point generated from a grid is from the true function.
So make a grid of x and y to a custom point density and see how close each point is to satisfying the equation.
In other words, if we can't get f(x,y) =0, perhaps we can get close to 0. Instead of looking for f(x,y) =0 look for f(x,y) > -\epsilon and f(x,y) < \epsilon.
\epsilon is your tolerance and if this condition fits within your tolerance of 0 and tuning the grid appropriately you can get your function plotted.
The code below does just that for a circle of radius 1 (f(x,y)= x^2 + y^2 -1 = 0). I used the symbol dr for \epsilon.
Also, to make sure the plt.plot function connects the lines in the correct order, I use a reversed version of the x values for the negative y values. That way, the evaluation of f(x,y) is done in a clockwise loop so that the nearest values are one after another. Without this, lines from opposite sides of the function would connect and it would appear slightly filled in.
import numpy as np
import matplotlib.pyplot as plt
r = 1 #arbitrary radius to set up the span of points
points = 250
dr = r/points #epsilon window
x=list(np.linspace(-5*r,5*r,5*points+1)) #setting up the x,y grid
y=x
xreversed = reversed(x) #reversing the array
x_0=[] #placeholder arrays
y_0=[]
for i in x:
for j in y:
if i**2 + j**2 -1 < dr and i**2+j**2 -1 > -dr and j >= 0: #positive values of y
x_0.append(i)
y_0.append(j)
for i in xreversed:
for j in y:
if i**2+j**2 -1 < dr and i**2+j**2 -1 > -dr and j < 0: #negative values of y, using x reversed
x_0.append(i)
y_0.append(j)
plt.plot(x_0,y_0)
plt.show()
Many thanks Steve, Mike, Alex. I have gone along with Steve's solution (please see code below). My only remaining issue is that the contour plot appears behind my gridlines, as opposed to a regular plot, which I can force to the front with zorder. Any more halp greatly appreciated.
Cheers,
Geddes
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import numpy as np
fig = plt.figure(1)
ax = fig.add_subplot(111)
# set up axis
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# setup x and y ranges and precision
x = np.arange(-0.5,5.5,0.01)
y = np.arange(-0.5,5.5,0.01)
# draw a curve
line, = ax.plot(x, x**2,zorder=100)
# draw a contour
X,Y=np.meshgrid(x,y)
F=X**Y
G=Y**X
ax.contour(X,Y,(F-G),[0],zorder=100)
#set bounds
ax.set_xbound(-1,7)
ax.set_ybound(-1,7)
#produce gridlines of different colors/widths
ax.xaxis.set_minor_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.2))
ax.xaxis.grid(True,'minor',linestyle='-')
ax.yaxis.grid(True,'minor',linestyle='-')
minor_grid_lines = [tick.gridline for tick in ax.xaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.xaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
minor_grid_lines = [tick.gridline for tick in ax.yaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.yaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
plt.show()