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.

B4X:
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:
B4X:
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
 

Daestrum

Expert
Licensed User
Longtime User
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:
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()
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
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:
B4X:
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")
 

peacemaker

Expert
Licensed User
Longtime User
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:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Same example, different design:
B4X:
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
 
Top