yeesian / ArchGDAL.jl

A high level API for GDAL - Geospatial Data Abstraction Library
https://yeesian.github.io/ArchGDAL.jl/stable/
Other
142 stars 26 forks source link

Consider setting up TerminalMenus #201

Open yeesian opened 3 years ago

yeesian commented 3 years ago

I've been toying with the following idea of using https://docs.julialang.org/en/v1/stdlib/REPL/#TerminalMenus to create interactive prompts in the REPL, for example:

julia> ds = AG.read("ospy/data1/sites.shp")
GDAL Dataset (Driver: ESRI Shapefile/ESRI Shapefile)
File(s):
  ospy/data1/sites.shp
  ospy/data1/sites.shx
  ospy/data1/sites.dbf
  ospy/data1/sites.prj
  ospy/data1/sites.sbn
  ospy/data1/sites.sbx
  ...

Number of feature layers: 1
  Layer 0: sites (wkbPoint)

julia> AG.getlayer(ds)
Choose layer:
 > 1
Layer: sites
  Geometry 0 (): [wkbPoint], POINT (455552.418360...), ...
     Field 0 (ID): [OFTInteger], 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, ...
     Field 1 (COVER): [OFTString], shrubs, trees, rocks, grass, shrubs, ...

It can go much further than that, e.g. getting prompts on what are the methods that can be called on that dataset, before iteratively diving deeper that way:

julia> AG.prompt(ds)
Choose method:
 > width
   height
   nlayer
   getdriver
   getlayer
512

julia> AG.prompt(ds)
Choose method:
   width
 > height
   nlayer
   getdriver
   getlayer
512

julia> AG.prompt(ds)
Choose method:
   width
   height
 > nlayer
   getdriver
   getlayer
1

julia> AG.prompt(ds)
Choose method:
   width
   height
   nlayer
 > getdriver
   getlayer
Driver: ESRI Shapefile/ESRI Shapefile

julia> AG.prompt(ds)
Choose method:
   width
   height
   nlayer
   getdriver
 > getlayer
Choose layer:
 > 1: sites
Layer: sites
  Geometry 0 (): [wkbPoint], POINT (455552.418360...), ...
     Field 0 (ID): [OFTInteger], 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, ...
     Field 1 (COVER): [OFTString], shrubs, trees, rocks, grass, shrubs, ...

But before I go down that rabbit hole, curious to hear people's thoughts on the matter -- @visr @evetion @rafaqz.


(relevant code for the above example)

function prompt(dataset::AbstractDataset)
    menu = REPL.TerminalMenus.RadioMenu([
        "width",
        "height",
        "nlayer",
        "getdriver",
        "getlayer",
    ])
    i = REPL.TerminalMenus.request("Choose method:", menu)
    return if i == 1
        width(dataset)
    elseif i == 2
        height(dataset)
    elseif i == 3
        nlayer(dataset)
    elseif i == 4
        getdriver(dataset)
    elseif i == 5
        getlayer(dataset)
    else
        nothing
    end
end

function getlayer(dataset::AbstractDataset)::IFeatureLayer
    menu = REPL.TerminalMenus.RadioMenu([
        "$i: $(getname(getlayer(dataset, i - 1)))"
        for i in 1:nlayer(dataset)
    ])
    i = REPL.TerminalMenus.request("Choose layer:", menu)
    return if i != -1
        getlayer(dataset, i - 1)
    else
        IFeatureLayer(C_NULL)
    end
end
visr commented 3 years ago

This looks really quite interesting, and appealing especially for exploratory / first time use. What about reproducability? Getting prompted while trying to run someones script could also be a bit annoying. Or would it be possible to convert the selection to code that gives the same result?

yeesian commented 3 years ago

Or would it be possible to convert the selection to code that gives the same result?

Yeah, all great questions -- I'm thinking it might be good to have it in a separate/experimental package for that reason, so that it can have more "client-heavy types" to track the history of commands/options/etc.

yeesian commented 3 years ago

I'm also looking at https://github.com/mapbox/rasterio#rasterio-cli and https://github.com/Toblerity/Fiona#fiona-cli and the GDAL utilities for inspiration on what the user experience might be like first.

yeesian commented 3 years ago

I do think that the Julia REPL is where I'd want it to be -- since we'd get access to displays and help+shell modes and all the facilities that comes with Julialang packages that way.

visr commented 3 years ago

Yeah, I think that makes sense. If it is for REPL, does it also work for VSCode inline evaluation, Pluto, IJulia, e.g. all interactive environments?

yeesian commented 3 years ago

This looks really quite interesting, and appealing especially for exploratory / first time use.

Yeah I'm now quite convinced now that it doesn't belong in this package (since it presumes an approach to working with open-ended user specifications), and should be fleshed out in a separate package that is concerned with end-user UX and workflows.

If it is for REPL, does it also work for VSCode inline evaluation, Pluto, IJulia, e.g. all interactive environments?

I don't think TerminalMenus would work for those, that's a great point. I haven't thought through how such a solution should pair with packages in https://github.com/JuliaGizmos and be useful for e.g. https://jupyterlab.readthedocs.io/en/stable/.