@@ -797,27 +797,109 @@ PYBIND11_MODULE(setup, module)
797797 },
798798 py::arg (" representation_type" )
799799 )
800-
801800 .def (
802801 " plot_system" ,
803- [](const Setup& self) {
804- py::module_ pv = py::module_::import (" pyvista" );
805- py::object plotter = pv.attr (" Plotter" )();
806-
807- py::cast (self.source ).attr (" add_to_scene" )(plotter);
802+ [](
803+ const Setup& self,
804+ const bool show_axes,
805+ const bool show_colorbar,
806+ const bool show_detector_cone,
807+ const bool show_unit_sphere,
808+ const double figure_size
809+ ) {
810+ py::module_ pyplot = py::module_::import (" matplotlib.pyplot" );
811+
812+ py::object figure = pyplot.attr (" figure" )(
813+ py::arg (" figsize" ) = py::make_tuple (figure_size, figure_size)
814+ );
815+
816+ py::object ax = figure.attr (" add_subplot" )(
817+ py::int_ (111 ),
818+ py::arg (" projection" ) = py::str (" 3d" )
819+ );
820+
821+ py::cast (self.source ).attr (" _add_to_ax" )(
822+ ax,
823+ py::arg (" show_axes" ) = show_axes
824+ );
808825
809826 self.scatterer ->init (self.source );
810827
811- py::cast (self.scatterer ).attr (" add_to_scene" )(plotter);
828+ py::cast (self.scatterer ).attr (" _add_to_ax" )(
829+ ax,
830+ py::arg (" show_axes" ) = show_axes,
831+ py::arg (" show_unit_sphere" ) = show_unit_sphere
832+ );
812833
813834 if (self.detector ) {
814835 self.detector ->medium ->initialize (self.source ->wavelength );
815836 self.detector ->initialize_mesh (self.scatterer );
816- py::cast (self.detector ).attr (" add_to_scene" )(plotter);
837+
838+ py::object detector_object = py::cast (self.detector );
839+
840+ if (py::hasattr (detector_object, " _add_to_ax" )) {
841+ py::dict detector_kwargs;
842+ detector_kwargs[" show_axes" ] = py::bool_ (show_axes);
843+
844+ if (py::hasattr (detector_object, " mode_field" )) {
845+ detector_kwargs[" show_colorbar" ] = py::bool_ (show_colorbar);
846+ detector_kwargs[" show_cone" ] = py::bool_ (show_detector_cone);
847+ }
848+ else {
849+ detector_kwargs[" show_cone" ] = py::bool_ (show_detector_cone);
850+ }
851+
852+ detector_object.attr (" _add_to_ax" )(ax, **detector_kwargs);
853+ }
817854 }
818855
819- plotter.attr (" show" )();
820- }
856+ figure.attr (" tight_layout" )();
857+ pyplot.attr (" show" )();
858+
859+ return figure;
860+ },
861+ py::arg (" show_axes" ) = false ,
862+ py::arg (" show_colorbar" ) = true ,
863+ py::arg (" show_detector_cone" ) = true ,
864+ py::arg (" show_unit_sphere" ) = true ,
865+ py::arg (" figure_size" ) = 7.0 ,
866+ R"pbdoc(
867+ Plot the full single-scatterer optical system using Matplotlib.
868+
869+ The plot includes the incident source, the scatterer, and the detector
870+ geometry when a detector is defined. The source is drawn using its
871+ propagation and polarization vectors. The scatterer is drawn using its
872+ normalized Matplotlib representation. The detector is initialized for
873+ the current scatterer and source before being drawn.
874+
875+ Parameters
876+ ----------
877+ show_axes : bool, optional
878+ If ``True``, display Cartesian axis labels, ticks, and panes.
879+ If ``False``, hide the Matplotlib 3D axis frame after setting
880+ the plotting limits.
881+ show_colorbar : bool, optional
882+ If ``True``, show the detector colorbar when the detector supports
883+ field-colored plotting, such as ``CoherentMode``.
884+ show_detector_cone : bool, optional
885+ If ``True``, draw the detector collection cone when supported.
886+ show_unit_sphere : bool, optional
887+ If ``True``, draw the transparent unit sphere for scatterer
888+ angular reference when supported.
889+ figure_size : float, optional
890+ Width and height of the Matplotlib figure in inches.
891+
892+ Returns
893+ -------
894+ matplotlib.figure.Figure
895+ Matplotlib figure containing the system visualization.
896+
897+ Notes
898+ -----
899+ This method replaces the previous PyVista-based visualization path.
900+ It uses the private ``_add_to_ax`` helpers exposed by source,
901+ scatterer, and detector bindings.
902+ )pbdoc"
821903 )
822904;
823905
0 commit comments