Loading GIS shapefile in Processing

Hello friendly people,

I would like to ask you about the optimal process of loading, drawing and using data of complex vector data (points, lines or polygons) such as GIS shapefiles. I have searched a lot and this is what I’ve found:

  1. Use the MapThing library as suggested here MapThing = a collection of classes for reading and displaying Shape files (a.k.a. ESRI shapefiles), CSV, and GPX data in a map-based sketch.
    Unfortunately MapThing seems to not read Shapefiles properly, even with the correct coordinate system.

  2. Convert the shapefile to GeoJSON and use the Unfolding Maps library and its GeoJSONReader class as explained here. Then the draw() function can show the vectors.

  3. Convert the shapefile to GeoJSON or CSV (table including coordinates), and use the native functions of Processing to extract data from it. This method is used in several tutorials across the web, but I could not find anything about how to draw polygons…

All those possibilities are getting me confused so if you had any clear and efficient (model shall be as light as possible) methodology and examples, I would be happy to learn from you. I put the emphasis on the fact that I want to (1) load, (2) draw and (3) use data included in GIS shapefiles. For example, showing polygons of buildings in a city with an attribute of number of storeys.

Thank you for your help,

Best regards,

Antoine Saurat

2 Likes

Hello friendly requestor,
I am currently working on the same problem: I have ESRI .shp shapefiles which I want to draw on a processing canvas.
I know it is neither a straightforward, nor a clear and efficient method, but my approach was to convert all the shapefiles to csv first, which is easily readable in Processing. I wrote a little script in Python to convert the shapefiles to csv using Python’s Geopandas Package (http://geopandas.org/) to convert my input data manually. This way, I can pass the shapefile’s geometry as well as other relevant information to Processing.

If you do not need to work on your input data dynamically, this might be a solution… So if you’re interested, I can share the code, which is pretty makeshift - but work’s for me!

Best
robo

Code looks like this:

Python script for converting .shp to .csv:

import geopandas
import pandas as pd

folder = '/path/to/Shapefiles/'
file = 'examples.shp'

osm_heide_buildings = geopandas.read_file(folder+file)

polygons = osm_heide_buildings['geometry']

pol_df = pd.DataFrame(columns=['long', 'lat'])
for i in range(len(polygons)):
    pol = polygons.iloc[i]
    pol_list = pd.DataFrame(list(pol.exterior.coords), columns=['long', 'lat'])
    # pol_df = pd.concat([pol_df, pd.Series(pol_list)]) # output is set of (long, lat) per row
    pol_df = pol_df.append(pol_list)

`pol_df.to_csv('shapes_pde/output.csv')

I then opened the output.csv and added the first column’s header “id” to then continue in Processing:

Table table;

ArrayList<Polygon> polygonsList = new ArrayList<Polygon>();


class Polygon
{
  float[] longitudes = new float[0];
  float[] latitudes = new float[0];

  Polygon()
  {
    longitudes = longitudes;
    latitudes = latitudes;
  }

  void draw()
  {
    beginShape();
    for (int i=0; i<latitudes.length; i++)
    {
      // println("lon " + longitudes[i] +" lat "+ latitudes[i]);
      stroke(0);
      vertex(longitudes[i], latitudes[i]);
      // point(longitudes[i], latitudes[i]);
    }
    endShape();
  }
}

void setup()
{
table = loadTable("output.csv", "header");
      for (TableRow row : table.rows())
      {
        int id = row.getInt("id");
        println("id = "+ id);
        if (id==0)
        {
          polygonsList.add(new Polygon());
        }
        Polygon lastPolygon = polygonsList.get(polygonsList.size()-1);

        String[] lats = split(row.getString("lat"), '.'); // lats[0] = ganze zahl; lats[1] = dezimalstellen
        String[] lons = split(row.getString("long"), '.');

        // fill String with zeros, until 7 digits long
        String latString = lats[1];
        for (int i = 0; i < 7-lats[1].length(); i++)
        {
          latString = latString + "0";
        }

        String lonString = lons[1];
        for (int i = 0; i < 7-lons[1].length(); i++)
        {
          lonString = lonString + "0";
        }

        //lats, lons to int
        float y = convertToRelativeXY(lonString, latString)[0];
        float x = convertToRelativeXY(lonString, latString)[1];

        //pass x,y to polygon
        lastPolygon.latitudes = append(lastPolygon.latitudes, y);
        lastPolygon.longitudes = append(lastPolygon.longitudes, x);
}

void draw()
{
    for (Polygon polygon : polygonsList)
    {
      polygon.draw();
    }
}

float[] convertToRelativeXY(String tempLon, String tempLat)
{
  int lon = int(tempLon);
  int lat = int(tempLat);
  int lonMin = 975364; //9.0975364; // y = 0
  int latMin = 1876916; //54.1876916; // x = 0
  int lonMax = 1143553; //9.1143553; // height
  int latMax = 1988598; //54.1988598; //width

  //relative x,y
  float tempX = float(lon - lonMin) / float(lonMax - lonMin) * width; //TODO: Rechnung besser mit floats? Überprüfen!
  float tempY = height - (float(lat - latMin) / float(latMax - latMin) * height);

  float[] vals = {tempY,tempX};
  return vals;
}

I hope this is any helpful…

Best
robo

Dear robo,

Thank you very much for your answer! I was kind of desperate about this issue. I will try your method for sure.

Best regards,

Antoine