JuliaGeo / Shapefile.jl

Parsing .shp files in Julia
http://juliageo.org/Shapefile.jl/
MIT License
82 stars 14 forks source link

Makie plot for Polyline not work #123

Open kongdd opened 3 weeks ago

kongdd commented 3 weeks ago
using Shapefile, GLMakie

shp = Shapefile.Table("hyd1_4l.shp") # river polylines
begin
  fig = Figure()
  ax = Axis(fig[1, 1])
  lines!.(ax, shp.geometry) # work
  lines!(ax, shp)           # not works
  fig
end

hyd1_4l.shp is available at hyd1_4l.zip

lines!(ax, shp) gives the error:

ERROR: ArgumentError:     Conversion failed for Lines (With conversion trait PointBased()) with args: Tuple{Vector{GeometryBasics.MultiLineString{2, Float64, GeometryBasics.LineString{2, Float64, Point{2, Float64}, Base.ReinterpretArray{GeometryBasics.Line{2, Float64}, 1, Tuple{Point{2, Float64}, Point{2, Float64}}, GeometryBasics.TupleView{Tuple{Point{2, Float64}, Point{2, Float64}}, 2, 1, Vector{Point{2, Float64}}}, false}}, Vector{GeometryBasics.LineString{2, Float64, Point{2, Float64}, Base.ReinterpretArray{GeometryBasics.Line{2, Float64}, 1, Tuple{Point{2, Float64}, Point{2, Float64}}, GeometryBasics.TupleView{Tuple{Point{2, Float64}, Point{2, Float64}}, 2, 1, Vector{Point{2, Float64}}}, false}}}}}} .
    Lines requires to convert to argument types Tuple{AbstractVector{<:Union{Point2, Point3}}}, which convert_arguments didn't succeed in.
    To fix this overload convert_arguments(P, args...) for Lines or PointBased() and return an object of type Tuple{AbstractVector{<:Union{Point2, Point3}}}.`

Stacktrace:
 [1] conversion_pipeline(P::Type{…}, used_attrs::Tuple{}, args::Tuple{…}, args_obs::Tuple{…}, user_attributes::Dict{…}, deregister::Vector{…}, recursion::Int64)
   @ Makie C:\Users\hydro\.julia\packages\Makie\8h0bl\src\interfaces.jl:241
 [2] conversion_pipeline(P::Type{…}, used_attrs::Tuple{}, args::Tuple{…}, args_obs::Tuple{…}, user_attributes::Dict{…}, deregister::Vector{…}, recursion::Int64)
   @ Makie C:\Users\hydro\.julia\packages\Makie\8h0bl\src\interfaces.jl:234
 [3] conversion_pipeline(P::Type{…}, used_attrs::Tuple{}, args::Tuple{…}, args_obs::Tuple{…}, user_attributes::Dict{…}, deregister::Vector{…})
   @ Makie C:\Users\hydro\.julia\packages\Makie\8h0bl\src\interfaces.jl:214
 [4] (Lines)(user_args::Tuple{Shapefile.Table{Union{Missing, Polyline}}}, user_attributes::Dict{Symbol, Any})
   @ Makie C:\Users\hydro\.julia\packages\Makie\8h0bl\src\interfaces.jl:272
 [5] _create_plot!(::Function, ::Dict{Symbol, Any}, ::Axis, ::Shapefile.Table{Union{Missing, Polyline}})
   @ Makie C:\Users\hydro\.julia\packages\Makie\8h0bl\src\figureplotting.jl:377
 [6] lines!(::Axis, ::Vararg{Any}; kw::@Kwargs{})
   @ MakieCore C:\Users\hydro\.julia\packages\MakieCore\hXATT\src\recipes.jl:440
 [7] lines!(::Axis, ::Vararg{Any})
   @ MakieCore C:\Users\hydro\.julia\packages\MakieCore\hXATT\src\recipes.jl:438
 [8] top-level scope
   @ debug.jl:9
Some type information was truncated. Use `show(err)` to see complete types.
rafaqz commented 3 weeks ago

So the problem is probably the Union of 2d/3d point types. But how does that even happen it's not allowed in the spec... So probably it's a bug.

kongdd commented 3 weeks ago

This problem might root in the _convert_array_arguments function. But not sure whether it is the problem of GeoInterfaceMakie or Makie.

Adding a new interface for AbstractVector{<:MultiLineString{N,T}} solved this issue.

import Makie: convert_arguments

function convert_arguments(PB::PointBased, linestring::AbstractVector{<:MultiLineString{N,T}}) where {N,T}
  T_out = float_type(T)
  arr = Point{N,T_out}[]
  n = length(linestring)
  for idx in 1:n
    append!(arr, convert_arguments(PB, linestring[idx])[1])
    if idx != n # don't add NaN at the end 
      push!(arr, Point{N,T_out}(NaN))
    end
  end
  return (arr,)
end

https://github.com/JuliaGeo/GeoInterface.jl/blob/main/GeoInterfaceMakie/src/GeoInterfaceMakie.jl#L32