<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://blog.geothings.ch/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https://blog.geothings.ch</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>
            This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It's free.
        </tabi:about_feeds>
        <tabi:visit_the_site>
            Visit website
        </tabi:visit_the_site>
        <tabi:recent_posts>
            Recent posts
        </tabi:recent_posts>
        <tabi:last_updated_on>
            Updated on $DATE
        </tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>python</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="https://blog.geothings.ch/skins/mint.css?h=504215cf6bc10586b487" /><title>geothings - python</title>
        <subtitle>spatial data | open source | oversharing</subtitle>
    <link href="https://blog.geothings.ch/tags/python/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://blog.geothings.ch/tags/python/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2024-08-16T00:00:00+00:00</updated><id>https://blog.geothings.ch/tags/python/atom.xml</id><entry xml:lang="en">
        <title>FME is getting expensive? Stop using it</title>
        <published>2024-08-16T00:00:00+00:00</published>
        <updated>2024-08-16T00:00:00+00:00</updated>
        <author>
            <name>jujube</name>
        </author>
        <link rel="alternate" href="https://blog.geothings.ch/blog/stop-using-fme/" type="text/html"/>
        <id>https://blog.geothings.ch/blog/stop-using-fme/</id>
        
            <content type="html">&lt;p&gt;I have trouble finding what happened at Safe Software at the beginning of 2024, but it seems that part of the company has been &lt;a rel=&quot;external&quot; href=&quot;https://betakit.com/us-based-jmi-equity-buys-out-safe-software-co-founder-in-strategic-investment/&quot;&gt;sold to an equity firm&lt;/a&gt;. No comment on that, but since then licenses prices seem to have taken a hit and customers are.. Well not very happy, especially regarding the communication around this increase:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://community.safe.com/integration-8/views-on-recent-fme-price-changes-34403&quot;&gt;Views on recent FME price changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.reddit.com/r/fme/comments/1e1bijf/safe_is_an_unreliable_partner/&quot;&gt;Safe is an unreliable partner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.reddit.com/r/fme/comments/13jl6dj/is_a_small_services_consultancy_using_fme_still/&quot;&gt;Is a small services consultancy using FME still viable? Sensible?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.reddit.com/r/gis/comments/12trnzg/i_am_hearing_rumors_of_an_extreme_price_jump_for/&quot;&gt;[…]rumors of an extreme price jump[]…&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Costs become unbearable for some companies and the look for alternatives is now a necessity. What can we do about it?&lt;/p&gt;
&lt;h2 id=&quot;about-fme-and-safe&quot;&gt;About FME and Safe&lt;/h2&gt;
&lt;p&gt;In itself I don’t have anything against FME, it does its job and if it allows more people to work with spatial data and create workflows then it’s cool. But there are things that I find, if not unacceptable, at least not very wise, and it’s not always Safe responsibility.&lt;/p&gt;
&lt;h3 id=&quot;safe-as-a-company&quot;&gt;Safe as a company&lt;/h3&gt;
&lt;p&gt;I never had to negotiate any license or contract with Safe, but people around me always seemed happy about their relation with their resellers and the flexibility that was allowed with their licenses. There was no problem having a home/student license for free if you wanted to fiddle around with FME and prices were rather stable.&lt;/p&gt;
&lt;p&gt;The rebranding and the sell at the beginning of 2024 has changed things, and some of the trust seems to be lost. The big problem is the way the company communicated the changes, which was apparently by giving no clear information. Increasing prices (reasonably) could hardly be considered a problem, that’s the world we’ve chosen, but at least having some transparency about it maintains the relation between seller and buyer. If you receive a x3 bill with a “go f“ck yourself if not happy”, this is at best disrespectful, at worst belittling, especially if you can’t act against this. And to me, &lt;strong&gt;the best answer to give is to gain independence and stop buying&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;fme-as-a-software&quot;&gt;FME as a software&lt;/h3&gt;
&lt;p&gt;As I said, I don’t have anything against FME itself. It makes workflows easy to create and push to production, (spatial) data processing accessible to a broader audience and gives you time to focus on something else if you have a GIS role in your company (see &lt;a rel=&quot;external&quot; href=&quot;https://www.geothings.ch/posts/on-gis/&quot;&gt;On GIS and their integration&lt;/a&gt; for that part of the problem). But making yourself totally dependant on a proprietary solution, with a near monopoly on the field, &lt;strong&gt;IS&lt;/strong&gt; a big problem, and honestly felt like a matter of time before it would happen. The situation is so problematic that some high level administrations (country level) are now negotiating terms with Safe because they are so dependant on FME that they can’t move easily from it, and will have no choice but to take the price hit if they don’t act. And maybe it’s common practice, I wouldn’t say I have enough experience to understand those kinds of negotiations, but it feels wrong.&lt;/p&gt;
&lt;p&gt;That’s were &lt;strong&gt;digital sovereignty&lt;/strong&gt; enter the game, regaining control over our processes, data, and costs. Some links :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://access.archive-ouverte.unige.ch/access/metadata/bbf62d17-891e-46e4-bde8-5666dda99237/download&quot;&gt;Digital Sovereignty in Switzerland : the laboratory of federalism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://framasoft.org/en/&quot;&gt;Framasoft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you work extensively with FME, I’d advise to take a step back and and have a look at what you need and how you could achieve this any other way, because most of the time, there are options, but we just don’t see them anymore. FME has become such an automatism that everything else is a blur, and worst, we lose skills and control.&lt;/p&gt;
&lt;h2 id=&quot;what-alternatives-are-there&quot;&gt;What alternatives are there?&lt;/h2&gt;
&lt;p&gt;The first step is to have a look at what you need to achieve. Let’s see how FME defines itself from their website:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Expansive Data Solutions → well it doesn’t mean anything so next.&lt;/li&gt;
&lt;li&gt;Data Transformation → Ok noted&lt;/li&gt;
&lt;li&gt;Entreprise Automation → Ok noted&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So we get data transformation and automation. Good.&lt;/p&gt;
&lt;h3 id=&quot;read-write-and-data-transformation&quot;&gt;Read, Write and Data transformation&lt;/h3&gt;
&lt;p&gt;Let’s start with the main reason for all of this. We read, transform and write data to solve problems and answer questions. Data need to be shaped into different models and linked with other data to bring additional knowledge. But how do we do that?&lt;/p&gt;
&lt;h4 id=&quot;transform-with-sql&quot;&gt;Transform with SQL&lt;/h4&gt;
&lt;p&gt;If you’re working with databases (PostgreSQL, MariaDB or even Oracle), you’re probably aware of their spatial capabilities. To me, SQL is a major skill, you can do &lt;strong&gt;a lot&lt;/strong&gt; with a single SQL query. There is even a chance that your FME workspace can be entirely replaced by a single SQL query.&lt;/p&gt;
&lt;p&gt;Now we want to Extract, Transform and Load data. Hum but wait, who said you can’t “transform” your data before even reading it? SQL allows you to do that; write your query, save it as a &lt;em&gt;view&lt;/em&gt; if you wish, and you have your result ready to be read, in sync with your tables.&lt;/p&gt;
&lt;p&gt;Let’s say you have &lt;em&gt;regions&lt;/em&gt; (polygons), &lt;em&gt;roads&lt;/em&gt; (lines) and &lt;em&gt;bus stops&lt;/em&gt; (points), and you want:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;road&lt;/em&gt; cut into portions by &lt;em&gt;region&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;road&lt;/em&gt; portions length&lt;/li&gt;
&lt;li&gt;to count &lt;em&gt;bus stops&lt;/em&gt; on each &lt;em&gt;road&lt;/em&gt; portion
&lt;ul&gt;
&lt;li&gt;if a &lt;em&gt;road&lt;/em&gt; has no &lt;em&gt;bus stop&lt;/em&gt; you want to have “No bus stop” instead of 0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;an attribute that says “Hopp Schwiiz !” if the &lt;em&gt;road&lt;/em&gt; portion is located in a &lt;em&gt;region&lt;/em&gt; where attribute &lt;em&gt;name&lt;/em&gt; is equal to “Switzerland”, else “Oh, no Hopp Schwiitz…”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You could have a FME workspace chaining writers, a clipper, a length calculator, aggregators, attributes managers etc. Or a single SQL query in the following manner (optimization not included):&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;SELECT&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    portion.name,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;    CASE&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; COUNT&lt;/span&gt;&lt;span&gt;(b.id) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        WHEN&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 0&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; THEN&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;No bus stop&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        ELSE&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; COUNT&lt;/span&gt;&lt;span&gt;(b.id)::&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;    END AS&lt;/span&gt;&lt;span&gt; n_bus_stop,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;    CASE&lt;/span&gt;&lt;span&gt; portion.name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        WHEN&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;Switzerland&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; THEN&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;Hopp Schwiiz !&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        ELSE&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;Oh, no Hopp Schwiitz...&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;    END AS&lt;/span&gt;&lt;span&gt; hop_suisse,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    St_Length(portion.geom) &lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;AS&lt;/span&gt;&lt;span&gt; portion_length,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    portion.geom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;FROM&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;SELECT&lt;/span&gt;&lt;span&gt; r.name, St_Intersection(l.geom, r.geom) &lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;AS&lt;/span&gt;&lt;span&gt; geom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        FROM&lt;/span&gt;&lt;span&gt; road l&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;        JOIN&lt;/span&gt;&lt;span&gt; region r &lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;ON&lt;/span&gt;&lt;span&gt; St_Intersects(l.geom, r.geom)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ) portion&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;LEFT JOIN&lt;/span&gt;&lt;span&gt; bus_stop b &lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;ON&lt;/span&gt;&lt;span&gt; St_Intersects(portion.geom, b.geom)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;GROUP BY&lt;/span&gt;&lt;span&gt; portion.name, portion.geom&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it, you can read this data, export it, do whatever you want with it. Everything done within the query is visible at once, and if it takes some time to get used to the syntax and be comfortable with it, it becomes much easier to understand what happens in a well written SQL query than in the tidiest FME workspace (personal opinion included).&lt;/p&gt;
&lt;p&gt;Another huge advantage of working with SQL is that you’re closer to a standard &lt;strong&gt;interoperable&lt;/strong&gt; format (with a grain of salt since we use Postgis here, which is Postgres specific). If you ever need to change your system, the required effort to make the conversion will be minimal compared to translating a FME workspace.&lt;/p&gt;
&lt;p&gt;You can import other data into your database to use it in your query, or use &lt;a rel=&quot;external&quot; href=&quot;https://www.postgresql.org/docs/current/postgres-fdw.html&quot;&gt;Foreign Data Wrappers&lt;/a&gt; (FDW) to read data from another database. You can combine your queries with tools such as &lt;a rel=&quot;external&quot; href=&quot;https://docs.getdbt.com/&quot;&gt;dbt&lt;/a&gt; (Core) to have a more complete environment, or build your own processes, with GDAL or using the programming language of your choice.&lt;/p&gt;
&lt;h4 id=&quot;read-and-write-with-gdal&quot;&gt;Read and write with GDAL&lt;/h4&gt;
&lt;p&gt;Back at it with &lt;a rel=&quot;external&quot; href=&quot;https://www.geothings.ch/posts/gdal-appreciation/&quot;&gt;GDAL&lt;/a&gt;, but it’s so versatile that it has to be in your toolkit. Your can read and write basically any format, and apply transformations on the fly.&lt;/p&gt;
&lt;p&gt;The series of command line tools that come with GDAL/OGR make it very complete and easy to use with raster or vector data.&lt;/p&gt;
&lt;p&gt;You could reuse your previous SQL query with GDAL to extract your data and save it in GeoPackage for example. I could just save my query into a file named &lt;code&gt;query_file.sql&lt;/code&gt; and run the following command:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ogr2ogr&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -f GPKG -sql @query_file.sql output.gpkg &amp;quot;PG:service=input_db&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember &lt;strong&gt;interoperability&lt;/strong&gt;? Well that’s a nice example, have one standard way of solving a problem and you can connect it with other without changing anything. &lt;strong&gt;You have many possibilities&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;do-everything-with-python-libraries&quot;&gt;Do everything with (Python) libraries&lt;/h4&gt;
&lt;p&gt;There are a bunch of libraries allowing you to read, transform and write data, using Python but not only. GDAL (omfg again) is also available in many languages through its bindings. If we focus on Python, a list (non-exhaustive of course) of libraries for working with spatial data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://shapely.readthedocs.io/en/stable/manual.html&quot;&gt;Shapely&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://geopandas.org/en/stable/index.html&quot;&gt;geopandas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://fiona.readthedocs.io/en/latest/index.html&quot;&gt;Fiona&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://xarray-spatial.readthedocs.io/en/latest/#&quot;&gt;xarray-spatial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://rasterio.readthedocs.io/en/latest/index.html#&quot;&gt;rasterio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s try somethings with &lt;code&gt;geopandas&lt;/code&gt;. If we consider that we are working with a single PostgreSQL database, we could reuse our earlier query to read the data and save it as a GeoPackage:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;import&lt;/span&gt;&lt;span&gt; geopandas&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; as&lt;/span&gt;&lt;span&gt; gpd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;from&lt;/span&gt;&lt;span&gt; sqlalchemy&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; import&lt;/span&gt;&lt;span&gt; create_engine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; run&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Connection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    db_connection_url&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;postgresql://username:password@localhost/dbname&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    con&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; create_engine&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;db_connection_url&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Open query file, apply and save&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;    with&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt; open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;query.sql&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; as&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        query&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;readlines&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        df&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gpd&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;read_postgis&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; con&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        df&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;to_file&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;my_analysis.gpkg&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; layer&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; driver&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;GPKG&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;        # Print the head for good measure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;        print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;df&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;head&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;if&lt;/span&gt;&lt;span&gt; __name__&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    run&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Will create a new file with your result saved in the &lt;code&gt;result&lt;/code&gt; layer. It should also print something like:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0       France            2  Oh, no Hopp Schwiitz...      823.126128  LINESTRING (2537525.502 1152634.769, 2537254.4...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1       France            1  Oh, no Hopp Schwiitz...      118.753415  LINESTRING (2537290.714 1152264.433, 2537281.7...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2        Italy  No bus stop  Oh, no Hopp Schwiitz...      686.494161  LINESTRING (2538145.102 1151496.452, 2538283.1...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3  Switzerland  No bus stop           Hopp Schwiiz !      123.440260  LINESTRING (2536930.949 1152095.427, 2536884.0...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4  Switzerland            1           Hopp Schwiiz !     1102.779141  LINESTRING (2537281.727 1152146.02, 2537249.56...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5  Switzerland            1           Hopp Schwiiz !      206.632320  LINESTRING (2538019.283 1151332.542, 2538145.1...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6  Switzerland  No bus stop           Hopp Schwiiz !     1207.518986  LINESTRING (2537677.993 1151998.178, 2537874.0...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was easy enough but we didn’t bring much since everything is done with SQL again. Let’s do the same thing but only using &lt;code&gt;geopandas&lt;/code&gt; capabilities:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;import&lt;/span&gt;&lt;span&gt; geopandas&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; as&lt;/span&gt;&lt;span&gt; gpd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;from&lt;/span&gt;&lt;span&gt; sqlalchemy&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; import&lt;/span&gt;&lt;span&gt; create_engine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; run&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Connection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    db_connection_url&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;postgresql://username:password@localhost/dbname&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    con&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; create_engine&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;db_connection_url&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Read roads, regions and bus_stops&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    roads&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gpd&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;read_postgis&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;road&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; con&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    regions&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gpd&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;read_postgis&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;region&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; con&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bus_stops&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gpd&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;read_postgis&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;bus_stop&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; con&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Intersection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    intersection&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; roads&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;overlay&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;regions&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; how&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;intersection&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Intersect bus stops&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    intersect&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; intersection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;sjoin&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;bus_stops&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; how&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; predicate&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;intersects&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Group by&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    groupby&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; intersect&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;groupby&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;geometry&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]).&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    output&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; groupby&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;reset_index&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;n_bus_stop&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Hop Suisse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;    output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;hop_suisse&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;Hopp Schwiiz !&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;loc&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;Switzerland&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;hop_suisse&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        &amp;quot;Oh, no Hopp Schwiitz...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # No bus stop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;loc&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;n_bus_stop&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt; 0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;hop_suisse&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;No bus stop&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Lost the Geo from GeoDataFrame at some point &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    output&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gpd&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GeoDataFrame&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; geometry&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;geometry&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # Length&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;    output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;portion_length&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;].&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    output&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;to_file&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;my_analysis.gpkg&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; layer&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;result_only_gpd&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; driver&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;GPKG&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;if&lt;/span&gt;&lt;span&gt; __name__&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    run&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doesn’t take much more. &lt;code&gt;Roads&lt;/code&gt;, &lt;code&gt;regions&lt;/code&gt; and &lt;code&gt;bus_stops&lt;/code&gt; could have been data from anywhere: another database, a csv file, a cloud hosted file, etc.&lt;/p&gt;
&lt;p&gt;Working with a programming language allows you to easily read multiple data sources and combine them using your custom “transformers”, which will basically be functions that you would have written and tailored to your need.&lt;/p&gt;
&lt;p&gt;But now let’s see what you can do to automate your process.&lt;/p&gt;
&lt;h3 id=&quot;automation&quot;&gt;Automation&lt;/h3&gt;
&lt;p&gt;Not sure about what is so incredible about giving scheduling capabilities within FME when &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Cron&quot;&gt;&lt;code&gt;cron&lt;/code&gt;&lt;/a&gt; is available by default in many Linux distributions. If you’re working on Windows you can also schedule things with the &lt;code&gt;Task Scheduler&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I feel like I’m oversimplifying things but I can’t see where. If you’re on Linux, you can schedule your data export task by adding such lines into your &lt;code&gt;crontab&lt;/code&gt; (&lt;code&gt;crontab -e&lt;/code&gt; to edit it):&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Everyday at 05:00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;00&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 5&lt;/span&gt;&lt;span&gt; * * *&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;  ogr2ogr -f GPKG -sql @query_file.sql output.gpkg &amp;quot;PG:service=input_db&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the task and send an email if it failed?&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;00&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 5&lt;/span&gt;&lt;span&gt; * * *&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;  if ! ogr2ogr -f GPKG -sql @query_file.sql output.gpkg &amp;quot;PG:service=input_db&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; then&lt;/span&gt;&lt;span class=&quot;z-11 z-i&quot;&gt; echo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;your export failed&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; mail&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -s &amp;quot;failing process&amp;quot; address@mail.me&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it. I doubt that FME brings so much on the table when it comes to scheduling tasks.&lt;/p&gt;
&lt;h3 id=&quot;and-that-s-it&quot;&gt;And that’s it?&lt;/h3&gt;
&lt;p&gt;I guess not, but I don’t think we will find many operations that are totally unfeasible without FME. If I’m missing something, please don’t hesitate to correct me.&lt;/p&gt;
&lt;h2 id=&quot;limitations&quot;&gt;Limitations&lt;/h2&gt;
&lt;p&gt;Unfortunately, there are some things that I don’t know how to do without FME, well at least one that I have no idea how to solve.&lt;/p&gt;
&lt;h3 id=&quot;dwg-and-the-closed-formats-problem&quot;&gt;DWG and the closed formats problem&lt;/h3&gt;
&lt;p&gt;DWGs are ***** everywhere when your have people doing CAD around you. They could use DXF, which is an open source equivalent, but no, AutoCAD then DWG (which is no data btw, it’s just lines ffs). And I have no clue how to tackle that, except through a long process of mentality change around the tools used.&lt;/p&gt;
&lt;p&gt;Earlier we saw that using standard formats can start a virtuous cycle, where you keep open the door for many solution to solve your problems. Well here we have the opposite, closed formats reduce the interoperability by making a handful of solutions your only options, and keep you from trying other things. If you need to have DWGs, then to my knowledge, FME becomes the only tool you can use to produce them programmatically from other data (even GDAL can’t all hope is lost). So from one license, you need “automatically” two.&lt;/p&gt;
&lt;p&gt;And then one company decide to increase there prices, and there is nothing you can do about it.&lt;/p&gt;
&lt;p&gt;In this case, the problem is to use a closed data format. To change that is to change deeply the habits of people using the tool creating this format, because, like with FME, there is a real addiction to the software. The skill becomes the software; not the technic, not the knowledge around the field, but just the software.&lt;/p&gt;
&lt;h3 id=&quot;and-that-s-it-for-now&quot;&gt;And that’s it for now&lt;/h3&gt;
&lt;p&gt;Fortunately, FME is not that essential. Maybe you won’t need to pay for the license for long… But I’m curious to read about what makes it a must-have for you. &lt;strong&gt;What can FME do that other tools cannot? Why is it necessary to you?&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Feels good to rant a bit. To summarize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn SQL&lt;/li&gt;
&lt;li&gt;Don’t be afraid of command lines and programming languages&lt;/li&gt;
&lt;li&gt;Have interoperability in mind&lt;/li&gt;
&lt;li&gt;Get away from closed data formats&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to talk about all of this or if you need help converting some processes from FME to more open solutions, hit me up on &lt;a rel=&quot;external&quot; href=&quot;https://tooting.ch/@jln_brnt&quot;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
</content>
        <summary type="html">Do you really need it in the first place? I really don&#39;t think so.</summary>
        </entry><entry xml:lang="en">
        <title>Opening and writing raster dataset with GDAL Rust</title>
        <published>2024-03-08T00:00:00+00:00</published>
        <updated>2024-03-08T00:00:00+00:00</updated>
        <author>
            <name>jujube</name>
        </author>
        <link rel="alternate" href="https://blog.geothings.ch/blog/rust-gdal/" type="text/html"/>
        <id>https://blog.geothings.ch/blog/rust-gdal/</id>
        
            <content type="html">&lt;p&gt;I’ve been trying to learn Rust lately. For some reason there is something that I find very appealing in this language. From all I could read, it’s very efficient in resources and memory, it’s fast, and it doesn’t let you mess around with memory. Regarding performances, it places itself next to C and C++, and when looking into the world of language performances, I learned that Python was kind of slow, around 100x slower according to some benchmarks. Obviously this value in itself doesn’t mean much, and many more aspects of a language must be taken account when choosing one for the task, but this information kind of planted its seed. It might be because I have a problem with inefficient and overly complicated process, but I find the idea to work with a system language very elegant.&lt;/p&gt;
&lt;p&gt;But we’re not here to talk about the Rust language in itself. We’ll see how to read and write raster data using the Rust binding for GDAL. Also, this is about how I tried to compare the Rust and Python bindings for GDAL and how I learned that it doesn’t change a thing in terms of performance.&lt;/p&gt;
&lt;h2 id=&quot;wait-what&quot;&gt;Wait what?&lt;/h2&gt;
&lt;p&gt;Well I started by thinking “Oh I can’t wait to see how faster GDAL in Rust is compared to Python”. So I started by reading a raster file and print some basic information. I use a band from a &lt;a rel=&quot;external&quot; href=&quot;https://browser.dataspace.copernicus.eu/&quot;&gt;Sentinel-2 image&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;how-to-open-a-raster-file&quot;&gt;How to open a raster file?&lt;/h3&gt;
&lt;p&gt;Let’s do it. We’ll be working with the GDAL crate from &lt;a rel=&quot;external&quot; href=&quot;https://crates.io/crates/gdal&quot;&gt;crates.io&lt;/a&gt; (&lt;code&gt;cargo add gdal&lt;/code&gt;) and the GDAL package prom &lt;a rel=&quot;external&quot; href=&quot;https://pypi.org/project/GDAL/&quot;&gt;PyPi&lt;/a&gt; (&lt;code&gt;pip install GDAL&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In Rust:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt;Dataset&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Open dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; Dataset&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;IMG.jp2&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;This raster has &lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; bands.&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;raster_count&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Read band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;rasterband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Print statistics&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;if let&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; Some&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;get_statistics&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt; true&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;    println!&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;        &amp;quot;[ STATS ] =  Minimum=&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;, Maximum=&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;, Mean=&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;, StdDev=&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span&gt;mean&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span&gt;std_dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;admonition warning&quot;&gt;
&lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;admonition-content&quot;&gt;
&lt;strong class=&quot;admonition-title&quot;&gt;WARNING&lt;/strong&gt;
&lt;p&gt;I’m using a lot of .unwrap(), which in very short will cause the code to panic if a problem occurs, this is for a quick and dirty test. Within a “production” environment you would handle errors and stuff.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And in Python:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;from&lt;/span&gt;&lt;span&gt; osgeo&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; import&lt;/span&gt;&lt;span&gt; gdal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;UseExceptions&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Open dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dataset&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;IMG.jp2&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; dataset&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;RasterCount&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;This raster contains &lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt;{&lt;/span&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; bands.&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Read band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcband&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; dataset&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetRasterBand&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Print statistics&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stats&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; srcband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetStatistics&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; True&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; True&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;[ STATS ] =  Minimum=%.3f, Maximum=%.3f, Mean=%.3f, StdDev=%.3f&amp;#39;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;    %&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; stats&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;] ))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;File opened and information read. We can compare their runtime.&lt;/p&gt;
&lt;h3 id=&quot;comparing-performances&quot;&gt;Comparing performances&lt;/h3&gt;
&lt;p&gt;Building the Rust program, then running and timing these two codes multiple times, we get results like follows:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Rust&lt;/th&gt;&lt;th&gt;Python&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;real    &lt;strong&gt;0m0.072s&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;real    &lt;strong&gt;0m0.156s&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user    0m0.154s&lt;/td&gt;&lt;td&gt;user    0m0.752s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sys     0m0.275s&lt;/td&gt;&lt;td&gt;sys     0m1.689s&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
&lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;admonition-content&quot;&gt;
&lt;strong class=&quot;admonition-title&quot;&gt;WARNING&lt;/strong&gt;
&lt;p&gt;This is a naive approach on testing and comparing performances, not a full-fledged benchmark.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Twice as fast without any processing or multi-threading, at that point I though “Oh it’s gonna be good”.&lt;/p&gt;
&lt;h2 id=&quot;let-s-add-some-writing-then&quot;&gt;Let’s add some writing then&lt;/h2&gt;
&lt;p&gt;It’s only the start, we’ll now read the data in our raster dataset and, since my source is in .jp2, write it in a new raster dataset in the GeoTiff format.&lt;/p&gt;
&lt;h3 id=&quot;how-to-write-a-raster-dataset-with-gdal-bindings&quot;&gt;How to write a raster dataset with GDAL bindings?&lt;/h3&gt;
&lt;p&gt;We will be using the Create() approach rather than the CreateCopy() (see the nuance in the &lt;a rel=&quot;external&quot; href=&quot;https://gdal.org/tutorials/raster_api_tut.html#using-createcopy&quot;&gt;doc&lt;/a&gt;). Geospatialized rasters come with series of metadata and overviews. The CreateCopy() automatically takes those from the source dataset and copy them into the destination. While this obviously simplifies the work if we don’t need to bring any change to these information, using Create() helps to better understand the structure of a raster. Also I have a quite important performance difference between the two and I’ve found Create() more efficient for my use case.&lt;/p&gt;
&lt;p&gt;So the code now becomes as follow.&lt;/p&gt;
&lt;p&gt;In Rust:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;z-10&quot;&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt;Dataset&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; DriverManager&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Open dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; Dataset&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;IMG.jp2&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;This raster has &lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; bands.&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;raster_count&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Get source dataset metadata&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; projection&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;projection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; spatial_ref&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;spatial_ref&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; geo_transform&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;geo_transform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; (&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;raster_size&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Read band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;rasterband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Get GeoTiff driver  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; DriverManager&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;get_driver_by_name&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;GTiff&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Create the destination dataset as mutable with 1 band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let mut&lt;/span&gt;&lt;span&gt; dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;create_with_band_type&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;IMG_as_tiff.gtiff&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    x&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; as isize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; as isize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Set metadata from source dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;set_geo_transform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;geo_transform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;set_projection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;set_spatial_ref&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;spatial_ref&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Get the destination band as mutable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let mut&lt;/span&gt;&lt;span&gt; dst_band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;rasterband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Read the source data as Buffer&amp;lt;u16&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;let&lt;/span&gt;&lt;span&gt; buf&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;read_as&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;u16&lt;/span&gt;&lt;span class=&quot;z-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;), (&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;), (&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;z-10 z-i&quot;&gt; None&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Write the data in the destination band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_band&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;), (&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;buf&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;// Close dataset for good conscience&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in Python:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Open dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;IMG.jp2&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;RasterCount&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;This raster has &lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt;{&lt;/span&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; bands.&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Get dataset metadata&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcprojection&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetProjection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcspatialref&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetSpatialRef&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcgeotransform&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetGeoTransform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;xsize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; ysize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; (&lt;/span&gt;&lt;span&gt;ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;RasterXSize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;RasterYSize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Get GeoTiff driver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fileformat&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;GTiff&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;driver&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetDriverByName&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;fileformat&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Create the destination dataset with 1 band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; driver&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;IMG_as_tiff.gtiff&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; xsize&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;xsize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; ysize&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;ysize&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;                    bands&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;nband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; eType&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;gdal&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span&gt;GDT_UInt16&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Set metadata from source dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;SetProjection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;srcprojection&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;SetGeoTransform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;srcgeotransform&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;SetSpatialRef&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;srcspatialref&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Get the destination band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcband&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetRasterBand&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Read the source data as Array&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;srcdata&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; srcband&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;ReadAsArray&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Write the data in the destination band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;GetRasterBand&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;WriteArray&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;srcdata&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Close dataset for good conscience&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_ds&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both codes should create a new raster file that resembles our source, but in GeoTiff. And that’s it, you can convert a raster file into any format. We’re just scratching the surface, you can subset data, reproject, transpose it if you want etc.&lt;/p&gt;
&lt;h3 id=&quot;but-let-s-compare-performances-again&quot;&gt;But let’s compare performances again&lt;/h3&gt;
&lt;p&gt;Now as “la cerise sur le gâteau”, let’s see how powerful Rust can be.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Rust&lt;/th&gt;&lt;th&gt;Python&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;real    &lt;strong&gt;0m1.024s&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;real    &lt;strong&gt;0m1.133s&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user    0m17.150s&lt;/td&gt;&lt;td&gt;user    0m17.335s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sys     0m1.629s&lt;/td&gt;&lt;td&gt;sys     0m2.089s&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Wait let me rerun.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Rust&lt;/th&gt;&lt;th&gt;Python&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;real    &lt;strong&gt;0m1.053s&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;real    &lt;strong&gt;0m1.141s&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;user    0m17.076s&lt;/td&gt;&lt;td&gt;user    0m17.324s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sys     0m1.608s&lt;/td&gt;&lt;td&gt;sys     0m2.134s&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Hmm.&lt;/p&gt;
&lt;h2 id=&quot;wait-what-bis&quot;&gt;Wait what? (bis)&lt;/h2&gt;
&lt;p&gt;Well that’s not what I expected.&lt;/p&gt;
&lt;p&gt;In the process I forgot something important, we are working with &lt;strong&gt;bindings&lt;/strong&gt;. Asking &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Language_binding&quot;&gt;Wikipedia&lt;/a&gt; what a binding is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In programming and software design, binding is an application programming interface (API) that provides glue code specifically made to allow a programming language to use a foreign library or operating system service (one that is not native to that language).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So from my understanding, working with Rust or Python or any other language bindings is just working with the API that let us call the underlying code, for GDAL written in C and C++. Thus the overhead that we generate is only the interaction with the library, not during the process itself, since it’s running C/C++ code. The difference that we observe is probably the same that we were observing when we just opened a file.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;GDAL raster processing is &lt;strong&gt;very&lt;/strong&gt; similar in Rust and Python. When working with its bindings, it doesn’t change much which language you use &lt;strong&gt;to perform the GDAL operations in themself&lt;/strong&gt;, since in any case you’re running C/C++ code from your program. But everything that is around need to be considered when choosing the right tool. If your program needs multi-threading then you’l probably chose Rust, if you need quick development without much optimization then Python might be a best fit. But it’s comfortable to see that the GDAL processing time won’t change significantly.&lt;/p&gt;
&lt;p&gt;I’m not at all trying to say that Rust is not worth it, I’m excited to go further into it and work on projects, but it remains a tool and there should be no injunction to use it if it doesn’t bring much to the table for your use case.&lt;/p&gt;
&lt;p&gt;Also it’s totally possible that I totally misunderstood something and that those comparisons are meaningless, happy to learn more about it.&lt;/p&gt;
</content>
        <summary type="html">Some first tries at using the GDAL/OGR binding in Rust 🦀</summary>
        </entry>
</feed>
