1313
1414from .bopdmd import BOPDMD
1515from .hankeldmd import HankelDMD
16+ from .havok import HAVOK
1617
1718mpl .rcParams ["figure.max_open_warning" ] = 0
1819
@@ -539,38 +540,38 @@ def plot_summary(
539540 order = "C" ,
540541 figsize = (12 , 8 ),
541542 dpi = 200 ,
543+ tight_layout_kwargs = None ,
542544 main_colors = ("r" , "b" , "g" , "gray" ),
543- max_plot = 50 ,
544- max_marker_size = 10 ,
545- vmax_scale = 0.9 ,
545+ mode_color = "k" ,
546546 mode_cmap = "bwr" ,
547- mode_color = "tab:orange" ,
548547 dynamics_color = "tab:blue" ,
548+ plot_semilogy = False ,
549+ remove_cmap_ticks = False ,
549550):
550551 """
551- Generate a 3x3 summarizing plot that contains the following components:
552+ Generate a 3 x 3 summarizing plot that contains the following components:
552553 - the singular value spectrum of the data
553- - the discrete-time and continuous-time dmd eigenvalues
554- - the three dmd modes specified by the index_modes parameter
554+ - the discrete-time and continuous-time DMD eigenvalues
555+ - the three DMD modes specified by the ` index_modes` parameter
555556 - the dynamics corresponding with each plotted mode
556557 Eigenvalues, modes, and dynamics are ordered according to the magnitude of
557558 their corresponding amplitude value. Singular values and eigenvalues that
558559 are associated with plotted modes and dynamics are also highlighted.
559560
560561 :param dmd: DMD instance.
561562 :type dmd: pydmd.DMDBase
562- :param continuous: whether or not the eigenvalues of the given DMD instance
563+ :param continuous: Whether or not the eigenvalues of the given DMD instance
563564 are continuous-time. If `False`, the eigenvalues are assumed to be the
564565 discrete-time eigenvalues. If `True`, the eigenvalues are taken to be
565- the continuous-time eigenvalues. Note that `BOPDMD` models always
566- compute continuous-time eigenvalues .
566+ the continuous-time eigenvalues. Note that `continuous` is
567+ automatically assumed to be true if a `BOPDMD` model is given .
567568 :type continuous: bool
568569 :param snapshots_shape: Shape of the snapshots. If not provided, the shape
569570 of the snapshots and modes is assumed to be the flattened space dim of
570571 the snapshot data.
571572 :type snapshots_shape: tuple(int, int)
572- :param index_modes: The indices of the modes to plot. By default, the first
573- three leading modes are plotted.
573+ :param index_modes: A list of the indices of the modes to plot. By default,
574+ the first three leading modes are plotted.
574575 :type index_modes: list
575576 :param filename: If specified, the plot is saved at `filename`.
576577 :type filename: str
@@ -588,16 +589,44 @@ def plot_summary(
588589 "C" is used by default.
589590 :type order: {"C", "F", "A"}
590591 :param figsize: Tuple in inches defining the figure size.
591- Deafult is (12, 8).
592592 :type figsize: tuple(int, int)
593+ :param dpi: Figure resolution.
594+ :type dpi: int
595+ :param tight_layout_kwargs: Optional dictionary of
596+ `matplotlib.pyplot.tight_layout()` parameters.
597+ :type tight_layout_kwargs: dict
593598 :param main_colors: Tuple of strings defining the colors used to denote
594599 eigenvalue, mode, dynamics associations. The first three colors are
595600 used to highlight the singular values and eigenvalues associated with
596601 the plotted modes and dynamics, while the fourth color is used to
597- denote all other singular values and eigenvalues. Default colors are
598- ("r","b","g","gray").
599- :type main_colors: tuple(str,str,str,str)
602+ denote all other values.
603+ :type main_colors: tuple(str, str, str, str)
604+ :param mode_color: Color used to plot the modes, if modes are 1D.
605+ :type mode_color: str
606+ :param mode_cmap: Colormap used to plot the modes, if modes are 2D.
607+ :type mode_cmap: str
608+ :param dynamics_color: Color used to plot the dynamics.
609+ :type dynamics_color: str
610+ :param plot_semilogy: Whether or not to plot the singular values on a
611+ semilogy plot. If `True`, a semilogy plot is used.
612+ :type plot_semilogy: bool
613+ :param remove_cmap_ticks: Whether or not to include the ticks on 2D mode
614+ plots. If `True`, ticks are removed from all 2D mode plots.
615+ :type remove_cmap_ticks: bool
600616 """
617+ # Other potential parameters to consider:
618+ # - ylims on the dynamics plots
619+ # - fontsizes
620+
621+ # All other potentially customizable values.
622+ # For now, we take them to be constants.
623+ max_plot = 50
624+ sval_ms = 8 # singular value marker size
625+ max_eig_ms = 10 # marker size of the most prominent eigenvalue
626+ vmax_scale = 0.9
627+
628+ if isinstance (dmd , HAVOK ):
629+ raise ValueError ("You should use HAVOK.plot_summary() instead." )
601630
602631 # Check that the DMD instance has been fitted.
603632 if dmd .modes is None :
@@ -629,7 +658,7 @@ def plot_summary(
629658 # Indices cannot go past the total number of available or plottable modes.
630659 elif np .any (np .array (index_modes ) >= min (len (dmd .eigs ), max_plot )):
631660 raise ValueError (
632- "Cannot view past mode {}." . format ( min (len (dmd .eigs ), max_plot ))
661+ f "Cannot view past mode { min (len (dmd .eigs ), max_plot )} ."
633662 )
634663
635664 # Sort eigenvalues, modes, and dynamics according to amplitude magnitude.
@@ -641,6 +670,7 @@ def plot_summary(
641670 # Get time step information for eigenvalue conversions.
642671 if isinstance (dmd , BOPDMD ):
643672 # BOPDMD models store time in the time attribute.
673+ time = dmd .time
644674 dt = dmd .time [1 ] - dmd .time [0 ]
645675 if not np .allclose (dmd .time [1 :] - dmd .time [:- 1 ], dt ):
646676 print (
@@ -651,12 +681,13 @@ def plot_summary(
651681 else :
652682 disc_eigs = np .exp (lead_eigs * dt )
653683 cont_eigs = lead_eigs
654- # For all other DMD instances, access dt using the time dictionaries.
655684 else :
656685 try :
686+ time = dmd .original_timesteps
657687 dt = dmd .original_time ["dt" ]
658688 except AttributeError :
659689 warnings .warn ("No time step information available. Using dt = 1." )
690+ time = np .arange (dmd .snapshots .shape [- 1 ])
660691 dt = 1.0
661692
662693 if continuous :
@@ -682,33 +713,35 @@ def plot_summary(
682713 3 , 3 , figsize = figsize , dpi = dpi
683714 )
684715
685- # Plot 1: Plot the singular value spectrum.
716+ # PLOT 1: Plot the singular value spectrum.
686717 s_var_plot = s_var [:max_plot ]
687718 eig_axes [0 ].set_title ("Singular Values" )
688719 eig_axes [0 ].set_ylabel ("% variance" )
689720 t = np .arange (len (s_var_plot )) + 1
690- eig_axes [0 ].plot (t , s_var_plot , "o" , c = main_colors [- 1 ], ms = 8 , mec = "k" )
721+ eig_axes [0 ].plot (t , s_var_plot , "o" , c = main_colors [- 1 ], ms = sval_ms , mec = "k" )
691722 for i , idx in enumerate (index_modes ):
692723 eig_axes [0 ].plot (
693- t [idx ], s_var_plot [idx ], "o" , c = main_colors [i ], ms = 8 , mec = "k"
724+ t [idx ], s_var_plot [idx ], "o" , c = main_colors [i ], ms = sval_ms , mec = "k"
694725 )
726+ if plot_semilogy :
727+ eig_axes [0 ].semilogy ()
695728
696- # Plots 2-3: Plot the eigenvalues (discrete-time and continuous-time).
729+ # PLOTS 2-3: Plot the eigenvalues (discrete-time and continuous-time).
697730 # Scale marker sizes to reflect the amount of variance captured.
698- ms_vals = max_marker_size * np .sqrt (s_var / s_var [0 ])
731+ ms_vals = max_eig_ms * np .sqrt (s_var / s_var [0 ])
699732 for i , (ax , eigs ) in enumerate (zip (eig_axes [1 :], [disc_eigs , cont_eigs ])):
700733 # Plot the complex plane axes.
701- ax .axvline (x = 0 , c = "k" , lw = 1 )
702- ax .axhline (y = 0 , c = "k" , lw = 1 )
734+ ax .axvline (x = 0 , c = "k" )
735+ ax .axhline (y = 0 , c = "k" )
703736 ax .axis ("equal" )
704- # Plot 2: Plot the discrete-time eigenvalues with the unit circle.
737+ # PLOT 2: Plot the discrete-time eigenvalues with the unit circle.
705738 if i == 0 :
706739 ax .set_title ("Discrete-time Eigenvalues" )
707740 t = np .linspace (0 , 2 * np .pi , 100 )
708741 ax .plot (np .cos (t ), np .sin (t ), c = "tab:blue" , ls = "--" )
709742 ax .set_xlabel ("Real" )
710743 ax .set_ylabel ("Imag" )
711- # Plot 3: Plot the continuous-time eigenvalues
744+ # PLOT 3: Plot the continuous-time eigenvalues.
712745 else :
713746 ax .set_title ("Continuous-time Eigenvalues" )
714747 ax .set_xlabel ("Imag" )
@@ -724,10 +757,10 @@ def plot_summary(
724757 else :
725758 ax .plot (eig .imag , eig .real , "o" , c = color , ms = ms_vals [idx ])
726759
727- # Plots 4-6: Plot the DMD modes.
760+ # PLOTS 4-6: Plot the DMD modes.
728761 for i , idx in enumerate (index_modes ):
729762 ax = mode_axes [i ]
730- ax .set_title (f"Mode { idx + 1 } " , c = main_colors [i ], fontsize = 15 )
763+ ax .set_title (f"Mode { idx + 1 } " , c = main_colors [i ])
731764 # Plot modes in 1D.
732765 if len (snapshots_shape ) == 1 :
733766 ax .plot (lead_modes [:, idx ].real , c = mode_color )
@@ -741,16 +774,21 @@ def plot_summary(
741774 divider = make_axes_locatable (ax )
742775 cax = divider .append_axes ("right" , size = "3%" , pad = 0.05 )
743776 fig .colorbar (im , cax = cax )
777+ if remove_cmap_ticks :
778+ ax .set_xticks ([])
779+ ax .set_yticks ([])
744780
745- # Plots 7-9: Plot the DMD mode dynamics.
781+ # PLOTS 7-9: Plot the DMD mode dynamics.
746782 for i , idx in enumerate (index_modes ):
747783 ax = dynamics_axes [i ]
748- ax .set_title ("Mode Dynamics" , c = main_colors [i ], fontsize = 12 )
749- ax .plot (lead_dynamics [idx ].real , c = dynamics_color )
784+ ax .set_title ("Mode Dynamics" , c = main_colors [i ])
785+ ax .plot (time , lead_dynamics [idx ].real , c = dynamics_color )
750786 ax .set_xlabel ("Time" )
751787
752788 # Padding between elements.
753- plt .tight_layout ()
789+ if tight_layout_kwargs is None :
790+ tight_layout_kwargs = {}
791+ plt .tight_layout (** tight_layout_kwargs )
754792
755793 # Save plot if filename is provided.
756794 if filename :
0 commit comments