I have certain function, for example sin(b*x), with sympy I get derivative and antiderivative expressions, but I need to plot these 3 functions in matplotlib. My problem is I can't convert correctly functions to numpy in order to plot in matplotlib. I have followed the documentation in sympy page with lambify function but it doesn't work. http://docs.sympy.org/latest/modules/utilities/lambdify.html
I have this code:
from sympy import Symbol, diff, integrate, sin, cos, Function
from sympy.utilities.lambdify import lambdify, implemented_function
from sympy.abc import x
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
def signal(b,x):
return sin(b*x)
def derivative(b,x):
yprime = diff(signal(b,x), x)
return yprime
def antiderivative(b,x):
anti = integrate(signal(b,x), x)
return anti
b = 5
evalfunc = lambdify((b,x), signal(b,x), modules=['numpy'])
evalderiv = lambdify((b,x), derivative(b,x), modules=['numpy'])
evalantideriv = lambdify((b,x), antiderivative(b,x), modules=['numpy'])
axis_color = 'lightgoldenrodyellow'
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
fig.subplots_adjust(left=0.25, bottom=0.25)
t = np.arange(-10, 10, 0.001)
[line] = ax.plot(t, evalfunc(b,t), linewidth=2, color='red')
[line2] = ax.plot(t, evalderiv(b,t), linewidth=2, color='blue')
[line3] = ax.plot(t, evalantideriv(b,t), linewidth=2, color='blue')
ax.set_xlim([-10, 10])
ax.set_ylim([-5, 5])
ax.grid()
plt.show()
It fails in ax.plot ValueError: sequence too large; cannot be greater than 32
Your code is not quite a minimal working example, but it requires only minimal changes to work.
You need to declare your b as real symbol before the derivation.
You set it as b=5 before the numerical evaluation.
See:
from sympy import Symbol, diff, integrate, sin, cos, Function
from sympy.utilities.lambdify import lambdify, implemented_function
from sympy.abc import x
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
def signal(b,x):
return sin(b*x)
def derivative(b,x):
yprime = diff(signal(b,x), x)
return yprime
def antiderivative(b,x):
anti = integrate(signal(b,x), x)
return anti
b = Symbol('b', real=True)
evalfunc = lambdify((b,x), signal(b,x), modules=['numpy'])
evalderiv = lambdify((b,x), derivative(b,x), modules=['numpy'])
evalantideriv = lambdify((b,x), antiderivative(b,x), modules=['numpy'])
axis_color = 'lightgoldenrodyellow'
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
fig.subplots_adjust(left=0.25, bottom=0.25)
t = np.arange(-10, 10, 0.001)
b = 5
[line] = ax.plot(t, evalfunc(b,t), linewidth=2, color='red')
[line2] = ax.plot(t, evalderiv(b,t), linewidth=2, color='blue')
[line3] = ax.plot(t, evalantideriv(b,t), linewidth=2, color='blue')
ax.set_xlim([-10, 10])
ax.set_ylim([-5, 5])
ax.grid()
plt.show()
Related
I am trying to plot a 2 variable function with additional parameters which can be changed. Below is the function-
f(x,y) = (x - a*y)/(b+y)
I want to plot it in 3d and would like to see the change in the plot by changing the values of a and b, i.e. when a=1 and b=0, etc.
I can plot it for specific a and b cases, below is the code that works for a=1 and b=0. Is there any way where I don't need to map separately for different cases of a and b?
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import numpy as np
x = np.linspace(30,7000,10000)
y = np.linspace(1,11000, 10000)
def delCAD(x,y):
return (x-y)/(y) # the function when a=1 and b=0
fig = plt.figure(figsize=(12,8))
ax = Axes3D(fig)
ax = fig.gca(projection = "3d")
surf = ax.plot_trisurf(x, y, delCAD(x,y), cmap = cm.coolwarm)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
I generally use IPython or Jupyter for that sort of thing — maybe that's an option for you? For example, using ipywidgets.interact():
import matplotlib.pyplot as plt
import numpy as np
from ipywidgets import interact
x = np.linspace(1, 20, 50)
y = np.linspace(1, 20, 50)
y, x = np.meshgrid(y, x)
def delCAD(x, y, a=1, b=0):
return (x - a * y) / (b + y)
#interact(a=(1, 10), b=(0, 10))
def plot(a, b):
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(12, 6))
surf = ax.plot_trisurf(x.flat, y.flat, delCAD(x, y, a, b).flat, cmap='coolwarm')
fig.colorbar(surf, ax=ax, shrink=0.5, aspect=5)
ax.view_init(elev=30, azim=160)
plt.show()
return
Produces this:
As well as the interact wrapper, I introduced the meshgrid line to compute all the locations in the grid, and I changed some of your parameters a bit so you can see more going on in the function. I hope you can unpick the various pieces to fit your needs.
I'm trying to Add the slider in the plot similar to the slider demo example.
I'm plotting fill_between which gives PolyCollection object.
Although I tried with plot too which give Line2D object as shown picture below, but plot doesn't update as expected as in demo.
code
import numpy as np
import scipy.stats as ss
import matplotlib.pyplot as plt
import matplotlib.widgets as widgets
def get_pdf(mu, sigma=1, offset=4):
o = sigma * offset
x = np.linspace(mu - o, mu + o, 100)
rv = ss.norm(mu, sigma)
return x, rv.pdf(x)
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
ax.fill_between(*get_pdf(0, 1), alpha=0.7)
# t = plt.fill_between(*get_pdf(2, 1), alpha=0.7) # this gives ployCollection
t = ax.plot(*get_pdf(2, 1), label='treatment', alpha=0.7)
a = plt.axes([0.25, 0.1, 0.5, 0.03])
slider = widgets.Slider(a, "shift", 0, 10, valinit=2, valstep=1)
def update(val):
x, y = get_pdf(val)
t[0].set_ydata(y)
fig.canvas.draw_idle()
slider.on_changed(update)
plt.show()
To update the line plot, t[0].set_xdata(x) needs to be set, as it is different for each call. In this particular case, get_pdf each time returns the same y.
Updating the coordinates of the polyCollection generated by fill_between doesn't seem to be possible. However, you can delete and recreate it at every update. Note that this is slower than just updating the coordinates.
import numpy as np
import scipy.stats as ss
import matplotlib.pyplot as plt
import matplotlib.widgets as widgets
def get_pdf(mu, sigma=1, offset=4):
o = sigma * offset
x = np.linspace(mu - o, mu + o, 100)
rv = ss.norm(mu, sigma)
return x, rv.pdf(x)
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
ax.fill_between(*get_pdf(0, 1), alpha=0.7)
t = ax.fill_between(*get_pdf(2), color='crimson', alpha=0.7)
a = plt.axes([0.25, 0.1, 0.5, 0.03])
slider = widgets.Slider(a, "shift", 0, 10, valinit=2, valstep=1)
def update(val):
global t
t.remove()
t = ax.fill_between(*get_pdf(val), color='crimson', alpha=0.7)
fig.canvas.draw_idle()
slider.on_changed(update)
plt.show()
I want to make a plot with square root scale using Python:
However, I have no idea how to make it. Matplotlib allows to make log scale but in this case I need something like power function scale.
You can make your own ScaleBase class to do this. I have modified the example from here (which made a square-scale, not a square-root-scale) for your purposes. Also, see the documentation here.
Note that to do this properly, you should probably also create your own custom tick locator; I haven't done that here though; I just manually set the major and minor ticks using ax.set_yticks().
import matplotlib.scale as mscale
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
import matplotlib.ticker as ticker
import numpy as np
class SquareRootScale(mscale.ScaleBase):
"""
ScaleBase class for generating square root scale.
"""
name = 'squareroot'
def __init__(self, axis, **kwargs):
# note in older versions of matplotlib (<3.1), this worked fine.
# mscale.ScaleBase.__init__(self)
# In newer versions (>=3.1), you also need to pass in `axis` as an arg
mscale.ScaleBase.__init__(self, axis)
def set_default_locators_and_formatters(self, axis):
axis.set_major_locator(ticker.AutoLocator())
axis.set_major_formatter(ticker.ScalarFormatter())
axis.set_minor_locator(ticker.NullLocator())
axis.set_minor_formatter(ticker.NullFormatter())
def limit_range_for_scale(self, vmin, vmax, minpos):
return max(0., vmin), vmax
class SquareRootTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
def transform_non_affine(self, a):
return np.array(a)**0.5
def inverted(self):
return SquareRootScale.InvertedSquareRootTransform()
class InvertedSquareRootTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
def transform(self, a):
return np.array(a)**2
def inverted(self):
return SquareRootScale.SquareRootTransform()
def get_transform(self):
return self.SquareRootTransform()
mscale.register_scale(SquareRootScale)
fig, ax = plt.subplots(1)
ax.plot(np.arange(0, 9)**2, label='$y=x^2$')
ax.legend()
ax.set_yscale('squareroot')
ax.set_yticks(np.arange(0,9,2)**2)
ax.set_yticks(np.arange(0,8.5,0.5)**2, minor=True)
plt.show()
This is old, but I made a quick-fix because i didn't want to bother with creating a custom tick-locator. If you are making a lot of plots with custom scales that is probably the way to go. Just plotting the function with the scale you want, then setting the ticks and changing the labels is quicker if you just need a plot or two.
Nx = 100
x = np.linspace(0,50,Nx)
y = np.sqrt(x)
fig, ax = plt.subplots(1, 1)
plt.plot(np.sqrt(x), y)
ax.set_xticks([np.sqrt(x[i]) for i in range(0, Nx, Nx // 10)])
ax.set_xticklabels([str(round(x[i],0))[:-2] for i in range(0, Nx, Nx // 10)])
plt.xlabel('x')
plt.ylabel(r'y = $\sqrt{x}$')
plt.grid()
plt.show()
produces the plot
I like lolopop's comment and tom's answer, a more quick and dirty solution would be using set_yticks and set_yticklabels as in the following:
x = np.arange(2, 15, 2)
y = x * x
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1.plot(x,y)
ax2.plot(x, np.sqrt(y))
ax2.set_yticks([2,4,6,8,10,12,14])
ax2.set_yticklabels(['4','16','36','64','100','144','196'])
Matplotlib now offers a powlaw norm. Thus setting power to 0.5 should do the trick!
C.f. Matplotlib Powerlaw norm
And their example:
"""
Demonstration of using norm to map colormaps onto data in non-linear ways.
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
from matplotlib.mlab import bivariate_normal
N = 100
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
'''
PowerNorm: Here a power-law trend in X partially obscures a rectified
sine wave in Y. We can remove gamma to 0.5 should do the trick using PowerNorm.
'''
X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]
Z1 = (1 + np.sin(Y * 10.)) * X**(2.)
fig, ax = plt.subplots(2, 1)
pcm = ax[0].pcolormesh(X, Y, Z1, norm=colors.PowerNorm(gamma=1./2.),
cmap='PuBu_r')
fig.colorbar(pcm, ax=ax[0], extend='max')
pcm = ax[1].pcolormesh(X, Y, Z1, cmap='PuBu_r')
fig.colorbar(pcm, ax=ax[1], extend='max')
fig.show()
This a simple way to graph
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams["figure.dpi"] = 140
fig, ax = plt.subplots()
ax.spines["left"].set_position("zero")
ax.spines["bottom"].set_position("zero")
ax.spines["right"].set_color("none")
ax.spines["top"].set_color("none")
ax.xaxis.set_ticks_position("bottom")
ax.yaxis.set_ticks_position("left")
origin = [0, 0]
# 45
plt.plot(
np.linspace(0, 1, 1000),
np.sqrt(np.linspace(0, 1, 1000)),
color="k",
)
ax.set_aspect("equal")
plt.xlim(-0.25, 1)
plt.ylim(0, 1)
plt.yticks(ticks=np.linspace(0, 1, 6))
plt.show()
I got a .dat file which contains the coordinates of a segment in 3d space.
The file has several lines, each single line characterizes the position at a particular time.
I tried this code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
dati = np.loadtxt('dati.dat')
t=0
p1=[dati[t,1],dati[t,2],dati[t,3]]
p2=[dati[t,4],dati[t,5],dati[t,6]]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
seg,=ax.plot(p1,p2)
def updateFigure(t,dati,seg):
p1=[dati[t,1],dati[t,2],dati[t,3]]
p2=[dati[t,4],dati[t,5],dati[t,6]]
seg.set_data(p1,p2)
return seg,
ani=animation.FuncAnimation(fig, updateFigure,iMax, fargs=(dati,seg), interval=100, blit=True)
plt.show()
The program doesn't report errors but the figure doesn't move.
The same code, a bit modified, in the 2d space works..
Instead of calling set_data, you could set seg._verts3d directly, though note that manipulating the private variable _verts3d is relying on an implementation detail, not part of the Line3D public interface:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
iMax = N = 500
theta = np.linspace(0, 6*np.pi, N)
x = np.cos(theta)
y = np.sin(theta)
z = np.linspace(0, 1, N)
step = 10
dati = np.column_stack(
[theta, x, np.roll(x, -step), np.roll(x, -2*step)
, y, np.roll(y, -step), np.roll(y, -2*step)
, z, np.roll(z, -step), np.roll(z, -2*step)])
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
seg, = plt.plot([], [])
ax.set_xlim3d(-1, 1)
ax.set_ylim3d(-1, 1)
ax.set_zlim3d(0, 1)
def init():
return seg,
def updateFigure(t):
p1 = dati[t, 1:4]
p2 = dati[t, 4:7]
p3 = dati[t, 7:10]
seg._verts3d = (p1, p2, p3)
return seg,
ani = animation.FuncAnimation(
fig, updateFigure
, init_func=init
, frames=iMax
, interval=5, blit=True)
plt.show()
I can't find a way to draw errorbars in a 3D scatter plot in matplotlib.
Basically, for the following piece of code
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y, Z = axes3d.get_test_data(1)
ax.scatter(X, Y, zs = Z, zdir = 'z')
I am looking for something like
ax.errorbar(X,Y, zs = Z, dY, dX, zserr = dZ)
Is there a way to do this in mplot3d? If not, are there other libraries with this function?
There is clearly example on forum http://mple.m-artwork.eu/home/posts/simple3dplotwith3derrorbars
Here is the code but is not built-in functionality:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as axes3d
fig = plt.figure(dpi=100)
ax = fig.add_subplot(111, projection='3d')
#data
fx = [0.673574075,0.727952994,0.6746285]
fy = [0.331657721,0.447817839,0.37733386]
fz = [18.13629648,8.620699842,9.807536512]
#error data
xerror = [0.041504064,0.02402152,0.059383144]
yerror = [0.015649804,0.12643117,0.068676131]
zerror = [3.677693713,1.345712547,0.724095592]
#plot points
ax.plot(fx, fy, fz, linestyle="None", marker="o")
#plot errorbars
for i in np.arange(0, len(fx)):
ax.plot([fx[i]+xerror[i], fx[i]-xerror[i]], [fy[i], fy[i]], [fz[i], fz[i]], marker="_")
ax.plot([fx[i], fx[i]], [fy[i]+yerror[i], fy[i]-yerror[i]], [fz[i], fz[i]], marker="_")
ax.plot([fx[i], fx[i]], [fy[i], fy[i]], [fz[i]+zerror[i], fz[i]-zerror[i]], marker="_")
#configure axes
ax.set_xlim3d(0.55, 0.8)
ax.set_ylim3d(0.2, 0.5)
ax.set_zlim3d(8, 19)
plt.show()
I ended up writing the method for matplotlib: official example for 3D errorbars:
import matplotlib.pyplot as plt
import numpy as np
ax = plt.figure().add_subplot(projection='3d')
# setting up a parametric curve
t = np.arange(0, 2*np.pi+.1, 0.01)
x, y, z = np.sin(t), np.cos(3*t), np.sin(5*t)
estep = 15
i = np.arange(t.size)
zuplims = (i % estep == 0) & (i // estep % 3 == 0)
zlolims = (i % estep == 0) & (i // estep % 3 == 2)
ax.errorbar(x, y, z, 0.2, zuplims=zuplims, zlolims=zlolims, errorevery=estep)
ax.set_xlabel("X label")
ax.set_ylabel("Y label")
ax.set_zlabel("Z label")
plt.show()