from __future__ import annotations import html 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 public_infrastructure_sites(): path = DATA / "public_infrastructure_sites.csv" if not path.exists(): return pd.DataFrame() return pd.read_csv(path) @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 fmt_int(value): try: return f"{int(float(value)):,}" except (TypeError, ValueError): return str(value) def fmt_float(value, digits=2): try: return f"{float(value):,.{digits}f}" except (TypeError, ValueError): return str(value) def pct(value, digits=1): try: return f"{float(value) * 100:.{digits}f}%" except (TypeError, ValueError): return str(value) def bar_row(label, value, max_value, color_class, note=""): width = 0 if max_value == 0 else max(2, min(100, (float(value) / float(max_value)) * 100)) safe_label = html.escape(str(label)) safe_note = html.escape(str(note)) return f""" """ def share_bar(label, value, color_class, note=""): safe_label = html.escape(str(label)) safe_note = html.escape(str(note)) try: width = max(2, min(100, float(value) * 100)) except (TypeError, ValueError): width = 0 return f""" """ def visual_story_html(): m = metrics() assessment = m["assessment"] stats = m["nuclear_statistical_tests"] primary = stats["tests_by_radius"]["50"] population = m["population_summary"] airport = m["airport_summary"] missing = m["missing_geocode_summary"] nuclear_mean = float(primary["nuclear_mean_reports_per_site"]) control_mean = float(primary["control_mean_reports_per_site"]) comparison_max = max(nuclear_mean, control_mean) nuclear_bars = ( bar_row("Nuclear power-plant sites", nuclear_mean, comparison_max, "fill-nuclear", "mean reports per site within 50 miles") + bar_row("Matched non-nuclear power controls", control_mean, comparison_max, "fill-control", "mean reports per site within 50 miles") ) bin_labels = { "lt_10k": "Places under 10k people", "10k_50k": "10k to 50k people", "50k_250k": "50k to 250k people", "250k_1m": "250k to 1M people", "gte_1m": "1M+ people", "unknown_population": "Unknown population", } population_bins = population["population_bin_event_distribution"] pop_rows = [] for key in ["lt_10k", "10k_50k", "50k_250k", "250k_1m", "gte_1m", "unknown_population"]: value = population_bins.get(key, {}).get("event_share", 0) pop_rows.append(share_bar(bin_labels[key], value, "fill-population", f"{fmt_int(population_bins.get(key, {}).get('event_count', 0))} rows")) population_bars = "".join(pop_rows) airport_rows = [] for radius in (10, 25, 50): event_key = f"event_share_within_{radius}_miles_major_airport" pop_key = f"population_weighted_share_within_{radius}_miles_major_airport" airport_rows.append(f"""
Within {radius} miles of a major scheduled airport
{share_bar("Public report rows", airport[event_key], "fill-airport", "event-place centroids")} {share_bar("Population-weighted places", airport[pop_key], "fill-baseline", "baseline geography")}
""") airport_bars = "".join(airport_rows) missing_max = max(missing["reason_bucket_counts"].values()) if missing.get("reason_bucket_counts") else 1 missing_bars = "".join( bar_row(label.replace("_", " ").title(), count, missing_max, "fill-gap", "rows needing recovery") for label, count in missing.get("reason_bucket_counts", {}).items() ) return f"""
Public-source evidence surface

The nuclear-specific UAP proximity claim does not hold in this dataset

We tested public geocoded report rows against nuclear power-plant sites and matched non-nuclear power-plant controls. The stronger visible pattern is reporting geography: where people live, report, and see the sky.

QuestionDo reports cluster near nuclear plants?
ControlCompare with similar non-nuclear power sites
ResultNo nuclear-specific lift observed

Matched controls are the comparison anchor

The 50-mile test compares nuclear power-plant sites with matched non-nuclear power-plant controls. If the nuclear claim were visible here, the nuclear bar would be clearly higher.

{nuclear_bars}
Nuclear/control ratio: {primary["nuclear_to_control_mean_ratio"]}. One-sided p-value for nuclear greater than controls: {primary["p_value_one_sided_nuclear_greater"]}.

Population is the first pattern to notice

Report rows are not evenly distributed across places. Place population and report count move together on a log scale.

{population["log_population_log_event_count_pearson"]}
log population vs. log report-count correlation
{fmt_int(population["matched_population_event_count"])} of {fmt_int(population["event_count"])} rows matched to Census population places.

Airport proximity mostly follows people

Major airports are close to many reports, but they are also close to much of the U.S. population.

{airport["event_nearest_major_airport_distance_median_miles"]} mi
median report-row distance to a major scheduled airport
Population-weighted Census-place median: {airport["population_weighted_nearest_major_airport_distance_median_miles"]} mi.

Reports span place sizes, with large places carrying much of the volume

These bars show the share of report rows by Census-place population bin. The table tabs remain available for exact rows.

{population_bars}

Airport proximity should be read against the population baseline

If public report rows and the population baseline are close, airport proximity is a confounder rather than a standalone explanation.

{airport_bars}

Uncertainty is visible, not hidden

{fmt_int(missing["missing_geocode_rows"])} U.S. rows did not resolve to Census place centroids. They are excluded from spatial tests until recovered by a public geocoder path.

{missing_bars}

How to read the evidence

SupportedPopulation/reporting geography is a strong observable factor.
ConfounderAirport proximity is measurable, but close to the population baseline.
Not supported hereA nuclear-specific proximity lift after matched power-plant controls.
Still outside scopeClassified activity, exact witness GPS, and case-level truth claims.
""" 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 public_infrastructure_html(): layer_stats = metrics().get("public_infrastructure_layers") or {} reports = layer_stats.get("layer_reports") or {} if not reports: return "" cards = [] labels = { "public_military_installation": "Public military installations", "public_nuclear_security_enterprise": "Public NNSA / nuclear-security-enterprise sites", "public_strategic_delivery_installation": "Public strategic-delivery subset", } for key in [ "public_military_installation", "public_nuclear_security_enterprise", "public_strategic_delivery_installation", ]: report = reports.get(key) or {} if not report: continue near_50 = (report.get("near_any_counts") or {}).get("50", 0) share_50 = report.get("event_share_within_50_miles", 0) cards.append( f"""
{html.escape(labels.get(key, key))}
{fmt_int(report.get("site_count", 0))} sites
{fmt_int(near_50)} public report rows within 50 miles ({pct(share_50)})
""" ) can_claim = "".join(f"
  • {html.escape(str(item))}
  • " for item in layer_stats.get("what_we_can_claim", [])) cannot_claim = "".join(f"
  • {html.escape(str(item))}
  • " for item in layer_stats.get("what_we_cannot_claim", [])) return f"""
    Added public infrastructure layer

    Military and nuclear-security infrastructure are descriptive context, not a causation test

    This layer adds official NTAD military installations and public NNSA/nuclear-security-enterprise anchors, including an NNSS public coordinate receipt. It helps people inspect proximity without implying classified activity, weapons storage, or attraction.

    {''.join(cards)}
    What this layer can say
      {can_claim}
    What this layer cannot say
      {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 filter_public_infrastructure(layer): df = public_infrastructure_sites().copy() if df.empty: return df if layer and layer != "All": df = df[df["site_layer"] == layer] cols = [ "site_name", "site_layer", "site_kind", "state", "coordinate_basis", "source_name", "source_confidence", "public_role", ] return df[[col for col in cols if col in df.columns]].head(300) 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 / "public_infrastructure_sites.csv", DATA / "public_infrastructure_site_summary.csv", DATA / "event_public_infrastructure_proximity.csv.gz", 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 = """ html, body, #root, .app, gradio-app { background: #f3f6fa !important; color: #18232f !important; } html body p, html body a, html body [role="link"] { color: #294860 !important; } .gradio-container { max-width: 1180px !important; margin-left: auto !important; margin-right: auto !important; color-scheme: light; background: #f3f6fa !important; color: #18232f !important; --body-background-fill: #f3f6fa; --body-text-color: #18232f; --block-background-fill: #ffffff; --block-border-color: #d7dde8; --block-label-text-color: #24324a; --input-background-fill: #ffffff; --input-border-color: #c8d2de; --button-secondary-background-fill: #ffffff; --button-secondary-text-color: #18232f; } .gradio-container, .gradio-container h1, .gradio-container h2, .gradio-container h3, .gradio-container h4, .gradio-container p, .gradio-container li, .gradio-container label, .gradio-container td, .gradio-container th, .gradio-container input, .gradio-container textarea, .gradio-container select { color: #18232f !important; } .gradio-container input, .gradio-container textarea, .gradio-container select, .gradio-container [data-testid="dropdown"], .gradio-container [data-testid="dropdown"] *, .gradio-container .dropdown, .gradio-container .dropdown *, .gradio-container .select-wrap, .gradio-container .select-wrap *, .gradio-container .wrap-inner, .gradio-container .wrap-inner *, .gradio-container .secondary-wrap, .gradio-container .secondary-wrap *, .gradio-container [role="listbox"], .gradio-container [role="listbox"] *, .gradio-container [role="option"], .gradio-container [role="option"] { color: #18232f !important; background-color: #ffffff !important; opacity: 1 !important; } .gradio-container [role="option"]:hover, .gradio-container [role="option"][aria-selected="true"], .gradio-container .option:hover, .gradio-container .item:hover { color: #0f2533 !important; background-color: #e7f1f7 !important; } .gradio-container .prose, .gradio-container .markdown, .gradio-container [data-testid="markdown"], .gradio-container [data-testid="block-label"], .gradio-container .dataframe, .gradio-container .wrap { color: #18232f !important; background: transparent; } .gradio-container button, .gradio-container [role="tab"], .gradio-container [role="button"] { color: #18232f !important; } .gradio-container a, .gradio-container footer, .gradio-container footer *, .gradio-container [data-testid="built-with"], .gradio-container [data-testid="built-with"] * { color: #294860 !important; } .gradio-container footer { background: #f3f6fa !important; } .gradio-container table, .gradio-container thead, .gradio-container tbody, .gradio-container tr, .gradio-container td, .gradio-container th { background-color: #ffffff !important; } .gradio-container code { color: #18232f !important; background: #eef2f6 !important; border: 1px solid #d7dde8; } .hero-panel { border: 1px solid #d7dde8; border-radius: 6px; padding: 24px; background: #f7fbfd; margin-bottom: 18px; } .eyebrow { color: #48606f; font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; } .hero-panel h1 { font-size: 32px; line-height: 1.14; margin: 8px 0 10px; color: #18232f; } .lede { font-size: 17px; max-width: 860px; color: #344554; } .claim-path { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px; margin-top: 18px; } .claim-path div { border-left: 4px solid #12719e; background: white; padding: 12px; } .claim-path span { display: block; color: #5b6975; font-size: 13px; font-weight: 700; } .claim-path strong { display: block; margin-top: 4px; color: #1d2b36; } .score-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; margin: 16px 0; } .score-card, .viz-card, .claim-box { border: 1px solid #d7dde8; border-radius: 6px; padding: 16px; background: #fff; } .label { font-weight: 700; color: #24324a; } .score { font-size: 30px; font-weight: 800; margin: 6px 0; } .small, .bar-note, .big-number-label { font-size: 13px; color: #536070; } .visual-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; } .viz-card h2, .claim-box h2 { font-size: 18px; margin: 0 0 8px; color: #18232f; } .viz-card p { color: #415160; margin-top: 0; } .wide { grid-column: 1 / -1; } .bar-row, .share-row { margin: 12px 0; } .bar-label, .share-label { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; margin-bottom: 4px; } .bar-track { height: 14px; background: #eceff3; border-radius: 4px; overflow: hidden; } .bar-fill { height: 100%; border-radius: 4px; } .fill-nuclear { background: #12719e; } .fill-control { background: #ca5800; } .fill-population { background: #408941; } .fill-airport { background: #af1f6b; } .fill-baseline { background: #696969; } .fill-gap { background: #e88e2d; } .takeaway { margin-top: 12px; padding: 10px 12px; background: #f4f6f8; border-left: 4px solid #696969; color: #25313c; } .big-number { font-size: 42px; font-weight: 850; color: #12719e; line-height: 1; margin-top: 12px; } .paired-block { margin: 14px 0 18px; } .paired-title { font-weight: 750; margin-bottom: 8px; color: #25313c; } .claim-box { margin-top: 16px; background: #fbfcff; } .claim-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; } .claim-grid div { background: white; border: 1px solid #d7dde8; border-radius: 6px; padding: 12px; } .claim-grid strong { display: block; color: #18232f; margin-bottom: 5px; } .claim-grid span { color: #40515f; } .infra-panel { border: 1px solid #d7dde8; border-radius: 6px; padding: 18px; background: #fff; margin: 16px 0; } .infra-panel h2 { font-size: 20px; margin: 6px 0 8px; color: #18232f; } .infra-panel p { color: #40515f; margin-top: 0; } .infra-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; margin: 14px 0; } .infra-card { border: 1px solid #d7dde8; border-radius: 6px; padding: 12px; background: #f7fbfd; } .infra-label { color: #425466; font-weight: 750; font-size: 13px; } .infra-sites { color: #12719e; font-size: 28px; font-weight: 850; margin-top: 4px; } .infra-detail { color: #25313c; font-size: 13px; } .infra-claim-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 10px; } .infra-claim-grid div { background: #fbfcff; border: 1px solid #d7dde8; border-radius: 6px; padding: 12px; } .infra-claim-grid ul { margin: 8px 0 0; padding-left: 18px; color: #40515f; } @media (prefers-color-scheme: dark) { .gradio-container { background: #f3f6fa !important; color: #18232f !important; } .hero-panel, .score-card, .viz-card, .claim-box, .claim-grid div { background-color: #ffffff !important; color: #18232f !important; } } @media (max-width: 760px) { .visual-grid { grid-template-columns: 1fr; } .hero-panel h1 { font-size: 26px; } } """ with gr.Blocks(css=css, title="Nuclear UAP Evidence Surface", theme=gr.themes.Soft()) as demo: gr.HTML(visual_story_html()) gr.HTML(public_infrastructure_html()) gr.HTML(score_cards()) with gr.Tabs(): with gr.Tab("Claim Boundaries"): gr.Markdown(overview_markdown()) 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("Military / NNSA Layer"): infra_layer = gr.Dropdown( choices=[ "All", "public_military_installation", "public_nuclear_security_enterprise", ], value="All", label="Public infrastructure layer", ) infra_table = gr.Dataframe(value=filter_public_infrastructure("All"), interactive=False, wrap=True) infra_layer.change(filter_public_infrastructure, infra_layer, infra_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)