@@ -3029,3 +3029,147 @@ def plot_discovered_by_diameter_impact_period(
30293029 plt .tight_layout (rect = [0 , 0 , 0.85 , 1 ])
30303030
30313031 return fig , ax
3032+
3033+
3034+ def plot_observed_vs_unobserved_elements (
3035+ summary : ImpactorResultSummary ,
3036+ diameter : float = 1 ,
3037+ ) -> Tuple [plt .Figure , plt .Axes ]:
3038+ """
3039+ Plot the distribution of objects in orbital element space with three categories:
3040+ - Discovered (blue)
3041+ - Observed but not discovered (yellow)
3042+ - Unobserved (red)
3043+
3044+ Parameters
3045+ ----------
3046+ summary : ImpactorResultSummary
3047+ The summary of impact study results.
3048+ diameter : float, optional
3049+ The diameter [km] to filter the results by, by default 1.
3050+
3051+ Returns
3052+ -------
3053+ Tuple[plt.Figure, plt.Axes]
3054+ The figure and axes objects for the plot.
3055+ """
3056+ # Filter to only include the given diameter
3057+ summary = summary .apply_mask (pc .equal (summary .orbit .diameter , diameter ))
3058+
3059+ if len (summary ) == 0 :
3060+ print (f"No data found for diameter { diameter } km." )
3061+ return
3062+
3063+ orbits_at_diameter = summary .apply_mask (pc .equal (summary .orbit .diameter , diameter ))
3064+ print ("num orbits:" , len (orbits_at_diameter ))
3065+
3066+ # Get Keplerian coordinates
3067+ kep_coordinates = summary .orbit .coordinates .to_keplerian ()
3068+ a_au = kep_coordinates .a .to_numpy (zero_copy_only = False )
3069+ i_deg = kep_coordinates .i .to_numpy (zero_copy_only = False )
3070+ e = kep_coordinates .e .to_numpy (zero_copy_only = False )
3071+
3072+ #print discovered objedts by those with a non null discovery time
3073+ discovered_objects = summary .apply_mask (pc .invert (pc .is_null (summary .discovery_time .days )))
3074+ print (discovered_objects )
3075+ #do the same for undiscovered by the null discovery time
3076+ undiscovered_objects = summary .apply_mask (pc .is_null (summary .discovery_time .days ))
3077+ print (undiscovered_objects )
3078+
3079+ #print the object names that are observed but not discovered
3080+
3081+ assert len (orbits_discovered ) + len (orbits_observed_not_discovered ) + len (orbits_unobserved ) == len (orbits_at_diameter )
3082+ # Create the plots
3083+ fig , axes = plt .subplots (1 , 2 , dpi = 200 , figsize = (18 , 7 ))
3084+
3085+ # --- Plot a vs i ---
3086+ # Plot discovered (blue) first
3087+ axes [0 ].scatter (
3088+ a_au [discovered_mask ],
3089+ i_deg [discovered_mask ],
3090+ c = 'blue' ,
3091+ alpha = 0.6 ,
3092+ label = 'Discovered' ,
3093+ s = 20
3094+ )
3095+ # Plot observed but not discovered (yellow) second
3096+ axes [0 ].scatter (
3097+ a_au [observed_not_discovered_mask ],
3098+ i_deg [observed_not_discovered_mask ],
3099+ c = 'yellow' ,
3100+ alpha = 0.6 ,
3101+ label = 'Observed (Not Discovered)' ,
3102+ s = 20
3103+ )
3104+ # Plot unobserved (red) last
3105+ axes [0 ].scatter (
3106+ a_au [unobserved_mask ],
3107+ i_deg [unobserved_mask ],
3108+ c = 'red' ,
3109+ alpha = 0.6 ,
3110+ label = 'Unobserved' ,
3111+ s = 20
3112+ )
3113+
3114+ axes [0 ].set_xlabel ("Semimajor Axis (a) [AU]" )
3115+ axes [0 ].set_ylabel ("Inclination (i) [deg]" )
3116+ axes [0 ].set_title ("a vs i" )
3117+ axes [0 ].legend ()
3118+ axes [0 ].grid (True , alpha = 0.3 )
3119+
3120+ # --- Plot a vs e ---
3121+ # Plot discovered (blue) first
3122+ axes [1 ].scatter (
3123+ a_au [discovered_mask ],
3124+ e [discovered_mask ],
3125+ c = 'blue' ,
3126+ alpha = 0.6 ,
3127+ label = 'Discovered' ,
3128+ s = 20
3129+ )
3130+ # Plot observed but not discovered (yellow) second
3131+ axes [1 ].scatter (
3132+ a_au [observed_not_discovered_mask ],
3133+ e [observed_not_discovered_mask ],
3134+ c = 'yellow' ,
3135+ alpha = 0.6 ,
3136+ label = 'Observed (Not Discovered)' ,
3137+ s = 20
3138+ )
3139+ # Plot unobserved (red) last
3140+ axes [1 ].scatter (
3141+ a_au [unobserved_mask ],
3142+ e [unobserved_mask ],
3143+ c = 'red' ,
3144+ alpha = 0.6 ,
3145+ label = 'Unobserved' ,
3146+ s = 20
3147+ )
3148+
3149+ axes [1 ].set_xlabel ("Semimajor Axis (a) [AU]" )
3150+ axes [1 ].set_ylabel ("Eccentricity (e)" )
3151+ axes [1 ].set_title ("a vs e" )
3152+ axes [1 ].legend ()
3153+ axes [1 ].grid (True , alpha = 0.3 )
3154+
3155+ # Add overall title with statistics
3156+ n_total = len (observed_mask )
3157+ n_discovered = discovered_mask .sum ()
3158+ n_observed_not_discovered = observed_not_discovered_mask .sum ()
3159+ n_unobserved = unobserved_mask .sum ()
3160+ assert n_total == n_discovered + n_observed_not_discovered + n_unobserved
3161+
3162+ percent_discovered = (n_discovered / n_total ) * 100
3163+ percent_observed_not_discovered = (n_observed_not_discovered / n_total ) * 100
3164+ percent_unobserved = (n_unobserved / n_total ) * 100
3165+
3166+ fig .suptitle (
3167+ f"Distribution of Objects (Diameter: { diameter } km)\n "
3168+ f"Total Objects: { n_total } , "
3169+ f"Discovered: { n_discovered } ({ percent_discovered :.1f} %), "
3170+ f"Observed Not Discovered: { n_observed_not_discovered } ({ percent_observed_not_discovered :.1f} %), "
3171+ f"Unobserved: { n_unobserved } ({ percent_unobserved :.1f} %)"
3172+ )
3173+
3174+ plt .tight_layout (rect = [0 , 0.03 , 1 , 0.95 ])
3175+ return fig , axes
0 commit comments