Skip to content

Commit af0850d

Browse files
committed
Merge branch 'kk/new-plots'
2 parents 987f6c6 + 320ebc3 commit af0850d

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

src/adam_impact_study/analysis/plots.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)