# Best Way of Handling Shapefiles in Makie

**URL:** https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028
**Category:** Visualization
**Tags:** plotting, visualization, makie, shapefile
**Created:** [November 5, 2021, 9:17pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028 "2021-11-05T21:17:28Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![TheCedarPrince](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thecedarprince/32/17323_2.png) [@TheCedarPrince](https://discourse.julialang.org/u/TheCedarPrince)
#### Post date: [November 5, 2021, 9:17pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/1 "2021-11-05T21:17:28Z")

</div>

Hi all,

What is the best way handle shapefiles with Makie?

For example, I have a shapefile that defines the states for each state in the United States. DataFrames can handle displaying the shapefile as follows:

```julia
julia>states
56×10 DataFrame
 Row │ geometry STATEFP STATENS AFFGEOID GEOID STUSPS NAME LSAD ALAND AWATER
     │ Polygon…? String String String String String String String Int64 Int64
─────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1 │ Polygon(1516 Points) 31 01779792 0400000US31 31 NE Nebraska 00 198956658395 1371829134
   2 │ Polygon(1847 Points) 53 01779804 0400000US53 53 WA Washington 00 172112588220 12559278850
   3 │ Polygon(434 Points) 35 00897535 0400000US35 35 NM New Mexico 00 314196306401 728776523
   4 │ Polygon(1260 Points) 46 01785534 0400000US46 46 SD South Dakota 00 196346981786 3382720225
   5 │ Polygon(3551 Points) 48 01779801 0400000US48 48 TX Texas 00 676653171537 19006305260   

```

Currently, if I try to plot polygons representing each shape using the `poly` function using the `geometry` column, I get this error:

```julia
ERROR: `Makie.convert_arguments` for the plot type Scatter{ArgType} where ArgType and its conversion trait PointBased() was unsuccessful.

The signature that could not be converted was:
::Shapefile.Point

Makie needs to convert all plot input arguments to types that can be consumed by the backends (typically Arrays with Float32 elements).
You can define a method for `Makie.convert_arguments` (a type recipe) for these types or their supertypes to make this set of arguments convertible (See http://makie.juliap
lots.org/stable/documentation/recipes/index.html).

Alternatively, you can define `Makie.convert_single_argument` for single arguments which have types that are unknown to Makie but which can be converted to known types and
fed back to the conversion pipeline.      

```

The way I can get around this is by doing this conversion:

```julia
states = joinpath(data_path, shape_file) |> Shapefile.Table |> DataFrame
state = states[1, :].geometry.points
points = [(state[i].x, state[i].y) for i in 1:length(state)]
points = Point2f0[points...]

f = Figure()
Axis(f[1, 1])
poly!(points)

```

Is this the easiest way to handle Shapefiles in Makie? Are there better ways of doing this? Thanks!

~ tcp 🌳

---

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [November 6, 2021, 7:02am UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/2 "2021-11-06T07:02:01Z")

</div>

I think this way you would lose possible holes in your polygons. A correct translation would be to a Polygon type from GeometryBasics, not a vector of points (which can’t have holes). But I’m not super well versed in the GeometryBasics infrastructure either.

---

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [November 6, 2021, 8:08am UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/3 "2021-11-06T08:08:01Z")

</div>

Here I tried something out, the conversion method is inefficient because the GeoInterface seems to create lots of little arrays. But hopefully it’s correct:

```julia
using Shapefile
using CairoMakie
using DataFrames
using GeometryBasics: Polygon

# I downloaded this manually and extracted the shape file
url = "https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_state_5m.zip"

shapefile = "Downloads/cb_2018_us_state_5m/cb_2018_us_state_5m.shp"
table = DataFrame(Shapefile.Table(shapefile))
filter!(:NAME => (
    x -> x ∉ [
        "Alaska",
        "American Samoa",
        "Guam",
        "Commonwealth of the Northern Mariana Islands",
        "United States Virgin Islands",
        "Hawaii",
        "Puerto Rico",
        ]),
    table)

function Makie.convert_arguments(::Type{<:Poly}, p::Shapefile.Polygon)
    # this is inefficient because it creates an array for each point
    polys = Shapefile.GeoInterface.coordinates(p)
    ps = map(polys) do pol
        Polygon(
            Point2f0.(pol[1]), # interior
            map(x -> Point2f.(x), pol[2:end]))
    end
    (ps,)
end

let
    f = Figure()
    ax = Axis(f[1, 1])
    foreach(table.geometry) do geo
        poly!(ax, geo)
    end
    f
end

```

 ![grafik](https://global.discourse-cdn.com/julialang/original/3X/3/8/384af3be27d50262f972c613d4f36d2607da4d19.png)

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [November 6, 2021, 12:18pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/4 "2021-11-06T12:18:30Z")

</div>

Alternatively, you can rely on the infrastructure surrounding the [GeoStats.jl](https://github.com/JuliaEarth/GeoStats.jl) project. You can load the shapefile using [GeoTables.jl](https://github.com/JuliaEarth/GeoTables.jl) and it will produce geometries from the [Meshes.jl](https://github.com/JuliaGeometry/Meshes.jl) project. Then you can use the [MeshViz.jl](https://github.com/JuliaGeometry/MeshViz.jl) recipes for Makie to visualize any kind of geospatial domain. The good thing about this solution is that it has a lot of options to color the boundaries of states, the polygons, vertices, etc. Special attention must be given to the `decimation` option, which is still needed currently to simplify polygons with thousands of vertices that are available on the internet, such as the polygons from the GADM project.

---

<div class="post-metadata">

### Author: ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)
#### Post date: [November 6, 2021, 1:19pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/5 "2021-11-06T13:19:30Z")

</div>

There is also [https://github.com/JuliaGeo/Shapefile.jl/pull/57](https://github.com/JuliaGeo/Shapefile.jl/pull/57)  
It has been open forever, since it’s not as sure anymore if we should switch Shapefile to GeometryBasics…  
Maybe we should just put that in a registered fork or so…

---

<div class="post-metadata">

### Author: ![TheCedarPrince](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thecedarprince/32/17323_2.png) [@TheCedarPrince](https://discourse.julialang.org/u/TheCedarPrince)
#### Post date: [November 8, 2021, 7:24pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/6 "2021-11-08T19:24:27Z")

</div>

@jules - thanks for that very comprehensive answer.  
It didn’t even dawn on me that such gapping could occur in my polygons.  
Marking your post as a solution for now.

@juliohm - this looks like a very robust pipeline that I wasn’t aware of and very straightforward.  
Will experiment with this.

Also, @visr commented that [GeoMakie.jl](http://juliaplots.org/GeoMakie.jl/stable/) might be worth looking into here too as well.

---

<div class="post-metadata">

### Author: ![YummyPampers2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yummypampers2/32/27328_2.png) [@YummyPampers2](https://discourse.julialang.org/u/YummyPampers2)
#### Post date: [December 17, 2021, 3:39am UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/7 "2021-12-17T03:39:18Z")

</div>

@juliohm – when I apply the following:

```julia
using GeoTables

NZL = GeoTables.gadm("NZL", children = true)
viz(NZL.geometry, decimation = 0.02)

```

obtained from [here](https://github.com/JuliaGeometry/MeshViz.jl)

I am returning a stream error as:

![image](https://global.discourse-cdn.com/julialang/original/3X/1/2/121d883118ae290022f8f3b71ab3d992312aa4cc.png)

Do I need to reference GeoStats.jl, if so, what components do  
I need to abstract to perform the instructions above?

Thanks,

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [December 17, 2021, 10:28am UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/8 "2021-12-17T10:28:03Z")

</div>

@YummyPampers2 are you sure the first line of code downloaded the geometries from the web successfully? You have to confirm with `y` in the prompt if this is the first time you are trying to visualize NZL. GeoTables.jl will download the data for the country of interest if it is not already on disk.

I did run the two lines you shared and it worked fine after confirmation. Please pay attention to the messages that are shown on the terminal at each step. Are you running this on the REPL or Pluto? Maybe Pluto is hidding these messages from you?

Another option is to set the environment variable `ENV["DATADEPS_ALWAYS_ACCEPT"] = true` at the top of your code so that the confirmation is automatic.

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [December 17, 2021, 11:08am UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/9 "2021-12-17T11:08:20Z")

</div>

@YummyPampers2 I’ve updated the underlying GADM.jl package to avoid this prompt from DataDeps.jl. I know many users will try this package on Pluto and asking beginners to set env variables is not ideal.

The updated version should be out in a couple of minutes: [https://github.com/JuliaRegistries/General/pull/50735](https://github.com/JuliaRegistries/General/pull/50735)

---

<div class="post-metadata">

### Author: ![YummyPampers2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yummypampers2/32/27328_2.png) [@YummyPampers2](https://discourse.julialang.org/u/YummyPampers2)
#### Post date: [December 17, 2021, 2:39pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/10 "2021-12-17T14:39:11Z")

</div>

@juliohm Thank you for your effort.

When I am using:

```julia
ENV["DATADEPS_ALWAYS_ACCEPT"] = true
NZL = GeoTables.gadm("NZL", children = true)
viz(NZL.geometry, decimation = 0.02)

```

I am getting an error regarding the viz  
method as:

![image](https://global.discourse-cdn.com/julialang/original/3X/3/b/3bd664bea671c9f15062234194cad3d06a4a4c4b.png)

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [December 17, 2021, 2:52pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/11 "2021-12-17T14:52:27Z")

</div>

You need to import the packages:

```julia
using GeoTables
using MeshViz

# choose a Makie backend
import GLMakie as Mke

```

---

<div class="post-metadata">

### Author: ![YummyPampers2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yummypampers2/32/27328_2.png) [@YummyPampers2](https://discourse.julialang.org/u/YummyPampers2)
#### Post date: [December 17, 2021, 4:36pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/12 "2021-12-17T16:36:45Z")

</div>

@juliohm Good Day Dr. H:

I was able to produce the following:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/7/f/7f469f2c4d5d1a4b7992a608c879cf6f9136f216.png)

I have since modified the code to  
include:

```julia
viz(NZL.geometry, decimation = 0.10, color = 1:nelements(NZL.geometry), 
    showboundary=true, colormap = :viridis)

```

I am noticing it is taking up a lot of RAM, everything is  
is lagging when I am running the kernels.

My intention is to produce something  
similar to a question I presented a  
colleague days ago [THREAD](https://discourse.julialang.org/t/practical-spatial-analysis-packages-in-julia/73177/4).

Also are there any wrappers that allow for  
some interactive display rather than the  
static one we rendered?

The goal is two-fold:

1. Highlight regions of interest.

2. Add annotations at centroids  
within those regions to explain certain  
characteristics of those regions.

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [December 17, 2021, 5:06pm UTC](https://discourse.julialang.org/t/best-way-of-handling-shapefiles-in-makie/71028/13 "2021-12-17T17:06:56Z")

</div>

Please start a new thread on Discourse. Also these questions have answers that you can find by yourself by searching and experimenting a bit more with the code.
