<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jeremy Salsburg</title>
    <description>The latest articles on DEV Community by Jeremy Salsburg (@jeremy_salsburg_00d273f85).</description>
    <link>https://dev.to/jeremy_salsburg_00d273f85</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4090335%2F894605b5-399e-46c2-b4fa-0d311136322c.png</url>
      <title>DEV Community: Jeremy Salsburg</title>
      <link>https://dev.to/jeremy_salsburg_00d273f85</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeremy_salsburg_00d273f85"/>
    <language>en</language>
    <item>
      <title>Proyecto STEM: construye un monitor de aeronaves con una API y datos abiertos</title>
      <dc:creator>Jeremy Salsburg</dc:creator>
      <pubDate>Sun, 23 Aug 2026 02:16:26 +0000</pubDate>
      <link>https://dev.to/jeremy_salsburg_00d273f85/proyecto-stem-construye-un-monitor-de-aeronaves-con-una-api-y-datos-abiertos-25e8</link>
      <guid>https://dev.to/jeremy_salsburg_00d273f85/proyecto-stem-construye-un-monitor-de-aeronaves-con-una-api-y-datos-abiertos-25e8</guid>
      <description>&lt;h1&gt;
  
  
  Proyecto STEM: construye un monitor de aeronaves con una API y datos abiertos
&lt;/h1&gt;

&lt;p&gt;Â¿Buscas un proyecto que combine programaciÃ³n, sistemas en tiempo real, GIS,&lt;br&gt;
ciencia de datos, radio y experimentaciÃ³n? Los datos de aeronaves ofrecen un&lt;br&gt;
caso prÃ¡ctico que puede crecer desde una consulta API de diez lÃ­neas hasta un&lt;br&gt;
laboratorio completo con Raspberry Pi y radio definida por software.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Transparencia: estoy afiliado con ADSBiq, el proyecto comunitario que ofrece&lt;br&gt;
estos recursos. La API, los ejemplos y la muestra educativa pueden utilizarse&lt;br&gt;
sin instalar hardware. Un receptor es completamente opcional.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Cuatro niveles posibles
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Primera consulta a una API
&lt;/h3&gt;

&lt;p&gt;Una aplicaciÃ³n puede solicitar aeronaves cercanas a una coordenada, buscar una&lt;br&gt;
matrÃ­cula o consultar actividad aeroportuaria. Es un ejercicio apropiado para&lt;br&gt;
JSON, HTTP, autenticaciÃ³n, manejo de errores y visualizaciÃ³n.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;respuesta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.adsbiq.com/v2/nearby&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.711&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;74.072&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;radius_nm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ADSBIQ_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;respuesta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;datos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;respuesta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nunca publiques una clave API en GitHub, un cuaderno o una captura de pantalla.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. AnÃ¡lisis reproducible con Parquet
&lt;/h3&gt;

&lt;p&gt;Una muestra caribeÃ±a de 100.000 observaciones estÃ¡ archivada en Zenodo con el&lt;br&gt;
DOI permanente &lt;a href="https://doi.org/10.5281/zenodo.22062551" rel="noopener noreferrer"&gt;10.5281/zenodo.22062551&lt;/a&gt;.&lt;br&gt;
DuckDB puede consultar el archivo comprimido directamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;celda_lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;celda_lon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;observaciones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="n"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;aeronaves&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;read_parquet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'caribbean_sample_2026-06-29.parquet'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;lat&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;lon&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;observaciones&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Las filas son cambios de estado: una instantÃ¡nea completa puede estar seguida&lt;br&gt;
por filas dispersas que contienen solamente los campos que cambiaron. Es un&lt;br&gt;
buen ejercicio de modelado temporal, particiones y reconstrucciÃ³n de estado.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. AplicaciÃ³n regional
&lt;/h3&gt;

&lt;p&gt;Un equipo puede crear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;un monitor para su ciudad, aeropuerto o regiÃ³n;&lt;/li&gt;
&lt;li&gt;un mapa de actividad y observaciones por altitud;&lt;/li&gt;
&lt;li&gt;una canalizaciÃ³n con DuckDB, Polars, pandas o PostGIS;&lt;/li&gt;
&lt;li&gt;un tablero de conectividad aÃ©rea regional;&lt;/li&gt;
&lt;li&gt;un experimento sobre cobertura, terreno y lÃ­nea de vista.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Preparamos pÃ¡ginas en espaÃ±ol con ideas y recursos para&lt;br&gt;
&lt;a href="https://adsbiq.com/comunidad/sudamerica?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=south_america_stem&amp;amp;utm_content=spanish-tutorial" rel="noopener noreferrer"&gt;SudamÃ©rica&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://adsbiq.com/comunidad/colombia?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=south_america_stem&amp;amp;utm_content=spanish-tutorial" rel="noopener noreferrer"&gt;Colombia&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://adsbiq.com/comunidad/peru?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=south_america_stem&amp;amp;utm_content=spanish-tutorial" rel="noopener noreferrer"&gt;PerÃº&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://adsbiq.com/comunidad/chile?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=south_america_stem&amp;amp;utm_content=spanish-tutorial" rel="noopener noreferrer"&gt;Chile&lt;/a&gt; y&lt;br&gt;
&lt;a href="https://adsbiq.com/comunidad/argentina?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=south_america_stem&amp;amp;utm_content=spanish-tutorial" rel="noopener noreferrer"&gt;Argentina&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Laboratorio opcional de radio
&lt;/h3&gt;

&lt;p&gt;Un club o laboratorio puede agregar un receptor pasivo de 1090 MHz utilizando&lt;br&gt;
una Raspberry Pi, un receptor RTL-SDR y una antena adecuada. El experimento&lt;br&gt;
permite medir cÃ³mo cambian las observaciones con la altura de antena, pÃ©rdidas&lt;br&gt;
de cable, edificios, terreno e interferencia.&lt;/p&gt;

&lt;p&gt;ADSBiq puede compartir datos junto con otras redes ADS-B. No es necesario&lt;br&gt;
abandonar ningÃºn servicio existente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preguntas de investigaciÃ³n
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Â¿CÃ³mo cambia la densidad de observaciones entre costa, montaÃ±a y selva?&lt;/li&gt;
&lt;li&gt;Â¿QuÃ© relaciÃ³n existe entre altitud y distancia de recepciÃ³n?&lt;/li&gt;
&lt;li&gt;Â¿CÃ³mo se reconstruye correctamente una trayectoria a partir de cambios?&lt;/li&gt;
&lt;li&gt;Â¿QuÃ© arquitectura soporta instantÃ¡neas y actualizaciones en tiempo real?&lt;/li&gt;
&lt;li&gt;Â¿DÃ³nde aportarÃ­a mÃ¡s un nuevo receptor universitario o comunitario?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  InterpretaciÃ³n responsable
&lt;/h2&gt;

&lt;p&gt;Estos son datos colaborativos e incompletos. La ausencia de observaciones no&lt;br&gt;
demuestra que no hubiera una aeronave. No deben utilizarse para navegaciÃ³n,&lt;br&gt;
separaciÃ³n, control, vigilancia, seguridad operacional ni decisiones crÃ­ticas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://adsbiq.com/api/docs?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=south_america_stem&amp;amp;utm_content=spanish-tutorial" rel="noopener noreferrer"&gt;DocumentaciÃ³n de la API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Sky-Power-Services/adsbiq-api-demo" rel="noopener noreferrer"&gt;CÃ³digo Python y cuaderno de cobertura&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://adsbiq.com/data?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=south_america_stem&amp;amp;utm_content=spanish-tutorial" rel="noopener noreferrer"&gt;Datos diarios en Parquet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://doi.org/10.5281/zenodo.22062551" rel="noopener noreferrer"&gt;Muestra citable en Zenodo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SerÃ­an muy Ãºtiles las sugerencias de docentes, estudiantes y comunidades&lt;br&gt;
tÃ©cnicas sudamericanas sobre ejercicios, traducciones y casos regionales.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>programming</category>
      <category>datascience</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Query 100,000 Caribbean Aircraft State Changes with DuckDB</title>
      <dc:creator>Jeremy Salsburg</dc:creator>
      <pubDate>Sun, 23 Aug 2026 02:01:21 +0000</pubDate>
      <link>https://dev.to/jeremy_salsburg_00d273f85/query-100000-caribbean-aircraft-state-changes-with-duckdb-2fl0</link>
      <guid>https://dev.to/jeremy_salsburg_00d273f85/query-100000-caribbean-aircraft-state-changes-with-duckdb-2fl0</guid>
      <description>&lt;h1&gt;
  
  
  Query 100,000 Caribbean Aircraft State Changes with DuckDB
&lt;/h1&gt;

&lt;p&gt;Real-world streaming data rarely arrives as perfectly reconstructed rows. To&lt;br&gt;
save bandwidth and storage, ADS-B archives can record a complete aircraft state&lt;br&gt;
followed by sparse rows containing only fields that changed.&lt;/p&gt;

&lt;p&gt;This tutorial uses a free, bounded Caribbean aircraft-data sample to explore&lt;br&gt;
that model directly with DuckDB. The file contains 100,000 observations, is&lt;br&gt;
only about 1.6 MB compressed, and has a permanent DOI.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclosure: I am affiliated with ADSBiq, the community-powered project that&lt;br&gt;
produced this dataset. The sample is free under ODbL-1.0, and no hardware is&lt;br&gt;
required.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  What is in the sample?
&lt;/h2&gt;

&lt;p&gt;The sample covers positioned observations between 5-30 degrees north and&lt;br&gt;
95-55 degrees west on June 29, 2026. Common columns include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ts&lt;/code&gt;: observation timestamp&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hex&lt;/code&gt;: ICAO 24-bit aircraft address&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flight&lt;/code&gt;: transmitted callsign&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lat&lt;/code&gt;, &lt;code&gt;lon&lt;/code&gt;: position&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;alt_baro&lt;/code&gt;: barometric altitude&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gs&lt;/code&gt;: ground speed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;track&lt;/code&gt;: direction of travel&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt;: aircraft type designator&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;is_snapshot&lt;/code&gt;: whether the row contains a complete state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;is_removed&lt;/code&gt;: whether the aircraft left coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rows after a snapshot can be sparse diffs. A null value therefore often means&lt;br&gt;
"unchanged," not "unknown forever."&lt;/p&gt;
&lt;h2&gt;
  
  
  Install DuckDB
&lt;/h2&gt;

&lt;p&gt;Use the DuckDB CLI or its Python package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;duckdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data is small enough for a laptop, but DuckDB can query Parquet lazily and&lt;br&gt;
push filters into the scan. There is no reason to load every column into a&lt;br&gt;
large dataframe first.&lt;/p&gt;
&lt;h2&gt;
  
  
  Query the Parquet file directly from Zenodo
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;duckdb&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://zenodo.org/api/records/22062551/files/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;caribbean_sample_2026-06-29.parquet/content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;con&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;duckdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INSTALL httpfs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LOAD httpfs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    SELECT
        count(*) AS rows,
        count(DISTINCT hex) AS aircraft,
        min(ts) AS first_observation,
        max(ts) AS last_observation
    FROM read_parquet(?)
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;fetchdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Count positioned observations by one-degree grid cell
&lt;/h2&gt;

&lt;p&gt;Grid aggregation gives a quick, privacy-safe view of where the sample contains&lt;br&gt;
observations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;grid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    SELECT
        floor(lat) AS latitude_cell,
        floor(lon) AS longitude_cell,
        count(*) AS observations,
        count(DISTINCT hex) AS aircraft
    FROM read_parquet(?)
    WHERE lat IS NOT NULL
      AND lon IS NOT NULL
    GROUP BY ALL
    ORDER BY observations DESC
    LIMIT 25
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;fetchdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This measures observations in the sample. It does &lt;strong&gt;not&lt;/strong&gt; measure all aircraft&lt;br&gt;
activity. Receiver locations, antenna height, terrain, interference, aircraft&lt;br&gt;
altitude, traffic, and time all affect crowdsourced coverage.&lt;/p&gt;
&lt;h2&gt;
  
  
  Start reconstruction with snapshots
&lt;/h2&gt;

&lt;p&gt;For analyses that do not need every intermediate state, begin with complete&lt;br&gt;
snapshot rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;snapshots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    SELECT hex, ts, flight, lat, lon, alt_baro, gs, track, type
    FROM read_parquet(?)
    WHERE is_snapshot
      AND lat BETWEEN 17 AND 19
      AND lon BETWEEN -68.5 AND -65
    ORDER BY ts
    LIMIT 1000
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;fetchdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a complete trajectory, partition by &lt;code&gt;hex&lt;/code&gt;, order by &lt;code&gt;ts&lt;/code&gt;, and forward-fill&lt;br&gt;
nullable state fields after a snapshot. Keep removal rows so that separate&lt;br&gt;
coverage sessions are not accidentally joined into one continuous flight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn it into a student or club project
&lt;/h2&gt;

&lt;p&gt;Useful extensions include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Compare observation density near different Caribbean airports.&lt;/li&gt;
&lt;li&gt;Visualize altitude against reception distance.&lt;/li&gt;
&lt;li&gt;Build a DuckDB or Polars pipeline that reconstructs selected aircraft.&lt;/li&gt;
&lt;li&gt;Design a live island aviation dashboard using the REST API.&lt;/li&gt;
&lt;li&gt;Measure how receiver or antenna changes affect subsequent observations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href="https://adsbiq.com/community/caribbean-stem?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=developer_ecosystem&amp;amp;utm_content=duckdb-tutorial" rel="noopener noreferrer"&gt;Caribbean STEM project page&lt;/a&gt;&lt;br&gt;
collects the API, dataset, coding examples, and optional receiver path. Regional&lt;br&gt;
versions are also available for Jamaica, Puerto Rico, Key West, and the Cayman&lt;br&gt;
Islands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://doi.org/10.5281/zenodo.22062551" rel="noopener noreferrer"&gt;Citable dataset: DOI 10.5281/zenodo.22062551&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Sky-Power-Services/adsbiq-api-demo" rel="noopener noreferrer"&gt;Python examples and coverage notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://adsbiq.com/data?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=developer_ecosystem&amp;amp;utm_content=duckdb-tutorial" rel="noopener noreferrer"&gt;Complete daily Parquet corpus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://adsbiq.com/api/docs?utm_source=devto&amp;amp;utm_medium=directory&amp;amp;utm_campaign=developer_ecosystem&amp;amp;utm_content=duckdb-tutorial" rel="noopener noreferrer"&gt;Live API documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Missing observations do not prove that no aircraft were present, and this data&lt;br&gt;
must not be used for navigation, separation, enforcement, or safety-of-life&lt;br&gt;
decisions.&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
