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