2025, Nov 25 11:00

How to Access and Plot Individual Terms from a SymPy ODE Solution Using args and subs

Extract and plot individual terms of a SymPy ODE general solution using .args and subs. Fix C1, C2 without copy-paste and visualize exponentials or Airy terms.

Extracting parts of a general ODE solution in Sympy without copy–paste

When Sympy solves a linear ODE, it returns a symbolic expression that is usually a sum of basis solutions multiplied by integration constants. That’s exactly what you want to plot and inspect piecewise, but the solver gives you a single expression like C1*exp(-z*sqrt(-e)) + C2*exp(z*sqrt(-e)). The practical question is how to access those individual terms directly from the returned object and plot them without manual copy and paste.

Minimal reproducible setup

The following snippet builds a simple second-order ODE, solves it, and prints the right-hand side of the solution:

import sympy as sp
u = sp.Symbol('u')
lam = sp.Symbol('lam')
g = sp.Function('g')
ode = sp.diff(g(u), u, 2) + lam * g(u)
res = sp.dsolve(ode, g(u))
print(res.rhs)

For this equation, the right-hand side is a sum of two exponentials, each multiplied by an integration constant.

What’s actually returned and why it’s tricky to slice

The object in res.rhs is a Sympy expression. It represents the whole general solution as a single symbolic tree. Trying to index res.rhs directly will not work, because it isn’t a Python list—it’s an expression. To pick out individual additive parts, you need to look at the expression’s internal operands.

Direct access to the summands

Sympy exposes the components of a symbolic expression through the args attribute. For a sum, args contains the additive terms in order, so you can pull them out by index and work with them independently.

# inspect individual parts of the RHS
print(res.rhs.args[0])  # first term
print(res.rhs.args[1])  # second term

This gives you access to each piece of the general solution without any copying.

From symbolic parts to plots

If you want to visualize a single term or the full solution, you’ll usually want to substitute numeric values for the integration constants. You can do that with subs and then pass the expression to plot.

# fix integration constants and plot the full solution
C1, C2 = sp.symbols("C1 C2")
full_expr = res.rhs.subs({C1: 2, C2: 3})
sp.plot(full_expr, (u, 0, 10))

If the goal is to plot one element of the general solution, access it via args and substitute only the relevant constant:

# plot just the first term with a chosen constant value
first_term = res.rhs.args[0]
one_piece = first_term.subs({C1: 1})
sp.plot(one_piece, (u, 0, 10))

The same approach applies when the solver returns special functions. For example, if a solution looks like C1*airyai(-e + z) + C2*airybi(-e + z), you can still access each part with .args[0] and .args[1] and then substitute numeric values for C1 or C2 before plotting.

Why this matters

When exploring many ODEs programmatically, you don’t want to manually extract pieces from printed strings. Treating the solver’s output as a real symbolic object means you can select terms, fix constants, and plot or further transform them in a controlled and repeatable way. That saves time and avoids mistakes, especially when solutions involve special functions like Airy functions.

Takeaways

Access the internal pieces of a Sympy solution via the args attribute, not by slicing the expression directly. Substitute numeric values for integration constants with subs, and then plot either the entire expression or any individual term you’ve extracted. This workflow scales cleanly from simple exponentials to solutions built from special functions.