from __future__ import annotations
import os
from functools import lru_cache
from pathlib import Path
import gradio as gr
import pandas as pd
ROOT = Path(__file__).parent
DATA = ROOT / "data"
@lru_cache(maxsize=1)
def metrics():
import json
return json.loads((DATA / "summary_metrics.json").read_text(encoding="utf-8"))
@lru_cache(maxsize=1)
def places():
return pd.read_csv(DATA / "place_exposure.csv")
@lru_cache(maxsize=1)
def missing_geocodes():
return pd.read_csv(DATA / "missing_geocode_examples.csv")
@lru_cache(maxsize=1)
def events():
return pd.read_csv(DATA / "event_explanatory_features.csv.gz")
def state_choices():
state_values = sorted(str(value) for value in places()["state"].dropna().unique())
return ["All"] + state_values
def bucket_choices():
values = sorted(str(value) for value in missing_geocodes()["reason_bucket"].dropna().unique())
return ["All"] + values
def population_bins():
return ["All", "lt_10k", "10k_50k", "50k_250k", "250k_1m", "gte_1m", "unknown_population"]
def score_cards():
m = metrics()
assessment = m["assessment"]
population = m["population_summary"]
airport = m["airport_summary"]
missing = m["missing_geocode_summary"]
return f"""
Population signal
{assessment["population_explanation_strength_score"]}/100
log-pop/report correlation {population["log_population_log_event_count_pearson"]}
Airport confounder
{assessment["airport_confounder_strength_score"]}/100
event median {airport["event_nearest_major_airport_distance_median_miles"]} mi
Nuclear non-support
{assessment["nuclear_non_support_strength_score"]}/100
matched controls beat nuclear in the primary test
Missing geocodes
{missing["missing_geocode_rows"]}
{missing["missing_geocode_share"]:.1%} of U.S. rows
"""
def overview_markdown():
m = metrics()
assessment = m["assessment"]
stats = m["nuclear_statistical_tests"]
primary = stats["tests_by_radius"]["50"]
can_claim = "\n".join(f"- {item}" for item in assessment["what_we_can_claim"])
cannot_claim = "\n".join(f"- {item}" for item in assessment["what_we_cannot_claim"])
return f"""
# Nuclear UAP Evidence Surface
This is a public-source, reduced analytical dataset for one question: do public UFO/UAP report rows cluster around nuclear power plants after ordinary controls?
**Finding:** {assessment["plain_english_assessment"]}
Primary 50-mile test:
- Public geocoded report rows: `{stats["uap_event_count"]:,}`
- Nuclear sites: `{stats["nuclear_site_count"]}`
- Matched non-nuclear controls: `{stats["control_site_count"]}`
- Nuclear/control mean ratio: `{primary["nuclear_to_control_mean_ratio"]}`
- One-sided p-value for nuclear greater than controls: `{primary["p_value_one_sided_nuclear_greater"]}`
## What it is
- A public-source evidence surface with hashes and receipts.
- A reduced table of place/date/shape/geocode/proximity features.
- A way to inspect population, airport, and nuclear-site proximity factors.
## What it is not
- It is not proof that any report is true or false.
- It is not a claim that aircraft explain every report.
- It is not exact sighting GPS; rows use public Census place centroids.
- It is not a test of classified weapons-site activity.
## What we can claim
{can_claim}
## What we cannot claim
{cannot_claim}
"""
def filter_places(state, min_events, sort_by):
df = places().copy()
if state and state != "All":
df = df[df["state"] == state]
df = df[df["event_count"].fillna(0) >= int(min_events)]
sort_col = "event_count" if sort_by == "Report count" else "events_per_100k_population"
df = df.sort_values(sort_col, ascending=False)
cols = [
"place_name",
"state",
"population",
"event_count",
"events_per_100k_population",
"nearest_major_airport_name",
"nearest_major_airport_distance_miles",
]
return df[cols].head(200)
def filter_events(state, pop_bin, airport_radius, sample_rows):
df = events().copy()
if state and state != "All":
df = df[df["state"] == state]
if pop_bin and pop_bin != "All":
df = df[df["population_bin"] == pop_bin]
if airport_radius == "Within 10 miles":
df = df[df["within_10_miles_major_airport"] == "yes"]
elif airport_radius == "Within 25 miles":
df = df[df["within_25_miles_major_airport"] == "yes"]
elif airport_radius == "Beyond 50 miles":
df = df[df["within_50_miles_major_airport"] == "no"]
cols = [
"event_date",
"city",
"state",
"shape",
"population_bin",
"nearest_major_airport_name",
"nearest_major_airport_distance_miles",
"nearest_nuclear_distance_miles",
"nearest_control_distance_miles",
]
return df[cols].head(int(sample_rows))
def filter_missing(bucket):
df = missing_geocodes().copy()
if bucket and bucket != "All":
df = df[df["reason_bucket"] == bucket]
return df.head(200)
def download_files():
files = [
DATA / "event_explanatory_features.csv.gz",
DATA / "place_exposure.csv",
DATA / "missing_geocode_examples.csv",
DATA / "nuclear_sites.csv",
DATA / "matched_controls.csv",
DATA / "site_proximity_summary.csv",
DATA / "statistical_tests.json",
DATA / "summary_metrics.json",
DATA / "source_receipts_combined.csv",
DATA / "artifact_manifest.json",
]
return [str(path) for path in files if path.exists()]
css = """
.gradio-container { max-width: 1180px !important; }
.score-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; margin: 16px 0; }
.score-card { border: 1px solid #d7dde8; border-radius: 6px; padding: 14px; background: #fbfcff; }
.label { font-weight: 700; color: #24324a; }
.score { font-size: 30px; font-weight: 800; margin: 6px 0; }
.small { font-size: 13px; color: #536070; }
"""
with gr.Blocks(css=css, title="Nuclear UAP Evidence Surface") as demo:
gr.Markdown(overview_markdown())
gr.HTML(score_cards())
with gr.Tabs():
with gr.Tab("Explore Places"):
with gr.Row():
place_state = gr.Dropdown(choices=state_choices(), value="All", label="State")
min_events = gr.Slider(0, 100, value=10, step=1, label="Minimum report rows")
place_sort = gr.Radio(["Report count", "Per-capita rate"], value="Report count", label="Sort")
place_table = gr.Dataframe(value=filter_places("All", 10, "Report count"), interactive=False, wrap=True)
for control in (place_state, min_events, place_sort):
control.change(filter_places, [place_state, min_events, place_sort], place_table)
with gr.Tab("Explore Event Rows"):
with gr.Row():
event_state = gr.Dropdown(choices=state_choices(), value="All", label="State")
event_bin = gr.Dropdown(choices=population_bins(), value="All", label="Population bin")
airport_filter = gr.Radio(["Any", "Within 10 miles", "Within 25 miles", "Beyond 50 miles"], value="Any", label="Major airport proximity")
sample_rows = gr.Slider(25, 500, value=100, step=25, label="Rows")
event_table = gr.Dataframe(value=filter_events("All", "All", "Any", 100), interactive=False, wrap=True)
for control in (event_state, event_bin, airport_filter, sample_rows):
control.change(filter_events, [event_state, event_bin, airport_filter, sample_rows], event_table)
with gr.Tab("Missing Geocodes"):
bucket = gr.Dropdown(choices=bucket_choices(), value="All", label="Gap bucket")
missing_table = gr.Dataframe(value=filter_missing("All"), interactive=False, wrap=True)
bucket.change(filter_missing, bucket, missing_table)
with gr.Tab("Downloads & Receipts"):
gr.Markdown("Download the reduced analytical tables, source receipts, hashes, and manifest. These exports do not include raw witness summaries.")
gr.File(value=download_files(), file_count="multiple", label="Dataset files")
if __name__ == "__main__":
server_port = int(os.environ.get("GRADIO_SERVER_PORT", "7860"))
server_name = os.environ.get("GRADIO_SERVER_NAME") or None
demo.launch(server_name=server_name, server_port=server_port)