Davide-sd / sympy-plot-backends

An improved plotting module for SymPy
BSD 3-Clause "New" or "Revised" License
42 stars 9 forks source link

Passing 3d keyword arguments to `matplotlib` backend #11

Closed James-G-Hill closed 1 year ago

James-G-Hill commented 1 year ago

The most recent version of matplotlib has new features that improve the 3d plot functionality:

https://matplotlib.org/3.6.0/users/prev_whats_new/whats_new_3.6.0.html#d-axes-improvements

Is there any way to pass these new arguments such as focal_length or roll to the 3d plots in this package yet? I haven't been able to figure out to do it.

Most specifically, I have also tried to set the aspect for a 3d plot to equal now that this functionality is working, but I can't seem to figure out how to do this. Is there a way to get the axes after creating a plot such as plot3d_spherical?

Davide-sd commented 1 year ago

I've just released a new version.

Here is an example:

from sympy import *
from spb import *
var("theta, phi")
p = plot3d_spherical(
    1, (theta, 0, 0.5 * pi), (phi, 0, 1.8 * pi), aspect="equal",
    camera=dict(elev=15, azim=-30, roll=10)
)

index

Is there a way to get the axes after creating a plot such as plot3d_spherical?

Continuing with the previous example, you can retrieve the figure and axis with the following plot attributes:

fig = p.fig
ax = p.ax

If your plot is displaying a colorbar, you can access and modify it by indexing fig.axes. In particular:

Is there any way to pass these new arguments such as focal_length or roll to the 3d plots in this package yet? I haven't been able to figure out to do it.

Now that you have ax, you can further modify the plot with standard matplotlib commands:

ax.set_proj_type('persp', 0.2)
fig

index

Note that I'm probably not going to add keyword arguments to set the projection. The backends are meant to do the heavy lifting (lambdify the expressions, discretize the ranges, apply colors). Everything else can be achieved by retrieving the figure (and axis) objects.

James-G-Hill commented 1 year ago

I've tested and it works great. Thanks!

Also, the demo on how to get the ax out of the plotting object is useful. Maybe I tried it and it didn't work with the older version of matplotlib I had installed until yesterday (I kept receiving errors with set_box_aspect which was widely recommended as a solution to the 3d axes scaling problem). After that I kept trying to use fig.axes or matplotlib.axes and not getting anywhere.

James-G-Hill commented 1 year ago

Also, after installing the new version, a chart I previously created no longer displays correctly:

z = Symbol('z', complex=True)

w = 1 / z

plot_complex(
    w.subs(z, z),
    (z, -1+I*-1, 1+I*1),
    threed=True,
    use_cm=True
)

This should produce a complex plot with a rainbow-colored 'floor' covering a square area over the real / imaginary double axis from -1+I-1 to 1+I1 but you will see it doesn't show the correct real or imaginary axis lengths. The range no longer seems to work correctly. complex_plot

I've tried replacing w.subs(z, z) with 1 / z but that's not the cause of the problem. It worked until immediately before I updated my sympy-plot-backend version.

Edit: checking again, it's possible that the expression is calculated correctly within the boundaries set, but the boundaries of the calculated area and the boundaries of the chart don't agree; presumably I have to put a limitation on the z axis because aspect='equal is now working whereas previously it didn't.

Note: adding aspect='auto' as a parameter returned the chart to as I expected. I thought auto was the default but must have been wrong.

James-G-Hill commented 1 year ago

Sorry, as to the above comment, I'm not sure whether aspect should be auto or equal as default: I don't think the documentation is 100% clear but auto is first in the list under aspect in the **kwargs section of the documentation:

https://matplotlib.org/stable/api/_as_gen/mpl_toolkits.mplot3d.axes3d.Axes3D.html

James-G-Hill commented 1 year ago

Hmm, think you need to ignore the above; the documentation states clearly for the complex plot there would aspect='equal' as default:

https://sympy-plot-backends.readthedocs.io/en/latest/modules/ccomplex.html#spb.ccomplex.complex.plot_complex

Davide-sd commented 1 year ago

I've just released a new version in which I improved the logic behind aspect. Now it is set to auto for 3D complex-related plots.