B4J Code Snippet [PyBridge] GeoDatapandas - powerful geospatial engine

Just a tiny glimpse to this powerful framework: https://geopandas.org/en/stable/

pip install geopandas
pip install matplotlib

Probably better to install in the global Python as this is a large framework.

Code: Copy
Dim FileName As String = File.Combine(File.DirApp, "countries.zip")
If File.Exists(FileName, "") = False Then
    Wait For (DownloadFile("https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip", FileName)) Complete (Success As Boolean)
    If Success = False Then Return
End If
Dim gpd As PyWrapper = Py.ImportModule("geopandas")
Dim gdf As PyWrapper = gpd.Run("read_file").Arg(FileName)
gdf.Run("head").Print
Py.WrapObject(CRLF).Run("join").Arg(gdf.GetField("columns")).Print
'add new column GDP / POP
gdf.Set("gdp_md_per_capita", gdf.Get("GDP_MD").Run("div").Arg(gdf.Get("POP_EST")))
gdf = gdf.Get(gdf.Get("CONTINENT").OprEqual("Asia")) 'gdf = gdf[gdf["CONTINENT] = "Asia"]
Dim ax As PyWrapper = gdf.Run("plot").ArgNamed("figsize", Array(15, 15)).ArgNamed("column", "gdp_md_per_capita") _
    .ArgNamed("cmap", "RdBu").ArgNamed("legend", True)
ax.Run("axis").Arg("off")
Dim plt As PyWrapper = Py.ImportModule("matplotlib.pyplot")
plt.Run("show")


1740385233719.png


Download file:
Code: Copy
Private Sub DownloadFile (Url As String, Output As String) As ResumableSub
    Log("Downloading file")
    Dim j As HttpJob
    j.Initialize("", Me)
    j.Download(Url)
    Wait For (j) JobDone (j As HttpJob)
    If j.Success = False Then
        Log(j.ErrorMessage)
    Else
        Dim out As OutputStream = File.OpenOutput(Output, "", False)
        File.Copy2(j.GetInputStream, out)
        out.Close
    End If
    j.Release
    Return j.Success
End Sub
 
Please dont take this the wrong way, I think its great that it it will run directly from B4J, but the code is so complex compared to just running a python script via Py.Run....
Python: Copy
import geopandas as gpd
import matplotlib.pyplot as plt

url = "https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip"
gdf = gpd.read_file(url)
#print(gdf.head())
#print(gdf.columns)
gdf["gdp_per_capita"] = gdf["GDP_MD"] / gdf["POP_EST"]
gdf = gdf[gdf["CONTINENT"]=="Asia"]
ax = gdf.plot(figsize=[15,15],column="gdp_per_capita",cmap="Spectral",legend=True)
plt.show()
 
1. You can of course add this script or parts of it to B4J directly. You can easily create a Sub that wraps the code. It is probably a better design compared to what I did.
2. I didn't want to download the file each time and I preferred to use OkHttpUtils2 for the download.

So a better comparison is with this code:
Code: Copy
gdf = gdf.Get(gdf.Get("CONTINENT").OprEqual("Asia"))
Dim ax As PyWrapper = gdf.Run("plot").ArgNamed("figsize", Array(15, 15)).ArgNamed("column", "gdp_md_per_capita") _
    .ArgNamed("cmap", "RdBu").ArgNamed("legend", True)
ax.Run("axis").Arg("off")
plt.Run("show")
 
Ohhh, nice results, if it would not require to know Python also :)
But seems, the truth is the halfway: to make _easy_ preparations by B4X (downloading the file), but all other hard & smart work - ready Py-script.
 
Last edited:
Same example, different design:
Code: Copy
Dim gpd As PyWrapper = Py.ImportModule("geopandas")
Dim gdf As PyWrapper = gpd.Run("read_file").Arg(FileName)
Wait For (ShowContinent(gdf, "North America")) Complete (Image As B4XBitmap)
ImageView1.SetBitmap(Image)
Wait For (ShowContinent(gdf, "South America")) Complete (Image As B4XBitmap)
ImageView2.SetBitmap(Image)

Private Sub ShowContinent (gdf As PyWrapper, Continent As Object) As ResumableSub
    Dim Code As String = $"
import matplotlib.pyplot as plt
import io
def ShowContinent (gdf, Continent):
    gdf["gdp_per_capita"] = gdf["GDP_MD"] / gdf["POP_EST"]
    gdf = gdf[gdf["CONTINENT"]== Continent]
    ax = gdf.plot(figsize=[15,15],column="gdp_per_capita",cmap="Spectral",legend=False)
    ax.axis("off")
    res = io.BytesIO()
    plt.savefig(res)
    return res
"$
    Wait For (Py.RunCode("ShowContinent", Array(gdf, Continent), Code).Fetch) Complete (Result As PyWrapper)
    Return Py.ImageFromBytes(Result.Value)
End Sub

1740394872117.png
 
Back
Top