--- title: Paradoxe de l’Animal Style toc: false --- # 🛸 Le Paradoxe de l’Animal Style > **Question absurde mais testable :** > Les OVNIs en Californie survolent-ils plus souvent des zones proches des In-N-Out ? ```js display(html` `); ``` ```js const [inNOut, ufoSightings] = await Promise.all([ FileAttachment("./data/in-n-out-ca-csv.json").json(), FileAttachment("./data/ufo-ca-sightings-v2.json").json(), ]); ``` ```js const [d3, topojson] = await Promise.all([ import("https://cdn.jsdelivr.net/npm/d3@7/+esm"), import("https://cdn.jsdelivr.net/npm/topojson-client@3/+esm"), ]); const usAtlasUrl = "https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json"; const us = await fetch(usAtlasUrl).then((r) => r.json()); const states = topojson.feature(us, us.objects.states); const california = states.features.find((s) => Number(s.id) === 6); ``` ```js function haversineKm(lat1, lon1, lat2, lon2) { const toRad = (deg) => (deg * Math.PI) / 180; const R = 6371; const dLat = toRad(lat2 - lat1); const dLon = toRad(lon2 - lon1); const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2; return 2 * R * Math.asin(Math.sqrt(a)); } function nearestStore(ufo, stores) { let bestStore = null; let bestDistance = Infinity; for (const store of stores) { const distance = haversineKm( ufo.latitude, ufo.longitude, store.latitude, store.longitude, ); if (distance < bestDistance) { bestDistance = distance; bestStore = store; } } return { store: bestStore, distanceKm: bestDistance }; } ``` ```js const shapes = [ "all", ...d3 .sort(Array.from(new Set(ufoSightings.map((d) => d.shape || "unknown")))) .slice(0, 20), ]; const selectedShape = view( Inputs.select(shapes, { label: "Filtre de forme OVNI", value: "all", format: (d) => (d === "all" ? "Toutes les formes" : d), }), ); const hungerRadiusKm = view( Inputs.range([5, 80], { label: "Curseur de fringale extraterrestre (km)", value: 24, step: 1, }), ); const hexbinWidth = view( Inputs.range([8, 28], { label: "Largeur des hexagones radar", value: 14, step: 1, }), ); ``` ```js const filteredUfo = ufoSightings.filter((ufo) => selectedShape === "all" ? true : ufo.shape === selectedShape, ); const enrichedUfo = filteredUfo.map((ufo) => { const nearest = nearestStore(ufo, inNOut); return { ...ufo, nearestStoreId: nearest.store?.id ?? null, nearestStoreLat: nearest.store?.latitude ?? null, nearestStoreLon: nearest.store?.longitude ?? null, nearestDistanceKm: nearest.distanceKm, closeToBurger: nearest.distanceKm <= hungerRadiusKm, }; }); const hungerRate = enrichedUfo.length > 0 ? (enrichedUfo.filter((d) => d.closeToBurger).length / enrichedUfo.length) * 100 : 0; const byStore = d3.rollups( enrichedUfo, (rows) => ({ sightings: rows.length, avgDuration: d3.mean(rows, (d) => d.durationSeconds) ?? 0, medDistance: d3.median(rows, (d) => d.nearestDistanceKm) ?? 0, }), (d) => d.nearestStoreId, ); const storeHotspots = byStore .map(([storeId, stats]) => { const store = inNOut.find((d) => d.id === storeId); if (!store) return null; return { ...store, sightings: stats.sightings, avgDuration: stats.avgDuration, medDistance: stats.medDistance, }; }) .filter(Boolean) .sort((a, b) => b.sightings - a.sightings); const topHotspots = storeHotspots.slice(0, 12); ``` ```js display(html`
${hungerRate.toFixed(1)}% des apparitions OVNI en Californie se produisent à moins de ${hungerRadiusKm} km d’un In-N-Out.
${conclusion}