forked from JuliaGeo/GeometryOps.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Geometry corrections, segmentization, type stability, benchmarks (Jul…
…iaGeo#69) # Change log: ## New features - Add a geometry correction framework with `fix` and one method, `ClosedRing()`, for it. Others can be added in future. - Add a `segmentize` method that corresponds to LibGEOS's density, that upsamples any geometry more complex than a line. - Add a benchmark framework which runs quickly and well, and can plot on CI. - Implement proof of concept benchmarks for some functions (`simplify` and `segmentize`). ## Code changes - Factor `reproject`'s implementation out to an extension on Proj - Provide a nice error hint if Proj isn't loaded and a user tries to use `reproject`. - Since we're getting rid of Proj, also factor out the GeodesicSegments implementation for `segementize`. - Various comment changes and documentation improvements.
- Loading branch information
Showing
29 changed files
with
1,132 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,28 +4,40 @@ authors = ["Anshul Singhvi <[email protected]> and contributors"] | |
version = "0.0.1" | ||
|
||
[deps] | ||
CoordinateTransformations = "150eb455-5306-5404-9cee-2592286d6298" | ||
ExactPredicates = "429591f6-91af-11e9-00e2-59fbe8cec110" | ||
GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" | ||
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" | ||
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" | ||
Proj = "c94c279d-25a6-4763-9509-64d165bea63e" | ||
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" | ||
|
||
[weakdeps] | ||
Proj = "c94c279d-25a6-4763-9509-64d165bea63e" | ||
|
||
[extensions] | ||
GeometryOpsProjExt = "Proj" | ||
|
||
[compat] | ||
CoordinateTransformations = "0.5, 0.6" | ||
ExactPredicates = "2" | ||
GeoInterface = "1.2" | ||
GeometryBasics = "0.4.7" | ||
LinearAlgebra = "1" | ||
Proj = "1" | ||
Statistics = "1" | ||
julia = "1.9" | ||
|
||
[extras] | ||
ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3" | ||
CoordinateTransformations = "150eb455-5306-5404-9cee-2592286d6298" | ||
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" | ||
GeoFormatTypes = "68eda718-8dee-11e9-39e7-89f7f65f511f" | ||
GeoJSON = "61d90e0f-e114-555e-ac52-39dfb47a3ef9" | ||
Proj = "c94c279d-25a6-4763-9509-64d165bea63e" | ||
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" | ||
LibGEOS = "a90b1aa1-3769-5649-ba7e-abc5a9d163eb" | ||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" | ||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" | ||
|
||
[targets] | ||
test = ["ArchGDAL", "Distributions", "GeoFormatTypes", "GeoJSON", "JLD2", "LibGEOS", "Random", "Test"] | ||
test = ["ArchGDAL", "CoordinateTransformations", "Distributions", "GeoFormatTypes", "GeoJSON", "Proj", "JLD2", "LibGEOS", "Random", "Test"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
using Printf, Statistics | ||
using Makie, MakieThemes | ||
using BenchmarkTools, Chairmarks | ||
|
||
function compute_gridsize(numplts::Int, nr::Int, nc::Int) | ||
# figure out how many rows/columns we need | ||
if nr < 1 | ||
if nc < 1 | ||
nr = round(Int, sqrt(numplts)) | ||
nc = ceil(Int, numplts / nr) | ||
else | ||
nr = ceil(Int, numplts / nc) | ||
end | ||
else | ||
nc = ceil(Int, numplts / nr) | ||
end | ||
nr, nc | ||
end | ||
|
||
function _prettytime(t::Real) | ||
if t < 1e-6 | ||
value, units = t * 1e9, "ns" | ||
elseif t < 1e-3 | ||
value, units = t * 1e6, "μs" | ||
elseif t < 1 | ||
value, units = t * 1e3, "ms" | ||
else | ||
value, units = t * 1, "s" | ||
end | ||
return string(@sprintf("%.1f", value), " ", units) | ||
end | ||
|
||
_prettytime(ts::AbstractArray{<: Real}) = _prettytime.(ts) | ||
|
||
|
||
function results_to_numbers(result::BenchmarkGroup, postprocess_times = Statistics.median, postprocess_numbers = identity) | ||
# First, we extract the keys from the result. | ||
# It's assumed that there is only one key per result, and that it's a number. | ||
numbers = identity.(collect(keys(result))) | ||
@assert numbers isa AbstractVector{<: Number} """ | ||
Extra keys involved in the benchmark group! | ||
Provide a pure group with only numerical keys. | ||
Got key types: | ||
$(unique(typeof.(numbers))) | ||
""" | ||
# We sort the numbers, and then we use them to get the results | ||
sort!(numbers) | ||
result_objects = getindex.((result,), numbers) | ||
# Now, we get the times, and return their medians. | ||
postprocessed_objects = postprocess_times.(result_objects) | ||
return postprocess_numbers.(numbers), getproperty.(postprocessed_objects, :time) | ||
end | ||
|
||
# function plot_trials(results; title = ) | ||
|
||
|
||
|
||
""" | ||
plot_trials(result, title_str; theme = MakieThemes.bbc())::Figure | ||
This function takes `result::BenchmarkTools.BenchmarkGroup` and plots the trials. It returns the figure. | ||
""" | ||
plot_trials(results; kwargs...) = begin | ||
fig = Figure() | ||
plot_trials(fig[1, 1], results; kwargs...) | ||
fig | ||
end | ||
|
||
function plot_trials( | ||
gp::Makie.GridPosition, | ||
results; | ||
theme = merge(deepcopy(Makie.CURRENT_DEFAULT_THEME), MakieThemes.bbc()), | ||
legend_position = Makie.automatic, #(1, 1, TopRight()), | ||
legend_orientation = :horizontal, | ||
legend_halign = 1.0, | ||
legend_valign = -0.25, | ||
) | ||
|
||
xs, ys, labels = [], [], [] | ||
for label in keys(results) | ||
current_result = results[label] | ||
if isempty(current_result) | ||
@warn "ResultSet with key $label is empty, skipping." | ||
continue | ||
end | ||
x, y = results_to_numbers(current_result) | ||
push!(xs, x) | ||
push!(ys, y) | ||
push!(labels, label) | ||
end | ||
|
||
tag_attrs = capture_tag_attrs(results.tags) | ||
tag_theme = merge(theme, tag_attrs) | ||
|
||
lp = if legend_position isa Makie.Automatic | ||
gp.layout[gp.span.rows, gp.span.cols, TopRight()] | ||
elseif legend_position isa Tuple | ||
gp.layout[legend_position...] | ||
elseif legend_position isa Union{Makie.GridPosition, Makie.GridSubposition} | ||
legend_position | ||
else | ||
error() | ||
end | ||
|
||
return Makie.with_theme(tag_theme) do | ||
ax = Axis( | ||
gp; | ||
tag_attrs.Axis..., | ||
xlabel = "Number of points", ylabel = "Time to calculate", | ||
xscale = log10, yscale = log10, ytickformat = _prettytime, | ||
) | ||
plots = [scatterlines!(ax, x, y; label = label) for (x, y, label) in zip(xs, ys, labels)] | ||
setproperty!.(getindex.(getproperty.(plots, :plots), 1), :alpha, 0.1) | ||
leg = Legend( | ||
lp, ax; | ||
tellwidth = legend_position isa Union{Tuple, Makie.Automatic} && (legend_position isa Makie.Automatic || length(legend_position) != 3) && legend_orientation == :vertical, | ||
tellheight = legend_position isa Union{Tuple, Makie.Automatic} && (legend_position isa Makie.Automatic || length(legend_position) != 3) && legend_orientation == :horizontal, | ||
halign = legend_halign, | ||
valign = legend_valign, | ||
orientation = legend_orientation | ||
) | ||
ax.xticksvisible[] = true | ||
ax.xtickcolor[] = ax.xgridcolor[] | ||
ax.xticklabelsvisible[] = true | ||
ax.yticks[] = Makie.LogTicks(Makie.WilkinsonTicks(7; k_min = 4)) | ||
ax.ygridwidth[] = 0.75 | ||
return ax | ||
end | ||
end | ||
|
||
const _tag_includelist = ["title", "subtitle"] | ||
|
||
function capture_tag_attrs(tags) | ||
attr_dict = Attributes() | ||
axis = attr_dict.Axis = Attributes() | ||
for tag in tags | ||
for possibility in sort(_tag_includelist; by = length) | ||
if startswith(tag, possibility) | ||
axis[Symbol(possibility)] = tag[(length(possibility) + 2):end] | ||
break | ||
end | ||
end | ||
end | ||
return attr_dict | ||
end | ||
|
||
function decompose_benchmarksuite_to_2ndlevel(result) | ||
# here, `result` is a BenchmarkGroup. | ||
|
||
end |
Oops, something went wrong.