2

The sympy plot command has a markers parameter:

markers : A list of dictionaries specifying the type the markers required. The keys in the dictionary should be equivalent to the arguments of the matplotlib's plot() function along with the marker related keyworded arguments.

How do I use the markers parameter? My failed attempts range from

from sympy import *
x = symbols ('x')
plot (sin (x), markers = 'o')

to

plot (sin (x), markers = list (dict (marker = 'o')))

2 Answers2

3

Nice find!

The documentation doesn't make things clear. Diving into the source code, leads to these lines in plot.py:

            for marker in parent.markers:
                # make a copy of the marker dictionary
                # so that it doesn't get altered
                m = marker.copy()
                args = m.pop('args')
                ax.plot(*args, **m)

So, sympy just calls matplotlib's plot with:

  • the args key of the dictionary as positional parameters
  • all the other keys of the dictionary as keyword parameters

As matplotlib's plot allows a huge variety of parameters, they all are supported here. They are primarily meant to show extra markers onto the plot (you need to give their positions).

An example:

from sympy import symbols, sin, plot

x = symbols('x')
plot(sin(x), markers=[{'args': [2, 0, 'go']},
                      {'args': [[1, 3], [1, 1], 'r*'], 'ms': 20},
                      {'args': [[2, 4, 6], [-1, 0, -1], ], 'color': 'turquoise', 'ls': '--', 'lw': 3}])

These get converted to:

ax.plot(2, 0, 'go')  # draw a green dot at position 2,0
ax.plot([3, 5], [1, 1], 'r*', ms=20)  # draw red stars of size 20 at positions 3,1 and 5,1
ax.plot([2, 4, 6], [-1, 0, -1], ], color='turquoise', ls='--', lw=3)
    # draw a dotted line from 2,-1  over 4,0 to 6,-1

using markers in sympy's plot

PS: The source code shows a similar approach for dictionaries with annotations, rectangles and fills (using plt.fillbetween()):

        if parent.annotations:
            for a in parent.annotations:
                ax.annotate(**a)
        if parent.rectangles:
            for r in parent.rectangles:
                rect = self.matplotlib.patches.Rectangle(**r)
                ax.add_patch(rect)
        if parent.fill:
            ax.fill_between(**parent.fill)
JohanC
  • 71,591
  • 8
  • 33
  • 66
1

(Updated using @cards suggestion (in comments) and this post.

You can add markers directly to the axis using the Matplotlib backend.

import sympy as sp
from sympy.plotting.plot import MatplotlibBackend

# plot with sympy
x = sp.symbols('x')

p0 = sp.plot(sp.sin(x),(x,-sp.pi,sp.pi),line_color='b',legend=True,show=False)

# point to be displayed
x0 = float(sp.pi/2)
y0 = float(sp.sin(sp.pi/2))

# plot with the commands from the backend (default matplotlib)
be = MatplotlibBackend(p0)
be.process_series()

plt = be.plt
plt.plot([x0,-x0],[y0,-y0],'r*',markersize=10,label="Star marker")

# Update the legend to include markers
plt.legend()

plt.show()

This solution also updates the legend with the markers.

Adding markers to Sympy plot

Donna
  • 1,390
  • 1
  • 14
  • 30
  • 1
    the 1st `show` is from `sympy` the 2nd from `matplotlib`. Better [subclass](https://stackoverflow.com/a/74245624/16462878) the backend or [smt similar](https://stackoverflow.com/a/70486636/16462878) to avoid confusion... and if possible use such approach only when needed – cards Nov 26 '22 at 22:24
  • 1
    in this case is even worst because you are using the matplotlib backend of a Python interactive shell (Jupyter, IPython,...) loaded with the build-it magic command `%matplotlib` (without it the points will not be displayed) – cards Nov 26 '22 at 22:59
  • Thank you @cards. I knew my solution only worked by accessing the built-in backend (which required `p0.show()`. I've updated my post with your much better solution for non-interactive plots. – Donna Nov 27 '22 at 04:25
  • 1
    I edited your answer, I hope you don't mind (too difficult to explain in comments). The idea of a backend is that you don't t its frontend counterpart as well:) I also fixed the [2nd link](https://stackoverflow.com/a/70486636/16462878) in the comments (the answer was partially correct) – cards Nov 27 '22 at 11:49