<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Geodata Ramblings Blog</title>
        <link>https://ricegeo.dev/</link>
        <description>Geodata Ramblings Blog</description>
        <lastBuildDate>Sun, 22 Mar 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[🛸 How I became a YouTube Certified™ quadcopter pilot]]></title>
            <link>https://ricegeo.dev/quadcopter</link>
            <guid>https://ricegeo.dev/quadcopter</guid>
            <pubDate>Sun, 22 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[An introduction to first-person-view (FPV) quadcopter flying, my learning approach, architecture]]></description>
            <content:encoded><![CDATA[<p>An introduction to first-person-view (FPV) quadcopter flying, my learning approach, architecture
diagram, and youtube videos...</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="discovering-first-person-view-fpv">Discovering First Person View (FPV)<a href="https://ricegeo.dev/quadcopter#discovering-first-person-view-fpv" class="hash-link" aria-label="Direct link to Discovering First Person View (FPV)" title="Direct link to Discovering First Person View (FPV)" translate="no">​</a></h2>
<p>In '25 my son, Sequoyah Rice, turned me on to FPV quadcopters by showing some videos he recorded
from his FPV goggles, featuring his acrobatic and freestyle moves. His skilled flying and
practical advice encouraged me launch into the sport and learn some foundational hardware and
electronics skills along the way. For which I am thankful! I'll share some of those tips below.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="freestyle-cinematics-and-many-other-genres">Freestyle, cinematics and many other genres<a href="https://ricegeo.dev/quadcopter#freestyle-cinematics-and-many-other-genres" class="hash-link" aria-label="Direct link to Freestyle, cinematics and many other genres" title="Direct link to Freestyle, cinematics and many other genres" translate="no">​</a></h2>
<p>First Person View (FPV) is a new phenomenon, sport, and hobby, which has only been accessible for
perhaps less than a decade, because of low-cost, miniaturized electronics and sensors. It's totally
immersive and exhilarating, with a live stream of video directly into your goggles, and complete
remote control over all flight parameters: throttle, yaw, pitch and roll. FPV quads (aka drones) are
characterized by high speed, maneuverability, and durability. High voltage lithium polymer
rechargeable batteries provide the juice which is required for these high performance craft.</p>
<p>There are several sub-genres and specializations of FPV, both good and nefarious. My interests are
mainly in Freestyle, Cruising and Cinematics.</p>
<ul>
<li class="">Cruising/Cinematic: Just exploring for recreation, or mount a 4K HD camera on a FPV quad to make
movies or short form content.</li>
<li class="">Freestyle: The culture around freestyle and acrobatics is fluid, with pilots constantly inventing
and naming new tricks and maneuvers, so the lexicon keeps evolving as the community pushes
creative boundaries, much like the culture of skateboarding and surfing.</li>
<li class="">Racing: Organizations like Drone Racing League and MultiGP have high speed race courses and
tournaments.</li>
<li class="">Sports: The Milano-Cortina 2026 Winter Olympics featured FPV quads streaming video in practically
every event, which was groundbreaking.</li>
<li class="">Long range, high speed, and other specializations.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-learn">How to learn<a href="https://ricegeo.dev/quadcopter#how-to-learn" class="hash-link" aria-label="Direct link to How to learn" title="Direct link to How to learn" translate="no">​</a></h2>
<p>This is the standard approach. Yes, you really need to learn on a simulator!</p>
<ol>
<li class="">Buy a radio controller with USB port for use with simulator software, and eventually for use with
your future quad. A real radio controller is required to build up your coordination and muscle
memory on the sticks/gimbals. I use the <a href="https://radiomasterrc.com/products/tx15-radio-controller-elrs-m2" target="_self" rel="noopener noreferrer" class="">RadioMaster
TX15</a>. Some planning is
required because the radio controller must use the same protocol as your future
quad's radio receiver. My kit uses <a href="https://www.expresslrs.org/" target="_self" rel="noopener noreferrer" class="">ExpressLRS</a>.</li>
<li class="">Buy a simulator game on <a href="https://store.steampowered.com/" target="_self" rel="noopener noreferrer" class="">Steam</a>. I tried several and prefer <a href="https://store.steampowered.com/curator/44872674" target="_self" rel="noopener noreferrer" class="">LiftOff</a>. It's affordable and has realistic physics.</li>
<li class="">Log at least 20 hours learning to fly in the simulator. There are <a href="https://www.youtube.com/@JoshuaBardwell" target="_self" rel="noopener noreferrer" class="">YouTube tutorial
videos</a> by Joshua Bardwell which step-by-step introduce
you to flying via the LiftOff simulator.</li>
<li class="">Learn to solder and how to use an electronics multimeter. For a DIY drone build there are 20+
solder joints, some of which are fairly intricate. Some folks were fortunate enough to learn
soldering in high school, but that wasn't the case for me. Learn the difference between
rosin-core and acid-core solder (I wasted some money, not knowing the difference). Rosin-core is
what you want.</li>
<li class="">Learn about the FAA's recreational use exemption and associated educational curricula. A sub-250
grams quadcopter kit is recommended.</li>
<li class="">Do the build then start flying. Details omitted 😅</li>
<li class="">Keep returning to the LiftOff simulator on bad weather days, or to learn new maneuvers in a safe
environment.</li>
</ol>
<p>Don't adore your quad too much. It's just a tool and it will inevitably get lost or destroyed.
However, the benefit of going the DIY build route is you can upgrade or replace any of the
individual components.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="architecture-diagram">Architecture diagram<a href="https://ricegeo.dev/quadcopter#architecture-diagram" class="hash-link" aria-label="Direct link to Architecture diagram" title="Direct link to Architecture diagram" translate="no">​</a></h2>
<p>This diagram explains the high level components in my build:</p>
<p><img decoding="async" loading="lazy" alt="FPV drone system diagram" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwJSIgdmlld0JveD0iMCAwIDY4MCA1ODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxkZWZzPgogIDxtYXJrZXIgaWQ9ImFycm93IiB2aWV3Qm94PSIwIDAgMTAgMTAiIHJlZlg9IjgiIHJlZlk9IjUiIG1hcmtlcldpZHRoPSI2IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0by1zdGFydC1yZXZlcnNlIj4KICAgIDxwYXRoIGQ9Ik0yIDFMOCA1TDIgOSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjb250ZXh0LXN0cm9rZSIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgogIDwvbWFya2VyPgogIDxzdHlsZT4KICAgIC50ICB7IGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsICJTZWdvZSBVSSIsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgZm9udC13ZWlnaHQ6IDQwMDsgZmlsbDogIzNkM2QzYTsgfQogICAgLnRzIHsgZm9udC1mYW1pbHk6IC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgIlNlZ29lIFVJIiwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogNDAwOyBmaWxsOiAjNWY1ZTVhOyB9CiAgICAudGggeyBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiA1MDA7IGZpbGw6ICMzZDNkM2E7IH0KCiAgICBnLmMtdGVhbCAgIHJlY3QgeyBmaWxsOiAjRTFGNUVFOyBzdHJva2U6ICMwRjZFNTY7IH0KICAgIGcuYy10ZWFsICAgLnRoICB7IGZpbGw6ICMwODUwNDE7IH0gZy5jLXRlYWwgICAudHMgeyBmaWxsOiAjMEY2RTU2OyB9CiAgICBnLmMtY29yYWwgIHJlY3QgeyBmaWxsOiAjRkFFQ0U3OyBzdHJva2U6ICM5OTNDMUQ7IH0KICAgIGcuYy1jb3JhbCAgLnRoICB7IGZpbGw6ICM0QTFCMEM7IH0gZy5jLWNvcmFsICAudHMgeyBmaWxsOiAjOTkzQzFEOyB9CiAgICBnLmMtcHVycGxlIHJlY3QgeyBmaWxsOiAjRUVFREZFOyBzdHJva2U6ICM1MzRBQjc7IH0KICAgIGcuYy1wdXJwbGUgLnRoICB7IGZpbGw6ICMyNjIxNUM7IH0gZy5jLXB1cnBsZSAudHMgeyBmaWxsOiAjNTM0QUI3OyB9CiAgICBnLmMtYmx1ZSAgIHJlY3QgeyBmaWxsOiAjRTZGMUZCOyBzdHJva2U6ICMxODVGQTU7IH0KICAgIGcuYy1ibHVlICAgLnRoICB7IGZpbGw6ICMwNDJDNTM7IH0gZy5jLWJsdWUgICAudHMgeyBmaWxsOiAjMTg1RkE1OyB9CiAgICBnLmMtZ3JheSAgIHJlY3QgeyBmaWxsOiAjRjFFRkU4OyBzdHJva2U6ICM1RjVFNUE7IH0KICAgIGcuYy1ncmF5ICAgLnRoICB7IGZpbGw6ICMyQzJDMkE7IH0gZy5jLWdyYXkgICAudHMgeyBmaWxsOiAjNUY1RTVBOyB9CgogICAgLmJvdW5kYXJ5ICAgICAgIHsgc3Ryb2tlOiAjM2QzZDNhOyB9CiAgICAuYm91bmRhcnktbGFiZWwgeyBmaWxsOiAjM2QzZDNhOyB9CiAgICAuYXJyICAgICAgICAgICAgeyBzdHJva2U6ICM4ODg3ODA7IHN0cm9rZS13aWR0aDogMXB4OyBmaWxsOiBub25lOyB9CiAgICAuY3RybC1wYXRoICAgICAgeyBzdHJva2U6ICMxODVGQTU7IH0KICAgIC5jdHJsLWxhYmVsICAgICB7IGZpbGw6ICMxODVGQTU7IH0KICAgIC52aWQtcGF0aCAgICAgICB7IHN0cm9rZTogIzk5M0MxRDsgfQogICAgLnZpZC1sYWJlbCAgICAgIHsgZmlsbDogIzk5M0MxRDsgfQogICAgLmxlZ2VuZC1ib3JkZXIgIHsgc3Ryb2tlOiAjYWFhOWEyOyB9CiAgICAubGVnZW5kLXRleHQgICAgeyBmaWxsOiAjNWY1ZTVhOyB9CiAgICAubGVnZW5kLWN0cmwgICAgeyBzdHJva2U6ICMxODVGQTU7IH0KICAgIC5sZWdlbmQtdmlkICAgICB7IHN0cm9rZTogIzk5M0MxRDsgfQogICAgLmxlZ2VuZC13aXJlICAgIHsgc3Ryb2tlOiAjODg4NzgwOyB9CgogICAgQG1lZGlhIChwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyaykgewogICAgICAudCwgLnRoIHsgZmlsbDogI2MyYzBiNjsgfQogICAgICAudHMgICAgIHsgZmlsbDogIzljOWE5MjsgfQoKICAgICAgZy5jLXRlYWwgICByZWN0IHsgZmlsbDogIzA4NTA0MTsgc3Ryb2tlOiAjNURDQUE1OyB9CiAgICAgIGcuYy10ZWFsICAgLnRoICB7IGZpbGw6ICM5RkUxQ0I7IH0gZy5jLXRlYWwgICAudHMgeyBmaWxsOiAjNURDQUE1OyB9CiAgICAgIGcuYy1jb3JhbCAgcmVjdCB7IGZpbGw6ICM3MTJCMTM7IHN0cm9rZTogI0YwOTk3QjsgfQogICAgICBnLmMtY29yYWwgIC50aCAgeyBmaWxsOiAjRjVDNEIzOyB9IGcuYy1jb3JhbCAgLnRzIHsgZmlsbDogI0YwOTk3QjsgfQogICAgICBnLmMtcHVycGxlIHJlY3QgeyBmaWxsOiAjM0MzNDg5OyBzdHJva2U6ICNBRkE5RUM7IH0KICAgICAgZy5jLXB1cnBsZSAudGggIHsgZmlsbDogI0NFQ0JGNjsgfSBnLmMtcHVycGxlIC50cyB7IGZpbGw6ICNBRkE5RUM7IH0KICAgICAgZy5jLWJsdWUgICByZWN0IHsgZmlsbDogIzBDNDQ3Qzsgc3Ryb2tlOiAjODVCN0VCOyB9CiAgICAgIGcuYy1ibHVlICAgLnRoICB7IGZpbGw6ICNCNUQ0RjQ7IH0gZy5jLWJsdWUgICAudHMgeyBmaWxsOiAjODVCN0VCOyB9CiAgICAgIGcuYy1ncmF5ICAgcmVjdCB7IGZpbGw6ICM0NDQ0NDE7IHN0cm9rZTogI0I0QjJBOTsgfQogICAgICBnLmMtZ3JheSAgIC50aCAgeyBmaWxsOiAjRDNEMUM3OyB9IGcuYy1ncmF5ICAgLnRzIHsgZmlsbDogI0I0QjJBOTsgfQoKICAgICAgLmJvdW5kYXJ5ICAgICAgIHsgc3Ryb2tlOiAjOWM5YTkyOyB9CiAgICAgIC5ib3VuZGFyeS1sYWJlbCB7IGZpbGw6ICM5YzlhOTI7IH0KICAgICAgLmFyciAgICAgICAgICAgIHsgc3Ryb2tlOiAjOWM5YTkyOyB9CiAgICAgIC5jdHJsLXBhdGggICAgICB7IHN0cm9rZTogIzM3OEFERDsgfQogICAgICAuY3RybC1sYWJlbCAgICAgeyBmaWxsOiAjMzc4QUREOyB9CiAgICAgIC52aWQtcGF0aCAgICAgICB7IHN0cm9rZTogI0Q4NUEzMDsgfQogICAgICAudmlkLWxhYmVsICAgICAgeyBmaWxsOiAjRDg1QTMwOyB9CiAgICAgIC5sZWdlbmQtYm9yZGVyICB7IHN0cm9rZTogIzQ0NDQ0MTsgfQogICAgICAubGVnZW5kLXRleHQgICAgeyBmaWxsOiAjOWM5YTkyOyB9CiAgICAgIC5sZWdlbmQtY3RybCAgICB7IHN0cm9rZTogIzM3OEFERDsgfQogICAgICAubGVnZW5kLXZpZCAgICAgeyBzdHJva2U6ICNEODVBMzA7IH0KICAgICAgLmxlZ2VuZC13aXJlICAgIHsgc3Ryb2tlOiAjOWM5YTkyOyB9CiAgICB9CiAgPC9zdHlsZT4KPC9kZWZzPgoKPCEtLSDilIDilIAgRFJPTkUgQk9VTkRBUlkg4pSA4pSAIC0tPgo8cmVjdCBjbGFzcz0iYm91bmRhcnkiIHg9IjIwIiB5PSIyMCIgd2lkdGg9IjM0MCIgaGVpZ2h0PSI1NDAiIHJ4PSIxNiIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIyLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjggNSIvPgo8dGV4dCBjbGFzcz0idHMgYm91bmRhcnktbGFiZWwiIHg9IjE5MCIgeT0iNDIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtd2VpZ2h0PSI1MDAiPkRyb25lPC90ZXh0PgoKPCEtLSDilIDilIAgUElMT1QgQk9VTkRBUlkg4pSA4pSAIC0tPgo8cmVjdCBjbGFzcz0iYm91bmRhcnkiIHg9IjM5MCIgeT0iMjAiIHdpZHRoPSIyNzAiIGhlaWdodD0iNTQwIiByeD0iMTYiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtZGFzaGFycmF5PSI4IDUiLz4KPHRleHQgY2xhc3M9InRzIGJvdW5kYXJ5LWxhYmVsIiB4PSI1MjUiIHk9IjQyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LXdlaWdodD0iNTAwIj5QaWxvdDwvdGV4dD4KCjwhLS0gNEsgQ2FtZXJhIC0tPgo8ZyBjbGFzcz0iYy10ZWFsIj4KICA8cmVjdCB4PSI0MCIgeT0iNjAiIHdpZHRoPSIxNjAiIGhlaWdodD0iNTYiIHJ4PSI4IiBzdHJva2Utd2lkdGg9IjAuNSIvPgogIDx0ZXh0IGNsYXNzPSJ0aCIgeD0iMTIwIiB5PSI4MiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZG9taW5hbnQtYmFzZWxpbmU9ImNlbnRyYWwiPjRLIHZpZGVvIGNhbWVyYTwvdGV4dD4KICA8dGV4dCBjbGFzcz0idHMiIHg9IjEyMCIgeT0iMTAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkb21pbmFudC1iYXNlbGluZT0iY2VudHJhbCI+UmVjb3JkcyB0byBTRCBjYXJkPC90ZXh0Pgo8L2c+Cgo8IS0tIFNEIGNhcmQgLS0+CjxnIGNsYXNzPSJjLWdyYXkiPgogIDxyZWN0IHg9IjQwIiB5PSIxMzQiIHdpZHRoPSIxNjAiIGhlaWdodD0iNDQiIHJ4PSI4IiBzdHJva2Utd2lkdGg9IjAuNSIvPgogIDx0ZXh0IGNsYXNzPSJ0aCIgeD0iMTIwIiB5PSIxNTYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJjZW50cmFsIj5TRCBjYXJkPC90ZXh0Pgo8L2c+CjxsaW5lIHgxPSIxMjAiIHkxPSIxMTYiIHgyPSIxMjAiIHkyPSIxMzQiIGNsYXNzPSJhcnIiIG1hcmtlci1lbmQ9InVybCgjYXJyb3cpIi8+Cgo8IS0tIEFuYWxvZyBGUFYgQ2FtZXJhIC0tPgo8ZyBjbGFzcz0iYy1jb3JhbCI+CiAgPHJlY3QgeD0iNDAiIHk9IjIxMCIgd2lkdGg9IjE2MCIgaGVpZ2h0PSI1NiIgcng9IjgiIHN0cm9rZS13aWR0aD0iMC41Ii8+CiAgPHRleHQgY2xhc3M9InRoIiB4PSIxMjAiIHk9IjIzMiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZG9taW5hbnQtYmFzZWxpbmU9ImNlbnRyYWwiPkFuYWxvZyBGUFYgY2FtZXJhPC90ZXh0PgogIDx0ZXh0IGNsYXNzPSJ0cyIgeD0iMTIwIiB5PSIyNTAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJjZW50cmFsIj5Mb3ctbGF0ZW5jeSBsaXZlIGZlZWQ8L3RleHQ+CjwvZz4KCjwhLS0gVlRYIC0tPgo8ZyBjbGFzcz0iYy1jb3JhbCI+CiAgPHJlY3QgeD0iNDAiIHk9IjI5NCIgd2lkdGg9IjE2MCIgaGVpZ2h0PSI1NiIgcng9IjgiIHN0cm9rZS13aWR0aD0iMC41Ii8+CiAgPHRleHQgY2xhc3M9InRoIiB4PSIxMjAiIHk9IjMxNiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZG9taW5hbnQtYmFzZWxpbmU9ImNlbnRyYWwiPlZpZGVvIHRyYW5zbWl0dGVyIChWVFgpPC90ZXh0PgogIDx0ZXh0IGNsYXNzPSJ0cyIgeD0iMTIwIiB5PSIzMzQiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJjZW50cmFsIj5Ccm9hZGNhc3RzIG9uIDUuOCBHSHo8L3RleHQ+CjwvZz4KPGxpbmUgeDE9IjEyMCIgeTE9IjI2NiIgeDI9IjEyMCIgeTI9IjI5NCIgY2xhc3M9ImFyciIgbWFya2VyLWVuZD0idXJsKCNhcnJvdykiLz4KCjwhLS0gQUlPIEZDICsgRVNDIC0tPgo8ZyBjbGFzcz0iYy1wdXJwbGUiPgogIDxyZWN0IHg9IjQwIiB5PSIzNzgiIHdpZHRoPSIzMDAiIGhlaWdodD0iNTYiIHJ4PSI4IiBzdHJva2Utd2lkdGg9IjAuNSIvPgogIDx0ZXh0IGNsYXNzPSJ0aCIgeD0iMTkwIiB5PSI0MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJjZW50cmFsIj5GbGlnaHQgY29udHJvbGxlciArIEVTQyAoQUlPKTwvdGV4dD4KICA8dGV4dCBjbGFzcz0idHMiIHg9IjE5MCIgeT0iNDE4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkb21pbmFudC1iYXNlbGluZT0iY2VudHJhbCI+U3RhYmlsaXNlcyBmbGlnaHQsIGRyaXZlcyA0IG1vdG9yczwvdGV4dD4KPC9nPgoKPCEtLSBSYWRpbyBSWCAtLT4KPGcgY2xhc3M9ImMtYmx1ZSI+CiAgPHJlY3QgeD0iNDAiIHk9IjQ2MiIgd2lkdGg9IjMwMCIgaGVpZ2h0PSI1NiIgcng9IjgiIHN0cm9rZS13aWR0aD0iMC41Ii8+CiAgPHRleHQgY2xhc3M9InRoIiB4PSIxOTAiIHk9IjQ4NCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZG9taW5hbnQtYmFzZWxpbmU9ImNlbnRyYWwiPlJhZGlvIHJlY2VpdmVyIChSWCk8L3RleHQ+CiAgPHRleHQgY2xhc3M9InRzIiB4PSIxOTAiIHk9IjUwMiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZG9taW5hbnQtYmFzZWxpbmU9ImNlbnRyYWwiPlJlY2VpdmVzIHBpbG90IGNvbnRyb2wgc2lnbmFsczwvdGV4dD4KPC9nPgo8bGluZSB4MT0iMTkwIiB5MT0iNDYyIiB4Mj0iMTkwIiB5Mj0iNDM0IiBjbGFzcz0iYXJyIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93KSIvPgoKPCEtLSBSYWRpbyBUWCAtLT4KPGcgY2xhc3M9ImMtYmx1ZSI+CiAgPHJlY3QgeD0iNDA4IiB5PSI2MCIgd2lkdGg9IjIzNCIgaGVpZ2h0PSI1NiIgcng9IjgiIHN0cm9rZS13aWR0aD0iMC41Ii8+CiAgPHRleHQgY2xhc3M9InRoIiB4PSI1MjUiIHk9IjgyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkb21pbmFudC1iYXNlbGluZT0iY2VudHJhbCI+UmFkaW8gdHJhbnNtaXR0ZXIgKFRYKTwvdGV4dD4KICA8dGV4dCBjbGFzcz0idHMiIHg9IjUyNSIgeT0iMTAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkb21pbmFudC1iYXNlbGluZT0iY2VudHJhbCI+U2VuZHMgc3RpY2sgaW5wdXRzIHZpYSAyLjQgR0h6PC90ZXh0Pgo8L2c+Cgo8IS0tIEZQViBHb2dnbGVzIC0tPgo8ZyBjbGFzcz0iYy1jb3JhbCI+CiAgPHJlY3QgeD0iNDA4IiB5PSIyNTAiIHdpZHRoPSIyMzQiIGhlaWdodD0iNTYiIHJ4PSI4IiBzdHJva2Utd2lkdGg9IjAuNSIvPgogIDx0ZXh0IGNsYXNzPSJ0aCIgeD0iNTI1IiB5PSIyNzIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJjZW50cmFsIj5GUFYgZ29nZ2xlczwvdGV4dD4KICA8dGV4dCBjbGFzcz0idHMiIHg9IjUyNSIgeT0iMjkwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkb21pbmFudC1iYXNlbGluZT0iY2VudHJhbCI+QW5hbG9nIHZpZGVvIHJlY2VpdmVyIGJ1aWx0LWluPC90ZXh0Pgo8L2c+Cgo8IS0tIEdvZ2dsZXMgU0QgY2FyZCAtLT4KPGcgY2xhc3M9ImMtZ3JheSI+CiAgPHJlY3QgeD0iNDA4IiB5PSIzMzAiIHdpZHRoPSIyMzQiIGhlaWdodD0iNDQiIHJ4PSI4IiBzdHJva2Utd2lkdGg9IjAuNSIvPgogIDx0ZXh0IGNsYXNzPSJ0aCIgeD0iNTI1IiB5PSIzNTIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJjZW50cmFsIj5TRCBjYXJkIChEVlIgcmVjb3JkaW5nKTwvdGV4dD4KPC9nPgo8bGluZSB4MT0iNTI1IiB5MT0iMzA2IiB4Mj0iNTI1IiB5Mj0iMzMwIiBjbGFzcz0iYXJyIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93KSIvPgoKPCEtLSBDT05UUk9MIExJTksgLS0+CjxwYXRoIGNsYXNzPSJjdHJsLXBhdGgiIGQ9Ik0gNTI1IDExNiBMIDUyNSAxNTUgTCAzNzAgMTU1IEwgMzcwIDQ5MCBMIDM0MiA0OTAiCiAgICAgIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtZGFzaGFycmF5PSI1IDMiIG1hcmtlci1lbmQ9InVybCgjYXJyb3cpIi8+Cjx0ZXh0IGNsYXNzPSJ0cyBjdHJsLWxhYmVsIiB4PSI0NDgiIHk9IjE0MSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC13ZWlnaHQ9IjUwMCI+RXhwcmVzc0xSUyAoRUxSUyk8L3RleHQ+Cjx0ZXh0IGNsYXNzPSJ0cyBjdHJsLWxhYmVsIiB4PSI0NDgiIHk9IjE1NSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+Mi40IEdIeiBjb250cm9sIGxpbms8L3RleHQ+Cgo8IS0tIFZJREVPIExJTksgLS0+CjxwYXRoIGNsYXNzPSJ2aWQtcGF0aCIgZD0iTSAyMDAgMzIyIEwgNDA4IDI3OCIKICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjUgMyIgbWFya2VyLWVuZD0idXJsKCNhcnJvdykiLz4KPHRleHQgY2xhc3M9InRzIHZpZC1sYWJlbCIgeD0iMzEyIiB5PSIyODMiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtd2VpZ2h0PSI1MDAiPk5UU0MgYW5hbG9nIHZpZGVvPC90ZXh0Pgo8dGV4dCBjbGFzcz0idHMgdmlkLWxhYmVsIiB4PSIzMTIiIHk9IjI5NiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+NS44IEdIeiB2aWRlbyBsaW5rPC90ZXh0PgoKPCEtLSBMRUdFTkQgLS0+CjxyZWN0IGNsYXNzPSJsZWdlbmQtYm9yZGVyIiB4PSI0MDgiIHk9IjQyMCIgd2lkdGg9IjIzNCIgaGVpZ2h0PSIxMjAiIHJ4PSI4IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjAuNSIvPgo8dGV4dCBjbGFzcz0idHMgbGVnZW5kLXRleHQiIHg9IjQyMCIgeT0iNDQyIj5TaWduYWwgdHlwZTwvdGV4dD4KPGxpbmUgY2xhc3M9ImxlZ2VuZC1jdHJsIiB4MT0iNDIwIiB5MT0iNDY0IiB4Mj0iNDYwIiB5Mj0iNDY0IiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlLWRhc2hhcnJheT0iNSAzIi8+Cjx0ZXh0IGNsYXNzPSJ0cyBsZWdlbmQtdGV4dCIgeD0iNDcwIiB5PSI0NjgiPlJhZGlvIGNvbnRyb2wgbGluazwvdGV4dD4KPGxpbmUgY2xhc3M9ImxlZ2VuZC12aWQiIHgxPSI0MjAiIHkxPSI0OTAiIHgyPSI0NjAiIHkyPSI0OTAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtZGFzaGFycmF5PSI1IDMiLz4KPHRleHQgY2xhc3M9InRzIGxlZ2VuZC10ZXh0IiB4PSI0NzAiIHk9IjQ5NCI+QW5hbG9nIHZpZGVvIGxpbms8L3RleHQ+CjxsaW5lIGNsYXNzPSJsZWdlbmQtd2lyZSIgeDE9IjQyMCIgeTE9IjUxNiIgeDI9IjQ2MCIgeTI9IjUxNiIgc3Ryb2tlLXdpZHRoPSIxIi8+Cjx0ZXh0IGNsYXNzPSJ0cyBsZWdlbmQtdGV4dCIgeD0iNDcwIiB5PSI1MjAiPldpcmVkIC8gb24tYm9hcmQ8L3RleHQ+Cgo8L3N2Zz4K" width="680" height="580" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="photo">Photo<a href="https://ricegeo.dev/quadcopter#photo" class="hash-link" aria-label="Direct link to Photo" title="Direct link to Photo" translate="no">​</a></h2>
<p>DIY FPV Drone Kit - QAV-S 2 Sub-250 Joshua Bardwell SE 3” - Analog</p>
<p><img decoding="async" loading="lazy" alt="Sub-250 gram FPV quadcopter" src="https://ricegeo.dev/assets/images/skysurfin-5ed02d60cd8e7f06f0baf9dd7558a96b.jpeg" width="1280" height="960" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="parts-list-and-software-links">Parts list and software links<a href="https://ricegeo.dev/quadcopter#parts-list-and-software-links" class="hash-link" aria-label="Direct link to Parts list and software links" title="Direct link to Parts list and software links" translate="no">​</a></h2>
<ul>
<li class="">🛸 Lumenier DIY FPV Drone Kit - QAV-S 2 Sub-250 Joshua Bardwell SE 3” - Analog with <a href="https://www.betaflight.com/" target="_self" rel="noopener noreferrer" class="">Betaflight</a></li>
<li class="">📡 iFlight Nano receiver with <a href="https://www.expresslrs.org/" target="_self" rel="noopener noreferrer" class="">ExpressLRS</a></li>
<li class="">🎮 Radiomaster TX15 controller with <a href="https://www.expresslrs.org/" target="_self" rel="noopener noreferrer" class="">ExpressLRS</a></li>
<li class="">🥽 SkyZone SKY04O PRO OLED FPV goggles + omni antenna: VAS Ion Pro, and patch antenna: TrueRC X-AIR MK. II</li>
<li class="">🎬 RunCam Thumb Pro 4K HD camera, post-processed with <a href="https://gyroflow.xyz/" target="_self" rel="noopener noreferrer" class="">GyroFlow</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="my-youtube-channel-westslopeflow">My YouTube channel: <a href="https://www.youtube.com/@westslopeflow" target="_self" rel="noopener noreferrer" class="">@westslopeflow</a><a href="https://ricegeo.dev/quadcopter#my-youtube-channel-westslopeflow" class="hash-link" aria-label="Direct link to my-youtube-channel-westslopeflow" title="Direct link to my-youtube-channel-westslopeflow" translate="no">​</a></h2>
<p>I create 4K HD FPV videos set to music, and <a href="https://www.youtube.com/@westslopeflow" target="_self" rel="noopener noreferrer" class="">post them to YouTube</a>. Consider adding a Like and Subscribe!</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/apAljZJTmn4?si=N4WsY6ReGR2UZadd" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>]]></content:encoded>
            <category>hardware</category>
            <category>raster</category>
            <category>tech</category>
            <category>gis</category>
        </item>
        <item>
            <title><![CDATA[Improve a hyperspectral imagery processing pipeline with Dagster]]></title>
            <link>https://ricegeo.dev/hab-detection-wyvern-hsi-dagster</link>
            <guid>https://ricegeo.dev/hab-detection-wyvern-hsi-dagster</guid>
            <pubDate>Wed, 13 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Part 2 of posts about using Wyvern's hyperspectral imagery Open Data Program for]]></description>
            <content:encoded><![CDATA[<p>Part 2 of posts about using Wyvern's hyperspectral imagery Open Data Program for
Harmful Algal Bloom (HAB) detection. Let's port the pipeline to Dagster, a production-grade data
orchestrator package...</p>
<p>Recap: In Part 1, I put on my Data Scientist hat and <a class="" target="_self" href="https://ricegeo.dev/hab-detection-wyvern-hsi">tried some exploratory data analysis using
Wyvern's hyperspectral imagery program</a>. The Jupyter notebook produced in
Part 1 was a quick study and does not represent production quality Python, routines, or algorithms.</p>
<p>Moving right along!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-use-a-data-orchestrator-like-dagster">Why use a data orchestrator like Dagster?<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#why-use-a-data-orchestrator-like-dagster" class="hash-link" aria-label="Direct link to Why use a data orchestrator like Dagster?" title="Direct link to Why use a data orchestrator like Dagster?" translate="no">​</a></h2>
<blockquote>
<p><a href="https://dagster.io/" target="_self" rel="noopener noreferrer" class="">Dagster</a> is a data orchestrator built for data engineers, with integrated
lineage, observability, a declarative programming model, and best-in-class testability.</p>
</blockquote>
<p>As a data engineer and software developer I've worked on many data pipelines, helped scientists
deploy their code, and produced data products in collaboration with scientists and business
stakeholders across tech startups, government agencies, and non-profit organizations.</p>
<p>There is an anti-pattern which to be honest seems to be the default and the status-quo. I've
perpetuated this problem, OK let's just call it a mistake. My colleagues have made this mistake too.
It usually plays out like:</p>
<ul>
<li class="">💡 We need to create some kind of data pipeline, workflow, or extract-transform-load (ETL), and we
need it as soon as possible! (Let's call it a "pipeline" for this post.)</li>
<li class="">🐍 We already know a programming language, like Python, Bash, or TypeScript.</li>
<li class="">🚧 We start coding the pipeline in our favorite language, using tried and true procedural and
object-oriented coding techniques like:<!-- -->
<ul>
<li class="">For Loops</li>
<li class="">If-Else Clauses</li>
<li class="">Classes and instances with state</li>
<li class="">Exception Handling</li>
</ul>
</li>
<li class="">🔥 Yeah! Making progress immediately, so we should have something prototyped within a few days,
then it should be slam dunk to get it ready for production!</li>
<li class="">⏳ Much time passes.</li>
<li class="">🪳 We now have a brittle, incomplete, hard to maintain, bad approximation, of a data orchestration
tool!</li>
</ul>
<p>In the following two sections, I pulled some insightful quotes from some other engineers about data
pipelines:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="opaque-and-fragile-pipelines">Opaque and fragile pipelines<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#opaque-and-fragile-pipelines" class="hash-link" aria-label="Direct link to Opaque and fragile pipelines" title="Direct link to Opaque and fragile pipelines" translate="no">​</a></h3>
<p>Quoting Brian Davis of Earthmover.io in <a href="https://earthmover.io/blog/tensorops-scientific-data-doesnt-have-to-hurt" target="_self" rel="noopener noreferrer" class="">TensorOps: Scientific Data Doesn’t Have to
Hurt</a>:</p>
<blockquote>
<p>Every dataset in the status quo is the sum of all its pipeline’s constituent steps. The serial
nature of this arrangement has serious implications:</p>
</blockquote>
<blockquote>
<ul>
<li class="">Did you discover a data error introduced upstream that needs cleaning or correction? Regenerate
the whole dataset.</li>
<li class="">Do you need to tweak the calculation for a derived quantity? Regenerate the whole dataset.</li>
<li class="">Do you want to inline a new variable upstream to improve your model? Regenerate the whole
dataset.</li>
<li class="">Does your customer want a subtly different deliverable? Rewrite the whole pipeline... then
regenerate the whole dataset.</li>
</ul>
</blockquote>
<blockquote>
<p>In short, every iterative change anywhere within a pipeline incurs the cost of a wholesale re-run.
And this means that, once you’ve moved past the prototyping phase, development slows to a crawl as
the value of any incremental improvements must be weighed against the cost of re-running the whole
pipeline. All that extra compute time. All that extra storage cost. It’s too expensive, in time
and resources and — most importantly — opportunity.</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="perks-of-having-an-orchestrator-in-your-data-eng-toolkit">Perks of having an orchestrator in your data eng. toolkit<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#perks-of-having-an-orchestrator-in-your-data-eng-toolkit" class="hash-link" aria-label="Direct link to Perks of having an orchestrator in your data eng. toolkit" title="Direct link to Perks of having an orchestrator in your data eng. toolkit" translate="no">​</a></h3>
<p>Quoting Matt Palmer in a <a href="https://www.databricks.com/resources/ebook/understanding-etl" target="_self" rel="noopener noreferrer" class="">Technical Guide published by O'Reilly and
Databricks</a>:</p>
<blockquote>
<p>Here’s a breakdown of the perks that come with having an orchestrator in your data engineering
toolkit:</p>
<ul>
<li class="">Workflow management: Orchestrators assist in defining, scheduling, and managing workflows
efficiently, ensuring tasks are executed in the right order by managing dependencies.</li>
<li class="">Automation: As engineers, we should be automating as much as possible (or feasible).
Orchestrators can be used to automate routine, repetitive, and even complex tasks, saving time and
ensuring tasks run as scheduled without manual intervention.</li>
<li class="">Error handling and recovery: Orchestrators often come with built-in error handling and recovery
mechanisms. They can retry a failed task, notify the team, or trigger other tasks to fix the
issue.</li>
<li class="">Monitoring and alerting: Monitoring workflows and receiving alerts for failures or delays are
crucial for maintaining reliable data pipelines. Orchestrators provide these capabilities.</li>
<li class="">Resource optimization: By managing when and where tasks run, orchestrators help optimize
resource use, which is crucial in environments with limited or costly resources.</li>
<li class="">Observability and debugging: Orchestrators provide a visual representation of workflows, log
management, and other debugging tools, which is invaluable for troubleshooting and optimizing
workflows.</li>
<li class="">Compliance and auditing: Orchestrators maintain an audit trail of all tasks, which is crucial
for compliance with data governance and other regulatory requirements.</li>
</ul>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pros-and-cons-of-jupyter-notebooks">Pros and Cons of Jupyter Notebooks<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#pros-and-cons-of-jupyter-notebooks" class="hash-link" aria-label="Direct link to Pros and Cons of Jupyter Notebooks" title="Direct link to Pros and Cons of Jupyter Notebooks" translate="no">​</a></h2>
<p>The pipeline developed in Part 1 was purely exploratory data analysis (EDA) and that analysis was
delivered as a Jupyter Notebook. Notebooks are widely used in Data Science for prototyping ideas as
well as sharing technical documentation with interactive scripts, in languages such as Python,
Julia, or Mojo.</p>
<p>Notebooks are a powerful tool for communication and sharing. For example Jeremy
Howard's FastAI Book, <a href="https://fastai.github.io/fastbook2e/" target="_self" rel="noopener noreferrer" class="">Deep Learning for Coders with Fastai and PyTorch: AI Applications Without a
PhD</a> is completely written and published with Jupyter
notebooks.</p>
<p>There are definitely some gotchas though:</p>
<ul>
<li class="">Global variables (state)</li>
<li class="">Out of order cell execution</li>
<li class="">Lack of code quality tools like type checking, linting, formatting, security scanning etc.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="port-the-data-pipeline-to-dagster">Port the data pipeline to Dagster<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#port-the-data-pipeline-to-dagster" class="hash-link" aria-label="Direct link to Port the data pipeline to Dagster" title="Direct link to Port the data pipeline to Dagster" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-a-dag">What's a DAG?<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#whats-a-dag" class="hash-link" aria-label="Direct link to What's a DAG?" title="Direct link to What's a DAG?" translate="no">​</a></h3>
<p>The "Dag" in Dagster stands for <a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph" target="_self" rel="noopener noreferrer" class="">Directed Acyclic
Graph</a>, which is a useful concept to be aware
of. Dagster's framework enables a modular, declarative approach to data engineering, making it
easier to manage dependencies, monitor execution, and ensure data quality.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="scaffold-a-new-dagster-project">Scaffold a new Dagster project<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#scaffold-a-new-dagster-project" class="hash-link" aria-label="Direct link to Scaffold a new Dagster project" title="Direct link to Scaffold a new Dagster project" translate="no">​</a></h3>
<p>Following the <a href="https://docs.dagster.io/getting-started/quickstart" target="_self" rel="noopener noreferrer" class="">Dagster quickstart</a>,
first, we'll install the projects dependencies per the <a href="https://docs.dagster.io/" target="_self" rel="noopener noreferrer" class="">Dagster docs</a>,
including the fantastic <a href="https://docs.astral.sh/uv/" target="_self" rel="noopener noreferrer" class="">uv package manager</a> for Python:</p>
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">Scaffolding steps</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Source code (shell)</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><ul>
<li class="">Install uv package manager</li>
<li class="">Use uv to create a new dagster project named "hab-detection-wyvern-hsi-dag" using create-dagster.</li>
<li class="">Add rest of python dependencies, copied from the Jupyter notebook.</li>
<li class="">Add new pystac-client dependency for dynamically querying the Wyvern STAC.</li>
<li class="">Make materialize assets persistent across runs of the dev server.</li>
</ul></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"># macOS and Linux installation of uv package manager</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ curl -LsSf https://astral.sh/uv/install.sh | sh</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Use uv to create a new dagster project named "pipeline" using create-dagster.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Respond y to the prompt to run uv sync after scaffolding.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ uvx create-dagster@latest project hab-detection-wyvern-hsi-dag</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># It created a scaffold of a project, including a Python venv and README.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ tree -a hab-detection-wyvern-hsi-dag/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">hab-detection-wyvern-hsi-dag/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├── .gitignore</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├── .venv/...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├── pyproject.toml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├── README.md</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├── src</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│   └── hab_detection_wyvern_hsi_dag</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│       ├── __init__.py</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│      ├── definitions.py</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│      └── defs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│          └── __init__.py</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├── tests</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│  └── __init__.py</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">└── uv.lock</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Add rest of python dependencies, copied from the Jupyter notebook</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ uv add rasterio shapely geopandas numpy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Add new dependency for dynamically querying the Wyvern STAC:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ uv add pystac-client</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Couple of housekeeping details, this makes materialized assets</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># persistent across runs of the dev server</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">mkdir -p  ~/.dagster</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">export DAGSTER_HOME=~/.dagster</span><br></span></code></pre></div></div></div></div></div>
<p>Now a Dagster pipeline is created, Python dependencies are installed, and we're ready to code!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="scaffold-an-assets-file">Scaffold an assets file<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#scaffold-an-assets-file" class="hash-link" aria-label="Direct link to Scaffold an assets file" title="Direct link to Scaffold an assets file" translate="no">​</a></h3>
<p>This is simply step 2 of the Dagster Quickstart:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ dg scaffold defs dagster.asset assets.py</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">...</span><br></span></code></pre></div></div>
<p>The following steps of the Quickstart are</p>
<ol start="3">
<li class="">Add data</li>
<li class="">Define the asset</li>
<li class="">Run the pipeline</li>
<li class="">Verify the results</li>
</ol>
<p>Here we'll diverge from the Quickstart, because this pipeline will fetch data from Wyvern's STAC
catalog, and derive other downstream data from there. There will be corresponding assets in each
node of the pipeline.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="declarative-workflows-are-the-best">Declarative workflows are the best<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#declarative-workflows-are-the-best" class="hash-link" aria-label="Direct link to Declarative workflows are the best" title="Direct link to Declarative workflows are the best" translate="no">​</a></h3>
<p>In Dagster you express declaratively what the inputs and outputs are for each node in the DAG.
Concerns like control flow, logging, serialization, etc. are handled by the orchestrator. Here is
one node from this pipeline, illustrating the declarative, Pythonic syntax.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token decorator annotation punctuation" style="color:#393A34">@dg</span><span class="token decorator annotation punctuation" style="color:#393A34">.</span><span class="token decorator annotation punctuation" style="color:#393A34">asset</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">green_r550_raster</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fetch_stac_item</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Item</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ndarray</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">dict</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Any</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    Read band from cloud object storage (Green 550nm for NDWI and RGB preview).</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    Returns tuple of (Numpy ndarray, raster metadata).</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    """</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    cog_asset </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fetch_stac_item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">assets</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">COG_ASSET_KEY</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">with</span><span class="token plain"> rio</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cog_asset</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">href</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        band_green_r550 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">descriptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Band_550"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        nodata_val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">nodatavals</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">band_green_r550</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 0-based index</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        green_r550 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">band_green_r550 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># read() uses 1-based index</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        meta </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">meta</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">copy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    green_r550</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">green_r550 </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> nodata_val</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">nan</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    meta</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"count"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">green_r550</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> meta</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>Using this declarative Python syntax, I added assets for each of the pipeline nodes from Part 1 (see
<a class="" target="_self" href="https://ricegeo.dev/hab-detection-wyvern-hsi#concept-of-a-production-pipeline">Concept of a production pipeline</a>).
Even at this early stage, Dagster can wire up the whole pipeline and visualize it, as shown below:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"># validate pipeline config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">dg check defs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># launch development server on localhost:3000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">dg dev</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="implement-all-the-asset-nodes">Implement all the asset nodes<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#implement-all-the-asset-nodes" class="hash-link" aria-label="Direct link to Implement all the asset nodes" title="Direct link to Implement all the asset nodes" translate="no">​</a></h3>
<p>The DAG implementation at this stage involves copying Python code from the Jupyter Notebook
cells, and then <a href="https://docs.dagster.io/guides/build/assets/passing-data-between-assets" target="_self" rel="noopener noreferrer" class="">passing data between the asset
nodes</a>. Dagster has about a
dozen built-in I/O managers to choose from, but for this introduction, we'll just use the default
<code>FilesystemIOManager</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="discovering-parallelism-naturally">Discovering parallelism naturally<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#discovering-parallelism-naturally" class="hash-link" aria-label="Direct link to Discovering parallelism naturally" title="Direct link to Discovering parallelism naturally" translate="no">​</a></h3>
<p>The process of creating the pipeline and passing data between the assets naturally decomposes the
problem. For example, in the Part 1 Jupyter notebook, there was one cell which - serially - fetched
6 raster bands from object storage.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">with</span><span class="token plain"> rio</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tampico_mx_url</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Blue 464nm for RGB preview</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    band_blue_r464 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">descriptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Band_464"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    blue_r464 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">band_blue_r464 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Green 550nm for NDWI and RGB preview</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    band_green_r550 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">descriptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Band_550"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    green_r550 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">band_green_r550 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Red 650nm for RGB preview</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    band_red_r650 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">descriptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Band_650"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    red_r650 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">band_red_r650 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Dark Red 669nm for NDCI</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    band_red_r669 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">descriptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Band_669"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    red_r669 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">band_red_r669 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Red Edge 712nm for NDCI</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    band_red_edge_r712 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">descriptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Band_712"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    red_edge_r712 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">band_red_edge_r712 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># NIR 849nm for NDWI</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    band_nir_r849 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">descriptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Band_849"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    nir_r849 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">band_nir_r849 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><br></span></code></pre></div></div>
<p>Certainly the above code cell could have been optimized to use async or multiprocessing Python code,
but that's extra coding, and an optimization that was not really intended in the exploratory data
analysis.</p>
<p>It turns out to be obvious how parallelize that using Dagster assets. As a bonus, the control flow
and parallelism comes for free from the data orchestrator.</p>
<p>Here is a visualization of the pipeline from the Dagster development server. The six raw bands
are modeled as separate Dagster assets, and therefore are materialized (generated) in parallel.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="visualization-of-dag-">Visualization of DAG 🎨<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#visualization-of-dag-" class="hash-link" aria-label="Direct link to Visualization of DAG 🎨" title="Direct link to Visualization of DAG 🎨" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Dagster assets visualization" src="https://ricegeo.dev/assets/images/dagster-pipeline-879ec5b726cdf1c3e90ff1c589ea8d4e.png" width="3248" height="2124" class="img_ev3q">
[The final DAG in Lineage view in Dagster]</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="python-debugger-fix-and-continue-work-avoidance-">Python debugger, fix-and-continue, work avoidance 🎉<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#python-debugger-fix-and-continue-work-avoidance-" class="hash-link" aria-label="Direct link to Python debugger, fix-and-continue, work avoidance 🎉" title="Direct link to Python debugger, fix-and-continue, work avoidance 🎉" translate="no">​</a></h3>
<p>Because Dagster is both a CLI tool, a web app, and a Python module, it delivers a great development
experience. Some aspects which I found beneficial:</p>
<ul>
<li class="">Edit pipeline code, while assets are being materialized! (multitasking)</li>
<li class="">Fix errors and then resume processing, right where the pipeline left off (work avoidance)</li>
<li class="">Python debugger (F5 debugging with VSCode)</li>
</ul>
<p>Example <code>launch.json</code> for VSCode</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"0.2.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"configurations"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Dagster Dev Server (Debug)"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"debugpy"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"request"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"launch"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"module"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dagster"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"args"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"dev"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"justMyCode"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"console"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"integratedTerminal"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">"cwd"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${workspaceFolder}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">             </span><span class="token property" style="color:#36acaa">"env"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token property" style="color:#36acaa">"DAGSTER_HOME"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"~/.dagster"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ecosystem-of-data-orchestrator-tools">Ecosystem of data orchestrator tools<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#ecosystem-of-data-orchestrator-tools" class="hash-link" aria-label="Direct link to Ecosystem of data orchestrator tools" title="Direct link to Ecosystem of data orchestrator tools" translate="no">​</a></h2>
<p>I hope you enjoyed this quick intro to <a href="https://dagster.io/" target="_self" rel="noopener noreferrer" class="">Dagster</a>, which barely scratched the
surface of it's capabilities! The greater ecosystem of data orchestrator tools is rich, here is
just a small cross section.</p>
<ul>
<li class=""><a href="https://airflow.apache.org/" target="_self" rel="noopener noreferrer" class="">Airflow</a> "Apache Airflow® is a platform created by the community to programmatically author, schedule and monitor workflows."</li>
<li class=""><a href="https://argo-workflows.readthedocs.io/en/stable/" target="_self" rel="noopener noreferrer" class="">Argo Workflows</a> is "an open source container-native workflow engine for orchestrating parallel jobs on Kubernetes."</li>
<li class=""><a href="https://aws.amazon.com/" target="_self" rel="noopener noreferrer" class="">AWS</a> Batch</li>
<li class=""><a href="https://aws.amazon.com/" target="_self" rel="noopener noreferrer" class="">AWS</a> Glue ETL and Workflows</li>
<li class=""><a href="https://aws.amazon.com/" target="_self" rel="noopener noreferrer" class="">AWS</a> Step Functions</li>
<li class=""><a href="https://docs.dask.org/en/stable/" target="_self" rel="noopener noreferrer" class="">Dask</a> "a Python library for parallel and distributed computing."</li>
<li class=""><a href="https://www.getdbt.com/" target="_self" rel="noopener noreferrer" class="">Dbt</a> "turns data work into a shared, scalable practice by bringing the best of software engineering to the analytics workflow."</li>
<li class=""><a href="https://www.gnu.org/software/make/" target="_self" rel="noopener noreferrer" class="">Make</a>: that's right, Make has been running software builds, DAGs, and data pipelines in Unix and Linux systems since the 1970's!</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="links-to-source-code-at-nbviewer-and-github">Links to source code at NBviewer and GitHub<a href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster#links-to-source-code-at-nbviewer-and-github" class="hash-link" aria-label="Direct link to Links to source code at NBviewer and GitHub" title="Direct link to Links to source code at NBviewer and GitHub" translate="no">​</a></h2>
<p>This walkthrough blog post was just a high level view.
The <a href="https://github.com/guidorice/hab-detection-wyvern-hsi" target="_self" rel="noopener noreferrer" class="">GitHub repository</a> has the pipeline source code, and Jupyter notebook.</p>
<ul>
<li class=""><a href="https://github.com/guidorice/hab-detection-wyvern-hsi/blob/main/hab-detection-wyvern-hsi-dag/src/hab_detection_wyvern_hsi_dag/defs/assets.py" target="_self" rel="noopener noreferrer" class="">Dagster pipeline source code at GitHub</a></li>
<li class=""><a href="https://nbviewer.org/github/guidorice/hab-detection-wyvern-hsi/blob/main/notebooks/eda-hab-detection-wyvern-hsi.ipynb" target="_self" rel="noopener noreferrer" class="">Notebook at NBviewer.org</a></li>
<li class=""><a href="https://github.com/guidorice/hab-detection-wyvern-hsi/blob/main/notebooks/eda-hab-detection-wyvern-hsi.ipynb" target="_self" rel="noopener noreferrer" class="">Notebook at GitHub</a></li>
</ul>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>]]></content:encoded>
            <category>cloud</category>
            <category>dev</category>
            <category>gdal-ogr</category>
            <category>gis</category>
            <category>linux</category>
            <category>python</category>
            <category>raster</category>
        </item>
        <item>
            <title><![CDATA[Harmful Algal Bloom 🦠 detection with Wyvern hyperspectral imagery]]></title>
            <link>https://ricegeo.dev/hab-detection-wyvern-hsi</link>
            <guid>https://ricegeo.dev/hab-detection-wyvern-hsi</guid>
            <pubDate>Thu, 08 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Let's embark on some exploratory data analysis using Wyvern's hyperspectral imagery Open Data Program. Harmful Algal]]></description>
            <content:encoded><![CDATA[<p>Let's embark on some exploratory data analysis using Wyvern's hyperspectral imagery Open Data Program. Harmful Algal
Bloom (HAB) detection is attempted using selected band wavelengths and raster analysis techniques. This is part 1 of 2
of a series about modern GIS pipelines leveraging Python and the open-source, cloud-native geospatial tech stack...</p>
<!-- -->
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Thanks Wyvern</div><div class="admonitionContent_BuS1"><p>2025-07 Thanks to Wyvern for <a href="https://www.linkedin.com/feed/update/urn:li:activity:7346567124296908800/" target="_self" rel="noopener noreferrer" class="">the mention and compliments about this blog post</a>!</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="part-1-of-2">Part 1 of 2<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#part-1-of-2" class="hash-link" aria-label="Direct link to Part 1 of 2" title="Direct link to Part 1 of 2" translate="no">​</a></h2>
<p>Data Engineering is a Software Engineering discipline, and one of the things data engineers do is help scientists get
their code into production, make it reproducible, and make it fast.</p>
<ol>
<li class="">In this post, I put on my Data Scientist hat and try some exploratory data analysis (EDA) using:
<a href="https://www.python.org/" target="_self" rel="noopener noreferrer" class="">Python</a>,
<a href="https://rasterio.readthedocs.io/en/stable/" target="_self" rel="noopener noreferrer" class="">RasterIO</a>,
<a href="https://numpy.org/" target="_self" rel="noopener noreferrer" class="">NumPy</a>,
<a href="https://shapely.readthedocs.io/en/stable/" target="_self" rel="noopener noreferrer" class="">Shapely</a>,
<a href="https://geopandas.org/en/stable/" target="_self" rel="noopener noreferrer" class="">GeoPandas</a>,
<a href="https://matplotlib.org/stable/" target="_self" rel="noopener noreferrer" class="">MatplotLib</a>,
<a href="https://ipyleaflet.readthedocs.io/en/latest/" target="_self" rel="noopener noreferrer" class="">Ipyleaflet</a>,
and <a href="https://docs.jupyter.org/en/stable/" target="_self" rel="noopener noreferrer" class="">Jupyter</a>.</li>
<li class="">In <a class="" target="_self" href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster">Part 2</a>, I wear my Data Engineer hat and port the Python code from the
notebook environment into Dagster, a production-grade data orchestrator.</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="harmful-algal-bloom-hab-in-the-news">Harmful Algal Bloom (HAB) in the news<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#harmful-algal-bloom-hab-in-the-news" class="hash-link" aria-label="Direct link to Harmful Algal Bloom (HAB) in the news" title="Direct link to Harmful Algal Bloom (HAB) in the news" translate="no">​</a></h2>
<p>The Guardian recently published this article with related facts, photos and interviews:</p>
<blockquote>
<p>As the Earth heats up, the amount of algae in our waterways is rapidly increasing, transforming the colour of lakes and killing entire ecosystems.
source: <a href="https://www.theguardian.com/environment/2025/jun/10/toxic-blooms-algae-marine-dead-zones-lakes-ecosystems-dead-elephants-fish-sea-lions-aoe" target="_self" rel="noopener noreferrer" class="">Patrick Greenfield, The Guardian, 2025-06-10</a></p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary-and-interactive-map">Summary and interactive map<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#summary-and-interactive-map" class="hash-link" aria-label="Direct link to Summary and interactive map" title="Direct link to Summary and interactive map" translate="no">​</a></h2>
<p>First try out this interactive map: Zoom in, pan, and switch the raster layers on and off. Each layer was produced in
the linked Python notebook, and introduced below.</p>
<!-- -->
<br>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>The rest of this post explains how these three map layers were generated. A Python notebook
with all the technical details and source code is linked at the bottom.</p></div></div>
<p>Apologies because the blog post title was slightly misleading. I am not detecting Harmful Algal Blooms (HAB), rather
calculating Normalized Difference Chlorophyll Index (NDCI). Chlorophyll-a is widely used as a representative indicator
for algae in water. It's the primary photosynthetic pigment found in almost all photosynthetic organisms, including
algae.</p>
<p>There are related indexes which could be explored in the same manner, such as Blue-Green Algae Index (BGI), Floating
Algae Index (FAI), and others. For further reading, Wyvern lists many indices and formulas in their <a href="https://knowledge.wyvern.space/" target="_self" rel="noopener noreferrer" class="">Knowledge
Center</a>.</p>
<p>The normalized difference indices presented here use conventional GIS raster analysis based on this
elegant and intuitive principle. Different materials on Earth's surface (water, vegetation, soil,
etc.) reflect and absorb electromagnetic radiation differently across various wavelengths. By
calculating the difference between reflectance values in two carefully selected spectral bands, then
normalizing this difference, we can highlight specific features while minimizing other factors like
atmospheric or illumination conditions.</p>
<p>The specific indices leveraged in this notebook are:</p>
<ol>
<li class="">Normalized Difference Water Index (NDWI): this index is leveraged to create a water mask, which is used later in the
pipeline.</li>
<li class="">Normalized Difference Chlorophyll Index (NDCI): is a simple alternative for detecting <a href="https://en.wikipedia.org/wiki/Chlorophyll_a" target="_self" rel="noopener noreferrer" class="">chlorophyll-a</a> in water bodies.</li>
</ol>
<p>The full Python notebook is linked below and can be previewed in NBviewer (recommended) or GitHub.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wyverns-hyperspectral-imagery-hsi">Wyvern's hyperspectral imagery (HSI)<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#wyverns-hyperspectral-imagery-hsi" class="hash-link" aria-label="Direct link to Wyvern's hyperspectral imagery (HSI)" title="Direct link to Wyvern's hyperspectral imagery (HSI)" translate="no">​</a></h2>
<p><a href="https://wyvern.space/" target="_self" rel="noopener noreferrer" class="">Wyvern Space's</a> hyperspectral imagery (HSI) has Visible and Near-Infrared (VNIR) sensors, with 5
meter spatial resolution, and between 23 and 32 hyperspectral bands. Leveraging it's narrow Full Width at Half Maximum
(FWHM) allows the sensor to distinguish between many different wavelengths of light.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="open-data-program">Open Data Program<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#open-data-program" class="hash-link" aria-label="Direct link to Open Data Program" title="Direct link to Open Data Program" translate="no">​</a></h3>
<p>It's excellent that Wyvern has embraced open standards by publishing with flexible licensing and a <a href="https://stacspec.org/en" target="_self" rel="noopener noreferrer" class="">Spatio-Temporal
Asset Catalog (STAC)</a>. To access Wyvern's Open Data Program, just browse to
<a href="https://wyvern.space/" target="_self" rel="noopener noreferrer" class="">https://wyvern.space</a> → Access Open Data.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="walkthrough-of-notebook">Walkthrough of notebook<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#walkthrough-of-notebook" class="hash-link" aria-label="Direct link to Walkthrough of notebook" title="Direct link to Walkthrough of notebook" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="find-a-scene-in-wyverns-catalog">Find a scene in Wyvern's catalog<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#find-a-scene-in-wyverns-catalog" class="hash-link" aria-label="Direct link to Find a scene in Wyvern's catalog" title="Direct link to Find a scene in Wyvern's catalog" translate="no">​</a></h3>
<p><a href="https://pystac-client.readthedocs.io/en/stable/" target="_self" rel="noopener noreferrer" class="">PySTAC client</a> and various other tools and SDKs can be used to search
for and download images and metadata from a STAC catalog. However, for this exploratory data analysis it was convenient
to browse the web interface (STAC Browser) and select an interesting scene.</p>
<p><img decoding="async" loading="lazy" alt="STAC catalog screenshot" src="https://ricegeo.dev/assets/images/stac-catalog-4f639a58ff0a1d9bae665a090304abf8.gif" width="3248" height="2124" class="img_ev3q">
Here I selected a scene from December 2024 of near Tampico, MX. It's a humid-subtropical region with both ocean and
freshwater features, which seems like a good starting point for Harmful Algal Bloom (HAB) detection.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="visualize-scene-preview-png-from-wyvern">Visualize Scene Preview PNG from Wyvern<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#visualize-scene-preview-png-from-wyvern" class="hash-link" aria-label="Direct link to Visualize Scene Preview PNG from Wyvern" title="Direct link to Visualize Scene Preview PNG from Wyvern" translate="no">​</a></h3>
<p>Wyvern provides an overview image of the satellite scene in PNG format, which they rendered from the peak Red, Green,
and Blue bands selected from the 32 bands in the source image. Some observations:</p>
<ul>
<li class="">There is no visible cloud coverage or fog. It is interesting to compare with the provided QA cloud/clear mask rasters
below.</li>
<li class="">Preview PNG image is not geo-referenced because PNG format does not (at least not directly) support that.</li>
<li class="">Preview PNG image does not appear particularly vibrant.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="wyvern preview png" src="https://ricegeo.dev/assets/images/scene-preview-867c057066e1b814bde88047e243659d.png" width="683" height="361" class="img_ev3q">
<br> (Wyvern's provided preview PNG. <a href="https://wyvern-prod-public-open-data-program.s3.ca-central-1.amazonaws.com/wyvern_dragonette-003_20241229T165203_12324bcb/wyvern_dragonette-003_20241229T165203_12324bcb_preview.png" target="_self" rel="noopener noreferrer" class="">Download full-sized image ~13MB</a>)</p>
<p>The source scene image is in Cloud Optimized Geotiff (COG) format and for the reasons listed above, I decided to create
a new preview image in Geotiff format in this pipeline.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="️-architectural-decision-surface-level-reflectance-processing">⚠️ Architectural decision: surface level reflectance processing<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#%EF%B8%8F-architectural-decision-surface-level-reflectance-processing" class="hash-link" aria-label="Direct link to ⚠️ Architectural decision: surface level reflectance processing" title="Direct link to ⚠️ Architectural decision: surface level reflectance processing" translate="no">​</a></h3>
<p>I will not apply surface level reflectance processing in this pipeline. There are many options but they all require fine
tuning and effort. Some examples are: ATCOR, 6S, iCOR, ACOLITE, SPy, HypPy, and ENVI. It is acknowledged this is a
shortcut, and for correctness or production usage, this pipeline should use Level 2A:</p>
<blockquote>
<p>Level 2A: Image data which has been atmospherically compensated/corrected to bottom-of-atmosphere (BOA) surface
reflectance and orthorectified with digital elevation model (DEM) terrain correction. <a href="https://knowledge.wyvern.space/" target="_self" rel="noopener noreferrer" class="">Wyvern Knowledge
Center</a></p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="visualize-qa-rasters-for-cloudclear-mask">Visualize QA rasters for cloud/clear mask<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#visualize-qa-rasters-for-cloudclear-mask" class="hash-link" aria-label="Direct link to Visualize QA rasters for cloud/clear mask" title="Direct link to Visualize QA rasters for cloud/clear mask" translate="no">​</a></h3>
<p>Wyvern provides cloud and clear mask rasters. There appears to be something wrong in this scene's cloud mask because
there is no detectable cloud coverage or fog or haze in the visual preview rasters, but there are clouds (1 value) on
the cloud mask raster.</p>
<p><img decoding="async" loading="lazy" alt="cloud mask raster" src="https://ricegeo.dev/assets/images/cloud-clear-rasters-2c5a5a97e4fee28c37467d3bc4aa3afe.png" width="988" height="577" class="img_ev3q">
<br>(in-notebook raster visualization)</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="️-architectural-decision-no-cloud-mask">⚠️ Architectural decision: no cloud mask<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#%EF%B8%8F-architectural-decision-no-cloud-mask" class="hash-link" aria-label="Direct link to ⚠️ Architectural decision: no cloud mask" title="Direct link to ⚠️ Architectural decision: no cloud mask" translate="no">​</a></h3>
<p>I will not use the clear/cloud mask layers for this pipeline. They don't seem accurate, or I cannot interpret the masks.
When closely inspecting the preview image above, it basically appears to be a cloud free scene.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="new-preview-image-in-geotiff-format">New preview image in Geotiff format<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#new-preview-image-in-geotiff-format" class="hash-link" aria-label="Direct link to New preview image in Geotiff format" title="Direct link to New preview image in Geotiff format" translate="no">​</a></h3>
<p>Moving right along. The Python notebook has all the details, but here is the next visual:</p>
<p><img decoding="async" loading="lazy" alt="preview rgb geotiff" src="https://ricegeo.dev/assets/images/preview-geotiff-web-5cd2807935a439cd7e7c941ceb5ee85e.png" width="320" height="490" class="img_ev3q">
<br>(in-notebook visualization of the new preview image Geotiff, RGB, web-ready).</p>
<p>This Geotiff meets the key requirements:</p>
<ul>
<li class="">Geo-referenced</li>
<li class="">Vibrant in appearance</li>
</ul>
<p>Also note this preview image is the satellite base-map which is loaded into the interactive map viewer above.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="normalized-difference-water-index-ndwi">Normalized Difference Water Index (NDWI)<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#normalized-difference-water-index-ndwi" class="hash-link" aria-label="Direct link to Normalized Difference Water Index (NDWI)" title="Direct link to Normalized Difference Water Index (NDWI)" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="formula">Formula<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#formula" class="hash-link" aria-label="Direct link to Formula" title="Direct link to Formula" translate="no">​</a></h4>
<p><img decoding="async" loading="lazy" alt="NDWI formula" src="https://ricegeo.dev/assets/images/ndwi-formula-7145f5a91716d2fc72673220321b62a5.png" width="340" height="84" class="img_ev3q"></p>
<p>Where:</p>
<ul>
<li class=""><strong>Green</strong> = Band 9 (550 nm)</li>
<li class=""><strong>NIR</strong> = Band 30 (849 nm)</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="range-and-interpretation">Range and interpretation<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#range-and-interpretation" class="hash-link" aria-label="Direct link to Range and interpretation" title="Direct link to Range and interpretation" translate="no">​</a></h4>
<p>The range is [-1, 1] and interpretation is 1 = water and -1 = no water. Values closer to 1 indicate high probability of water, while values closer to -1 indicate non-water features like vegetation or dry soil. In typical applications:</p>
<ul>
<li class="">Values &gt; 0.3: Usually indicate water bodies</li>
<li class="">Values between 0 and 0.3: May indicate wet soil or mixed pixels</li>
<li class="">Values &lt; 0: Usually indicate vegetation or dry soil</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="make-water-mask-raster-from-ndwi">Make water mask raster from NDWI<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#make-water-mask-raster-from-ndwi" class="hash-link" aria-label="Direct link to Make water mask raster from NDWI" title="Direct link to Make water mask raster from NDWI" translate="no">​</a></h4>
<p>These images are copied from the notebook to visualize the pipeline for producing a water mask from NDWI.</p>
<p><img decoding="async" loading="lazy" alt="NDWI bands" src="https://ricegeo.dev/assets/images/ndwi-bands-preview-b888b29860bedb912a2e31931a093afc.png" width="989" height="569" class="img_ev3q">
<img decoding="async" loading="lazy" alt="NDWI preview" src="https://ricegeo.dev/assets/images/ndwi-preview-5000d6de27c35d9ce9ebe5c1cbd3a794.png" width="488" height="490" class="img_ev3q">
<img decoding="async" loading="lazy" alt="water mask" src="https://ricegeo.dev/assets/images/water-mask-preview-6d4c1c320efbb82bab0f6d9be7da7412.png" width="357" height="490" class="img_ev3q">
<br> (in-notebook visualizations of rasters)</p>
<p><img decoding="async" loading="lazy" alt="water mask vector" src="https://ricegeo.dev/assets/images/water-mask-preview-vectors-ef498bf771e280ec4d3ebf4ad067a6ca.png" width="1763" height="797" class="img_ev3q">
<br> (screen capture of in-notebook polygonized water mask in GeoJSON vector format)</p>
<div class="theme-admonition theme-admonition-danger admonition_xJq3 alert alert--danger"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"></path></svg></span>danger</div><div class="admonitionContent_BuS1"><p>There could be some quality issues with the generated water mask. Although it generally looks good, it is also detecting water on top of some buildings, so the threshold might need to be greater than 0.3 for less sensitivity.</p></div></div>
<p><img decoding="async" loading="lazy" alt="water mask QA" src="https://ricegeo.dev/assets/images/water-mask-qa-2019b43def0c41d7ad9a16c15b38ace3.png" width="1258" height="488" class="img_ev3q">
<br>(example of possible water on building roofs? pooled rainwater?)</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="normalized-difference-chlorophyll-index-ndci">Normalized Difference Chlorophyll Index (NDCI)<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#normalized-difference-chlorophyll-index-ndci" class="hash-link" aria-label="Direct link to Normalized Difference Chlorophyll Index (NDCI)" title="Direct link to Normalized Difference Chlorophyll Index (NDCI)" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="formula-1">Formula<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#formula-1" class="hash-link" aria-label="Direct link to Formula" title="Direct link to Formula" translate="no">​</a></h4>
<p><img decoding="async" loading="lazy" alt="NDCI formula" src="https://ricegeo.dev/assets/images/ndci-formula-237ab61bbefe2fff56a15632546cac89.png" width="360" height="92" class="img_ev3q"></p>
<p>Where</p>
<ul>
<li class=""><strong>RedEdge</strong> = Band 21 (712 nm)</li>
<li class=""><strong>Red</strong> = Band 17 (669 nm)</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="range-and-interpretation-1">Range and interpretation<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#range-and-interpretation-1" class="hash-link" aria-label="Direct link to Range and interpretation" title="Direct link to Range and interpretation" translate="no">​</a></h4>
<p>The range is [-1, 1] and the interpretation is:</p>
<ul>
<li class="">Higher positive values indicate higher chlorophyll-a concentration</li>
<li class="">Values near zero suggest low chlorophyll-a levels</li>
<li class="">Typical range is approximately -0.1 to +0.3 for most inland waters</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="make-ndci-rasters">Make NDCI rasters<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#make-ndci-rasters" class="hash-link" aria-label="Direct link to Make NDCI rasters" title="Direct link to Make NDCI rasters" translate="no">​</a></h4>
<p>These images are copied from the notebook to visualize the pipeline for calculating NDCI and creating the NDCI rasters.</p>
<p><img decoding="async" loading="lazy" alt="NDCI bands" src="https://ricegeo.dev/assets/images/ndci-bands-preview-9d7d3e734c33bfa085ce0845acd0f2dc.png" width="993" height="790" class="img_ev3q">
<img decoding="async" loading="lazy" alt="NDCI" src="https://ricegeo.dev/assets/images/ndci-preview-ec2dc5f1b6328e17d2cc668ff0bae73e.png" width="479" height="490" class="img_ev3q"></p>
<ul>
<li class="">Higher positive values indicate higher chlorophyll-a concentration</li>
<li class="">Values near zero suggest low chlorophyll-a levels</li>
<li class="">Typical range is approximately -0.1 to +0.3 for most inland waters</li>
</ul>
<p>Also note this NDCI raster is a layer which is loaded into the interactive map viewer above.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="concept-of-a-production-pipeline">Concept of a production pipeline<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#concept-of-a-production-pipeline" class="hash-link" aria-label="Direct link to Concept of a production pipeline" title="Direct link to Concept of a production pipeline" translate="no">​</a></h2>
<p>The linked Python notebook demonstrates a proof-of-concept, and it makes the following data products:</p>
<p>visual preview rasters</p>
<ul>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-L1B-viz.geotiff</li>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-L1B-viz-epsg-3857.geotiff</li>
</ul>
<p>NDWI-based water mask: analysis-ready, web-ready raster and vector</p>
<ul>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-water-mask.geotiff</li>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-water-mask-viz.geotiff</li>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-water-mask-viz-epsg-3857.geotiff</li>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-water-mask.geojson</li>
</ul>
<p>NDCI: analysis-ready and web-ready raster</p>
<ul>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-NDCI.geotiff</li>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-NDCI-viz.geotiff</li>
<li class="">wyvern_dragonette-003_20241229T165203_12324bcb-NDCI-viz-web-epsg-3857.geotiff</li>
</ul>
<p>What would this notebook look like in terms of a production pipeline? Here is a first diagram of a
pipeline, which it is also useful to know, is a Directed Acyclic Graph (DAG). In <a class="" target="_self" href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster">Part
2</a>, I wear my Data Engineer hat and port the Python code from the
notebook environment into Dagster, a production-grade data orchestrator.</p>
<svg xmlns="http://www.w3.org/2000/svg" width="669" height="1031" style="background:#fff;background-color:#fff;color-scheme:light" viewBox="-0.5 -0.5 669 1031"><rect width="100%" height="100%" fill="#fff" style="fill:#fff"></rect><g data-cell-id="0"><g data-cell-id="1"><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-3"><path fill="none" d="M93 60v20-12 13.63" pointer-events="stroke" style="stroke:#000"></path><path d="m93 86.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-1"><rect width="185" height="60" x="0.5" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:183px;height:1px;padding-top:30px;margin-left:2px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">STAC Catalog API query: data product,&nbsp; location + date range</div></div></div></foreignObject><text x="93" y="34" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">STAC Catalog API query: data pr...</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-5"><path fill="none" d="M93 148v20-8 13.63" pointer-events="stroke" style="stroke:#000"></path><path d="m93 178.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-37"><path fill="none" d="M33 118H13v583h13.63" pointer-events="stroke" style="stroke:#000"></path><path d="m31.88 701-7 3.5 1.75-3.5-1.75-3.5Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-51"><path fill="none" d="M153 118h225v55.63" pointer-events="stroke" style="stroke:#000"></path><path d="m378 178.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-2"><rect width="120" height="60" x="33" y="88" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:118px;height:1px;padding-top:118px;margin-left:34px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Read 6 of 32 raster bands from cloud object storage</div></div></div></foreignObject><text x="93" y="122" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Read 6 of 32 r...</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-12"><path fill="none" d="M33 210H13v211h13.63" pointer-events="stroke" style="stroke:#000"></path><path d="m31.88 421-7 3.5 1.75-3.5-1.75-3.5Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-4"><rect width="120" height="60" x="33" y="180" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:118px;height:1px;padding-top:210px;margin-left:34px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Make validity masks</div></div></div></foreignObject><text x="93" y="214" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Make validity masks</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-9"><path fill="none" d="M378 240v20-4 13.63" pointer-events="stroke" style="stroke:#000"></path><path d="m378 274.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-6"><rect width="120" height="60" x="318" y="180" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:118px;height:1px;padding-top:210px;margin-left:319px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Make Visual RGB preview raster</div></div></div></foreignObject><text x="378" y="214" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Make Visual RGB prev...</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-47"><path fill="none" d="M378 306v8.63" pointer-events="stroke" style="stroke:#000"></path><path d="m378 319.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-10"><path fill="none" d="M523 291h85.5l-.5 672.63" pointer-events="stroke" style="stroke:#000"></path><path d="m608 968.88-3.49-7 3.49 1.75 3.51-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-8"><rect width="290" height="30" x="233" y="276" fill="#fff" stroke="#000" pointer-events="all" rx="4.5" ry="4.5" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:288px;height:1px;padding-top:291px;margin-left:234px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">{scene_id}-L1B-viz.geotiff</div></div></div></foreignObject><text x="378" y="295" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">{scene_id}-L1B-viz.geotiff</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-19"><path fill="none" d="M93 451v20-10 13.63" pointer-events="stroke" style="stroke:#000"></path><path d="m93 479.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-12"><rect width="120" height="60" x="33" y="391" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:118px;height:1px;padding-top:421px;margin-left:34px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Calculate NDWI index</div></div></div></foreignObject><text x="93" y="425" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Calculate NDWI index</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-39"><path fill="none" d="M93 731v37.63" pointer-events="stroke" style="stroke:#000"></path><path d="m93 773.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-14"><rect width="120" height="60" x="33" y="671" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:118px;height:1px;padding-top:701px;margin-left:34px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Calculate NDCI index</div></div></div></foreignObject><text x="93" y="705" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Calculate NDCI index</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-20"><path fill="none" d="M93 541v123.63" pointer-events="stroke" style="stroke:#000"></path><path d="m93 669.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-22"><path fill="none" d="M153 511h73.63" pointer-events="stroke" style="stroke:#000"></path><path d="m231.88 511-7 3.5 1.75-3.5-1.75-3.5Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-23"><path fill="none" d="M153 511h73.63" pointer-events="stroke" style="stroke:#000"></path><path d="m231.88 511-7 3.5 1.75-3.5-1.75-3.5Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-25"><path fill="none" d="M153 511h21.3v135h14.83" pointer-events="stroke" style="stroke:#000"></path><path d="m194.38 646-7 3.5 1.75-3.5-1.75-3.5Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-18"><rect width="120" height="60" x="33" y="481" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:118px;height:1px;padding-top:511px;margin-left:34px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Make water mask raster</div></div></div></foreignObject><text x="93" y="515" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Make water mask rast...</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-49"><path fill="none" d="M378 528.5v6.13" pointer-events="stroke" style="stroke:#000"></path><path d="m378 539.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-8"><path fill="none" d="M523 511h85.5l-.49 452.63" pointer-events="stroke" style="stroke:#000"></path><path d="m608 968.88-3.49-7 3.5 1.75 3.5-1.74Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-21"><rect width="290" height="35" x="233" y="493.5" fill="#fff" stroke="#000" pointer-events="all" rx="5.25" ry="5.25" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:288px;height:1px;padding-top:511px;margin-left:234px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">{scene_id}-water-mask.geotiff<br>{scene_id}-water-mask-viz.geotiff</div></div></div></foreignObject><text x="378" y="515" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">{scene_id}-water-mask.geotiff...</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-27"><path fill="none" d="M275.5 646h43.63" pointer-events="stroke" style="stroke:#000"></path><path d="m324.38 646-7 3.5 1.75-3.5-1.75-3.5Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-24"><rect width="80" height="30" x="195.5" y="631" fill="#fff" stroke="#000" pointer-events="all" rx="4.5" ry="4.5" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:78px;height:1px;padding-top:646px;margin-left:197px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Polygonize</div></div></div></foreignObject><text x="236" y="650" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Polygonize</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-6"><path fill="none" d="M525.5 646h83l-.49 327.63" pointer-events="stroke" style="stroke:#000"></path><path d="m608 978.88-3.49-7 3.5 1.75 3.5-1.74Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-26"><rect width="200" height="30" x="325.5" y="631" fill="#fff" stroke="#000" pointer-events="all" rx="4.5" ry="4.5" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:198px;height:1px;padding-top:646px;margin-left:327px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">{scene_id}-water-mask.geojson</div></div></div></foreignObject><text x="426" y="650" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">{scene_id}-water-mask.geojson</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-50"><path fill="none" d="M378 571v3.63" pointer-events="stroke" style="stroke:#000"></path><path d="m378 579.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-28"><rect width="80" height="30" x="338" y="541" fill="#fff" stroke="#000" pointer-events="all" rx="4.5" ry="4.5" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:78px;height:1px;padding-top:556px;margin-left:339px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Transform</div></div></div></foreignObject><text x="378" y="560" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Transform</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-48"><path fill="none" d="M378 351v3.63" pointer-events="stroke" style="stroke:#000"></path><path d="m378 359.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-29"><rect width="80" height="30" x="338" y="321" fill="#fff" stroke="#000" pointer-events="all" rx="4.5" ry="4.5" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:78px;height:1px;padding-top:336px;margin-left:339px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Transform</div></div></div></foreignObject><text x="378" y="340" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Transform</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-9"><path fill="none" d="M523 376h85.5l-.49 587.63" pointer-events="stroke" style="stroke:#000"></path><path d="m608 968.88-3.49-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-30"><rect width="290" height="30" x="233" y="361" fill="#fff" stroke="#000" pointer-events="all" rx="4.5" ry="4.5" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:288px;height:1px;padding-top:376px;margin-left:234px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">{scene_id}-L1B-viz-epsg-3857.geotiff</div></div></div></foreignObject><text x="378" y="380" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">{scene_id}-L1B-viz-epsg-3857.geotiff</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-7"><path fill="none" d="M523 588.5h85.5l-.49 375.13" pointer-events="stroke" style="stroke:#000"></path><path d="m608 968.88-3.49-7 3.5 1.75 3.5-1.74Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-34"><rect width="290" height="30" x="233" y="581" fill="#fff" stroke="#000" pointer-events="all" rx="4.5" ry="4.5" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:288px;height:1px;padding-top:596px;margin-left:234px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal"><div>{scene_id}-water-mask-viz-epsg-3857.geotiff</div></div></div></div></foreignObject><text x="378" y="600" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">{scene_id}-water-mask-viz-epsg-3857.geotiff</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-41"><path fill="none" d="M153 805h40v-1h33.63" pointer-events="stroke" style="stroke:#000"></path><path d="m231.88 804-7 3.5 1.75-3.5-1.75-3.5Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-38"><rect width="120" height="60" x="33" y="775" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:118px;height:1px;padding-top:805px;margin-left:34px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Make NDCI rasters</div></div></div></foreignObject><text x="93" y="809" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Make NDCI rasters</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-4"><path fill="none" d="M378 820v8.63" pointer-events="stroke" style="stroke:#000"></path><path d="m378 833.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-5"><path fill="none" d="M523 804h85v159.63" pointer-events="stroke" style="stroke:#000"></path><path d="m608 968.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-40"><rect width="290" height="32" x="233" y="788" fill="#fff" stroke="#000" pointer-events="all" rx="4.8" ry="4.8" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:288px;height:1px;padding-top:804px;margin-left:234px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">{scene_id}-NDCI.geotiff<div><div>{scene_id}-NDCI-viz.geotiff</div></div></div></div></div></foreignObject><text x="378" y="808" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">{scene_id}-NDCI.geotiff...</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="OJW0tq4aHfshG87-vFjV-46"><path fill="none" d="M378 865v20-24 13.63" pointer-events="stroke" style="stroke:#000"></path><path d="m378 879.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-44"><rect width="80" height="30" x="338" y="835" fill="#fff" stroke="#000" pointer-events="all" rx="4.5" ry="4.5" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:78px;height:1px;padding-top:850px;margin-left:339px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Transform</div></div></div></foreignObject><text x="378" y="854" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Transform</text></switch></g><g stroke="#000" stroke-miterlimit="10" data-cell-id="K9LZBKAtgWK0p3kn8oWN-3"><path fill="none" d="M533 901h75v62.63" pointer-events="stroke" style="stroke:#000"></path><path d="m608 968.88-3.5-7 3.5 1.75 3.5-1.75Z" pointer-events="all" style="fill:#000;stroke:#000"></path></g><g data-cell-id="OJW0tq4aHfshG87-vFjV-45"><rect width="310" height="40" x="223" y="881" fill="#fff" stroke="#000" pointer-events="all" rx="6" ry="6" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:308px;height:1px;padding-top:901px;margin-left:224px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal"><div>{scene_id}-NDCI-viz-web-epsg-3857.geotiff</div></div></div></div></foreignObject><text x="378" y="905" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">{scene_id}-NDCI-viz-web-epsg-3857.geotiff</text></switch></g><g data-cell-id="K9LZBKAtgWK0p3kn8oWN-1"><rect width="120" height="60" x="548" y="970" fill="#fff" stroke="#000" pointer-events="all" rx="9" ry="9" style="fill:#fff;stroke:#000"></rect><switch transform="translate(-.5 -.5)"><foreignObject width="100%" height="100%" pointer-events="none" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow:visible;text-align:left"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe center;width:118px;height:1px;padding-top:1000px;margin-left:549px"><div style="box-sizing:border-box;font-size:0;text-align:center;color:#000"><div style="display:inline-block;font-size:12px;font-family:&amp;quot;color:#000;line-height:1.2;pointer-events:all;white-space:normal;word-wrap:normal">Pipeline finish</div></div></div></foreignObject><text x="608" y="1004" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12" text-anchor="middle">Pipeline finish</text></switch></g></g></g></svg>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="links-to-notebook-at-nbviewer-and-github">Links to notebook at NBviewer and GitHub<a href="https://ricegeo.dev/hab-detection-wyvern-hsi#links-to-notebook-at-nbviewer-and-github" class="hash-link" aria-label="Direct link to Links to notebook at NBviewer and GitHub" title="Direct link to Links to notebook at NBviewer and GitHub" translate="no">​</a></h2>
<p>This walkthrough blog post was just a high level view. The notebook has a lot more explanatory text and Python source
code.</p>
<ul>
<li class=""><a href="https://nbviewer.org/github/guidorice/hab-detection-wyvern-hsi/blob/main/notebooks/eda-hab-detection-wyvern-hsi.ipynb" target="_self" rel="noopener noreferrer" class="">View notebook at NBviewer.org</a></li>
<li class=""><a href="https://github.com/guidorice/hab-detection-wyvern-hsi/blob/main/notebooks/eda-hab-detection-wyvern-hsi.ipynb" target="_self" rel="noopener noreferrer" class="">View at Github</a></li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>imagery attribution</div><div class="admonitionContent_BuS1"><p>©2024 Wyvern Incorporated. All Rights Reserved.</p></div></div>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>edits</div><div class="admonitionContent_BuS1"><ul>
<li class="">2025-06-04 Remove Claude 3.7 quote and attribution and just inline the content (seems like best practice these days).</li>
<li class="">2025-06-09 Correct the number of bands in Dragonette constellation: 23-32.</li>
<li class="">2025-06-10 Add Guardian article about HABs.</li>
<li class="">2025-07-26 Add link to Wyvern's write up and feature.</li>
<li class="">2025-08-10 Add link to <a class="" target="_self" href="https://ricegeo.dev/hab-detection-wyvern-hsi-dagster">Part 2</a>!</li>
</ul></div></div>]]></content:encoded>
            <category>cloud</category>
            <category>dev</category>
            <category>gdal-ogr</category>
            <category>gis</category>
            <category>linux</category>
            <category>map</category>
            <category>python</category>
            <category>raster</category>
            <category>react</category>
            <category>vector</category>
        </item>
        <item>
            <title><![CDATA[GIS command-line "gems" for Linux and macOS]]></title>
            <link>https://ricegeo.dev/gis-cli-gems</link>
            <guid>https://ricegeo.dev/gis-cli-gems</guid>
            <pubDate>Sun, 16 Mar 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[In this part two of Linux posts, we'll discover some Geographic Information Systems (GIS) command-line interface (CLI)]]></description>
            <content:encoded><![CDATA[<p>In this part two of Linux posts, we'll discover some Geographic Information Systems (GIS) command-line interface (CLI)
"gems" which work on Linux, Unix, or macOS. This is by no means an exhaustive list, and the intent is just to illustrate
how powerful and extensible the Linux development environment is for geodata wrangling...</p>
<p>In part one of this series, I shared my <a class="" target="_self" href="https://ricegeo.dev/linux-user-30-years">story of being a Linux user for 30 years</a>.
Now let's dive into some specific, useful GIS related commands.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="gdal">GDAL<a href="https://ricegeo.dev/gis-cli-gems#gdal" class="hash-link" aria-label="Direct link to GDAL" title="Direct link to GDAL" translate="no">​</a></h2>
<p><a href="https://gdal.org/" target="_self" rel="noopener noreferrer" class="">Geospatial Data Abstraction Library (GDAL)</a> installs literally 30+ different <a href="https://gdal.org/en/stable/programs" target="_self" rel="noopener noreferrer" class="">raster utility
programs</a>, like <code>gdalinfo</code>, <code>gdalwarp</code>, <code>gdal_translate</code>, <code>gdal_merge</code>,
<code>gdal_polygonize</code> and many more.</p>
<p>Do you have a GIS raster which you want to work with or convert? Begin with <code>gdalinfo {filename}</code> to inspect it's bands,
CRS, resolution, and other metadata. GDAL supports dozens of raster drivers for just about any raster file format you
can think of. Common use cases include:</p>
<ul>
<li class="">reading metadata</li>
<li class="">converting formats</li>
<li class="">reprojecting</li>
<li class="">masking</li>
<li class="">merging</li>
<li class="">rasterization</li>
<li class="">vectorizing / polygonizing</li>
<li class="">building overviews</li>
<li class="">Virtual Raster Tiles (VRTs): a powerful feature for working with virtual datasets.</li>
</ul>
<p>GDAL can also read directly from object storage (AWS S3), using it's <a href="https://gdal.org/en/stable/user/virtual_file_systems.html" target="_self" rel="noopener noreferrer" class="">Virtual File Systems drivers</a>, for example:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ gdalinfo /vsis3/sentinel-cogs/sentinel-s2-l2a-cogs/46/C/DB/2022/10/S2B_46CDB_20221003_0_L2A/B02.tif</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Driver: GTiff/GeoTIFF</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Files: /vsis3/sentinel-cogs/sentinel-s2-l2a-cogs/46/C/DB/2022/10/S2B_46CDB_20221003_0_L2A/B02.tif</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Size is 10980, 10980</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Coordinate System is:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">PROJCRS["WGS 84 / UTM zone 46S",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">...</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ogr">OGR<a href="https://ricegeo.dev/gis-cli-gems#ogr" class="hash-link" aria-label="Direct link to OGR" title="Direct link to OGR" translate="no">​</a></h2>
<p>OGR Simple Features Library (OGR) is included with GDAL, which is why they are often referred to as "GDAL/OGR". OGR
installs <a href="https://gdal.org/en/stable/programs" target="_self" rel="noopener noreferrer" class="">several vector programs</a>:</p>
<ul>
<li class=""><code>ogrinfo</code> works just like <code>gdalinfo</code>, but for vector data.</li>
<li class=""><code>ogr2ogr</code> is indispensable for converting between vector formats as well as searching, filtering and
transforming vector datasets.</li>
</ul>
<p>OGR supports dozens of <a href="https://gdal.org/en/stable/drivers/vector" target="_self" rel="noopener noreferrer" class="">vector drivers</a> for just about any vector
file format imaginable.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pdal">PDAL<a href="https://ricegeo.dev/gis-cli-gems#pdal" class="hash-link" aria-label="Direct link to PDAL" title="Direct link to PDAL" translate="no">​</a></h2>
<p><a href="https://pdal.io/" target="_self" rel="noopener noreferrer" class="">Point Data Abstraction Library (PDAL)</a> is very much like GDAL, but PDAL is for translating and manipulating point cloud data, for example Lidar.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pdal --help</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="jq">Jq<a href="https://ricegeo.dev/gis-cli-gems#jq" class="hash-link" aria-label="Direct link to Jq" title="Direct link to Jq" translate="no">​</a></h2>
<p><code>jq</code> is a command-line JSON processor. Technically it's not a GIS-specific tool, however it is a lightweight and
flexible command-line JSON processor. The <a href="https://geojson.org/" target="_self" rel="noopener noreferrer" class="">GeoJSON</a> format is common in GIS applications,
especially in web applications with RESTful APIs, and GeoJSON is also the foundation for the <a href="https://stacspec.org/" target="_self" rel="noopener noreferrer" class="">SpatioTemporal Asset
Catalog (STAC)</a> specification.  Typical usage includes:</p>
<ol>
<li class="">pretty-printing</li>
<li class="">querying and filtering</li>
<li class="">printing feature attributes</li>
</ol>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">jq --help</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rasterio">Rasterio<a href="https://ricegeo.dev/gis-cli-gems#rasterio" class="hash-link" aria-label="Direct link to Rasterio" title="Direct link to Rasterio" translate="no">​</a></h2>
<p><a href="https://rasterio.readthedocs.io/en/stable/" target="_self" rel="noopener noreferrer" class="">Rasterio</a> is a Python library that reads and writes geospatial raster
datasets. It's built on top of GDAL and Numpy, and provides a Pythonic interface to GDAL's data model. Rasterio is a
powerful tool for reading and writing raster data in Python.</p>
<p>Rasterio also installs a cli program, <code>rio</code>, which is similar in purpose to GDAL's command line programs but <code>rio</code> is
simpler, friendlier, and has better support for <a href="https://cogeo.org/" target="_self" rel="noopener noreferrer" class="">Cloud Optimized Geotiff (COG)</a>. Here is a quick
start to install <code>rio</code>:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">python -m venv venv/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">source venv/bin/activate</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pip install rasterio</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rio --help</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="fiona">Fiona<a href="https://ricegeo.dev/gis-cli-gems#fiona" class="hash-link" aria-label="Direct link to Fiona" title="Direct link to Fiona" translate="no">​</a></h2>
<blockquote>
<p>Fiona can read and write real-world data using multi-layered GIS formats, zipped and in-memory virtual file systems,
from files on your hard drive or in cloud storage. This project includes Python modules and a command line interface
(CLI). <a href="https://fiona.readthedocs.io/en/latest/README.html" target="_self" rel="noopener noreferrer" class="">Fiona docs</a></p>
</blockquote>
<p>Fiona also installs a cli program, <code>fio</code>. Here is a quick start to install <code>fio</code>:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">python -m venv venv/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">source venv/bin/activate</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pip install fiona</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fio --help</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="duckdb">DuckDB<a href="https://ricegeo.dev/gis-cli-gems#duckdb" class="hash-link" aria-label="Direct link to DuckDB" title="Direct link to DuckDB" translate="no">​</a></h2>
<p><a href="https://duckdb.org/" target="_self" rel="noopener noreferrer" class="">DuckDB</a> is an in-process, analytical, portable database which supports geospatial formats and
queries. I don't have experience with it  (yet) but <a href="https://tech.marksblogg.com/wyvern-open-data-feed.html" target="_self" rel="noopener noreferrer" class="">Mark Litwintschik recently wrote a blog
post</a> about <a href="https://wyvern.space/" target="_self" rel="noopener noreferrer" class="">Wyvern's</a> Open Data feed of
hyperspectral remote sensing imagery, where he uses <code>duckdb</code> as well as several other Linux cli tools.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">duckdb --help</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docker-one-liners-">Docker one-liners 🐳<a href="https://ricegeo.dev/gis-cli-gems#docker-one-liners-" class="hash-link" aria-label="Direct link to Docker one-liners 🐳" title="Direct link to Docker one-liners 🐳" translate="no">​</a></h2>
<p>Install <a href="https://www.docker.com/" target="_self" rel="noopener noreferrer" class="">Docker Desktop</a> (Mac, Win) or Docker Engine (Linux) and then you can run lightweight
containers, as shown in the following examples:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="titiler-raster-tiling">TiTiler raster tiling<a href="https://ricegeo.dev/gis-cli-gems#titiler-raster-tiling" class="hash-link" aria-label="Direct link to TiTiler raster tiling" title="Direct link to TiTiler raster tiling" translate="no">​</a></h3>
<p><a href="https://developmentseed.org/titiler/" target="_self" rel="noopener noreferrer" class="">TiTiler</a>, pronounced tee-tiler (ti is the diminutive version of the french petit
which means small), is a set of Python modules that focus on creating <a href="https://fastapi.tiangolo.com/" target="_self" rel="noopener noreferrer" class="">FastAPI</a>
applications for dynamic tiling. A common use case is on-demand raster tiles from <a href="https://cogeo.org/" target="_self" rel="noopener noreferrer" class="">Cloud Optimized Geotiff
(COG)</a> hosted in S3 or other object storage.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">docker run --name try-titiler \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --platform=linux/amd64 -p 8000:8000 --rm \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ghcr.io/developmentseed/titiler:latest \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  uvicorn titiler.application.main:app --host 0.0.0.0 --port 8000 --workers 1</span><br></span></code></pre></div></div>
<p>Then browse to <a href="http://localhost:8000/" target="_self" rel="noopener noreferrer" class="">http://localhost:8000</a> to start using TiTiler.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="postgresql-with-postgis">PostgreSQL with PostGIS<a href="https://ricegeo.dev/gis-cli-gems#postgresql-with-postgis" class="hash-link" aria-label="Direct link to PostgreSQL with PostGIS" title="Direct link to PostgreSQL with PostGIS" translate="no">​</a></h3>
<p><a href="https://postgis.net/" target="_self" rel="noopener noreferrer" class="">PostGIS</a> extends the capabilities of the <a href="https://www.postgresql.org/" target="_self" rel="noopener noreferrer" class="">PostgreSQL</a> relational
database by adding support for storing, indexing, and querying geospatial data. Why fumble around with a download and a
GUI installer, when you can just run one docker command! Remember to replace the password string <code>*****</code> with a new password:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">mkdir -p ~/pgdata</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">docker run --name try-postgis \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -p 5432:5432 --rm \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -e POSTGRES_PASSWORD=***** \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -e PGDATA=/var/lib/postgresql/data/pgdata \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -v ${HOME}/pgdata:/var/lib/postgresql/data \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  postgis/postgis:17-3.5</span><br></span></code></pre></div></div>
<p>Then connect to Postgres using <code>psql</code>, DBeaver, PgAdmin, or any Postgres SDK. The latest version tags for the docker
image e.g. <code>postgis:17-3.5</code> are <a href="https://github.com/postgis/docker-postgis" target="_self" rel="noopener noreferrer" class="">available on GitHub</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="qgis-as-raster-tile-server">QGIS as raster tile server<a href="https://ricegeo.dev/gis-cli-gems#qgis-as-raster-tile-server" class="hash-link" aria-label="Direct link to QGIS as raster tile server" title="Direct link to QGIS as raster tile server" translate="no">​</a></h3>
<p>Do you have a <a href="https://www.qgis.org/" target="_self" rel="noopener noreferrer" class="">QGIS</a> project (<code>.qgz</code> file) with 42 map layers which you worked on for 18 months,
and now you have to publish it to the web? 😅 No problem- QGIS Server can serve up raster tiles via open standards like
WMTS, WMS, XYZ, TMS, WFS, or WCS.</p>
<ul>
<li class="">XYZ format may be easiest for integration with the <a href="https://www.mapbox.com/" target="_self" rel="noopener noreferrer" class="">Mapbox</a>,
<a href="https://openlayers.org/" target="_self" rel="noopener noreferrer" class="">OpenLayers</a>, and <a href="https://leafletjs.com/" target="_self" rel="noopener noreferrer" class="">Leaflet</a> web map packages.</li>
<li class="">QGIS Server can be slow, depending on the complexity of your map layers, so you will likely want to setup a caching
layer such as <a href="https://varnish-cache.org/" target="_self" rel="noopener noreferrer" class="">Varnish</a>, <a href="http://tilestache.org/" target="_self" rel="noopener noreferrer" class="">TileStache</a>, or a cloud CDN.</li>
</ul>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">docker run --name try-qgis-server \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:80 --rm \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -v /path/to/your/project.qgz:/etc/qgisserver/project.qgz \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  -e QGIS_PROJECT_FILE=/etc/qgisserver/project.qgz \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  qgis/qgis-server:latest</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>Some additional setup may be needed</p><ol>
<li class="">If your QGIS project references data that isn't embedded in the QGZ file, you'll need to add volume mounts for those
data directories as well.</li>
<li class="">Some additional project and layer configuration may be needed. More info at <a href="https://docs.qgis.org/latest/en/docs/server_manual" target="_self" rel="noopener noreferrer" class="">QGIS Server docs</a>.</li>
</ol></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cloud-native-geospatial-cng">Cloud-Native Geospatial (CNG)<a href="https://ricegeo.dev/gis-cli-gems#cloud-native-geospatial-cng" class="hash-link" aria-label="Direct link to Cloud-Native Geospatial (CNG)" title="Direct link to Cloud-Native Geospatial (CNG)" translate="no">​</a></h2>
<p>Check out the <a href="https://guide.cloudnativegeo.org/" target="_self" rel="noopener noreferrer" class="">Cloud-Optimized Geospatial Formats Guide</a> for more useful recipes,
formats, and programs.</p>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>edits</div><div class="admonitionContent_BuS1"><ul>
<li class="">2025-03-21 Update Docker commands for consistency and macOS usage.</li>
</ul></div></div>]]></content:encoded>
            <category>cloud</category>
            <category>dev</category>
            <category>gis</category>
            <category>gdal-ogr</category>
            <category>linux</category>
            <category>python</category>
            <category>webdev</category>
        </item>
        <item>
            <title><![CDATA[Celebrating 30 years as a Linux user]]></title>
            <link>https://ricegeo.dev/linux-user-30-years</link>
            <guid>https://ricegeo.dev/linux-user-30-years</guid>
            <pubDate>Sat, 08 Feb 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[In this post, I'll share my 30 year journey with Linux and explore how it shaped my future as a developer. Along the]]></description>
            <content:encoded><![CDATA[<p>In this post, I'll share my 30 year journey with Linux and explore how it shaped my future as a developer. Along the
way, we'll take a nostalgic stroll down computer hardware memory lane. We'll touch on challenges with legacy MS
Windows systems today, in the public sector. In a followup post we'll look at various useful Linux/macOS commands for
GIS and geodata wrangling...</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>disclaimer</div><div class="admonitionContent_BuS1"><p>These views and opinions are my solely my own, and do not represent my employer.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-linux">What is Linux<a href="https://ricegeo.dev/linux-user-30-years#what-is-linux" class="hash-link" aria-label="Direct link to What is Linux" title="Direct link to What is Linux" translate="no">​</a></h2>
<blockquote>
<p>Linux has been around since the mid-1990s and has since reached a user-base that spans the globe. Linux is actually everywhere: It's in your phones, your thermostats, in your cars, refrigerators, Roku devices, and televisions. It also runs most of the Internet, all of the world's <a href="https://www.top500.org/" target="_self" rel="noopener noreferrer" class="">top 500 supercomputers</a>, and the world's stock exchanges. Source: <a href="https://www.linux.com/what-is-linux/" target="_self" rel="noopener noreferrer" class="">The Linux Foundation</a></p>
</blockquote>
<p>This is expanded below in <a href="https://ricegeo.dev/linux-user-30-years#linux-won-the-internet-and-developer-mind-share" class="" target="_self">Postscript: Linux won the Internet and developer mind-share</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="hello-tux">Hello, Tux<a href="https://ricegeo.dev/linux-user-30-years#hello-tux" class="hash-link" aria-label="Direct link to Hello, Tux" title="Direct link to Hello, Tux" translate="no">​</a></h3>
<!-- -->
<div style="float:left;margin-right:1em"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 216 256" width="100px"><title>Tux</title><defs><linearGradient id="a"><stop offset="0"></stop><stop offset="1" stop-opacity="0.25"></stop></linearGradient><linearGradient id="g"><stop offset="0" stop-color="#110800"></stop><stop offset="0.59" stop-color="#a65a00" stop-opacity="0.8"></stop><stop offset="1" stop-color="#ff921e" stop-opacity="0"></stop></linearGradient><linearGradient id="h"><stop offset="0" stop-color="#7c7c7c"></stop><stop offset="1" stop-color="#7c7c7c" stop-opacity="0.33"></stop></linearGradient><linearGradient id="i"><stop offset="0" stop-color="#7c7c7c"></stop><stop offset="1" stop-color="#7c7c7c" stop-opacity="0.33"></stop></linearGradient><linearGradient id="b"><stop offset="0" stop-color="#b98309"></stop><stop offset="1" stop-color="#382605"></stop></linearGradient><linearGradient id="c"><stop offset="0" stop-color="#ebc40c"></stop><stop offset="1" stop-color="#ebc40c" stop-opacity="0"></stop></linearGradient><linearGradient id="d"><stop offset="0"></stop><stop offset="1" stop-opacity="0"></stop></linearGradient><linearGradient id="e"><stop offset="0" stop-color="#3e2a06"></stop><stop offset="1" stop-color="#ad780a"></stop></linearGradient><linearGradient id="f"><stop offset="0" stop-color="#f3cd0c"></stop><stop offset="1" stop-color="#f3cd0c" stop-opacity="0"></stop></linearGradient><linearGradient id="j"><stop offset="0" stop-color="#fefefc"></stop><stop offset="0.75" stop-color="#fefefc"></stop><stop offset="1" stop-color="#d4d4d4"></stop></linearGradient><linearGradient id="k"><stop offset="0" stop-color="#757574" stop-opacity="0"></stop><stop offset="0.25" stop-color="#757574"></stop><stop offset="0.5" stop-color="#757574"></stop><stop offset="1" stop-color="#757574" stop-opacity="0"></stop></linearGradient><linearGradient id="n"><stop offset="0" stop-color="#949494" stop-opacity="0.39"></stop><stop offset="0.5" stop-color="#949494"></stop><stop offset="1" stop-color="#949494" stop-opacity="0.39"></stop></linearGradient><linearGradient id="l"><stop offset="0" stop-color="#c8c8c8"></stop><stop offset="1" stop-color="#797978"></stop></linearGradient><linearGradient id="o"><stop offset="0" stop-color="#747474"></stop><stop offset="0.13" stop-color="#8c8c8c"></stop><stop offset="0.25" stop-color="#a4a4a4"></stop><stop offset="0.5" stop-color="#d4d4d4"></stop><stop offset="0.62" stop-color="#d4d4d4"></stop><stop offset="1" stop-color="#7c7c7c"></stop></linearGradient><linearGradient id="m"><stop offset="0" stop-color="#646464" stop-opacity="0"></stop><stop offset="0.31" stop-color="#646464" stop-opacity="0.58"></stop><stop offset="0.47" stop-color="#646464"></stop><stop offset="0.73" stop-color="#646464" stop-opacity="0.26"></stop><stop offset="1" stop-color="#646464" stop-opacity="0"></stop></linearGradient><linearGradient id="p"><stop offset="0" stop-color="#020204"></stop><stop offset="0.73" stop-color="#020204"></stop><stop offset="1" stop-color="#5c5c5c"></stop></linearGradient><linearGradient id="q"><stop offset="0" stop-color="#d2940a"></stop><stop offset="0.75" stop-color="#d89c08"></stop><stop offset="0.87" stop-color="#b67e07"></stop><stop offset="1" stop-color="#946106"></stop></linearGradient><linearGradient id="r"><stop offset="0" stop-color="#ad780a"></stop><stop offset="0.12" stop-color="#d89e08"></stop><stop offset="0.25" stop-color="#edb80b"></stop><stop offset="0.39" stop-color="#ebc80d"></stop><stop offset="0.53" stop-color="#f5d838"></stop><stop offset="0.77" stop-color="#f6d811"></stop><stop offset="1" stop-color="#f5cd31"></stop></linearGradient><linearGradient id="s"><stop offset="0" stop-color="#3a2903"></stop><stop offset="0.55" stop-color="#735208"></stop><stop offset="1" stop-color="#ac8c04"></stop></linearGradient><linearGradient id="t"><stop offset="0" stop-color="#f5ce2d"></stop><stop offset="1" stop-color="#d79b08"></stop></linearGradient><linearGradient href="#b" id="V" x1="23.18" x2="64.31" y1="193.01" y2="262.02" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#c" id="Z" x1="64.47" x2="77.41" y1="210.83" y2="235.21" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#d" id="ab" x1="146.93" x2="150.2" y1="211.96" y2="235.73" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#e" id="ad" x1="151.5" x2="192.94" y1="253.02" y2="185.84" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#f" id="ah" x1="162.81" x2="161.59" y1="180.67" y2="191.64" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#i" id="ar" x1="165.69" x2="168.27" y1="173.58" y2="173.47" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#k" id="at" x1="84.29" x2="89.32" y1="46.64" y2="55.63" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#m" id="ay" x1="83.59" x2="94.48" y1="32.51" y2="43.63" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#n" id="aB" x1="117.87" x2="123.66" y1="47.25" y2="54.11" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#o" id="aE" x1="112.9" x2="131.32" y1="36.23" y2="47.01" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#m" id="aG" x1="119.16" x2="131.42" y1="31.56" y2="43.14" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#r" id="aP" x1="78.09" x2="126.77" y1="69.26" y2="68.88" gradientUnits="userSpaceOnUse"></linearGradient><linearGradient href="#t" id="aW" x1="126.74" x2="126.74" y1="67.49" y2="71.09" gradientUnits="userSpaceOnUse"></linearGradient><filter id="H"><feGaussianBlur stdDeviation="0.64 0.55"></feGaussianBlur></filter><filter id="K"><feGaussianBlur stdDeviation="0.98"></feGaussianBlur></filter><filter id="M"><feGaussianBlur stdDeviation="0.68"></feGaussianBlur></filter><filter id="N" width="2.6" height="1.4" x="-0.8" y="-0.2"><feGaussianBlur stdDeviation="1.25"></feGaussianBlur></filter><filter id="O" width="2.6" height="2" x="-0.8" y="-0.5"><feGaussianBlur stdDeviation="1.78 2.19"></feGaussianBlur></filter><filter id="P" width="1.6" height="1.6" x="-0.3" y="-0.3"><feGaussianBlur stdDeviation="1.73"></feGaussianBlur></filter><filter id="Q" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.78"></feGaussianBlur></filter><filter id="R" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.98"></feGaussianBlur></filter><filter id="T" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="1.19 1.17"></feGaussianBlur></filter><filter id="W" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="3.38"></feGaussianBlur></filter><filter id="Y"><feGaussianBlur stdDeviation="2.1 2.06"></feGaussianBlur></filter><filter id="aa"><feGaussianBlur stdDeviation="0.32"></feGaussianBlur></filter><filter id="ac"><feGaussianBlur stdDeviation="1.95 1.9"></feGaussianBlur></filter><filter id="ae" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="4.12"></feGaussianBlur></filter><filter id="ag" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="3.12 3.37"></feGaussianBlur></filter><filter id="ai" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.41"></feGaussianBlur></filter><filter id="ak" width="1.6" height="1.6" x="-0.3" y="-0.3"><feGaussianBlur stdDeviation="2.45"></feGaussianBlur></filter><filter id="am" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="1.12 0.81"></feGaussianBlur></filter><filter id="ap" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.88"></feGaussianBlur></filter><filter id="au" width="1.6" height="1.6" x="-0.3" y="-0.3"><feGaussianBlur stdDeviation="0.44"></feGaussianBlur></filter><filter id="az"><feGaussianBlur stdDeviation="0.12"></feGaussianBlur></filter><filter id="aC" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.45"></feGaussianBlur></filter><filter id="aH"><feGaussianBlur stdDeviation="0.13"></feGaussianBlur></filter><filter id="aI" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="1.75"></feGaussianBlur></filter><filter id="aJ"><feGaussianBlur stdDeviation="0.8 0.74"></feGaussianBlur></filter><filter id="aM" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.77"></feGaussianBlur></filter><filter id="aO"><feGaussianBlur stdDeviation="0.65"></feGaussianBlur></filter><filter id="aQ" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.73"></feGaussianBlur></filter><filter id="aT" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.1"></feGaussianBlur></filter><filter id="aV"><feGaussianBlur stdDeviation="0.1"></feGaussianBlur></filter><filter id="aX" width="1.4" height="1.4" x="-0.2" y="-0.2"><feGaussianBlur stdDeviation="0.23"></feGaussianBlur></filter><radialGradient href="#a" id="G" cx="0" cy="0" r="1" gradientTransform="matrix(19 0 0 18 61.18 121.19)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#a" id="J" cx="0" cy="0" r="1" gradientTransform="matrix(23.6 0 0 18 125.74 131.6)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#a" id="L" cx="0" cy="0" r="1" gradientTransform="matrix(9.35 0 0 10 94.21 127.47)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#g" id="aj" cx="0" cy="0" r="1" gradientTransform="matrix(18.9901 5.08838 -5.34203 19.9367 169.71 194.53)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#g" id="al" cx="0" cy="0" r="1" gradientTransform="matrix(19.7224 -.83351 .62745 14.84675 169.71 189.89)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#h" id="ao" cx="0" cy="0" r="1" gradientTransform="rotate(23.5 -332.242 532.18)scale(6.95 3.21)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#j" id="as" cx="0" cy="0" r="1" gradientTransform="matrix(10.23944 -.10723 .1642 15.67914 86.49 51.41)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#l" id="aw" cx="0" cy="0" r="1" gradientTransform="rotate(-9.35 309.884 -497.172)scale(6.25 5.77)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#j" id="aA" cx="0" cy="0" r="1" gradientTransform="rotate(-1.8 1695.327 -3731.952)scale(13.64 15.68)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#p" id="aK" cx="0" cy="0" r="1" gradientTransform="rotate(-36 141.335 -120.193)scale(11.44 10.38)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#q" id="aL" cx="0" cy="0" r="1" gradientTransform="matrix(25.10142 -10.34606 7.26701 17.6311 109.77 70.61)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#s" id="aS" cx="0" cy="0" r="1" gradientTransform="matrix(1.32 0 0 1.42 92.11 59.88)" gradientUnits="userSpaceOnUse"></radialGradient><radialGradient href="#s" id="aU" cx="0" cy="0" r="1" gradientTransform="matrix(2.78 0 0 1.62 104.65 59.7)" gradientUnits="userSpaceOnUse"></radialGradient><clipPath id="I"><use href="#u"></use></clipPath><clipPath id="S"><use href="#v"></use></clipPath><clipPath id="U"><use href="#w"></use></clipPath><clipPath id="X"><use href="#x"></use></clipPath><clipPath id="af"><use href="#y"></use></clipPath><clipPath id="aq"><use href="#z"></use></clipPath><clipPath id="ax"><use href="#A"></use></clipPath><clipPath id="av"><use href="#B"></use></clipPath><clipPath id="aF"><use href="#C"></use></clipPath><clipPath id="aD"><use href="#D"></use></clipPath><clipPath id="aN"><use href="#E"></use></clipPath><clipPath id="aR"><use href="#F"></use></clipPath><clipPath id="aY"><use href="#E"></use><use href="#F"></use></clipPath></defs><path id="u" fill="#020204" d="M106.95 0c-6 0-12.02 1.18-17.46 4.12-5.78 3.11-10.52 8.09-13.43 13.97-2.92 5.88-4.06 12.16-4.24 19.08-.33 13.14.3 26.92 1.29 39.41.26 3.8.74 6.02.25 9.93-1.62 8.3-8.88 13.88-12.76 21.17-4.27 8.04-6.07 17.13-9.29 25.65-2.95 7.79-7.09 15.1-9.88 22.95-3.91 10.97-5.08 23.03-2.5 34.39 1.97 8.66 6.08 16.78 11.62 23.73-.8 1.44-1.58 2.91-2.4 4.34-2.57 4.43-5.71 8.64-7.17 13.55-.73 2.45-1.02 5.07-.55 7.59s1.75 4.93 3.75 6.53c1.31 1.04 2.9 1.72 4.53 2.1 1.63.37 3.32.46 5 .43 6.37-.14 12.55-2.07 18.71-3.69 3.66-.96 7.34-1.81 11.03-2.58 13.14-2.69 27.8-1.61 39.99.15 4.13.63 8.23 1.44 12.29 2.43 6.36 1.54 12.69 3.5 19.23 3.69 1.72.05 3.46-.03 5.14-.4 1.68-.38 3.31-1.06 4.65-2.13 2.01-1.6 3.29-4.02 3.76-6.54s.18-5.15-.56-7.61c-1.48-4.92-4.65-9.11-7.27-13.52-1.04-1.75-2-3.53-3.03-5.28 7.9-8.87 14.26-19.13 17.94-30.4 4.01-12.3 4.75-25.55 3.06-38.38s-5.76-25.27-11.11-37.05c-6.72-14.76-12.37-20.1-16.47-33.07-4.42-14.02-.77-30.61-4.06-43.32-1.17-4.32-3.04-8.45-5.45-12.23-2.82-4.43-6.4-8.39-10.65-11.47C124.13 2.62 115.61 0 106.95 0"></path><path fill="#fdfdfb" d="M83.13 74c-.9 1.13-1.48 2.49-1.84 3.89-.35 1.4-.48 2.85-.54 4.3-.11 2.89.07 5.83-.7 8.62-.82 2.98-2.65 5.57-4.44 8.08-3.11 4.36-6.25 8.84-7.78 13.97a24.8 24.8 0 0 0-.91 9.62c-3.47 5.1-6.48 10.53-8.98 16.18-3.78 8.57-6.37 17.69-7.28 27.01-1.12 11.41.34 23.15 4.85 33.69 3.25 7.63 8.11 14.6 14.38 20.04a49.2 49.2 0 0 0 10.5 6.97c13.11 6.45 29.31 6.46 42.2-.41 6.74-3.59 12.43-8.84 17.91-14.15 3.3-3.2 6.59-6.48 9.11-10.32 4.85-7.41 6.54-16.41 7.59-25.2 1.83-15.36 1.89-31.6-4.85-45.53-2.32-4.8-5.41-9.22-9.12-13.05-.98-6.7-2.93-13.27-5.76-19.42-2.05-4.45-4.54-8.68-6.44-13.18-.78-1.85-1.46-3.75-2.32-5.56-.87-1.81-1.93-3.55-3.39-4.94-1.48-1.42-3.33-2.43-5.28-3.07-1.95-.65-4.01-.94-6.06-1.04-4.11-.21-8.22.33-12.33.16-3.27-.13-6.53-.7-9.8-.51-1.63.1-3.26.39-4.78 1.01-1.52.61-2.92 1.56-3.94 2.84"></path><path fill="url(#G)" d="M68.67 115.18c.87 1.31-.55 5.84 19.86 2.94 0 0-3.59.39-7.12 1.21-5.49 1.84-10.27 3.89-13.97 6.61-3.65 2.7-6.33 6.21-9.68 9.22 0 0 5.43-9.92 6.78-12.91 1.36-2.99-.22-2.85.85-7.25s3.69-8.63 3.69-8.63-2.14 6.22-.41 8.81" clip-path="url(#I)" filter="url(#H)" opacity="0.25"></path><path fill="url(#J)" d="M134.28 113.99c-4.16 2.9-6.6 2.56-11.64 3.12-5.05.57-18.7.36-18.7.36s1.97-.03 6.36.78c4.38.82 13.31 1.6 18.34 3.51 5.04 1.92 6.87 2.47 9.93 4.4 4.35 2.75 7.55 7.06 11.71 10.08 0 0 .2-4-1.48-6.99s-6.2-7.7-7.53-12.1c-1.32-4.4-1.96-13.04-1.96-13.04s-.88 6.99-5.03 9.88" clip-path="url(#I)" filter="url(#K)" opacity="0.42"></path><path fill="url(#L)" d="M95.17 107.81c-.16 1.25-.36 2.5-.6 3.74-.12.61-.26 1.22-.48 1.8-.23.58-.56 1.14-1.02 1.55-.41.37-.9.62-1.4.85-1.94.88-4.01 1.47-6.12 1.74.84.06 1.68.14 2.53.23.53.06 1.06.12 1.57.25.52.14 1.03.34 1.46.65.47.35.84.82 1.12 1.34.55 1.02.73 2.2.83 3.37.13 1.48.14 2.98.03 4.46.1-.99.31-1.98.62-2.92.57-1.72 1.47-3.32 2.69-4.65.49-.52 1.02-1.01 1.6-1.42a8.86 8.86 0 0 1 6.24-1.51c-2.21.09-4.44-.6-6.2-1.93-.9-.68-1.68-1.52-2.22-2.5a7 7 0 0 1-.65-5.05" clip-path="url(#I)" filter="url(#M)" opacity="0.2"></path><path d="M89.85 137.14a75.4 75.4 0 0 0-2.17 12.31c-.55 5.87-.42 11.78-.74 17.67-.26 4.99-.85 10.04.02 14.97a25.3 25.3 0 0 0 2.2 6.78c.16-.82.29-1.64.36-2.47.37-4-.3-8.01-.53-12.01-.4-7.02.57-14.04.97-21.06.3-5.39.27-10.8-.11-16.19" clip-path="url(#I)" filter="url(#N)" opacity="0.11"></path><path fill="#7c7c7c" d="M160.08 131.23c1.03-.16 7.34 5.21 6.48 7.21-.86 1.99-2.49.79-3.65.8-1.16.02-4.33 1.46-4.86.55-.54-.91 1.4-3.03 2.41-4.81.82-1.43-1.4-3.59-.38-3.75" clip-path="url(#I)" filter="url(#O)" opacity="0.75"></path><path fill="#7c7c7c" d="M121.52 11.12c-2.21 1.56-1.25 3.51-.3 5.46.95 1.96-2.09 7.59-2.12 7.83s5.98-2.85 7.62-4.87c1.94-2.37 6.83 3.22 6.56 2.37.01-1.52-9.55-12.34-11.76-10.79" clip-path="url(#I)" filter="url(#P)"></path><path fill="#838384" d="M138.27 76.63c-1.86 1.7.88 4.25 2.17 7.24.81 1.86 3.04 4.49 5.2 4.07 1.63-.32 2.63-2.66 2.48-4.3-.3-3.18-2.98-3.93-4.93-5.02-1.54-.86-3.61-3.18-4.92-1.99" clip-path="url(#I)" filter="url(#Q)"></path><path id="v" fill="#020204" d="M63.98 100.91c-6.1 6.92-12.37 13.63-15.81 21.12-1.71 3.8-2.51 7.93-3.68 11.93-1.32 4.54-3.12 8.94-5.14 13.22-1.87 3.95-3.93 7.81-5.98 11.66-1.5 2.81-3.02 5.67-3.54 8.81-.41 2.48-.18 5.04.46 7.47.63 2.43 1.64 4.75 2.79 6.98 4.88 9.55 12.21 17.77 20.89 24.07 3.94 2.85 8.15 5.32 12.58 7.35 2.4 1.09 4.92 2.07 7.56 2.11 1.32.03 2.65-.19 3.86-.72 1.2-.53 2.28-1.38 3-2.49.88-1.36 1.18-3.05 1-4.66s-.81-3.15-1.65-4.53c-2.06-3.38-5.31-5.83-8.44-8.25a283 283 0 0 1-19.55-16.58c-1.76-1.65-3.53-3.34-4.76-5.42-1.2-2.02-1.85-4.32-2.29-6.63-1.21-6.33-.9-12.99 1.25-19.07.85-2.38 1.96-4.65 3.04-6.93 1.86-3.95 3.62-7.98 6.07-11.6 3.05-4.51 7.13-8.33 9.61-13.17 2.1-4.09 2.95-8.68 3.76-13.2.64-3.54 1.85-7 2.47-10.54-1.21 2.3-5.11 6.07-7.5 9.07"></path><path fill="#7c7c7c" d="M56.96 126.1c-2 1.84-3.73 3.97-5.13 6.31-2.3 3.84-3.65 8.16-5.33 12.31-1.24 3.09-2.69 6.2-2.86 9.53-.09 1.71.16 3.42.22 5.13s-.1 3.49-.94 4.98a6.05 6.05 0 0 1-3.22 2.71c1.83.61 3.45 1.79 4.6 3.33.96 1.3 1.58 2.81 2.41 4.18.68 1.12 1.51 2.16 2.54 2.97 1.02.82 2.25 1.4 3.54 1.56 1.79.23 3.65-.36 4.97-1.58-1.66-15.55-.14-31.42 4.44-46.37.29-.94.59-1.89.67-2.87.07-.99-.12-2.03-.72-2.81a2.99 2.99 0 0 0-2.77-1.17c-.52.06-1.03.26-1.45.57-.42.32-.76.74-.97 1.22" clip-path="url(#S)" filter="url(#R)" opacity="0.95"></path><path id="w" fill="#020204" d="M162.76 127.12c5.24 4.22 8.57 10.59 9.6 17.24.8 5.18.28 10.51-.89 15.62-1.17 5.12-2.97 10.06-4.77 15-.71 1.96-1.43 3.95-1.71 6.02-.29 2.08-.11 4.27.89 6.11 1.15 2.11 3.29 3.56 5.59 4.24 2.27.68 4.72.66 7.02.09s6.17-1.31 8.04-2.77c4.75-3.69 5.88-10.1 7.01-15.72 1.17-5.87.6-12.02-.43-17.95-1.41-8.09-3.78-15.99-6.79-23.62a82.3 82.3 0 0 0-8.44-15.96c-3.32-4.89-8.02-8.7-11.5-13.48-1.21-1.66-2.66-3.38-3.84-5.06-2.56-3.62-1.98-2.94-3.57-5.29-1.15-1.7-2.97-2.28-4.88-3.02-1.92-.74-4.06-.96-6.04-.41-2.6.73-4.73 2.79-5.86 5.24-1.13 2.46-1.33 5.28-.89 7.95.57 3.44 2.14 6.64 3.92 9.64 2 3.39 4.32 6.66 7.35 9.18 3.16 2.63 6.98 4.37 10.19 6.95"></path><path fill="#838384" d="M150.42 118.99c.42.4.86.81 1.31 1.19 3.22 2.63 4.93 5.58 8.2 8.16 5.34 4.22 10.75 11.5 11.8 18.15.82 5.19-.26 8.01-1.58 14.12-1.32 6.12-5.06 14.78-7.09 20.68-.8 2.35 1.64 1.38 1.32 3.86-.16 1.22-.18 2.45-.03 3.67.02-.23.03-.48.06-.71.39-3.38 1.42-6.63 2.55-9.82 2.17-6.13 4.66-12.15 6.38-18.45 1.72-6.29 1.53-10.82.63-16.23-1.13-6.81-5.09-13.09-10.69-17.24-3.97-2.93-8.64-4.81-12.86-7.38" clip-path="url(#U)" filter="url(#T)"></path><path id="x" fill="url(#V)" d="M34.98 175.33c1.38-.57 2.93-.68 4.39-.41 1.47.27 2.86.91 4.09 1.74 2.47 1.68 4.3 4.12 6.05 6.54 4.03 5.54 7.9 11.2 11.42 17.08 2.85 4.78 5.46 9.71 8.76 14.18 2.15 2.93 4.57 5.64 6.73 8.55 2.16 2.92 4.07 6.08 5.03 9.58 1.25 4.55.76 9.56-1.4 13.75-1.52 2.95-3.86 5.48-6.7 7.19S67.52 256 64.2 256c-5.27 0-10.42-2.83-15.32-4.78-9.98-3.98-20.82-5.22-31.11-8.32-3.16-.95-6.27-2.08-9.45-2.95-1.42-.39-2.85-.73-4.19-1.34-1.34-.6-2.59-1.51-3.33-2.77-.57-.98-.8-2.13-.8-3.26 0-1.14.28-2.26.67-3.32.77-2.13 2.02-4.06 2.86-6.17 1.37-3.44 1.62-7.23 1.43-10.93-.18-3.69-.78-7.36-1.03-11.05-.12-1.65-.16-3.32.16-4.95.31-1.62 1.01-3.21 2.2-4.35 1.1-1.06 2.55-1.69 4.05-2 1.49-.31 3.03-.32 4.55-.29s3.05.12 4.57-.01c1.52-.12 3.05-.46 4.37-1.22 1.26-.72 2.29-1.79 3.14-2.96s1.54-2.45 2.25-3.72c.7-1.26 1.43-2.52 2.36-3.64.92-1.12 2.06-2.09 3.4-2.64"></path><path fill="#d99a03" d="M37.16 177.7c1.25-.5 2.67-.56 3.98-.26 1.32.3 2.55.94 3.61 1.77 2.14 1.65 3.62 3.97 5.05 6.26 3.42 5.54 6.76 11.15 9.92 16.86 2.4 4.31 4.68 8.7 7.62 12.65 1.95 2.62 4.18 5.03 6.17 7.62s3.76 5.41 4.64 8.56c1.14 4.05.68 8.54-1.28 12.26-1.42 2.68-3.58 4.96-6.2 6.48a15.94 15.94 0 0 1-8.69 2.14c-4.82-.22-9.23-2.63-13.77-4.26-8.71-3.16-18.14-3.59-27.08-6.05-3.2-.87-6.32-2.03-9.53-2.84-1.43-.36-2.88-.66-4.23-1.23s-2.62-1.45-3.36-2.72c-.54-.95-.76-2.06-.73-3.15.04-1.09.31-2.17.7-3.19.78-2.04 2-3.88 2.78-5.92 1.19-3.08 1.34-6.47 1.12-9.76s-.8-6.56-1-9.85c-.08-1.48-.1-2.97.2-4.41.3-1.45.93-2.85 1.98-3.89 1.14-1.13 2.7-1.74 4.29-1.99 1.58-.24 3.19-.13 4.78.01 1.6.14 3.2.32 4.8.23 1.6-.1 3.22-.49 4.54-1.39 1.2-.81 2.1-2 2.79-3.27s1.18-2.64 1.71-3.98c.52-1.35 1.09-2.69 1.91-3.89.82-1.19 1.93-2.24 3.28-2.79" clip-path="url(#X)" filter="url(#W)"></path><path fill="#f5bd0c" d="M35.99 174.57c1.22-.6 2.65-.72 3.98-.45s2.57.92 3.62 1.77c2.09 1.7 3.43 4.13 4.67 6.51 2.84 5.46 5.5 11.04 8.9 16.19 2.48 3.73 5.33 7.2 7.83 10.92 3.39 5.03 6.15 10.57 7.29 16.5.76 4 .74 8.31-1.18 11.9-1.27 2.37-3.32 4.31-5.75 5.52-2.42 1.22-5.21 1.71-7.92 1.47-4.27-.37-8.14-2.47-12.16-3.94-7.13-2.59-14.84-3.22-22.18-5.18-3.09-.82-6.13-1.89-9.26-2.54-1.39-.29-2.8-.5-4.12-1s-2.57-1.33-3.25-2.55c-.47-.86-.63-1.86-.56-2.84.07-.97.36-1.92.74-2.83.77-1.8 1.9-3.46 2.49-5.32.88-2.75.52-5.72-.14-8.53-.65-2.8-1.6-5.55-1.89-8.41-.13-1.27-.13-2.57.17-3.82.29-1.25.88-2.45 1.81-3.34 1.2-1.15 2.88-1.73 4.56-1.89 1.67-.16 3.35.06 5.01.3s3.34.5 5.01.42c1.68-.07 3.39-.51 4.7-1.54 1.3-1.02 2.12-2.53 2.59-4.09.47-1.57.62-3.2.81-4.82s.43-3.26 1.06-4.77 1.69-2.9 3.17-3.64" clip-path="url(#X)" filter="url(#Y)"></path><path fill="url(#Z)" d="M51.2 188.21c2.25 4.06 3.62 8.72 5.85 12.82 2.05 3.77 4.38 7.65 6.46 11.12.93 1.55 3.09 3.93 5.27 7.62 1.98 3.34 3.98 8.01 5.1 9.58-.64-1.84-1.96-6.77-3.54-10.28-1.47-3.28-3.19-5.15-4.24-6.92-2.08-3.47-4.33-6.6-6.47-9.91-2.95-4.57-5.2-9.68-8.43-14.03" clip-path="url(#X)" filter="url(#aa)"></path><path fill="url(#ab)" d="M198.7 215.61c-.4 1.33-1.02 2.62-1.81 3.8-1.75 2.59-4.3 4.55-6.84 6.35-4.33 3.07-8.85 5.89-12.89 9.38-2.7 2.34-5.17 4.97-7.45 7.73-1.95 2.36-3.79 4.84-6.02 6.94-2.25 2.12-4.89 3.84-7.74 4.77-3.47 1.13-7.13 1.08-10.47.22-2.34-.6-4.63-1.64-6.08-3.53s-1.92-4.44-2.09-6.94c-.3-4.42.23-8.93.71-13.42.4-3.73.77-7.46.92-11.18.27-6.77-.18-13.47-1.09-20.05-.16-1.11-.32-2.22-.23-3.35.09-1.14.47-2.32 1.27-3.2.74-.81 1.77-1.29 2.79-1.52 1.02-.24 2.06-.25 3.09-.28 2.43-.06 4.86-.21 7.25.01 1.51.13 2.99.41 4.49.55 2.51.24 5.12.12 7.64-.62 2.71-.8 5.29-2.29 8.05-2.7 1.13-.17 2.26-.15 3.36.01 1.12.15 2.24.46 3.1 1.15.66.52 1.14 1.23 1.51 1.99.56 1.14.9 2.39 1.1 3.68.17 1.14.24 2.31.53 3.41.48 1.81 1.58 3.35 2.89 4.6 1.32 1.25 2.85 2.24 4.39 3.22 1.53.97 3.07 1.93 4.7 2.73.77.38 1.56.72 2.29 1.15.74.44 1.42.97 1.91 1.67.66.95.92 2.2.72 3.43" clip-path="url(#I)" filter="url(#ac)" opacity="0.2"></path><path id="y" fill="url(#ad)" d="M213.47 222.92c-2.26 2.68-5.4 4.45-8.53 6.05-5.33 2.71-10.86 5.1-15.87 8.37-3.36 2.19-6.46 4.76-9.36 7.53-2.48 2.37-4.83 4.9-7.61 6.91-2.81 2.03-6.05 3.5-9.48 4.01-.95.14-1.9.21-2.86.21-3.24 0-6.48-.78-9.46-2.08-2.7-1.17-5.3-2.86-6.86-5.36-1.56-2.52-1.92-5.59-1.92-8.56-.01-5.23.96-10.41 1.87-15.57.76-4.29 1.48-8.58 1.95-12.91.85-7.86.84-15.81.28-23.71-.1-1.32-.21-2.65-.01-3.96s.74-2.62 1.74-3.48c.93-.8 2.17-1.16 3.4-1.22 1.22-.07 2.44.12 3.65.3 2.85.42 5.73.74 8.52 1.48 1.76.46 3.48 1.08 5.23 1.56 2.94.79 6.01 1.17 9.02.82 3.25-.38 6.41-1.6 9.68-1.52 1.34.03 2.67.28 3.95.69 1.3.41 2.59 1 3.55 1.98.73.74 1.24 1.67 1.62 2.64.57 1.44.88 2.98 1.01 4.52.11 1.37.09 2.76.35 4.11.43 2.21 1.6 4.24 3.04 5.97 1.45 1.74 3.18 3.21 4.91 4.66s3.46 2.89 5.32 4.16c.87.6 1.77 1.16 2.6 1.81.83.66 1.59 1.42 2.11 2.34.45.81.69 1.72.69 2.65 0 .52-.07 1.04-.23 1.56-.45 1.43-1.28 2.82-2.3 4.04"></path><path fill="#cd8907" d="M213.21 216.12c-.53 1.33-1.28 2.58-2.22 3.67-2.07 2.42-4.93 4.01-7.78 5.44-4.88 2.44-9.92 4.58-14.5 7.52-3.06 1.97-5.9 4.28-8.55 6.78-2.26 2.13-4.41 4.41-6.95 6.21-2.57 1.83-5.53 3.14-8.65 3.6-3.8.56-7.72-.16-11.25-1.67-2.46-1.06-4.84-2.56-6.27-4.83-1.42-2.26-1.75-5.02-1.75-7.69-.02-4.71.87-9.37 1.71-14 .7-3.85 1.36-7.71 1.78-11.6.76-7.08.73-14.22.25-21.32-.08-1.19-.17-2.39.01-3.57s.67-2.35 1.57-3.13c.85-.73 1.99-1.05 3.11-1.1 1.11-.06 2.22.12 3.33.28 2.61.38 5.23.67 7.78 1.33 1.61.42 3.18.98 4.78 1.4 2.68.72 5.49 1.06 8.24.74 2.97-.34 5.85-1.44 8.83-1.37 1.23.03 2.44.26 3.61.62 1.19.37 2.37.9 3.25 1.78.66.67 1.11 1.51 1.48 2.38.53 1.29.89 2.67.91 4.07.03 1.46-.28 2.92-.09 4.37.16 1.17.66 2.28 1.3 3.28.63 1 1.4 1.91 2.17 2.81 1.48 1.75 2.96 3.53 4.82 4.87 2.11 1.53 4.62 2.43 6.8 3.85.65.43 1.28.91 1.74 1.54.78 1.06.98 2.5.54 3.74" clip-path="url(#af)" filter="url(#ae)"></path><path fill="#f5c021" d="M212.91 214.61c-.6 1.35-1.37 2.6-2.28 3.71-2.12 2.58-4.99 4.35-8 5.49-4.97 1.88-10.39 2.13-15.26 4.27-2.97 1.3-5.65 3.26-8.36 5.12-2.18 1.49-4.42 2.94-6.82 3.98-2.72 1.19-5.6 1.85-8.5 2.32-1.84.29-3.71.51-5.57.41s-3.72-.54-5.37-1.49c-1.24-.72-2.36-1.75-3.03-3.1-.73-1.49-.86-3.24-.85-4.94.05-4.5 1.02-8.96.99-13.47-.03-3.93-.81-7.8-1.03-11.72-.43-7.54 1.19-15.2-.24-22.59-.22-1.19-.53-2.37-.52-3.58.01-.6.1-1.21.31-1.77.22-.55.56-1.06 1.01-1.42.39-.29.84-.47 1.31-.56.46-.08.94-.06 1.41.01.93.15 1.82.51 2.73.78 2.6.78 5.35.76 8 1.35 1.66.36 3.26.97 4.91 1.41 2.75.76 5.63 1.08 8.46.75 3.04-.36 6.01-1.46 9.07-1.38 1.26.03 2.5.26 3.71.62s2.42.87 3.34 1.8c.65.67 1.13 1.52 1.51 2.4.57 1.29.96 2.69.95 4.11-.01.74-.12 1.47-.19 2.21-.06.74-.08 1.49.09 2.2.18.72.55 1.37.97 1.96s.9 1.12 1.34 1.7c1.22 1.61 2.1 3.49 3.05 5.3s2.02 3.6 3.53 4.91c2.05 1.77 4.7 2.48 6.99 3.89.67.41 1.31.89 1.78 1.55.38.52.63 1.15.73 1.81.09.65.03 1.34-.17 1.96" clip-path="url(#af)" filter="url(#ag)"></path><path fill="url(#ah)" d="M148.08 181.58c2.82-.76 5.22 1.38 7.27 2.99 1.32 1.13 3.24.85 4.86.9 2.69-.09 5.36.45 8.05.12 5.3-.45 10.49-1.75 15.81-1.97 2.54-.16 5.4-.31 7.59 1.17.89.62 2.2 3.23 3.07 2.25-.36-2.74-2.39-5.39-5.11-6.12-2.14-.34-4.3.25-6.46.06-6.39-.15-12.75-1.34-19.16-1-4.46.04-8.91-.17-13.37-.34-1.75-.36-2.37 1.19-3.32 1.79.25.19.34.25.77.15" clip-path="url(#af)" filter="url(#ai)"></path><path fill="url(#aj)" d="M185.49 187.61c-.48-.95-1.36-1.66-2.35-2.07-.98-.41-2.06-.55-3.13-.54-2.13.02-4.25.57-6.38.39-1.79-.16-3.49-.83-5.24-1.26-1.81-.44-3.73-.61-5.52-.12-1.92.52-3.61 1.81-4.67 3.49-.94 1.48-1.38 3.23-1.52 4.98s.01 3.5.19 5.25c.12 1.26.27 2.52.57 3.75.31 1.23.78 2.43 1.52 3.46 1.07 1.48 2.66 2.54 4.37 3.17 2.8 1.03 5.98.98 8.73-.15 4.88-2.12 9.01-5.92 11.52-10.6.91-1.68 1.61-3.47 2.06-5.31.18-.74.32-1.49.32-2.25.01-.75-.12-1.52-.47-2.19" clip-path="url(#af)" filter="url(#ak)" opacity="0.35"></path><path fill="url(#al)" d="M185.49 184.89c-.48-.69-1.36-1.2-2.35-1.5-.98-.3-2.06-.39-3.13-.39-2.13.02-4.25.42-6.38.28-1.79-.11-3.49-.6-5.24-.9-1.81-.32-3.73-.45-5.52-.09-1.92.37-3.61 1.3-4.67 2.52-.94 1.07-1.38 2.34-1.52 3.6s.01 2.53.19 3.79c.12.91.27 1.83.57 2.72.31.89.78 1.76 1.52 2.5 1.07 1.07 2.66 1.83 4.37 2.29 2.8.75 5.98.71 8.73-.11 4.88-1.53 9.01-4.28 11.52-7.66.91-1.22 1.61-2.51 2.06-3.84.18-.54.32-1.08.32-1.62.01-.55-.12-1.11-.47-1.59" clip-path="url(#af)" filter="url(#am)" opacity="0.35"></path><path id="z" fill="#020204" d="M189.55 178.72c-.35-.95-.97-1.79-1.72-2.47s-1.64-1.2-2.57-1.6c-1.86-.79-3.89-1.09-5.89-1.46-1.87-.35-3.74-.78-5.62-1.1-1.96-.33-3.98-.55-5.92-.11-1.69.38-3.26 1.26-4.54 2.43s-2.28 2.63-3 4.21c-1.27 2.79-1.67 5.92-1.43 8.97.18 2.27.76 4.61 2.25 6.32 1.21 1.39 2.92 2.26 4.68 2.78 3.04.9 6.35.85 9.36-.13a24.7 24.7 0 0 0 12.35-9.29c.98-1.43 1.82-2.98 2.2-4.66.29-1.28.3-2.66-.15-3.89"></path><defs><path id="an" d="M168.89 171.07c-.47.03-.93.08-1.4.17-2.99.53-5.73 2.42-7.27 5.03-1.09 1.85-1.58 4.03-1.43 6.17.07-1.5.46-2.97 1.19-4.28 1.23-2.23 3.47-3.91 5.98-4.37 1.54-.28 3.13-.11 4.68.08 1.5.19 3 .39 4.47.7 2.28.5 4.53 1.26 6.44 2.59.44.31.86.66 1.21 1.08.35.41.62.89.73 1.42.15.78-.07 1.6-.46 2.29-.39.7-.92 1.3-1.48 1.86-.46.46-.94.89-1.43 1.32 2.21-.43 4.44-1.03 6.28-2.31.77-.55 1.48-1.2 1.94-2.02.46-.83.65-1.83.43-2.75-.16-.62-.5-1.19-.92-1.67s-.93-.87-1.45-1.24a17.27 17.27 0 0 0-7.81-2.99c-1.8-.33-3.61-.61-5.42-.83-1.41-.18-2.86-.33-4.28-.25"></path></defs><use href="#an" fill="url(#ao)" clip-path="url(#aq)" filter="url(#ap)"></use><use href="#an" fill="url(#ar)" clip-path="url(#aq)" filter="url(#ap)"></use><path id="A" fill="url(#as)" d="M84.45 38.28c-1.53.08-3 .79-4.12 1.84-1.13 1.05-1.92 2.43-2.41 3.88-.97 2.92-.75 6.08-.53 9.15.2 2.77.41 5.6 1.45 8.18.52 1.3 1.25 2.51 2.22 3.51.97.99 2.2 1.76 3.55 2.09 1.26.32 2.62.26 3.86-.13 1.25-.4 2.38-1.11 3.32-2.02 1.36-1.33 2.27-3.07 2.8-4.9s.68-3.75.65-5.66c-.04-2.38-.35-4.77-1.09-7.03-.75-2.26-1.94-4.4-3.6-6.11-.8-.83-1.72-1.55-2.75-2.06-1.04-.51-2.2-.8-3.35-.74"></path><path id="B" fill="#020204" d="M80.75 50.99c-.32 1.94-.33 3.97.33 5.81.44 1.22 1.17 2.33 2.05 3.28.57.62 1.23 1.18 1.99 1.55.77.37 1.65.52 2.48.32.76-.19 1.42-.68 1.91-1.29s.82-1.34 1.05-2.09c.69-2.21.58-4.62-.11-6.83-.49-1.61-1.32-3.16-2.6-4.24-.62-.52-1.34-.93-2.12-1.11-.78-.19-1.63-.14-2.36.19-.81.37-1.44 1.07-1.85 1.86s-.62 1.67-.77 2.55"></path><path fill="url(#at)" d="M84.84 49.59c.21.55.91.75 1.3 1.19.37.42.76.87.97 1.4.39 1.01-.39 2.51.43 3.23.25.22.77.23 1.02 0 .99-.9.77-2.71.38-3.99-.36-1.15-1.23-2.25-2.31-2.8-.5-.26-1.25-.47-1.68-.11-.27.24-.24.74-.11 1.08" clip-path="url(#av)" filter="url(#au)"></path><path fill="url(#aw)" d="M81.14 44.46c2.32-1.38 5.13-1.7 7.82-1.45 2.68.26 5.27 1.04 7.87 1.75 1.91.52 3.84 1 5.63 1.84 1.78.84 3.44 2.08 4.43 3.8.16.27.29.56.46.83s.37.52.62.71.57.32.88.3c.16-.01.32-.05.45-.13.14-.08.26-.2.33-.34.08-.16.11-.35.1-.53s-.05-.36-.1-.54c-.65-2.37-2.19-4.38-3.35-6.55-.7-1.3-1.28-2.66-1.98-3.96-2.43-4.45-6.42-7.94-10.95-10.21s-9.59-3.36-14.65-3.65c-5.86-.35-11.73.35-17.51 1.37-2.51.44-5.06.96-7.27 2.21-1.11.62-2.13 1.42-2.92 2.42-.8.99-1.36 2.18-1.55 3.44-.17 1.22.01 2.47.44 3.62.42 1.15 1.08 2.2 1.86 3.15 1.54 1.91 3.53 3.39 5.36 5.03 1.83 1.63 3.52 3.44 5.57 4.79 1.02.68 2.13 1.24 3.31 1.57s2.44.42 3.64.17c1.24-.25 2.4-.86 3.41-1.64 1.01-.77 1.88-1.7 2.71-2.66 1.66-1.93 3.21-4.04 5.39-5.34" clip-path="url(#ax)"></path><path fill="url(#ay)" d="M90.77 36.57c2.16 2.02 3.76 4.52 4.85 7.16-.48-2.91-1.23-5.26-3.13-7.16-1.16-1.09-2.49-2.05-3.98-2.72-1.32-.59-2.77-.96-3.61-.97-.83-.02-1.03 0-1.2.01-.18.01-.31.01.23.08.54.06 1.75.39 3.05.97s2.62 1.54 3.79 2.63" filter="url(#az)"></path><path id="C" fill="url(#aA)" d="M111.61 38.28c-2.39 1.65-4.4 3.94-5.38 6.68-1.24 3.45-.77 7.31.43 10.77 1.22 3.55 3.27 6.93 6.36 9.06 1.54 1.07 3.33 1.8 5.19 2.02 1.87.22 3.8-.09 5.47-.95 2.02-1.06 3.57-2.91 4.53-4.98.96-2.08 1.37-4.37 1.5-6.66.16-2.9-.12-5.86-1.08-8.61-1.04-2.99-2.92-5.75-5.58-7.47-1.32-.86-2.83-1.45-4.4-1.67a9.4 9.4 0 0 0-4.67.52c-.84.33-1.62.78-2.37 1.29"></path><path id="D" fill="#020204" d="M117.14 45.52c-.9.06-1.78.37-2.55.85-.76.48-1.41 1.13-1.92 1.88-1.03 1.49-1.48 3.31-1.55 5.12-.05 1.35.1 2.72.55 4s1.2 2.47 2.25 3.33c1.07.89 2.42 1.42 3.81 1.49 1.39.06 2.79-.34 3.93-1.13.91-.63 1.64-1.5 2.16-2.48.52-.97.84-2.05.98-3.15.25-1.93-.03-3.95-.93-5.69-.89-1.74-2.41-3.17-4.24-3.84-.8-.29-1.65-.44-2.49-.38"></path><path fill="url(#aB)" d="M122.71 53.36c1-1-.71-3.65-2.05-4.74-.97-.78-3.78-1.61-3.66-.75.12.85 1.39 1.95 2.23 2.79 1.05 1.03 3 3.18 3.48 2.7" clip-path="url(#aD)" filter="url(#aC)"></path><path fill="url(#aE)" d="M102.56 47.01c2.06-1.71 4.45-3.01 7-3.8 5.25-1.62 11.2-.98 15.84 1.97 1.6 1.01 3.03 2.27 4.52 3.45 1.48 1.17 3.06 2.27 4.85 2.9.97.34 2 .54 3.02.43.92-.09 1.81-.44 2.57-.96.76-.53 1.4-1.23 1.88-2.02.96-1.58 1.27-3.5 1.1-5.34-.33-3.69-2.41-6.94-4.15-10.21-.55-1.02-1.07-2.06-1.73-3.01-2.01-2.93-5.23-4.86-8.6-5.99s-6.93-1.54-10.46-1.98c-1.58-.2-3.17-.41-4.74-.22-1.81.22-3.51.95-5.28 1.4-.84.22-1.69.37-2.52.61s-1.65.57-2.33 1.11c-.98.79-1.6 1.98-1.87 3.21-.27 1.24-.21 2.52-.01 3.77.39 2.5 1.33 4.93 1.24 7.46-.06 1.73-.61 3.44-.54 5.17.02.51.12 1.55.21 2.05" clip-path="url(#aF)"></path><path fill="url(#aG)" d="M119.93 31.18c-.41.52-.78 1.08-1.07 1.7 1.85.4 3.61 1.16 5.19 2.21 3.06 2.03 5.38 4.99 7.01 8.29.38-.42.72-.87 1.02-1.37-1.64-3.44-4-6.55-7.16-8.65-1.52-1-3.21-1.77-4.99-2.18" filter="url(#aH)"></path><path fill-opacity="0.259" d="M81.12 89.33c1.47 4.26 4.42 7.89 7.92 10.72 1.16.95 2.39 1.82 3.76 2.43 1.36.62 2.87.97 4.36.84 1.46-.12 2.85-.7 4.13-1.42s2.46-1.59 3.7-2.37c2.12-1.35 4.39-2.44 6.6-3.64 2.65-1.45 5.23-3.1 7.46-5.14 1.03-.93 1.98-1.95 3.11-2.75 1.13-.81 2.49-1.39 3.87-1.29 1.04.07 2.01.51 3.03.73.51.11 1.03.16 1.55.08.51-.08 1.01-.29 1.37-.67.44-.46.64-1.12.61-1.76-.02-.63-.24-1.25-.54-1.81-.59-1.13-1.49-2.1-1.89-3.31-.36-1.08-.29-2.24-.26-3.37.03-1.14.01-2.32-.51-3.33-.4-.76-1.07-1.37-1.83-1.77-.76-.41-1.62-.62-2.48-.7-1.72-.16-3.44.18-5.17.27-2.28.13-4.58-.15-6.87-.02-2.85.18-5.65 1-8.51 1.01-3.26.01-6.52-1.06-9.74-.55-1.39.22-2.71.72-4.03 1.16-1.33.45-2.7.84-4.1.82-1.59-.03-3.13-.58-4.72-.69-.79-.06-1.6 0-2.35.28-.74.28-1.41.79-1.78 1.5-.21.4-.31.86-.33 1.31-.02.46.04.91.15 1.36.22.88.63 1.71.96 2.55 1.2 3.07 1.46 6.42 2.53 9.53" clip-path="url(#I)" filter="url(#aI)"></path><path d="M77.03 77.2c2.85 1.76 5.41 3.93 7.56 6.39 1.99 2.29 3.68 4.89 6.29 6.58 1.83 1.2 4.04 1.87 6.28 2.08 2.63.24 5.29-.15 7.83-.84 2.35-.63 4.62-1.53 6.7-2.71 3.97-2.25 7.28-5.55 11.65-7.03.95-.33 1.94-.56 2.86-.96.92-.39 1.79-.99 2.23-1.83.42-.82.4-1.75.54-2.64.15-.96.48-1.88.66-2.83s.2-1.96-.24-2.83c-.37-.72-1.04-1.29-1.81-1.66-.77-.36-1.64-.52-2.51-.56-1.72-.08-3.43.33-5.16.47-2.28.19-4.58-.08-6.87-.01-2.85.08-5.66.67-8.51.8-3.25.14-6.49-.34-9.74-.44-1.41-.05-2.83-.03-4.21.2-1.39.22-2.75.65-3.92 1.37-1.14.69-2.07 1.64-3.11 2.45-.52.41-1.08.78-1.68 1.07-.61.28-1.28.48-1.96.51-.35.01-.71-.01-1.05.04-.59.08-1.13.39-1.47.83-.34.45-.47 1.02-.36 1.55" clip-path="url(#I)" filter="url(#aJ)" opacity="0.3"></path><path fill="url(#aK)" d="M91.66 58.53c1.53-1.71 2.57-3.8 4.03-5.56.73-.88 1.58-1.69 2.57-2.26s2.15-.89 3.29-.79c1.27.11 2.46.74 3.39 1.61s1.62 1.97 2.17 3.12c.53 1.11.95 2.28 1.71 3.24.81 1.02 1.94 1.71 2.97 2.52.51.4 1.01.83 1.41 1.34.41.51.72 1.1.86 1.74.13.65.06 1.33-.16 1.95-.23.62-.61 1.18-1.09 1.64-.95.92-2.25 1.42-3.56 1.6-2.62.37-5.27-.41-7.92-.34-2.67.08-5.29 1.02-7.97.93-1.33-.05-2.69-.38-3.79-1.14-.55-.39-1.03-.88-1.38-1.45a4.1 4.1 0 0 1-.58-1.9c-.02-.64.13-1.28.39-1.86.25-.59.61-1.12 1.01-1.62.81-.99 1.8-1.81 2.65-2.77"></path><path id="E" fill="url(#aL)" d="M77.14 75.05c.06.26.15.5.28.73.23.38.57.69.93.95.36.27.75.49 1.13.72 2.01 1.27 3.65 3.04 5.11 4.92 1.95 2.52 3.68 5.31 6.29 7.14 1.84 1.3 4.04 2.03 6.28 2.26 2.63.26 5.29-.16 7.83-.91 2.35-.69 4.62-1.66 6.7-2.95 3.97-2.44 7.28-6.02 11.65-7.63.95-.35 1.94-.6 2.86-1.03.92-.44 1.79-1.08 2.23-2 .42-.88.4-1.9.54-2.87.15-1.03.48-2.03.66-3.06s.2-2.13-.24-3.08c-.37-.78-1.04-1.4-1.81-1.79-.77-.4-1.64-.58-2.51-.62-1.72-.08-3.43.36-5.16.52-2.28.21-4.58-.09-6.87-.02-2.85.09-5.66.73-8.51.87-3.25.15-6.49-.35-9.74-.48-1.41-.06-2.83-.04-4.22.2-1.39.23-2.75.71-3.91 1.51-1.13.78-2.03 1.84-3.07 2.74-.52.45-1.08.86-1.7 1.16-.61.3-1.29.49-1.98.47-.35-.01-.72-.06-1.05.04-.21.07-.4.2-.56.35-.16.16-.29.34-.41.52-.29.42-.54.87-.75 1.34"></path><path fill="#d9b30d" d="M89.9 78.56a5.77 5.77 0 0 0 .56 4.11c.68 1.24 1.84 2.2 3.19 2.65 1.7.57 3.62.29 5.21-.54.93-.48 1.77-1.16 2.3-2.06.27-.44.46-.94.53-1.46.06-.51.02-1.05-.16-1.54-.2-.53-.56-1-.99-1.37a4.5 4.5 0 0 0-1.5-.82c-1.08-.36-2.77-.66-3.91-.68-2.02-.04-4.9.34-5.23 1.71" clip-path="url(#aN)" filter="url(#aM)"></path><path fill="#604405" d="M84.31 67.86c-1.16.68-2.27 1.43-3.36 2.2-.57.41-1.15.84-1.45 1.47-.21.44-.26.94-.27 1.43 0 .5.03.99-.04 1.48-.04.33-.13.66-.14.99-.01.17 0 .34.04.5.05.16.13.32.24.44.15.16.35.26.56.32s.42.09.64.14c1.01.24 1.89.86 2.66 1.56.77.69 1.47 1.48 2.28 2.13 2.18 1.78 5.07 2.52 7.89 2.56 2.82.05 5.61-.54 8.36-1.16 2.16-.49 4.32-.99 6.39-1.76 3.2-1.18 6.16-2.96 8.72-5.19 1.17-1.01 2.26-2.12 3.57-2.94 1.15-.73 2.44-1.21 3.62-1.9.11-.06.21-.13.3-.2.1-.08.18-.18.24-.28.09-.19.09-.42.03-.62s-.18-.38-.31-.55c-.15-.18-.31-.34-.49-.5-1.23-1.05-2.89-1.43-4.51-1.56-1.61-.12-3.24-.03-4.83-.3-1.5-.25-2.92-.81-4.37-1.27-1.52-.49-3.07-.87-4.64-1.13-3.71-.61-7.52-.49-11.19.27-3.49.73-6.87 2.05-9.94 3.87" clip-path="url(#aN)" filter="url(#aO)"></path><path id="F" fill="url(#aP)" d="M83.94 63.95a20.8 20.8 0 0 0-4.43 4.04c-.72.89-1.38 1.86-1.74 2.94-.29.86-.39 1.76-.57 2.65-.07.33-.15.66-.14 1 0 .16.02.33.07.5.05.16.14.31.25.43.2.2.47.31.74.37.28.05.56.06.84.09 1.25.15 2.4.75 3.44 1.47 1.04.71 2 1.55 3.07 2.22 2.35 1.49 5.16 2.15 7.95 2.26 2.78.11 5.56-.31 8.3-.86 2.17-.43 4.33-.95 6.39-1.76 3.16-1.25 6.01-3.16 8.72-5.19 1.24-.92 2.46-1.87 3.57-2.94.37-.37.74-.74 1.14-1.08.4-.33.85-.62 1.35-.78.76-.24 1.58-.17 2.37-.04.59.1 1.18.23 1.78.21.3-.02.6-.07.88-.18s.54-.28.73-.52c.25-.3.38-.7.38-1.09 0-.4-.12-.79-.32-1.13-.4-.68-1.09-1.14-1.81-1.46-.99-.44-2.06-.65-3.11-.91-3.23-.78-6.37-1.93-9.34-3.41-1.48-.73-2.92-1.54-4.37-2.32-1.5-.8-3.02-1.57-4.64-2.07-3.64-1.1-7.6-.74-11.19.51a23.9 23.9 0 0 0-10.31 7.05"></path><path fill="#f6da4a" d="M109.45 64.75c-.2-.24-.48-.42-.78-.51s-.62-.09-.93-.04c-.62.11-1.18.44-1.7.8-1.47 1.01-2.77 2.26-3.91 3.64-1.5 1.83-2.74 3.94-3.16 6.27-.07.39-.11.8-.07 1.19.05.4.2.79.49 1.07.24.25.58.4.92.45.35.05.71 0 1.04-.11.66-.22 1.21-.69 1.74-1.15 2.87-2.58 5.47-5.66 6.51-9.38.1-.37.19-.75.19-1.14s-.1-.78-.34-1.09" clip-path="url(#aR)" filter="url(#aQ)"></path><path fill="url(#aS)" d="M92.72 59.06c-.77-.25-2.03 1.1-1.62 1.79.11.19.46.43.7.3.35-.19.64-.89 1.02-1.16.25-.18.2-.84-.1-.93" filter="url(#aT)" opacity="0.8"></path><path fill="url(#aU)" d="M102.56 59.42c.2.64 1.23.53 1.83.84.52.27.94.86 1.53.88.56.01 1.44-.2 1.51-.76.09-.73-.98-1.2-1.67-1.47-.89-.34-2.03-.52-2.86-.06-.19.11-.4.36-.34.57" filter="url(#aV)" opacity="0.8"></path><path fill="url(#aW)" d="M129.27 69.15a2.42 3.1 16.94 0 1-2.81 3.04 2.42 3.1 16.94 0 1-2.12-3.04 2.42 3.1 16.94 0 1 2.81-3.05 2.42 3.1 16.94 0 1 2.12 3.05" clip-path="url(#aY)" filter="url(#aX)"></path></svg></div>
<p>Supposedly <a href="https://en.wikipedia.org/wiki/Linus_Torvalds" target="_self" rel="noopener noreferrer" class="">Linus Torvalds</a>, the inventor of Linux, was inspired by a different
penguin illustration, which appears <a href="https://en.wikipedia.org/wiki/Tux_(mascot)" target="_self" rel="noopener noreferrer" class="">in this wikipedia article</a>. The Tux
mascot later evolved from that and became the official Linux icon and logo shown here.
[image attribution: <a href="mailto:lewing@isc.tamu.edu" target="_self" rel="noopener noreferrer" class="">lewing@isc.tamu.edu</a> Larry Ewing and The GIMP, CC0, via Wikimedia Commons]</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="94-linux-appears-on-the-scene">'94 Linux appears on the scene<a href="https://ricegeo.dev/linux-user-30-years#94-linux-appears-on-the-scene" class="hash-link" aria-label="Direct link to '94 Linux appears on the scene" title="Direct link to '94 Linux appears on the scene" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-unix-philosophy">The Unix philosophy<a href="https://ricegeo.dev/linux-user-30-years#the-unix-philosophy" class="hash-link" aria-label="Direct link to The Unix philosophy" title="Direct link to The Unix philosophy" translate="no">​</a></h3>
<p>Linux and Unix are very similar. Unix has been around since the '70s. Unix is fundamentally a programming environment
that unifies user and development spaces. It's philosophy centers on creating programs that:</p>
<ul>
<li class="">Perform single tasks effectively</li>
<li class="">Work together through pipelines</li>
<li class="">Process text streams</li>
<li class="">Function as filters (input to output)</li>
<li class="">Prioritize portability over efficiency</li>
</ul>
<p>The system is designed to be literate and self-documenting through:</p>
<ul>
<li class="">Integrated documentation (man pages, help flags)</li>
<li class="">Built-in command inspection tools</li>
<li class="">Interactive learning features</li>
<li class="">Human-readable source code and configuration</li>
<li class="">Transparent system structure</li>
</ul>
<p>This design creates an environment where using the system and developing for it are seamlessly integrated, making Unix
highly extensible and learnable.</p>
<p>Circa '94, just out of college, I got really interested in Linux, and wanted to get into programming. I asked my father
"What programming language do you think I should I learn?". He had some earlier experience with software projects in
the field of ecological and weather modeling. He considered it for long pause, and then said "I think you should learn
C!".</p>
<p>Even though I never mastered the C language, it was the right guidance. Knowing a modicum of C means you
understand compilers, libraries, static and dynamic linking, cache hierarchy, pointers, storage, I/O, etc.
With that foundation you can understand any other programming language or operating system.</p>
<p><img decoding="async" loading="lazy" alt="Linux books" src="https://ricegeo.dev/assets/images/linux-books-array-7ac4dfe2b59dfd9db327b0831472feb3.png" width="2330" height="488" class="img_ev3q"></p>
<p>I saved my favorite books from this time period mostly as a reminder how much it made an impression on me. Kernighan later wrote "The Go Programming Language" which is one of the best programming books ever.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="linux-kernel-version-1x">Linux kernel version 1.x<a href="https://ricegeo.dev/linux-user-30-years#linux-kernel-version-1x" class="hash-link" aria-label="Direct link to Linux kernel version 1.x" title="Direct link to Linux kernel version 1.x" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="micron-millennia-desktop-pc">Micron Millennia desktop PC<a href="https://ricegeo.dev/linux-user-30-years#micron-millennia-desktop-pc" class="hash-link" aria-label="Direct link to Micron Millennia desktop PC" title="Direct link to Micron Millennia desktop PC" translate="no">​</a></h3>
<div style="float:left;margin-right:1em;width:200px"><p><img decoding="async" loading="lazy" alt="Linux on a x86 desktop PC" src="https://ricegeo.dev/assets/images/micron-82329f2010f823ec785a6b47d79317fb.jpg" width="320" height="221" class="img_ev3q"></p></div>
<p>Also circa '94 I installed Linux on my home computer which was a Micron. Manufactured in Idaho (It came from the
factory with a potato sticker on it). I experimented a lot with building the Linux kernel from sources and configuring
dual-boot systems. [image attribution: Akbkuku, <a href="https://creativecommons.org/licenses/by/4.0" target="_self" rel="noopener noreferrer" class="">CC BY 4.0</a> , via Wikimedia Commons]</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="95-reality-construction-company">'95 Reality Construction Company<a href="https://ricegeo.dev/linux-user-30-years#95-reality-construction-company" class="hash-link" aria-label="Direct link to '95 Reality Construction Company" title="Direct link to '95 Reality Construction Company" translate="no">​</a></h2>
<p>Circa '95 in Albuquerque NM, I had graduated from college the year before, and I was really poor and mostly working in
restaurants. My friends Kyle, Spiros, Antonio, and I decided to try creating web pages, first for fun, and then for
profit. We got a few customers and had this idea to start a tech company. We called it Reality Construction Company
(RCC). We were hosting the pages and web apps at a local Internet service provider (ISP), named <a href="https://www.swcp.com/" target="_self" rel="noopener noreferrer" class="">Southwest Cyberport
(SWCP)</a>. We were self-taught developers and designers, and were not very good at automating and
scripting things. Most (all?) good developers are self-taught though!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="96-southwest-cyberport">'96 Southwest Cyberport<a href="https://ricegeo.dev/linux-user-30-years#96-southwest-cyberport" class="hash-link" aria-label="Direct link to '96 Southwest Cyberport" title="Direct link to '96 Southwest Cyberport" translate="no">​</a></h2>
<p><a href="https://www.swcp.com/" target="_self" rel="noopener noreferrer" class="">SWCP</a> was growing rapidly, because the Internet was just being commercialized and popularized.
The owners of SWCP are a nice couple named Jamey and Mark Costlow. They offered me a technical support job for their
Internet access, web hosting, email and FTP services business.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sunos-and-solaris">SunOS and Solaris<a href="https://ricegeo.dev/linux-user-30-years#sunos-and-solaris" class="hash-link" aria-label="Direct link to SunOS and Solaris" title="Direct link to SunOS and Solaris" translate="no">​</a></h3>
<div style="float:left;margin-right:1em"><p><img decoding="async" loading="lazy" alt="Sun SPARC pizza boxes" src="https://ricegeo.dev/assets/images/sun-pizza-boxes-de709b90e64b1b1b0b7a92e6ed6f64a3.jpg" width="150" height="150" class="img_ev3q"></p></div>
<p>[image attribution: <a href="https://www.flickr.com/photos/jonmasters/11650824704/" target="_self" rel="noopener noreferrer" class="">jonmasters</a>, CC BY-NC-SA 2.0]</p>
<p>As a bonus I got to learn about Unix because the Costlows were also very technical and system administrators. They were
running SunOS and Solaris Unix. I guess I was kind of an apprentice sys-admin. At one point early on, there was a
folding table with about a dozen of these Sun SPARC aka "pizza boxes". The folding table was sagging from the weight,
more than a bit.</p>
<p>I learned about the X-Windows display system and we used early versions of Python, TCL, PHP, Perl, Java, Javascript,
MySQL, and Postgres. Customers had access to many of these tools which enabled building of dynamic web pages using CGI
and HTML. The web servers were multi-user systems, so learning Unix was mandatory for any kind of databases or
interactive web apps.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tech-kids">Tech-Kids<a href="https://ricegeo.dev/linux-user-30-years#tech-kids" class="hash-link" aria-label="Direct link to Tech-Kids" title="Direct link to Tech-Kids" translate="no">​</a></h3>
<p>Mark and Jamey were part of a group which someone named "Tech-Kids". I was de-facto part of it because I worked at
SWCP, but I was not anywhere near as smart and cool as most of those folks. They had their own Internet Relay Chat
(IRC) channel and I remember going to a house party or two.</p>
<p>Over the next several years many of the group moved to Silicon Valley, and I'm sure they were super successful in the
Tech industry there. I stayed in New Mexico- as I was already California escapee.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="linux-saves-the-day">Linux saves the day<a href="https://ricegeo.dev/linux-user-30-years#linux-saves-the-day" class="hash-link" aria-label="Direct link to Linux saves the day" title="Direct link to Linux saves the day" translate="no">​</a></h3>
<p>I think it was Brendan Conoboy who first introduced Linux into the SWCP system. He quickly deployed it as a software
firewall to plug some security holes and put the Sun machines behind a NAT. Before long, all the SunOS and Solaris
"pizza boxes" had been migrated to Linux servers. Brendan went on to maintain the <a href="https://gcc.gnu.org/" target="_self" rel="noopener noreferrer" class="">GCC compiler</a>,
and then moved to a long career at <a href="https://www.redhat.com/en" target="_self" rel="noopener noreferrer" class="">Red Hat Linux</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="97-linux-kernel-version-2x">'97 Linux kernel version 2.x<a href="https://ricegeo.dev/linux-user-30-years#97-linux-kernel-version-2x" class="hash-link" aria-label="Direct link to '97 Linux kernel version 2.x" title="Direct link to '97 Linux kernel version 2.x" translate="no">​</a></h2>
<p>In these days, multiprocessing (SMP) was added, and the range of supported hardware architectures was broadened. I
tried it out on some relatively ancient hardware. Each one of these was like a puzzle to figure out how to load and run
the OS and various packages.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sun-sparcstation-slc">Sun SPARCStation SLC<a href="https://ricegeo.dev/linux-user-30-years#sun-sparcstation-slc" class="hash-link" aria-label="Direct link to Sun SPARCStation SLC" title="Direct link to Sun SPARCStation SLC" translate="no">​</a></h3>
<div style="float:left;margin-right:1em;width:200px"><p><img decoding="async" loading="lazy" alt="Sun SPARCstation" src="https://ricegeo.dev/assets/images/SPARCstationSLC-ffe8d87ceb25c994159072d2914df70f.jpg" width="300" height="300" class="img_ev3q"></p></div>
<p>I installed Linux on this little terminal. These were available for free or cheap. It had a monochrome monitor which
was pleasing to the eyes. I got X-Windows running, and could browse the web using <a href="https://en.wikipedia.org/wiki/Netscape_Navigator" target="_self" rel="noopener noreferrer" class="">Netscape
Navigator</a>. In grayscale- so cool. It was quiet too because of being
fanless. But so slow. [image attribution: <a href="https://blog.dshr.org/2024/04/the-little-garden.html" target="_self" rel="noopener noreferrer" class="">David Rosenthal</a> CC
BY-SA 3.0 US]</p>
<br>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="dec-alpha">DEC Alpha<a href="https://ricegeo.dev/linux-user-30-years#dec-alpha" class="hash-link" aria-label="Direct link to DEC Alpha" title="Direct link to DEC Alpha" translate="no">​</a></h3>
<div style="float:left;margin-right:1em;width:200px"><p><img decoding="async" loading="lazy" alt="DEC Alpha" src="https://ricegeo.dev/assets/images/dec-alpha-ad4362f5e490db76b45c5be99a8d5d63.jpg" width="750" height="372" class="img_ev3q"></p></div>
<p>I also installed Linux on this Digital Equipment Corp (DEC) workstation. Also available free or cheap.
[image attribution: <a href="https://www.computinghistory.org.uk/det/12417/Digital-DEC-Multia-(Alpha-Generation)/" target="_self" rel="noopener noreferrer" class="">The Centre for Computing History</a>]</p>
<br>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="macos-x-bsd-unix-for-the-masses">macOS X, BSD Unix for the masses<a href="https://ricegeo.dev/linux-user-30-years#macos-x-bsd-unix-for-the-masses" class="hash-link" aria-label="Direct link to macOS X, BSD Unix for the masses" title="Direct link to macOS X, BSD Unix for the masses" translate="no">​</a></h2>
<p>macOS 9 and older had a reputation for instability (crashing, and showing the "bomb" screen), because of it's system
architecture.</p>
<p>Circa 2001, macOS X revolutionized all that because it introduced preemptive multitasking, protected memory, and a
BSD-Unix based subsystem. Finally an OS with a nice graphical interface, and an actual Unix environment with all the
tools and compilers one needs.</p>
<p>The last time I went to a developer conference, there was literally a sea of macOS laptops. Apple really has gained
traction with developers as well as creative designers. Of course there is always cross section of hardcore Linux folks
to running Lenovo Thinkpads or <a href="https://system76.com/" target="_self" rel="noopener noreferrer" class="">System 76</a> laptops. We'll dig into <a href="https://ricegeo.dev/linux-user-30-years#linux-won-the-internet-and-developer-mind-share" class="" target="_self">developer mind-share more
below</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="linux-at-national-center-for-genome-resources-ncgr">Linux at National Center for Genome Resources (NCGR)<a href="https://ricegeo.dev/linux-user-30-years#linux-at-national-center-for-genome-resources-ncgr" class="hash-link" aria-label="Direct link to Linux at National Center for Genome Resources (NCGR)" title="Direct link to Linux at National Center for Genome Resources (NCGR)" translate="no">​</a></h2>
<p>When I worked at <a href="https://www.ncgr.org/" target="_self" rel="noopener noreferrer" class="">NCGR</a> it was my first exposure to an on-premises data center with a <strong>lot</strong> of
compute and storage. I learned how to parallelize jobs, and submit batches to a cluster of bare metal Linux servers.
Lots of Bash shell scripting, Makefiles, Perl and Python. A single genome sequencer instrument can output terabytes of
data per day, so the compute and storage requirements were substantial.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mike-warrens-linux-top500-stunt-at-descartes-labs">Mike Warren's Linux Top500 "stunt" at Descartes Labs<a href="https://ricegeo.dev/linux-user-30-years#mike-warrens-linux-top500-stunt-at-descartes-labs" class="hash-link" aria-label="Direct link to Mike Warren's Linux Top500 &quot;stunt&quot; at Descartes Labs" title="Direct link to Mike Warren's Linux Top500 &quot;stunt&quot; at Descartes Labs" translate="no">​</a></h2>
<p>I worked at <a href="https://descarteslabs.com/" target="_self" rel="noopener noreferrer" class="">Descartes Labs</a> when Mike Warren, the CTO, used a cluster of cloud VMs to
compete in a supercomputing contest. This was a first time ever for a team to place in the list of top 500
supercomputers using cloud resources. <a href="https://medium.com/descarteslabs-team/thunder-from-the-cloud-40-000-cores-running-in-concert-on-aws-bf1610679978" target="_self" rel="noopener noreferrer" class="">Thunder from the Cloud: 40,000 Cores Running in Concert on
AWS</a>
is an inspiring story about the democratization of computing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="taking-stock-windows-at-usda">Taking stock: Windows at USDA<a href="https://ricegeo.dev/linux-user-30-years#taking-stock-windows-at-usda" class="hash-link" aria-label="Direct link to Taking stock: Windows at USDA" title="Direct link to Taking stock: Windows at USDA" translate="no">​</a></h2>
<p>My current role is contractor to the U.S. Department of Agriculture (USDA), Farm Production and Conservation Business
Center (FPAC) and Natural Resources Conservation Service (NRCS). I was hired to work on a re-architecture and AWS cloud
migration of a legacy application. I was actually very surprised to find that basically the entire system is MS
Windows. The status quo for desktop computers is, unsurprisingly, Windows. But the servers, databases, and
Extract-Transform-Load (ETL) pipelines are also Windows based. Visual Studio Pro, SQL Server Integration Services
(SSIS), and SQL Server Management Studio (SSMS) and Remote desktop are required. Chasing down the required software
installations, licenses and elevated privileges for Windows authentication literally takes weeks. Then one is hobbled
by GUI-only applications and a very lacking command line experience.</p>
<p>Linux/macOS has <a href="https://ricegeo.dev/linux-user-30-years#linux-won-the-internet-and-developer-mind-share" class="" target="_self">indisputably won</a> on Internet servers, web
development, as well as scientific computing and High Performance Computing (HPC). So why does it feel like I've
teleported back 30 years into a giant corporation? Incredible. How is this even possible? Because that's basically
exactly what it is. I was able to more or less sort out the history of how we arrived in this state:</p>
<blockquote>
<p>FPAC (Farm Production and Conservation) is a mission area within USDA that includes NRCS (Natural Resources Conservation Service) as one of it's agencies, alongside FSA (Farm Service Agency) and RMA (Risk Management Agency).
The Windows infrastructure entrenchment in FPAC largely stems from the 1990s modernization efforts. Key factors:</p>
</blockquote>
<blockquote>
<ul>
<li class="">FSA's legacy AS/400 systems were migrated to Windows-based solutions</li>
<li class="">Large contractors (particularly IBM) implemented Service Center Information Management System (SCIMS) using Microsoft technologies</li>
<li class="">County offices standardized on Windows desktops for program delivery</li>
<li class="">Custom applications were built on .NET/SQL Server stack</li>
<li class="">GIS tools like Toolkit initially developed for Windows platforms</li>
</ul>
</blockquote>
<blockquote>
<p>This created a Microsoft-centric ecosystem that persists today, despite NRCS maintaining some Unix/Linux systems for scientific computing and conservation planning tools.  [Source: Claude 3.5 Sonnet]</p>
</blockquote>
<p>I am advocating for a Docker container (Linux) based development approach, Postgres, and AWS deployment, for the
modernization of this particular app.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="postscript">Postscript<a href="https://ricegeo.dev/linux-user-30-years#postscript" class="hash-link" aria-label="Direct link to Postscript" title="Direct link to Postscript" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="linux-won-the-internet-and-developer-mind-share">Linux won the Internet and developer mind-share<a href="https://ricegeo.dev/linux-user-30-years#linux-won-the-internet-and-developer-mind-share" class="hash-link" aria-label="Direct link to Linux won the Internet and developer mind-share" title="Direct link to Linux won the Internet and developer mind-share" translate="no">​</a></h3>
<p>Numbers reflect 2024 estimates across enterprise and public infrastructure. Source: Claude.ai</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="percent-of-internet-infrastructure">Percent of Internet infrastructure<a href="https://ricegeo.dev/linux-user-30-years#percent-of-internet-infrastructure" class="hash-link" aria-label="Direct link to Percent of Internet infrastructure" title="Direct link to Percent of Internet infrastructure" translate="no">​</a></h3>
<table><thead><tr><th>System Category</th><th>Linux/Unix Usage</th><th>Notes</th></tr></thead><tbody><tr><td>Container Orchestration</td><td>~98%</td><td>Kubernetes, Docker dominance</td></tr><tr><td>Web Servers</td><td>~90%</td><td>Apache, Nginx, BSD variants</td></tr><tr><td>Network Routers</td><td>~95%</td><td>Enterprise and carrier-grade</td></tr><tr><td>Network Switches</td><td>~85%</td><td>BSD and Linux variants</td></tr><tr><td>IoT Devices</td><td>~85%</td><td>Android, embedded Linux, BSD</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="developer-mind-share">Developer mind-share<a href="https://ricegeo.dev/linux-user-30-years#developer-mind-share" class="hash-link" aria-label="Direct link to Developer mind-share" title="Direct link to Developer mind-share" translate="no">​</a></h3>
<table><thead><tr><th>Developer Category</th><th>Linux/Unix/macOS Usage</th><th>Key Drivers</th></tr></thead><tbody><tr><td>Cloud/DevOps</td><td>~90%</td><td>Container ecosystems, server management</td></tr><tr><td>Embedded/IoT</td><td>~85%</td><td>Linux development requirements</td></tr><tr><td>Security/Pentesting</td><td>~80%</td><td>Unix tooling, Kali Linux</td></tr><tr><td>Data Science</td><td>~75%</td><td>Unix tools, Python ecosystem</td></tr><tr><td>Web Development</td><td>~70%</td><td>macOS popularity, cross-platform tools</td></tr><tr><td>Mobile Dev</td><td>~65%</td><td>macOS for iOS, Linux for Android</td></tr><tr><td>Game Development</td><td>~45%</td><td>Windows still dominant</td></tr><tr><td>Enterprise/.NET</td><td>~35%</td><td>Windows prevalence</td></tr></tbody></table>
<p>macOS is included in the table because it has a BSD Unix subsystem and command line experience, which is explored
in the section <a href="https://ricegeo.dev/linux-user-30-years#macos-x-bsd-unix-for-the-masses" class="" target="_self">macOS X, BSD Unix for the masses</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="next-steps">Next steps<a href="https://ricegeo.dev/linux-user-30-years#next-steps" class="hash-link" aria-label="Direct link to Next steps" title="Direct link to Next steps" translate="no">​</a></h3>
<p>I am currently working on AWS Certified Solutions Architect (AWS CSA-A) certification, and plan to pursue the Data
Engineering track after that.</p>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>edits</div><div class="admonitionContent_BuS1"><ul>
<li class="">2025-05-02 Clarify some comments about macOS &lt; X</li>
</ul></div></div>]]></content:encoded>
            <category>book</category>
            <category>cloud</category>
            <category>dev</category>
            <category>linux</category>
            <category>photo</category>
            <category>tech</category>
        </item>
        <item>
            <title><![CDATA[Servant leadership in a data engineering role]]></title>
            <link>https://ricegeo.dev/servant-leadership-data-eng</link>
            <guid>https://ricegeo.dev/servant-leadership-data-eng</guid>
            <pubDate>Thu, 17 Oct 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[This post explores the concept of servant leadership in the context of government consulting as a tech worker, and]]></description>
            <content:encoded><![CDATA[<p>This post explores the concept of servant leadership in the context of government consulting as a tech worker, and
reflects about Large Language Models (LLMs) as a productivity tool...</p>
<p>I recently applied for a position with a consulting company, <a href="https://www.xentity.com/" target="_self" rel="noopener noreferrer" class="">Xentity Corp</a>, and the concept of
"servant leadership" was briefly mentioned by an interviewer.</p>
<p>After the interview I wanted to better understand what servant leadership means, so I asked <a href="https://claude.ai/" target="_self" rel="noopener noreferrer" class="">Claude (3.5
Sonnet)</a> for some book recommendations or online materials. I tried to get Claude to narrow down
responses to government consulting and data engineering. I went back and forth with Claude. All of the recommendations
were OK, but nothing was really jumping out at me for a book to read, or papers to download.</p>
<p>Then it occurred to me this is a LLM so why don't I ask it to summarize the material? This is what LLMs are great at:
synthesizing and generating reviews of material in a digestible and understandable way. Here is an excerpt, just the
end of conversation:</p>
<blockquote>
<p>[Q] Have not been able to find a good book that I am interested in reading. Please summarize servant leadership in the context of government consulting- for a tech position (data engineer).</p>
</blockquote>
<blockquote>
<p>[A] I understand you haven't found a book that captures your interest. Let me summarize servant leadership in the context of government consulting for a tech position like a data engineer:
Servant leadership in government consulting as a data engineer involves:</p>
<ol>
<li class="">Prioritizing stakeholder needs:<!-- -->
<ul>
<li class="">Focus on understanding and meeting the needs of government clients and end-users.</li>
<li class="">Actively listen to requirements and pain points before proposing solutions.</li>
</ul>
</li>
<li class="">Empowering team members and clients:<!-- -->
<ul>
<li class="">Share knowledge and skills to help government staff better understand data processes.</li>
<li class="">Mentor junior team members and client personnel in data engineering practices.</li>
</ul>
</li>
<li class="">Ethical data handling:<!-- -->
<ul>
<li class="">Prioritize data privacy, security, and responsible use of public information.</li>
<li class="">Advocate for transparent data practices and clear communication of data limitations.</li>
</ul>
</li>
<li class="">Long-term thinking:<!-- -->
<ul>
<li class="">Design scalable, maintainable data solutions that will serve the government beyond your contract.</li>
<li class="">Consider the long-term impact of data architecture decisions on future government operations.</li>
</ul>
</li>
<li class="">Collaborative approach:<!-- -->
<ul>
<li class="">Work closely with other departments and stakeholders to ensure data solutions align with broader government goals.</li>
<li class="">Facilitate cross-functional communication to bridge gaps between technical and non-technical teams.</li>
</ul>
</li>
<li class="">Continuous improvement:<!-- -->
<ul>
<li class="">Regularly seek feedback on data solutions and processes.</li>
<li class="">Stay updated on emerging technologies and best practices to better serve government clients.</li>
</ul>
</li>
<li class="">Accountability and transparency:<!-- -->
<ul>
<li class="">Take responsibility for project outcomes and be open about challenges or limitations.</li>
<li class="">Provide clear, understandable explanations of complex data concepts to non-technical stakeholders.</li>
</ul>
</li>
<li class="">Public service mindset:<!-- -->
<ul>
<li class="">Align data engineering efforts with the broader mission of improving government services and citizens' lives.</li>
<li class="">Consider the societal impact of data-driven decisions and advocate for equitable solutions.</li>
</ul>
</li>
</ol>
</blockquote>
<blockquote>
<p>In practice, this might involve:</p>
<ul>
<li class="">Developing user-friendly data dashboards for government decision-makers</li>
<li class="">Creating efficient data pipelines that respect resource constraints of government systems</li>
<li class="">Implementing data governance practices that ensure compliance with public sector regulations</li>
<li class="">Conducting workshops to upskill government staff in data literacy and basic data engineering concepts</li>
</ul>
</blockquote>
<blockquote>
<p>Would you like me to expand on any specific aspect of this summary?</p>
</blockquote>
<p>Overall, this was a really good LLM interaction! It was genuinely helpful, and everything seemed legitimate in the
response. In future posts I will share some LLM failure modes that I have seen or learned about. I am both fascinated
and biased about LLMs, having studied Linguistic Anthropology as an undergraduate.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>announcement</div><div class="admonitionContent_BuS1"><p>I start working at Xentity in October 2024 as a Senior Data Engineer contracted to U.S. Department of
Agriculture (USDA), Natural Resources Conservation Service (NRCS).</p></div></div>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>]]></content:encoded>
            <category>tech</category>
            <category>ai</category>
            <category>dev</category>
        </item>
        <item>
            <title><![CDATA[Irrigation in the West, visualized with National Hydrography Dataset]]></title>
            <link>https://ricegeo.dev/irrigation-in-the-west</link>
            <guid>https://ricegeo.dev/irrigation-in-the-west</guid>
            <pubDate>Sat, 21 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[In the United States there is a clear pattern of human settlement where to the East, there is more than 30]]></description>
            <content:encoded><![CDATA[<p>In the United States there is a clear pattern of human settlement where to the East, there is more than 30
inches of rainfall and so crops can be grown without irrigation, and to the West, irrigation is required. This post is
an exploration of population density, precipitation rates, and the National Hydrography Dataset (NHD)...</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="average-annual-precipitation">Average annual precipitation<a href="https://ricegeo.dev/irrigation-in-the-west#average-annual-precipitation" class="hash-link" aria-label="Direct link to Average annual precipitation" title="Direct link to Average annual precipitation" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="us precipitation inches" src="https://ricegeo.dev/assets/images/us-precip-inches-e15cba8d784637f7366a29360dfb1936.png" title="us precipitation inches" width="2785" height="1873" class="img_ev3q"> <br>
<!-- -->Attribution: United States Department of the Interior nepes, Public domain, via Wikimedia Commons</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="population-density">Population density<a href="https://ricegeo.dev/irrigation-in-the-west#population-density" class="hash-link" aria-label="Direct link to Population density" title="Direct link to Population density" translate="no">​</a></h2>
<p>I added the blue dotted line to hilite the pattern going from Wisconsin down to Texas.</p>
<p><img decoding="async" loading="lazy" alt="us population density" src="https://ricegeo.dev/assets/images/us-population-density-bda357822bf8115b1e78662c56c613cf.jpg" title="us population density" width="2560" height="2022" class="img_ev3q"> <br>
<!-- -->Attribution: SEDACMaps, The Trustees of Columbia University in the City of New York: <a href="https://creativecommons.org/licenses/by/4.0" target="_self" rel="noopener noreferrer" class="">CC BY 4.0</a> , via Wikimedia Commons</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="acequias-canals-and-ditches-in-the-west">Acequias, canals, and ditches in the West<a href="https://ricegeo.dev/irrigation-in-the-west#acequias-canals-and-ditches-in-the-west" class="hash-link" aria-label="Direct link to Acequias, canals, and ditches in the West" title="Direct link to Acequias, canals, and ditches in the West" translate="no">​</a></h2>
<p>In the West, human settlements were only possible where water exists and agriculture was possible. Acequias,
irrigation ditches and canals are the technology that makes this possible.</p>
<blockquote>
<p>An acequia is a community-operated watercourse used in Spain and former Spanish colonies in the Americas for
irrigation. Acequias are found in parts of Spain, the Andes, northern Mexico, and the modern-day American Southwest
(northern New Mexico and southern Colorado). source: <a href="https://en.wikipedia.org/wiki/Acequia" target="_self" rel="noopener noreferrer" class="">Wikipedia</a>.</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="visualize-irrigation-with-the-nhd">Visualize irrigation with the NHD<a href="https://ricegeo.dev/irrigation-in-the-west#visualize-irrigation-with-the-nhd" class="hash-link" aria-label="Direct link to Visualize irrigation with the NHD" title="Direct link to Visualize irrigation with the NHD" translate="no">​</a></h2>
<p>Here are some screen captures of the Southwest US and also the Grand Valley in Colorado. The patterns of irrigation
development are correlated with the population density map (above).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="southwest-us-irrigation">Southwest US irrigation<a href="https://ricegeo.dev/irrigation-in-the-west#southwest-us-irrigation" class="hash-link" aria-label="Direct link to Southwest US irrigation" title="Direct link to Southwest US irrigation" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Southwest us" src="https://ricegeo.dev/assets/images/nhd-canal-ditch-8f73b8e249983b64f68cb0e9a4f889c7.jpg" title="Southwest us" width="5518" height="3196" class="img_ev3q"> <br>
<!-- -->Map data sourced from the National Hydrography Dataset (NHD), U.S. Geological Survey, ©OpenStreetMap contributors</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="grand-valley-colorado-irrigation">Grand Valley, Colorado irrigation<a href="https://ricegeo.dev/irrigation-in-the-west#grand-valley-colorado-irrigation" class="hash-link" aria-label="Direct link to Grand Valley, Colorado irrigation" title="Direct link to Grand Valley, Colorado irrigation" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Grand valley CO" src="https://ricegeo.dev/assets/images/nhd-canal-ditch-2-b089f26a147473e3f02e5a9aa5f42437.jpg" title="Grand valley CO" width="5518" height="3196" class="img_ev3q"> <br>
<!-- -->Map data sourced from the National Hydrography Dataset (NHD), U.S. Geological Survey, ©OpenStreetMap contributors</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="technical-approach">Technical approach<a href="https://ricegeo.dev/irrigation-in-the-west#technical-approach" class="hash-link" aria-label="Direct link to Technical approach" title="Direct link to Technical approach" translate="no">​</a></h2>
<ol>
<li class="">
<p>Researched the NHD and <a href="https://www.usgs.gov/national-hydrography/access-national-hydrography-products" target="_self" rel="noopener noreferrer" class="">found download options</a></p>
</li>
<li class="">
<p>Downloaded with <code>curl</code> and unzipped the national NHD file</p>
</li>
</ol>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">curl -O https://prd-tnm.s3.amazonaws.com/StagedProducts/Hydrography/NHDPlusHR/National/GDB/NHDPlus_H_National_Release_1_GDB.zip</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">unzip NHDPlus_H_National_Release_1_GDB.zip</span><br></span></code></pre></div></div>
<p>Contained in the zip archive is a 99GB geopackage file: <code>NHD_H_National_GPKG.gpkg</code>.</p>
<ol start="3">
<li class="">
<p>Explored the features and attributes in <a href="https://qgis.org/" target="_self" rel="noopener noreferrer" class="">QGIS</a>. The dataset has many layers and feature codes.
For this quick exploration, I focused on the layer <code>NHDFlowLine</code> and the feature code <code>33600:"Canal/Ditch"</code>.</p>
</li>
<li class="">
<p>Used <a href="https://gdal.org/en/latest/" target="_self" rel="noopener noreferrer" class="">GDAL/OGR</a> to efficiently filter on the <code>fcode</code> attribute, producing a new
geopackage file: <code>canal-ditch.gpkg</code>.</p>
</li>
</ol>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ogr2ogr canal-ditch.gpkg NHD_H_National_GPKG.gpkg \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    -sql "SELECT * FROM NHDFlowline WHERE fcode = 33600"</span><br></span></code></pre></div></div>
<ol start="5">
<li class="">In a new <a href="https://qgis.org/" target="_self" rel="noopener noreferrer" class="">QGIS</a> project, add an OpenStreetMap XYZ Tiles layer, and the <code>canal-ditch.gpkg</code> geopackage.</li>
</ol>
<p>I hope you enjoyed this ramble through a population map, precipitation map, and finally the NHD dataset.</p>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>edits</div><div class="admonitionContent_BuS1"><ul>
<li class="">2024-09-21 Fix attribution for population density map.</li>
</ul></div></div>]]></content:encoded>
            <category>linux</category>
            <category>gis</category>
            <category>gdal-ogr</category>
            <category>map</category>
            <category>vector</category>
        </item>
        <item>
            <title><![CDATA[Like mapstodon.space]]></title>
            <link>https://ricegeo.dev/on-mastodon</link>
            <guid>https://ricegeo.dev/on-mastodon</guid>
            <pubDate>Tue, 17 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[If you have interest in alternative and decentralized social media, be sure to check out our]]></description>
            <content:encoded><![CDATA[<p>If you have interest in alternative and decentralized social media, be sure to check out our
<a href="https://joinmastodon.org/" target="_self" rel="noopener noreferrer" class="">Mastodon</a> community!
My profile: <a href="https://mapstodon.space/@guidorice" target="_self" rel="noopener noreferrer" class="">https://mapstodon.space/@guidorice</a></p>
<blockquote>
<p>Mapstodon.space is an online community dedicated to cartography &amp; geospatial enthusiasts.
<a href="https://mapstodon.space/about" target="_self" rel="noopener noreferrer" class="">https://mapstodon.space/about</a></p>
</blockquote>]]></content:encoded>
            <category>dev</category>
            <category>gis</category>
            <category>tech</category>
        </item>
        <item>
            <title><![CDATA[The Power of Where]]></title>
            <link>https://ricegeo.dev/the-power-of-where-book</link>
            <guid>https://ricegeo.dev/the-power-of-where-book</guid>
            <pubDate>Fri, 06 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[I recommend the new book The Power of Where, by Jack Dangermond and Esri (2024). Here's my short review of this]]></description>
            <content:encoded><![CDATA[<p>I recommend the new book <strong>The Power of Where</strong>, by Jack Dangermond and Esri (2024). Here's my short review of this
new book...</p>
<p>My GIS certificate program, <a href="https://www.psu.edu/" target="_self" rel="noopener noreferrer" class="">Penn State</a> '16, included an intensive crash course in Esri ArcGIS.
More recently, in my professional experience as a developer, I have used free and open source software like
<a href="https://qgis.org/" target="_self" rel="noopener noreferrer" class="">QGIS</a>, <a href="https://postgis.net/" target="_self" rel="noopener noreferrer" class="">PostGIS</a>, <a href="https://gdal.org/en/latest/" target="_self" rel="noopener noreferrer" class="">GDAL/OGR</a>,
<a href="https://rasterio.readthedocs.io/en/stable/" target="_self" rel="noopener noreferrer" class="">Rasterio</a>, and <a href="https://geopandas.org/en/stable/" target="_self" rel="noopener noreferrer" class="">GeoPandas</a>. It's great
to see the Esri persepective again. As a bootstrapped company for over 50 years, it invests massively into research and
development.</p>
<p>This book is a hybrid of a visually appealing coffee-table type of book, with a gentle intro to the state of the art in
GIS and the "geographic approach" as well. It would make a nice gift to friends or family who don't yet understand the
appeal of GIS and the richness of geodata.</p>
<p><img decoding="async" loading="lazy" alt="the power of where image" src="https://ricegeo.dev/assets/images/screenshot-6c792291410e4a7d23dfa9b14c514ee5.png" title="the power of where" width="2070" height="1162" class="img_ev3q"></p>
<p>Check out the book at</p>
<ul>
<li class=""><a href="https://libraryfinder.org/" target="_self" rel="noopener noreferrer" class="">Your local library!</a></li>
<li class=""><a href="https://www.esri.com/en-us/esri-press/browse/the-power-of-where" target="_self" rel="noopener noreferrer" class="">Esri Press</a></li>
<li class=""><a href="https://www.amazon.com/Power-Where-Geographic-Approach-Challenges/dp/1589486064" target="_self" rel="noopener noreferrer" class="">Amazon</a></li>
</ul>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>]]></content:encoded>
            <category>book</category>
            <category>dev</category>
            <category>gis</category>
            <category>tech</category>
        </item>
        <item>
            <title><![CDATA[Announcing mojo-pytest]]></title>
            <link>https://ricegeo.dev/mojo-pytest</link>
            <guid>https://ricegeo.dev/mojo-pytest</guid>
            <pubDate>Thu, 05 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[mojo-pytest is a Mojo🔥 language test runner plugin for pytest.]]></description>
            <content:encoded><![CDATA[<p><code>mojo-pytest</code> is a Mojo🔥 language test runner plugin for <code>pytest</code>.
Try it for your mixed Python and Mojo codebases. Here are some tips and example command line usage...</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-mojo">What is Mojo<a href="https://ricegeo.dev/mojo-pytest#what-is-mojo" class="hash-link" aria-label="Direct link to What is Mojo" title="Direct link to What is Mojo" translate="no">​</a></h2>
<blockquote>
<p>Mojo is a new programming language that bridges the gap between research and production by combining Python syntax
and ecosystem with systems programming and metaprogramming features. Mojo is still young, but it is designed to become
a superset of Python over time. source: <a href="https://docs.modular.com/mojo/manual/" target="_self" rel="noopener noreferrer" class="">Mojo docs</a></p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-pytest">What is pytest<a href="https://ricegeo.dev/mojo-pytest#what-is-pytest" class="hash-link" aria-label="Direct link to What is pytest" title="Direct link to What is pytest" translate="no">​</a></h2>
<blockquote>
<p>The <code>pytest</code> framework makes it easy to write small, readable tests, and can scale to support complex functional
testing for applications and libraries. source: <a href="https://docs.pytest.org/en/stable/" target="_self" rel="noopener noreferrer" class="">pytest docs</a></p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pytest-meet-mojo">pytest, meet Mojo<a href="https://ricegeo.dev/mojo-pytest#pytest-meet-mojo" class="hash-link" aria-label="Direct link to pytest, meet Mojo" title="Direct link to pytest, meet Mojo" translate="no">​</a></h2>
<p><a href="https://github.com/guidorice/mojo-pytest" target="_self" rel="noopener noreferrer" class="">This package</a> implements a <code>pytest</code> plugin to discover and run Mojo tests,
alongside your Python tests. Although <code>pytest</code> does not have any awareness of Mojo source or package structure,
<code>pytest</code> is extensible. In summary, <code>plugin.py</code> calls <code>mojo test</code> in a sub-process and parses the outputs and exit codes.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example-test-using-mojo-standard-library">Example test using Mojo standard library<a href="https://ricegeo.dev/mojo-pytest#example-test-using-mojo-standard-library" class="hash-link" aria-label="Direct link to Example test using Mojo standard library" title="Direct link to Example test using Mojo standard library" translate="no">​</a></h3>
<p>This simple Mojo module shows testing native Mojo code, and also calling into a Python module
for testing vs reference implementation.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># file: example_tests/my_package/test_fibonacci.mojo</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> python </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> Python</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> testing </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> assert_equal</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> my_package</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">fibonacci </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> fibonacci</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">test_fibonacci</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    Test fibonacci 10th number.</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    """</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expect </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">55</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    got </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fibonacci</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    assert_equal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">got</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> expect</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">test_fibonacci_reference</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    Test mojo fibonacci versus python "reference" implementation.</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    """</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    py </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Python</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">import_module</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"my_package.fibonacci"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> n </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        expect </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> py</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">fibonacci</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        got </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fibonacci</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        assert_equal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">got</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> expect</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p><code>pytest</code> runs both the Python tests, and the Mojo tests. Example command line usage:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ pytest --mojo-include example_src/ example_tests/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">================================ test session starts =======================</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rootdir: /Users/guidorice/mojo/mojo-pytest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">configfile: pyproject.toml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">plugins: mojo-24.5</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">collected 6 items                                                          </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">example_tests/my_package/my_test.mojo .                              [ 16%]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">example_tests/my_package/test_fibonacci.mojo ..                      [ 50%]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">example_tests/my_package/test_fibonacci.py .                         [ 66%]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">example_tests/my_package/test_fire.🔥 .                              [ 83%]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">example_tests/my_package/test_random_tensor.mojo .                   [100%]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">================================ 6 passed in 13.55s =======================</span><br></span></code></pre></div></div>
<p>Check it out at the GitHub repo: <a href="https://github.com/guidorice/mojo-pytest" target="_self" rel="noopener noreferrer" class="">https://github.com/guidorice/mojo-pytest</a>.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>For compatibility, <code>mojo-pytest</code> follows the version numbering of <code>mojo</code>, ex: v24.5.</p></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p><a href="https://github.com/guidorice/mojo-pytest/wiki#2024-07-17-here-is-a-performance-tip" target="_self" rel="noopener noreferrer" class="">To increase testing speed, try running pytest in parallel mode</a></p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="contributor">Contributor<a href="https://ricegeo.dev/mojo-pytest#contributor" class="hash-link" aria-label="Direct link to Contributor" title="Direct link to Contributor" translate="no">​</a></h2>
<p>Thanks to Leandro Leites Barrios <a href="https://github.com/lleites" target="_self" rel="noopener noreferrer" class="">@lleiets</a> for contributions and suggesting
the idea of using the <code>pytest</code> plugin API, instead of just a config script.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="further-reading">Further reading<a href="https://ricegeo.dev/mojo-pytest#further-reading" class="hash-link" aria-label="Direct link to Further reading" title="Direct link to Further reading" translate="no">​</a></h2>
<ul>
<li class="">See the GitHub repo <a href="https://github.com/guidorice/mojo-pytest" target="_self" rel="noopener noreferrer" class="">https://github.com/guidorice/mojo-pytest</a> for more about <code>mojo-pytest</code>.</li>
<li class=""><a href="https://docs.modular.com/mojo/manual/" target="_self" rel="noopener noreferrer" class="">Mojo language manual</a></li>
<li class=""><a href="https://github.com/modular/max" target="_self" rel="noopener noreferrer" class="">Mojo GitHub repository</a></li>
</ul>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>edits</div><div class="admonitionContent_BuS1"><ul>
<li class="">2025-03-11 Update links to Mojo language manual.</li>
<li class="">2024-10-17 Remove <code>var</code> from code snippets: it's optional in latest Mojo release.</li>
</ul></div></div>]]></content:encoded>
            <category>mojo</category>
            <category>python</category>
            <category>dev</category>
            <category>testing</category>
        </item>
        <item>
            <title><![CDATA[Mojo Modcon (23) contest finalist]]></title>
            <link>https://ricegeo.dev/mojo-modcon23-contest</link>
            <guid>https://ricegeo.dev/mojo-modcon23-contest</guid>
            <pubDate>Wed, 04 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[In November 2023 I was the #6 finalist in the ModCon23 contest for the new programming language,]]></description>
            <content:encoded><![CDATA[<p>In November 2023 I was the #6 finalist in the ModCon23 contest for the new programming language,
<a href="https://docs.modular.com/mojo/manual/" target="_self" rel="noopener noreferrer" class="">Mojo🔥</a>. Calculating an envelope is a fundamental part of spatial analysis. The
envelope (aka: bounds, bbox, mbr) is usually defined by an xmin, ymin, xmax, and ymax representing the minimum and
maximum x (longitude) and y (latitude) coordinates that encompass the bounded feature(s)...</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>The content in this post is from 2023-11-30, before this blog existed.</p></div></div>
<p><img decoding="async" loading="lazy" alt="bounding box" src="https://ricegeo.dev/assets/images/bounding_box-8dd053484221d8d501ee021775d07534.png" title="spatial envelope" width="599" height="536" class="img_ev3q"> <br>
<!-- -->Figure attribution: <a href="https://docs.qgis.org/" target="_self" rel="noopener noreferrer" class="">QGIS documentation</a>: Fig. 27.53 Black lines represent the bounding boxes of
each polygon feature.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-mojo">What is Mojo<a href="https://ricegeo.dev/mojo-modcon23-contest#what-is-mojo" class="hash-link" aria-label="Direct link to What is Mojo" title="Direct link to What is Mojo" translate="no">​</a></h2>
<blockquote>
<p>Mojo is a new programming language that bridges the gap between research and production by combining Python syntax
and ecosystem with systems programming and metaprogramming features. Mojo is still young, but it is designed to become
a superset of Python over time. source: <a href="https://docs.modular.com/mojo/manual/" target="_self" rel="noopener noreferrer" class="">Mojo docs</a></p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="contest-submission">Contest submission<a href="https://ricegeo.dev/mojo-modcon23-contest#contest-submission" class="hash-link" aria-label="Direct link to Contest submission" title="Direct link to Contest submission" translate="no">​</a></h2>
<p>Calculates the spatial envelope, and explores the performance of Python, NumPy, and Mojo. The Mojo final implementation
is 20X to 600X faster than Python, and 1.3X to 4X faster than NumPy.</p>
<p><img decoding="async" loading="lazy" alt="benchmarks image" src="https://ricegeo.dev/assets/images/benchmarks-1-f90ad85525129fcd75121da6cd42e60e.png" title="benchmarks image" width="886" height="547" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="further-reading">Further reading<a href="https://ricegeo.dev/mojo-modcon23-contest#further-reading" class="hash-link" aria-label="Direct link to Further reading" title="Direct link to Further reading" translate="no">​</a></h2>
<ul>
<li class="">See the GitHub repo <a href="https://github.com/guidorice/modcon23-contest" target="_self" rel="noopener noreferrer" class="">https://github.com/guidorice/modcon23-contest</a>
for a more detailed writeup, source code, and more benchmark results.</li>
<li class=""><a href="https://www.modular.com/modverse/modverse-weekly-issue-11" target="_self" rel="noopener noreferrer" class="">Announcement of all the winners in Modverse weekly #11</a></li>
<li class=""><a href="https://docs.modular.com/mojo/manual/" target="_self" rel="noopener noreferrer" class="">Mojo language manual</a></li>
<li class=""><a href="https://github.com/modular/max" target="_self" rel="noopener noreferrer" class="">Mojo GitHub repository</a></li>
</ul>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>edits</div><div class="admonitionContent_BuS1"><ul>
<li class="">2025-03-11 Update Further Reading and links to Mojo manual and GitHub.</li>
<li class="">2024-09-20 Add explanation of spatial envelope, and inserted QGIS docs figure.</li>
</ul></div></div>]]></content:encoded>
            <category>mojo</category>
            <category>python</category>
            <category>gis</category>
            <category>contest</category>
            <category>simd</category>
            <category>benchmarking</category>
            <category>vector</category>
        </item>
        <item>
            <title><![CDATA[What it's like to work for a growth stage startup]]></title>
            <link>https://ricegeo.dev/growth-stage-startups</link>
            <guid>https://ricegeo.dev/growth-stage-startups</guid>
            <pubDate>Tue, 03 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[In August, Regrow Agriculture Inc had a big round of layoffs affecting 20% of the company]]></description>
            <content:encoded><![CDATA[<p>In August, <a href="https://www.regrow.ag/" target="_self" rel="noopener noreferrer" class="">Regrow Agriculture Inc</a> had a big round of layoffs affecting 20% of the company
and, startlingly, 40% of the technical team. The geospatial engineering team was effected at a level of 3/5, including
my job. Writing down some parting thoughts...</p>
<p>Regrow was the second venture capital backed startup which I worked for, the first being <a href="https://descarteslabs.com/" target="_self" rel="noopener noreferrer" class="">Descartes
Labs</a> from '17-'19. They had quite a lot in common, being geospatial tech companies, both
in series B or growth phase. Observing some of the common patterns I saw:</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pros">Pros<a href="https://ricegeo.dev/growth-stage-startups#pros" class="hash-link" aria-label="Direct link to Pros" title="Direct link to Pros" translate="no">​</a></h2>
<p>🤩 Work with more talented engineers and scientists</p>
<p>🚀 Quickly level up skills especially in distributed systems, data engineering and big data</p>
<p>✈️ Build the airplane while flying it. Not really a Pro or a Con, more "it is what it is"</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cons">Cons<a href="https://ricegeo.dev/growth-stage-startups#cons" class="hash-link" aria-label="Direct link to Cons" title="Direct link to Cons" translate="no">​</a></h2>
<p>🙈 Hiring is going faster than the company ops, culture and institutional knowledge can absorb the new resources</p>
<p>📉 No stability- the market and investors can change their minds so quickly</p>
<p>P.S. I recommend the book <a href="https://www.hello-startup.net/" target="_self" rel="noopener noreferrer" class="">Hello Startup  by Yevgeniy (Jim) Brikman</a>.</p>
<hr>
<p>🌎 Thanks for rambling! 👋🏼</p>]]></content:encoded>
            <category>dev</category>
            <category>tech</category>
            <category>book</category>
        </item>
        <item>
            <title><![CDATA[Hello World 2.0]]></title>
            <link>https://ricegeo.dev/hello-world-v2</link>
            <guid>https://ricegeo.dev/hello-world-v2</guid>
            <pubDate>Mon, 02 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[My first hello world post included the famous "earthrise" Apollo 8 photo. Just]]></description>
            <content:encoded><![CDATA[<p>My <a class="" target="_self" href="https://ricegeo.dev/hello-world">first hello world post</a> included the famous "earthrise" Apollo 8 photo. Just
for fun here's an interactive 3D globe in the browser. Compliments of <a href="https://mapbox.com/" target="_self" rel="noopener noreferrer" class="">Mapbox</a>, using their free
tier. This demo uses a React .tsx component in a docusaurus .mdx page...</p>
<!-- -->
<!-- -->
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">3D Globe</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Source Code</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// filename map.tsx</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> useRef</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useEffect</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useState </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">MapComponent</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> mapContainer </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> map </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">mapboxgl</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setMapboxgl</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// effect: react reference to the window mapboxgl object. mapboxgl is loaded in &lt;head&gt;.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mapboxgl</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">setMapboxgl</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mapboxgl</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> checkMapboxGL </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">setInterval</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mapboxgl</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token function" style="color:#d73a49">setMapboxgl</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mapboxgl</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token function" style="color:#d73a49">clearInterval</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">checkMapboxGL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">clearInterval</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">checkMapboxGL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// effect: setup and tear down map component</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">mapboxgl</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// setup access token</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        mapboxgl</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">accessToken </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'*****'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// create map</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">mapboxgl</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            container</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> mapContainer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            projection</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'globe'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            style</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'mapbox://styles/mapbox/standard-satellite'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            center</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">85</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// lon, lat</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            zoom</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1.5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'style.load'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setFog</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                color</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'rgb(186, 210, 235)'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Lower atmosphere</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string-property property" style="color:#36acaa">'high-color'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'rgb(36, 92, 223)'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Upper atmosphere</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string-property property" style="color:#36acaa">'horizon-blend'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.02</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Atmosphere thickness (default 0.2 at low zooms)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string-property property" style="color:#36acaa">'space-color'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'rgb(11, 11, 25)'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Background color</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string-property property" style="color:#36acaa">'star-intensity'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.6</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Background star brightness (default 0.35 at low zoooms )</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addControl</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">mapboxgl</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">NavigationControl</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">mapboxgl</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">div ref</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">mapContainer</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> style</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> height</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'500px'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'100%'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">div</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre></div></div></div></div></div>
<blockquote>
<p>A globe! Yes, you're very clever. (reference:  map projections explained in <a href="https://xkcd.com/977/" target="_self" rel="noopener noreferrer" class="">XKCD #977</a>)</p>
</blockquote>]]></content:encoded>
            <category>webdev</category>
            <category>react</category>
            <category>map</category>
            <category>gis</category>
        </item>
        <item>
            <title><![CDATA[Hello World]]></title>
            <link>https://ricegeo.dev/hello-world</link>
            <guid>https://ricegeo.dev/hello-world</guid>
            <pubDate>Sun, 01 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Earthrise photo \]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="Earthrise photo" src="https://ricegeo.dev/assets/images/apollo08_earthrise-082d84237fc047598c879db737d461f2.webp" width="1041" height="1000" class="img_ev3q"> <br>
<!-- -->Image Credit: <a href="https://www.nasa.gov/image-article/apollo-8-earthrise/" target="_self" rel="noopener noreferrer" title="Earthrise photo" class="">NASA</a></p>
<p>👋🏼 Welcome to Geodata Ramblings</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="topics">Topics<a href="https://ricegeo.dev/hello-world#topics" class="hash-link" aria-label="Direct link to Topics" title="Direct link to Topics" translate="no">​</a></h2>
<ul>
<li class="">Geodata</li>
<li class="">GIS</li>
<li class="">Geospatial software</li>
<li class="">Deep learning, ML and AI</li>
<li class="">Mojo language</li>
<li class="">Python language</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tech-stack">Tech stack<a href="https://ricegeo.dev/hello-world#tech-stack" class="hash-link" aria-label="Direct link to Tech stack" title="Direct link to Tech stack" translate="no">​</a></h2>
<ul>
<li class="">Building this with <a href="https://docusaurus.io/" target="_self" rel="noopener noreferrer" class="">Docusaurus</a> and it's been really convenient
to get started!</li>
<li class="">Deployed with <a href="https://www.netlify.com/" target="_self" rel="noopener noreferrer" class="">Netlify</a>!</li>
</ul>]]></content:encoded>
            <category>photo</category>
            <category>1st post 😎</category>
        </item>
    </channel>
</rss>