How to plot a sympy.jl piecewise function?

Hello, good afternoon.
Im trying to plot a piecewise function using sympy.jl and plots.jl withou success. May someone help please?

let
	@syms y C
	# Define os pontos do gráfico. Eles são necessários
	# para encontrar a área da forma de onda que iremos integrar.
	p1 = point(0, 0)
	p2 = point(1, 50)
	p3 = point(2, 0)
	p4 = point(3, -50)
	p5 = point(4, 0)

	@info lineexp
	# y - yn = m(x -xn). Devemos usar a função linear e calcular
	# o coeficiente angular(m), e o coeficiente linear (c).
	# O coeficiente angular é encontrado por Δy/Δx.
	# 0 < t < 1
	m1 = (p2.y - p1.y)/(p2.x - p1.x)
	l1 = first(solve(subs(lineexp, m=>m1, c=>0), y))
	# 1 < t < 3
	m2 = (p3.y - p2.y)/(p3.x - p2.x)
	l2 = first(solve(subs(y - p2.y ~ m*(t - p2.x), m=>m2), y))
	# 3 < t < 4
	m3 = (p5.y - p4.y)/(p5.x - p4.x)
	l3 = first(solve(subs(y - p4.y ~ m*(t - p4.x), m=>m3), y))
	# Olhe na figura de forma de onda do exemplo
	v = sympy.Piecewise(
		(l1, Gt(t, 0) & Gt(1, t)),
		(l2, Gt(t, 1) & Gt(3, t)),
		(l3, Gt(t, 3) & Gt(4, t))
	)

	@info v

	# Calcularemos a função de i
	fi = C*diff(v)
	@info fi
	iresult = simplify(subs(fi, C=>200e-6))
	@info iresult
	firesult = lambdify(iresult, t)
	time = LinRange(0, 4, 1000)
	ydata = firesult.(collect(time))
    plot(time, ydata)

end
MethodError: objects of type Float64 are not callable

The object of type `Float64` exists, but no method is defined for this combination of argument types when trying to treat it as a callable object.

Maybe you forgot to use an operator such as *, ^, %, / etc. ?

Something like that in books:

In Plots.jl’s plot() use the line type keyword: lt=:step, once you’ve sorted out your error.

1 Like

but the function is failing on line ydata = firesult.(collect(time))

MethodError: objects of type Float64 are not callable

The object of type `Float64` exists, but no method is defined for this combination of argument types when trying to treat it as a callable object.

Maybe you forgot to use an operator such as *, ^, %, / etc. ?

Cant understand as the data type is a function with a t parameter

Callable function with a single variable t

Looks like some issue with lambdify. This should work for a plot:

plot(t -> float(v(t)), a, b, lt = :step)

what are a, and b variables? If they are x and y data, I dont have y, because firesult is not working.

They are just numbers to pass to plot (0 and 4 in your case), as any other function would be plotted. (The issue here, is the lambdify call doesn’t work well with the last condition. If you put true instead of Gt(t, 3) & Gt(4, t) then the plot should happen as desired: plot(v, 0, 4; lt=:step).

1 Like

If I put true, I will loose the range information. Is it not important to plot the derivative?

image

	v = sympy.Piecewise(
		(l1, true),
		(l2, true),
		(l3, true)
	)

	@info v

	# Calcularemos a função de i
	fi = C*diff(v)
	@info fi
	iresult = simplify(subs(fi, C=>200e-6))
	@info iresult
	firesult = lambdify(iresult)
	@info firesult
	time = LinRange(0, 4, 1000)
	plot(p -> float(v(p)), 0, 4, lt=:step)

Tryed it here, it plots, but its wrong:

And with the diff function (firesult), are wrong also:

I can create a conventional function with ifs based on this
image

But I’ll loose all facilities of sympy.

Well, did with python

y = symbols('y')
p1 = Point(0, 0)
p2 = Point(1, 50)
p3 = Point(2, 0)
p4 = Point(3, -50)
p5 = Point(4, 0)

display(linexp)

# Encontrar as partes das funções no gráfico
# y - yn = m(x - xn)
# 0 < t < 1
m1 = (p2.y - p1.y)/(p2.x - p1.x)
l1 = solve(linexp.subs({m: m1, c: 0}), y)[0]
# 1 < t < 3
m2 = (p3.y - p2.y)/(p3.x - p2.x)
l2 = solve(Eq(y - p2.y, m*(t - p2.x)).subs(m, m2), y)[0]
print(">>>")
print(m2) 
display(l2)
# 3 < t < 4
m3 = (p5.y - p4.y)/(p5.x - p4.x)
l3 = solve(Eq(y - p4.y, m*(t - p4.x)).subs(m, m3), y)[0] 
display(l1)
display(l2)
display(l3)

t_sym = symbols('t')
v = Piecewise(
    (l1, And(t_sym > 0, t_sym < 1)),
    (l2, And(1 < t_sym, t_sym < 3)),
    (l3, And(3 < t_sym, t_sym < 4)),
    (0, True)
)
display(v)

fi = C*diff(v)
iresult = sp.simplify(fi.subs(C, 200e-6))
display(iresult)
sp.plot(iresult)

Glad it worked out. For anyone playing along at home, this would also work within SymPy.jl:

v = sympy.Piecewise(
       (l1, Gt(t, 0) & Gt(1, t)),                
       (l2, Gt(t, 1) & Gt(3, t)),
       (l3, Gt(t, 3) & Gt(4, t)),
       (0, true))
plot(v, -10, 10; le=:step)
1 Like

Yep. It worked. This shows that the issue was the NAN in piecewise function.
Thank you. When you add the condition (0, true), the result in the differentiated function was (0, otherwise).