diff --git a/.github/workflows/Documenter.yml b/.github/workflows/Documenter.yml index f5434069..2dd7c2ac 100644 --- a/.github/workflows/Documenter.yml +++ b/.github/workflows/Documenter.yml @@ -31,23 +31,29 @@ jobs: # Build job build: runs-on: ubuntu-latest + env: + DISPLAY: ':0' + GKSwstype: "100" + JULIA_DEBUG: "Documenter" + DATADEPS_ALWAYS_ACCEPT: true + RASTERDATASOURCES_PATH: "~/.julia/artifacts/RasterDataSources" + JULIA_PKG_SERVER: "" steps: - name: Checkout uses: actions/checkout@v5 + - name: Install documentation dependencies + run: sudo apt-get update && sudo apt-get install -y xorg-dev mesa-utils xvfb libgl1 freeglut3-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev xsettingsd x11-xserver-utils - name: Setup Julia uses: julia-actions/setup-julia@v2 - name: Pull Julia cache uses: julia-actions/cache@v2 - - name: Install documentation dependencies - run: sudo apt-get update && sudo apt-get install -y xorg-dev mesa-utils xvfb libgl1 freeglut3-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev xsettingsd x11-xserver-utils - name: Install custom documentation dependencies - run: DISPLAY=:0 xvfb-run -s '-screen 0 1024x768x24' julia --project=docs -e 'using Pkg; Pkg.resolve(); Pkg.instantiate(); Pkg.precompile()' + run: DISPLAY=:0 xvfb-run -s '-screen 0 1024x768x24' julia --project=docs -e 'using Pkg; Pkg.instantiate(); Pkg.precompile()' - name: Build and deploy + uses: julia-actions/julia-docdeploy@v1 + with: + prefix: xvfb-run + install-package: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key - GKSwstype: "100" - JULIA_DEBUG: "Documenter" - DATADEPS_ALWAYS_ACCEPT: true - run: | - DISPLAY=:0 xvfb-run -s '-screen 0 1024x768x24' julia --project=docs/ --color=yes docs/make.jl diff --git a/docs/make.jl b/docs/make.jl index 1d1249a9..42d80a5d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -24,6 +24,7 @@ makedocs(; "Ice loss animation" => "examples/iceloss_ex.md", "Interpolation on the fly" => "examples/interpolation.md", "Map3D" => "examples/map-3d.md", + "PlotConfig" => "examples/plotconfig.md", ], "API" => "api.md", ], diff --git a/docs/src/examples/map-3d.md b/docs/src/examples/map-3d.md index 72f1b2a7..141f9cb7 100644 --- a/docs/src/examples/map-3d.md +++ b/docs/src/examples/map-3d.md @@ -24,7 +24,7 @@ delta = 0.3 ext = Rect2f(lon - delta / 2, lat - delta / 2, delta, delta) cfg = Tyler.PlotConfig( preprocess=pc -> map(p -> p .* 2, pc), - shading=FastShading, colorrange=(2000, 5000), + shading=true, colorrange=(2000, 5000), colormap=:alpine ) m = Tyler.Map3D(ext; provider=ElevationProvider(nothing), plot_config=cfg) @@ -56,7 +56,7 @@ provider = Tyler.GeoTilePointCloudProvider() image = ElevationProvider(nothing) cfg = Tyler.MeshScatterPlotconfig(; markersize=2) m1 = Tyler.Map3D(ext; provider=provider, plot_config=cfg) -cfg = Tyler.PlotConfig(preprocess=pc -> map(p -> p .* 2, pc), shading=FastShading, colormap=:alpine) +cfg = Tyler.PlotConfig(preprocess=pc -> map(p -> p .* 2, pc), shading=true, colormap=:alpine) m2 = Tyler.Map3D(m1; provider=image, plot_config=cfg) m1 ```` @@ -100,7 +100,7 @@ delta = 0.5 ext = Rect2f(lon - delta / 2, lat - delta / 2, delta, delta) cfg = Tyler.PlotConfig( preprocess=pc -> map(p -> p .* 2, pc), - shading=FastShading, + shading=true, material=plastic_material(), colormap=:alpine ) @@ -131,3 +131,10 @@ cp(Tyler) ``` ![](../assets/pointclouds.png) + +## Data source types + +``` +Tyler.ElevationData +Tyler.PointCloudData +``` diff --git a/docs/src/examples/plotconfig.md b/docs/src/examples/plotconfig.md new file mode 100644 index 00000000..f3440d8c --- /dev/null +++ b/docs/src/examples/plotconfig.md @@ -0,0 +1,68 @@ +# PlotConfig + +PlotConfig is a powerful tool to influence how tiles are plotted. +It has a preprocess + postprocess function and allows to pass any plot attribute to the tile. +These attributes are global and will be passed to every tile plot. + +Here's a simple example of plotting only the red channel of image data. + +## Simple example + +```@example plotconfig +using Tyler, GLMakie +using Extents +using Colors + +config = Tyler.PlotConfig(; + preprocess = (data) -> RGBf.(Colors.red.(data), 0, 0), # extract only the red channel of the data + postprocess = (plot) -> translate!(plot, 0, 0, 1), + # attributes... +) +lat, lon = (52.395593, 4.884704) +delta = 0.1 +extent = Extent(; X=(lon - delta / 2, lon + delta / 2), Y=(lat - delta / 2, lat + delta / 2)) +Tyler.Map(extent; provider=Tyler.TileProviders.Esri(:WorldImagery), plot_config=config) +``` + +The data you get in the `preprocess` function is whatever the tile provider returns. +So it can be a matrix of RGBs (`Colors.AbstractColorant`s), or `ElevationData` or `PointCloudData`. + +You need to write your plot config according to the provider you intend to use, and the type of axis you are plotting into. +For example, a `Map` in a GeoAxis will use `GeoMakie.meshimage` plots instead of `Makie.image` plots, and so on. + +## Example with elevation data + +```@example plotconfig +using Tyler, GLMakie +using Tyler: ElevationProvider + +lat, lon = (47.087441, 13.377214) +delta = 0.3 +ext = Rect2f(lon-delta/2, lat-delta/2, delta, delta) +cfg = Tyler.PlotConfig(; + preprocess = function (data::Tyler.ElevationData) + data.elevation .= sqrt.(data.elevation) + data + end, +) +m = Tyler.Map3D(ext; provider=ElevationProvider(), plot_config=cfg) +``` + +Compare this to plotting the elevation data without a plot config: + +```@example plotconfig +m = Tyler.Map3D(ext; provider=ElevationProvider()) +``` + +## Types of plot config + +All plot configs inherit from `AbstractPlotConfig`. But there are some specialized plot configs for specific use cases. + +The usual plot config is `PlotConfig`, but there is also `DebugPlotConfig` for debugging purposes, and `MeshScatterPlotconfig` for point clouds. +You can also create your own plot configs by inheriting from `AbstractPlotConfig` and following the implementation of e.g. `DebugPlotConfig`! + +``` +Tyler.PlotConfig +Tyler.DebugPlotConfig +Tyler.MeshScatterPlotConfig +``` diff --git a/ext/TylerGeoMakieExt/tile-plotting.jl b/ext/TylerGeoMakieExt/tile-plotting.jl index d26da3dc..7ada85d8 100644 --- a/ext/TylerGeoMakieExt/tile-plotting.jl +++ b/ext/TylerGeoMakieExt/tile-plotting.jl @@ -18,6 +18,9 @@ function create_tileplot!( source = tile_crs[2], # tile_crs is a tuple of (tile, crs), we can pass the CRS directly to GeoMakie though config.attributes... ) + # For a pure GeoAxis this is OK, because it is guaranteed to be 2D. + # But for a 3D axis like GlobeAxis this is not OK and has to be removed. + translate!(plot, 0, 0, -10) return plot end diff --git a/src/tile-fetching.jl b/src/tile-fetching.jl index fc244e77..ea16af1a 100644 --- a/src/tile-fetching.jl +++ b/src/tile-fetching.jl @@ -234,18 +234,18 @@ function optimal_zoom(crs, diagonal, diagonal_resolution, zoom_range, old_zoom) # TODO, this should come from provider tile_diag_res = norm((255, 255)) target_ntiles = diagonal_resolution / tile_diag_res - canditates_dict = Dict{Int,Float64}() + candidates_dict = Dict{Int,Float64}() candidates = @NamedTuple{z::Int, ntiles::Float64}[] for z in zoom_range ext = Extents.extent(Tile(0, 0, z), crs) mini, maxi = Point2.(ext.X, ext.Y) diag = norm(maxi .- mini) ntiles = diagonal / diag - canditates_dict[z] = ntiles + candidates_dict[z] = ntiles push!(candidates, (; z, ntiles)) end - if haskey(canditates_dict, old_zoom) # for the first invokation, old_zoom is 0, which is not a candidate - old_ntiles = canditates_dict[old_zoom] + if haskey(candidates_dict, old_zoom) # for the first invokation, old_zoom is 0, which is not a candidate + old_ntiles = candidates_dict[old_zoom] # If the old zoom level is close to the target number of tiles, return it # to change the zoom level less often if old_ntiles > (target_ntiles - 1) && old_ntiles < (target_ntiles + 1) diff --git a/src/tile-plotting.jl b/src/tile-plotting.jl index fde14f3a..b81d2747 100644 --- a/src/tile-plotting.jl +++ b/src/tile-plotting.jl @@ -56,11 +56,11 @@ Creates a `PlotConfig` object to influence how tiles are being plotted. ```julia using Tyler, GLMakie +using Colors -config = PlotConfig( - preprocess = (data) -> data .+ 1, +config = Tyler.PlotConfig( + preprocess = (data) -> RGBf.(Colors.red.(data), 0, 0), # extract only the red channel of the data postprocess = (plot) -> translate!(plot, 0, 0, 1), - color = :red ) lat, lon = (52.395593, 4.884704) delta = 0.1