Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Figures with CairoMakie use meshes, resulting in excessively large file sizes #181

Closed
noahrhodes opened this issue Nov 8, 2023 · 1 comment · Fixed by MakieOrg/Makie.jl#3605

Comments

@noahrhodes
Copy link

I'd like to make some nice looking figures, but when saving to vector formats the file sizes are enormous and I wouldn't be able to include them in a publication. Presumably this is because of the conversion from multi-polygon to mesh for the GeoJSON data results in many more

There are some other issues related to poly and mesh #9 #144. There are mostly performance related, and it seems like the performance issues with large polygons were fixed after updates to GeoJSON #63 and some faster paths in Makie for vectors of multi-polygons #2599. In CairoMakie a similar issue #834 was brought up for contour plots having very large files sizes as a result of mesh triangulation instead of using polys when saving plots.

When creating a plot with GeoMakie, it can create a polygon based plot (see example below), but CairoMakie will use a fallback conversion to mesh when it draws the plot.
Presumably this function should be called when CairoMakie renders the plot (specializing on polygons::AbstractArray{<: MultiPolygon}). Instead this fallback function is used which winds up converting the geo axis to a mesh.

This occurs because in drawplot() draw_poly will specialize on to_value.(poly.input_args)... and this results in to_value.(poly.input_args) = (FeatureCollection with 127 Features,). It seems like that should somehow result in a multi-polygon instead of a FeatureCollection in order to allow the dispatch to call the correct function.

From here I do not know enough about the internals of Makie, CairoMakie, and GeoMakie to understand where the the disconnect is between poly!(ga,land_geo) creating a multi-polygon plot and draw_plot being handed a FeatureCollection, or in what package the correct fix needs to be created.

(Because a mesh is used, it also means that saving to .svg will create a .png embedded into the .svg, rather than an actual vector format. Saving to .pdf is the only way to get a vector format when a mesh is used in a plot layer.)

Example

Plotting geosjon will create a multi-polygon

# This example was contributed by Martijn Visser (@visr)
using Makie, CairoMakie, GeoMakie
using GeoMakie.GeoJSON
using GeometryBasics
using Downloads

source = "+proj=longlat +datum=WGS84"
dest = "+proj=natearth2"

url = "https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/geojson/"
land = Downloads.download(url * "ne_110m_land.geojson")
land_geo = GeoJSON.read(read(land, String))
pop = Downloads.download(url * "ne_10m_populated_places_simple.geojson")
pop_geo = GeoJSON.read(read(pop, String))


fig = Figure(resolution = (1000,500))
ga = GeoAxis(
    fig[1, 1];
    source = source,
    dest = dest
)

poly!(ga, land_geo, color=:black)
ga

julia> ga
Axis with 5 plots:
 ┣━ Lines{Tuple{Vector{Point{2, Float32}}}}
 ┣━ Lines{Tuple{Vector{Point{2, Float32}}}}
 ┣━ Lines{Tuple{Vector{Point{2, Float32}}}}
 ┣━ Lines{Tuple{Vector{Point{2, Float32}}}}
 ┗━ Poly{Tuple{Vector{MultiPolygon{2, Float32, Polygon{2, Float32, Point{2, Float32}, LineString{2, Float32, Point{2, Float32}, Base.ReinterpretArray{Line{2, Float32}, 1, Tuple{Point{2, Float32}, Point{2, Float32}}, TupleView{Tuple{Point{2, Float32}, Point{2, Float32}}, 2, 1, Vector{Point{2, Float32}}}, false}}, Vector{LineString{2, Float32, Point{2, Float32}, Base.ReinterpretArray{Line{2, Float32}, 1, Tuple{Point{2, Float32}, Point{2, Float32}}, TupleView{Tuple{Point{2, Float32}, Point{2, Float32}}, 2, 1, Vector{Point{2, Float32}}}, false}}}}, Vector{Polygon{2, Float32, Point{2, Float32}, LineString{2, Float32, Point{2, Float32}, Base.ReinterpretArray{Line{2, Float32}, 1, Tuple{Point{2, Float32}, Point{2, Float32}}, TupleView{Tuple{Point{2, Float32}, Point{2, Float32}}, 2, 1, Vector{Point{2, Float32}}}, false}}, Vector{LineString{2, Float32, Point{2, Float32}, Base.ReinterpretArray{Line{2, Float32}, 1, Tuple{Point{2, Float32}, Point{2, Float32}}, TupleView{Tuple{Point{2, Float32}, Point{2, Float32}}, 2, 
1, Vector{Point{2, Float32}}}, false}}}}}}}}}

Using to_value should presumably return something that is ::AbstractArray{<: MultiPolygon}

allplots = Makie.collect_atomic_plots(fig.scene; is_atomic_plot = CairoMakie.is_cairomakie_atomic_plot)
poly_plot = allplots[39]
to_value.(poly_plot.input_args) # returns `(FeatureCollection with 127 Features,)`

Saving/visualizing this figure will use a mesh

save("test.svg", fig)  # creates an embedded png in an svg because of the mesh
save("test.pdf", fig) # creates a vector format, but very large file size because of the mesh
@asinghvi17
Copy link
Member

yeah CairoMakie has regressed a bit unfortunately. This has been a consistent issue specifically because CairoMakie checks the input types of the call to poly...we are looking into this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants