From 6d1c723e4bf495b8630d9a34ad50f5665b6f9e99 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 12 Nov 2019 16:03:54 +0100 Subject: [PATCH 001/184] create stub --- Project.toml | 1 + src/backends.jl | 55 +++++++++++++++++++++++++++++++++++++++ src/backends/pgfplotsx.jl | 13 +++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/backends/pgfplotsx.jl diff --git a/Project.toml b/Project.toml index 087277df..685dbd8e 100644 --- a/Project.toml +++ b/Project.toml @@ -15,6 +15,7 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e" NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043" diff --git a/src/backends.jl b/src/backends.jl index 26f01c91..d8074d35 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -252,6 +252,7 @@ end @init_backend PlotlyJS @init_backend GR @init_backend PGFPlots +@init_backend PGFPlotsX @init_backend InspectDR @init_backend HDF5 @@ -661,3 +662,57 @@ const _inspectdr_marker = Symbol[ ] const _inspectdr_scale = [:identity, :ln, :log2, :log10] +# ------------------------------------------------------------------------------ +# pgfplotsx + +const _pgfplotsx_attr = merge_with_base_supported([ + :annotations, + :background_color_legend, :background_color_inside, :background_color_outside, + :foreground_color_legend, :foreground_color_grid, :foreground_color_axis, + :foreground_color_text, :foreground_color_border, + :label, + :seriescolor, :seriesalpha, + :linecolor, :linestyle, :linewidth, :linealpha, + :markershape, :markercolor, :markersize, :markeralpha, + :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, + :fillrange, :fillcolor, :fillalpha, + :bins, + :layout, + :title, :window_title, + :guide, :lims, :ticks, :scale, :flip, + :match_dimensions, + :titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign, + :titlefontrotation, :titlefontcolor, + :legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign, + :legendfontrotation, :legendfontcolor, + :tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign, + :tickfontrotation, :tickfontcolor, + :guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign, + :guidefontrotation, :guidefontcolor, + :grid, :gridalpha, :gridstyle, :gridlinewidth, + :legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry, + :fill_z, :line_z, :marker_z, :levels, + :ribbon, :quiver, + :orientation, + :overwrite_figure, + :polar, + :aspect_ratio, + :normalize, :weights, + :inset_subplots, + :bar_width, + :arrow, + :framestyle, + :tick_direction, + :camera, + :contour_labels, +]) +const _pgfplotsx_seriestype = [ + :path, :scatter, :straightline, + :heatmap, :pie, :image, + :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, + :shape +] +const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] +const _pgfplotsx_marker = _allMarkers +const _pgfplotsx_scale = [:identity, :log10] +is_marker_supported(::PGFPlotsXBackend, shape::Shape) = false diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl new file mode 100644 index 00000000..27122d8b --- /dev/null +++ b/src/backends/pgfplotsx.jl @@ -0,0 +1,13 @@ +# -------------------------------------------------------------------------------------- +function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) +end + +function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) +end + +function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) +end + +function _display(plt::Plot{PGFPlotsXBackend}) + +end From 54fc1ff69cfa3b4c1771a02e2681776bc9b53312 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 12 Nov 2019 16:27:27 +0100 Subject: [PATCH 002/184] create display methods --- src/backends/pgfplotsx.jl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 27122d8b..19522d8e 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,13 +1,25 @@ # -------------------------------------------------------------------------------------- +# display calls this and then _display +function _update_plot_object(plt::Plot{PGFPlotsXBackend}) + plt.o = PGFPlotsX.Axis() +end + function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) + plt.o end function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) + show(io, mime, plt.o) +end + +function _show(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsXBackend}) + display("image/png", plt.o) end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) + PGFPlotsX.print_tex(plt.o) end function _display(plt::Plot{PGFPlotsXBackend}) - + plt.o end From 37300a934570ba1ab41f972afb9ef0e2136356c4 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 12 Nov 2019 16:55:13 +0100 Subject: [PATCH 003/184] not displaying in Juno --- src/backends/pgfplotsx.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 19522d8e..e85e0933 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,11 +1,13 @@ +using PGFPlotsX: PGFPlotsX # -------------------------------------------------------------------------------------- # display calls this and then _display function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsX.Axis() + push!( plt.o, PGFPlotsX.Plot(PGFPlotsX.Coordinates(1:5,1:5)) ) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) - plt.o + show(io, mime, plt.o) end function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) @@ -13,7 +15,7 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) end function _show(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsXBackend}) - display("image/png", plt.o) + show(io, mime, plt.o) end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) From ca600e9d760cd44d44263c6de19e4502c048a68b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 13 Nov 2019 12:12:31 +0100 Subject: [PATCH 004/184] fix display --- src/backends/pgfplotsx.jl | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index e85e0933..a62f2317 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,9 +1,18 @@ using PGFPlotsX: PGFPlotsX # -------------------------------------------------------------------------------------- -# display calls this and then _display +# display calls this and then _display, its called 3 times for plot(1:5) function _update_plot_object(plt::Plot{PGFPlotsXBackend}) - plt.o = PGFPlotsX.Axis() - push!( plt.o, PGFPlotsX.Plot(PGFPlotsX.Coordinates(1:5,1:5)) ) + plt.o = PGFPlotsX.GroupPlot() + + local axis + for sp in plt.subplots + axis = PGFPlotsX.Axis() + for series in series_list(sp) + series_plot = PGFPlotsX.Plot(PGFPlotsX.Coordinates(series[:x],series[:y])) + push!( axis, series_plot ) + end + end + push!( plt.o, axis ) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) @@ -23,5 +32,8 @@ function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend end function _display(plt::Plot{PGFPlotsXBackend}) + # fn = string(tempname(),".svg") + # PGFPlotsX.pgfsave(fn, plt.o) + # open_browser_window(fn) plt.o end From 9e74976d6d97c0f7731fec2e3bf17ff8a54ddea9 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 13 Nov 2019 16:00:50 +0100 Subject: [PATCH 005/184] axes labels, legend entries, line color, marker shapes --- src/backends/pgfplotsx.jl | 60 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index a62f2317..44ac5994 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,38 @@ using PGFPlotsX: PGFPlotsX + +const _pgfplotsx_linestyles = KW( + :solid => "solid", + :dash => "dashed", + :dot => "dotted", + :dashdot => "dashdotted", + :dashdotdot => "dashdotdotted", +) + +const _pgfplotsx_markers = KW( + :none => "none", + :cross => "+", + :xcross => "x", + :+ => "+", + :x => "x", + :utriangle => "triangle*", + :dtriangle => "triangle*", + :circle => "*", + :rect => "square*", + :star5 => "star", + :star6 => "asterisk", + :diamond => "diamond*", + :pentagon => "pentagon*", + :hline => "-", + :vline => "|" +) + +const _pgfplotsx_legend_pos = KW( + :bottomleft => "south west", + :bottomright => "south east", + :topright => "north east", + :topleft => "north west", + :outertopright => "outer north east", +) # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) function _update_plot_object(plt::Plot{PGFPlotsXBackend}) @@ -6,10 +40,32 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) local axis for sp in plt.subplots - axis = PGFPlotsX.Axis() + bb = bbox(sp) + axis = PGFPlotsX.@pgf PGFPlotsX.Axis( + { + xlabel = sp.attr[:xaxis][:guide], + ylabel = sp.attr[:yaxis][:guide], + height = string(height(bb)), + width = string(width(bb)), + title = sp[:title], + }, + ) for series in series_list(sp) - series_plot = PGFPlotsX.Plot(PGFPlotsX.Coordinates(series[:x],series[:y])) + opt = series.plotattributes + series_plot = PGFPlotsX.@pgf PGFPlotsX.Plot( + { + color = opt[:linecolor], + mark = _pgfplotsx_markers[opt[:markershape]], + # TODO: how to do nested options? + # "mark options" = "{color = $(opt[:markercolor])}", + }, + PGFPlotsX.Coordinates(series[:x],series[:y]) + ) push!( axis, series_plot ) + if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end end end push!( plt.o, axis ) From 97c0161b9d8b818469402b17bd66cbde53275e65 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 14 Nov 2019 07:37:21 +0100 Subject: [PATCH 006/184] markercolor --- src/backends/pgfplotsx.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 44ac5994..d2fc8622 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -56,8 +56,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) { color = opt[:linecolor], mark = _pgfplotsx_markers[opt[:markershape]], - # TODO: how to do nested options? - # "mark options" = "{color = $(opt[:markercolor])}", + mark_options = {color = opt[:markercolor]}, }, PGFPlotsX.Coordinates(series[:x],series[:y]) ) From c984722807cb5aed5ad29018c5c5c47a5e8a3179 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 14 Nov 2019 16:45:31 +0100 Subject: [PATCH 007/184] fix code loading --- Project.toml | 1 - src/backends.jl | 1 - src/init.jl | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 685dbd8e..087277df 100644 --- a/Project.toml +++ b/Project.toml @@ -15,7 +15,6 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e" NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043" diff --git a/src/backends.jl b/src/backends.jl index d8074d35..f9b7ce12 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -37,7 +37,6 @@ macro init_backend(s) _backendType[Symbol($str)] = $T _backendSymbol[$T] = Symbol($str) _backend_packages[Symbol($str)] = Symbol($package_str) - # include("backends/" * $str * ".jl") end) end diff --git a/src/init.jl b/src/init.jl index bffc99f2..41519404 100644 --- a/src/init.jl +++ b/src/init.jl @@ -31,6 +31,7 @@ function __init__() @require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl")) @require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl")) @require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl")) + @require PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" include(joinpath(@__DIR__, "backends", "pgfplotsx.jl")) @require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" include(joinpath(@__DIR__, "backends", "plotlyjs.jl")) @require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include(joinpath(@__DIR__, "backends", "pyplot.jl")) @require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" include(joinpath(@__DIR__, "backends", "unicodeplots.jl")) From 5920f3b34d3a8a841daa2dad6d34d6e0e0e68171 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 14 Nov 2019 22:31:22 +0100 Subject: [PATCH 008/184] options translation part 1, use Options instead of @pgf --- src/backends/pgfplotsx.jl | 420 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 400 insertions(+), 20 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index d2fc8622..455f61cc 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,5 +1,3 @@ -using PGFPlotsX: PGFPlotsX - const _pgfplotsx_linestyles = KW( :solid => "solid", :dash => "dashed", @@ -33,41 +31,423 @@ const _pgfplotsx_legend_pos = KW( :topleft => "north west", :outertopright => "outer north east", ) + +const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] +const _pgfx_framestyle_defaults = Dict(:semi => :box) +## -------------------------------------------------------------------------------------- +function pgfx_framestyle(style::Symbol) + if style in _pgfx_framestyles + return style + else + default_style = get(_pgfx_framestyle_defaults, style, :axes) + @warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.") + default_style + end +end + +pgfx_thickness_scaling(plt::Plot) = plt[:thickness_scaling] +pgfx_thickness_scaling(sp::Subplot) = pgfx_thickness_scaling(sp.plt) +pgfx_thickness_scaling(series) = pgfx_thickness_scaling(series[:subplot]) + +function pgfx_fillstyle(plotattributes, i = 1) + cstr = get_fillcolor(plotattributes, i) + a = alpha(cstr) + fa = get_fillalpha(plotattributes, i) + if fa !== nothing + a = fa + end + fill => cstr, fill_opacity => a +end + +function pgfx_linestyle(linewidth::Real, color, α = 1, linestyle = "solid") + cstr = plot_color(color, α) + a = alpha(cstr) + return PGFPlotsX.Options( + "color" => cstr, + "draw opacity" => a, + "line width" => linewidth, + get(_pgfplotsx_linestyles, linestyle, "solid") => nothing + ) +end + +function pgfx_linestyle(plotattributes, i = 1) + lw = pgfx_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i) + lc = get_linecolor(plotattributes, i) + la = get_linealpha(plotattributes, i) + ls = get_linestyle(plotattributes, i) + return pgfx_linestyle(lw, lc, la, ls) +end + +function pgfx_font(fontsize, thickness_scaling = 1, font = "\\selectfont") + fs = fontsize * thickness_scaling + return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}") +end + +function pgfx_marker(plotattributes, i = 1) + shape = _cycle(plotattributes[:markershape], i) + cstr = plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)) + a = alpha(cstr) + cstr_stroke = plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)) + a_stroke = alpha(cstr_stroke) + return PGFPlotsX.Options( + "mark" => get(_pgfplotsx_markers, shape, "*"), + "mark size" => pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i), + "mark options" => PGFPlotsX.Options( + "color" => cstr_stroke, + "draw opacity" => a_stroke, + "fill" => cstr, + "fill opacity" => a, + "line width" => pgfx_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i), + "rotate" => (shape == :dtriangle ? 180 : 0), + get(_pgfplotsx_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid") => nothing + ) + ) +end + +function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) + # Construct the style string. + # Currently supports color and orientation + cstr = val.font.color + a = alpha(cstr) + #TODO: translate this + push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text + x, y, + style=""" + $(get(_pgfx_annotation_halign,val.font.halign,"")), + color=$cstr, draw opacity=$(convert(Float16,a)), + rotate=$(val.font.rotation), + font=$(pgfx_font(val.font.pointsize, thickness_scaling)) + """)) +end +## -------------------------------------------------------------------------------------- +# TODO: translate these if needed +function pgf_series(sp::Subplot, series::Series) + plotattributes = series.plotattributes + st = plotattributes[:seriestype] + series_collection = PGFPlots.Plot[] + + # function args + args = if st == :contour + plotattributes[:z].surf, plotattributes[:x], plotattributes[:y] + elseif is3d(st) + plotattributes[:x], plotattributes[:y], plotattributes[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = plotattributes[:x], plotattributes[:y] + rad2deg.(theta), r + else + plotattributes[:x], plotattributes[:y] + end + + # PGFPlots can't handle non-Vector? + args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector + collect(a) + else + a + end, args) + + if st in (:contour, :histogram2d) + style = [] + kw = KW() + push!(style, pgf_linestyle(plotattributes)) + push!(style, pgf_marker(plotattributes)) + push!(style, "forget plot") + + kw[:style] = join(style, ',') + func = if st == :histogram2d + PGFPlots.Histogram2 + else + kw[:labels] = series[:contour_labels] + kw[:levels] = series[:levels] + PGFPlots.Contour + end + push!(series_collection, func(args...; kw...)) + + else + # series segments + segments = iter_segments(series) + for (i, rng) in enumerate(segments) + style = [] + kw = KW() + push!(style, pgf_linestyle(plotattributes, i)) + push!(style, pgf_marker(plotattributes, i)) + + if st == :shape + push!(style, pgf_fillstyle(plotattributes, i)) + end + + # add to legend? + if i == 1 && sp[:legend] != :none && should_add_to_legend(series) + if plotattributes[:fillrange] !== nothing + push!(style, "forget plot") + push!(series_collection, pgf_fill_legend_hack(plotattributes, args)) + else + kw[:legendentry] = plotattributes[:label] + if st == :shape # || plotattributes[:fillrange] !== nothing + push!(style, "area legend") + end + end + else + push!(style, "forget plot") + end + + seg_args = (arg[rng] for arg in args) + + # include additional style, then add to the kw + if haskey(_pgf_series_extrastyle, st) + push!(style, _pgf_series_extrastyle[st]) + end + kw[:style] = join(style, ',') + + # add fillrange + if series[:fillrange] !== nothing && st != :shape + push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + end + + # build/return the series object + func = if st == :path3d + PGFPlots.Linear3 + elseif st == :scatter + PGFPlots.Scatter + else + PGFPlots.Linear + end + push!(series_collection, func(seg_args...; kw...)) + end + end + series_collection +end + +function pgf_fillrange_series(series, i, fillrange, args...) + st = series[:seriestype] + style = [] + kw = KW() + push!(style, "line width = 0") + push!(style, "draw opacity = 0") + push!(style, pgf_fillstyle(series, i)) + push!(style, pgf_marker(series, i)) + push!(style, "forget plot") + if haskey(_pgf_series_extrastyle, st) + push!(style, _pgf_series_extrastyle[st]) + end + kw[:style] = join(style, ',') + func = is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear + return func(pgf_fillrange_args(fillrange, args...)...; kw...) +end + +function pgf_fillrange_args(fillrange, x, y) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] + return x_fill, y_fill +end + +function pgf_fillrange_args(fillrange, x, y, z) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; y[n:-1:1]; x[1]] + z_fill = [z; _cycle(fillrange, n:-1:1); z[1]] + return x_fill, y_fill, z_fill +end + +function pgf_fill_legend_hack(plotattributes, args) + style = [] + kw = KW() + push!(style, pgf_linestyle(plotattributes, 1)) + push!(style, pgf_marker(plotattributes, 1)) + push!(style, pgf_fillstyle(plotattributes, 1)) + push!(style, "area legend") + kw[:legendentry] = plotattributes[:label] + kw[:style] = join(style, ',') + st = plotattributes[:seriestype] + func = if st == :path3d + PGFPlots.Linear3 + elseif st == :scatter + PGFPlots.Scatter + else + PGFPlots.Linear + end + return func(([arg[1]] for arg in args)...; kw...) +end + +# -------------------------------------------------------------------------------------- +function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) + axis = sp[Symbol(letter,:axis)] + + # turn off scaled ticks + push!(opt, "scaled $(letter) ticks" => "false", + string(letter,:label) => axis[:guide], + ) + + # set to supported framestyle + framestyle = pgfx_framestyle(sp[:framestyle]) + + # axis label position + labelpos = "" + if letter == :x && axis[:guide_position] == :top + labelpos = "at={(0.5,1)},above," + elseif letter == :y && axis[:guide_position] == :right + labelpos = "at={(1,0.5)},below," + end + + # Add label font + cstr = plot_color(axis[:guidefontcolor]) + α = alpha(cstr) + push!(opt, string(letter, "label style") => PGFPlotsX.Options( + labelpos => nothing, + "font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)), + "color" => cstr, + "draw opacity" => α, + "rotate" => axis[:guidefontrotation], + ) + ) + + # flip/reverse? + axis[:flip] && push!(opt, "$letter dir" => "reverse") + + # scale + scale = axis[:scale] + if scale in (:log2, :ln, :log10) + push!(opt, string(letter,:mode) => "log") + scale == :ln || push!(opt, "log basis $letter" => "$(scale == :log2 ? 2 : 10)") + end + + # ticks on or off + if axis[:ticks] in (nothing, false, :none) || framestyle == :none + push!(opt, "$(letter)majorticks" => "false") + end + + # grid on or off + if axis[:grid] && framestyle != :none + push!(opt, "$(letter)majorgrids" => "true") + else + push!(opt, "$(letter)majorgrids" => "false") + end + + # limits + # TODO: support zlims + if letter != :z + lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) + push!( opt, + string(letter,:min) => lims[1], + string(letter,:max) => lims[2] + ) + end + + if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none + ticks = get_ticks(sp, axis) + #pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values + tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1] + push!(opt, string(letter, "tick") => string("{", join(tick_values,","), "}")) + if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto + # wrap the power part of label with } + tick_labels = Vector{String}(undef, length(ticks[2])) + for (i, label) in enumerate(ticks[2]) + base, power = split(label, "^") + power = string("{", power, "}") + tick_labels[i] = string(base, "^", power) + end + push!(opt, string(letter, "ticklabels") => string("{\$", join(tick_labels,"\$,\$"), "\$}")) + elseif axis[:showaxis] + tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2] + if axis[:formatter] in (:scientific, :auto) + tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$") + tick_labels = replace.(tick_labels, Ref("×" => "\\times")) + end + push!(opt, string(letter, "ticklabels") => string("{", join(tick_labels,","), "}")) + else + push!(opt, string(letter, "ticklabels") => "{}") + end + push!(opt, string(letter, "tick align") => (axis[:tick_direction] == :out ? "outside" : "inside")) + cstr = plot_color(axis[:tickfontcolor]) + α = alpha(cstr) + push!(opt, string(letter, "ticklabel style") => PGFPlotsX.Options( + "font" => pgfx_font(axis[:tickfontsize], pgfx_thickness_scaling(sp)), + "color" => cstr, + "draw opacity" => α, + "rotate" => axis[:tickfontrotation] + ) + ) + push!(opt, string(letter, " grid style") => pgfx_linestyle(pgfx_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle]) + ) + end + + # framestyle + if framestyle in (:axes, :origin) + axispos = framestyle == :axes ? "left" : "middle" + if axis[:draw_arrow] + push!(opt, string("axis ", letter, " line") => axispos) + else + # the * after line disables the arrow at the axis + push!(opt, string("axis ", letter, " line*") => axispos) + end + end + + if framestyle == :zerolines + push!(opt, string("extra ", letter, " ticks") => "0") + push!(opt, string("extra ", letter, " tick labels") => "") + push!(opt, string("extra ", letter, " tick style") => PGFPlotsX.Options( + "grid" => "major", + "major grid style" => pgfx_linestyle(pgfx_thickness_scaling(sp), axis[:foreground_color_border], 1.0) + ) + ) + end + + if !axis[:showaxis] + push!(opt, "separate axis lines") + end + if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none) + push!(opt, string(letter, " axis line style") => "{draw opacity = 0}") + else + push!(opt, string(letter, " axis line style") => pgfx_linestyle(pgfx_thickness_scaling(sp), axis[:foreground_color_border], 1.0) + ) + end +end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsX.GroupPlot() - local axis for sp in plt.subplots bb = bbox(sp) - axis = PGFPlotsX.@pgf PGFPlotsX.Axis( - { - xlabel = sp.attr[:xaxis][:guide], - ylabel = sp.attr[:yaxis][:guide], - height = string(height(bb)), - width = string(width(bb)), - title = sp[:title], - }, + axis_opt = PGFPlotsX.Options( + "height" => string(height(bb)), + "width" => string(width(bb)), + "title" => sp[:title], + ) + for letter in (:x, :y, :z) + if letter != :z || is3d(sp) + pgfx_axis!(axis_opt, sp, letter) + end + end + axis = PGFPlotsX.Axis( + axis_opt ) for series in series_list(sp) opt = series.plotattributes - series_plot = PGFPlotsX.@pgf PGFPlotsX.Plot( - { - color = opt[:linecolor], - mark = _pgfplotsx_markers[opt[:markershape]], - mark_options = {color = opt[:markercolor]}, - }, - PGFPlotsX.Coordinates(series[:x],series[:y]) + segments = iter_segments(series) + for (i, rng) in enumerate(segments) + series_plot = PGFPlotsX.Plot( + merge( + PGFPlotsX.Options( + "color" => opt[:linecolor] + ), + pgfx_marker(opt, i) + ), + PGFPlotsX.Coordinates(series[:x],series[:y]) ) - push!( axis, series_plot ) + push!( axis, series_plot ) + end if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) ) end end + push!( plt.o, axis ) end - push!( plt.o, axis ) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) From cbc0419c6e1a9deac1af3450586826d6234e0986 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 08:52:56 +0100 Subject: [PATCH 009/184] legend styling --- src/backends/pgfplotsx.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 455f61cc..0a1f58f6 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -413,10 +413,21 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for sp in plt.subplots bb = bbox(sp) + legpos = sp[:legend] + if haskey(_pgfplotsx_legend_pos, legpos) + legpos = _pgfplotsx_legend_pos[legpos] + end + cstr = plot_color(sp[:background_color_legend]) + a = alpha(cstr) axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), "title" => sp[:title], + "legend style" => PGFPlotsX.Options( + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, + "fill" => cstr, + "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + ) ) for letter in (:x, :y, :z) if letter != :z || is3d(sp) From 6b6d589aa7ff34ffa4130959e918e4b3d5b708ad Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 09:42:05 +0100 Subject: [PATCH 010/184] translate pgf_add_aanotation! --- src/backends/pgfplotsx.jl | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 0a1f58f6..fd1decac 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -34,6 +34,14 @@ const _pgfplotsx_legend_pos = KW( const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] const _pgfx_framestyle_defaults = Dict(:semi => :box) + +# we use the anchors to define orientations for example to align left +# one needs to use the right edge as anchor +const _pgfx_annotation_halign = KW( + :center => "", + :left => "right", + :right => "left" +) ## -------------------------------------------------------------------------------------- function pgfx_framestyle(style::Symbol) if style in _pgfx_framestyles @@ -109,15 +117,18 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) # Currently supports color and orientation cstr = val.font.color a = alpha(cstr) - #TODO: translate this - push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text - x, y, - style=""" - $(get(_pgfx_annotation_halign,val.font.halign,"")), - color=$cstr, draw opacity=$(convert(Float16,a)), - rotate=$(val.font.rotation), - font=$(pgfx_font(val.font.pointsize, thickness_scaling)) - """)) + push!(o, ["\\node", + PGFPlotsX.Options( + get(_pgfx_annotation_halign,val.font.halign,"") => nothing, + "color" => cstr, + "draw opacity" => convert(Float16, a), + "rotate" => val.font.rotation, + "font" => pgfx_font(val.font.pointsize, thickness_scaling) + ), + " at ", + PGFPlotsX.Coordinate(x, y), + "{$(val.str).};" + ]) end ## -------------------------------------------------------------------------------------- # TODO: translate these if needed From 86643058b6fad8434b56e80785fa252513fd06ea Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 13:47:04 +0100 Subject: [PATCH 011/184] apply annotations --- src/backends/pgfplotsx.jl | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index fd1decac..becb538a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -135,7 +135,7 @@ end function pgf_series(sp::Subplot, series::Series) plotattributes = series.plotattributes st = plotattributes[:seriestype] - series_collection = PGFPlots.Plot[] + series_collection = PGFPlotsX.Plot[] # function args args = if st == :contour @@ -154,11 +154,11 @@ function pgf_series(sp::Subplot, series::Series) end # PGFPlots can't handle non-Vector? - args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector - collect(a) - else - a - end, args) + # args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector + # collect(a) + # else + # a + # end, args) if st in (:contour, :histogram2d) style = [] @@ -452,17 +452,24 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) opt = series.plotattributes segments = iter_segments(series) for (i, rng) in enumerate(segments) - series_plot = PGFPlotsX.Plot( - merge( - PGFPlotsX.Options( - "color" => opt[:linecolor] - ), - pgfx_marker(opt, i) - ), - PGFPlotsX.Coordinates(series[:x],series[:y]) - ) - push!( axis, series_plot ) + # TODO: make segmented series end + # TODO: different seriestypes, histogramms, contours, etc. + series_plot = PGFPlotsX.Plot( + merge( + PGFPlotsX.Options( + "color" => opt[:linecolor] + ), + pgfx_marker(opt, i) + ), + PGFPlotsX.Coordinates(series[:x],series[:y]) + ) + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) + end + push!( axis, series_plot ) if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) ) From 1f566294acac3ae87ee2a2ec811a8e4a0bdc6b40 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 15:47:36 +0100 Subject: [PATCH 012/184] basic 3D --- src/backends/pgfplotsx.jl | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index becb538a..b094a4e8 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -451,18 +451,29 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for series in series_list(sp) opt = series.plotattributes segments = iter_segments(series) + segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) - # TODO: make segmented series + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end # TODO: different seriestypes, histogramms, contours, etc. - series_plot = PGFPlotsX.Plot( + # TODO: colorbars + # TOOD: gradients + if is3d(series) + series_func = opt -> PGFPlotsX.Plot3(opt, + PGFPlotsX.Coordinates(series[:x],series[:y],series[:z]) + ) + else + series_func = opt -> PGFPlotsX.Plot(opt, + PGFPlotsX.Coordinates(series[:x],series[:y]) + ) + end + series_plot = series_func( merge( PGFPlotsX.Options( "color" => opt[:linecolor] ), - pgfx_marker(opt, i) + segment_opt ), - PGFPlotsX.Coordinates(series[:x],series[:y]) ) # add series annotations anns = series[:series_annotations] From d8c48f1a8501d3fde652d588f6b387ddb77cb866 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 16:13:54 +0100 Subject: [PATCH 013/184] translate pgf_fillrange_series --- src/backends/pgfplotsx.jl | 62 ++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index b094a4e8..d7e8c3ea 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -32,6 +32,15 @@ const _pgfplotsx_legend_pos = KW( :outertopright => "outer north east", ) +const _pgfx_series_extrastyle = KW( + :steppre => "const plot mark right", + :stepmid => "const plot mark mid", + :steppost => "const plot", + :sticks => "ycomb", + :ysticks => "ycomb", + :xsticks => "xcomb", +) + const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] const _pgfx_framestyle_defaults = Dict(:semi => :box) @@ -64,7 +73,7 @@ function pgfx_fillstyle(plotattributes, i = 1) if fa !== nothing a = fa end - fill => cstr, fill_opacity => a + PGFPlotsX.Options("fill" => cstr, "fill opacity" => a) end function pgfx_linestyle(linewidth::Real, color, α = 1, linestyle = "solid") @@ -232,21 +241,18 @@ function pgf_series(sp::Subplot, series::Series) series_collection end -function pgf_fillrange_series(series, i, fillrange, args...) +function pgfx_fillrange_series!(opt, series, i, fillrange, args...) st = series[:seriestype] - style = [] - kw = KW() - push!(style, "line width = 0") - push!(style, "draw opacity = 0") - push!(style, pgf_fillstyle(series, i)) - push!(style, pgf_marker(series, i)) - push!(style, "forget plot") - if haskey(_pgf_series_extrastyle, st) - push!(style, _pgf_series_extrastyle[st]) + push!(opt, "line width" => 0) + push!(opt, "draw opacity" => 0) + push!(opt, pgfx_fillopt(series, i)) + push!(opt, pgfx_marker(series, i)) + push!(opt, "forget plot" => nothing) + if haskey(_pgfx_series_extraopt, st) + push!(opt, _pgfx_series_extrastyle[st] => nothing) end - kw[:style] = join(style, ',') - func = is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear - return func(pgf_fillrange_args(fillrange, args...)...; kw...) + # TODO: what are those fillrange_args about? + # return func(pgf_fillrange_args(fillrange, args...)...; kw...) end function pgf_fillrange_args(fillrange, x, y) @@ -450,14 +456,33 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) ) for series in series_list(sp) opt = series.plotattributes + st = series[:seriestype] + series_opt = PGFPlotsX.Options( + "color" => opt[:linecolor] + ) segments = iter_segments(series) segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + if st == :shape + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + # TODO: is this necessary? + # seg_args = (arg[rng] for arg in args) + # TODO: translate this + # # add fillrange + # if series[:fillrange] !== nothing && st != :shape + # push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + # end + end + #include additional style + if haskey(_pgfx_series_extrastyle, st) + push!(series_opt, _pgfx_series_extrastyle[st] => nothing) end # TODO: different seriestypes, histogramms, contours, etc. # TODO: colorbars - # TOOD: gradients + # TODO: gradients if is3d(series) series_func = opt -> PGFPlotsX.Plot3(opt, PGFPlotsX.Coordinates(series[:x],series[:y],series[:z]) @@ -468,12 +493,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) ) end series_plot = series_func( - merge( - PGFPlotsX.Options( - "color" => opt[:linecolor] - ), - segment_opt - ), + merge(series_opt, segment_opt), ) # add series annotations anns = series[:series_annotations] From 2bf3ddf45b062de7fe164d3a638b63729d58f894 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 16:41:47 +0100 Subject: [PATCH 014/184] add guard against overexecution --- src/backends/pgfplotsx.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index becb538a..228b3ea3 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -419,7 +419,13 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) +let n_calls = 0 +function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) + n_calls = 0 +end + function _update_plot_object(plt::Plot{PGFPlotsXBackend}) +if n_calls === 0 plt.o = PGFPlotsX.GroupPlot() for sp in plt.subplots @@ -478,6 +484,8 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) push!( plt.o, axis ) end end +n_calls += 1 +end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) show(io, mime, plt.o) From cd55218a2c5419a4b189d75506b79a6f2fe65890 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 18 Nov 2019 11:51:03 +0100 Subject: [PATCH 015/184] translated pgf_fillrange_series --- src/backends/pgfplotsx.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index f6c539f5..9f8678c8 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -241,8 +241,9 @@ function pgf_series(sp::Subplot, series::Series) series_collection end -function pgfx_fillrange_series!(opt, series, i, fillrange, args...) +function pgfx_fillrange_series(series, i, fillrange, args...) st = series[:seriestype] + opt = PGFPlotsX.Options() push!(opt, "line width" => 0) push!(opt, "draw opacity" => 0) push!(opt, pgfx_fillopt(series, i)) @@ -251,18 +252,18 @@ function pgfx_fillrange_series!(opt, series, i, fillrange, args...) if haskey(_pgfx_series_extraopt, st) push!(opt, _pgfx_series_extrastyle[st] => nothing) end - # TODO: what are those fillrange_args about? - # return func(pgf_fillrange_args(fillrange, args...)...; kw...) + func = is3d(series) ? PGFPlotsX.Plot3 : PGFPlotsX.Plot + return func(opt, pgfx_fillrange_args(fillrange, args...)...) end -function pgf_fillrange_args(fillrange, x, y) +function pgfx_fillrange_args(fillrange, x, y) n = length(x) x_fill = [x; x[n:-1:1]; x[1]] y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] return x_fill, y_fill end -function pgf_fillrange_args(fillrange, x, y, z) +function pgfx_fillrange_args(fillrange, x, y, z) n = length(x) x_fill = [x; x[n:-1:1]; x[1]] y_fill = [y; y[n:-1:1]; x[1]] From c39613ddd830c6edc7550f6d297c086520caacda Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 18 Nov 2019 16:13:56 +0100 Subject: [PATCH 016/184] translation of pgf_colormap --- src/backends/pgfplotsx.jl | 83 ++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 9f8678c8..0093e35a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -52,6 +52,14 @@ const _pgfx_annotation_halign = KW( :right => "left" ) ## -------------------------------------------------------------------------------------- +# Generates a colormap for pgfplots based on a ColorGradient +# TODO: maybe obsolete +function pgfx_colormap(grad::ColorGradient) + join(map(grad.colors) do c + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c)) + end,", ") +end + function pgfx_framestyle(style::Symbol) if style in _pgfx_framestyles return style @@ -426,13 +434,11 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) -let n_calls = 0 function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) - n_calls = 0 + # TODO: don't rebuild plots so often end function _update_plot_object(plt::Plot{PGFPlotsXBackend}) -if n_calls === 0 plt.o = PGFPlotsX.GroupPlot() for sp in plt.subplots @@ -458,12 +464,60 @@ if n_calls === 0 pgfx_axis!(axis_opt, sp, letter) end end + # Search series for any gradient. In case one series uses a gradient set + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + push!(axis_opt, + "colormap" => "{plots}{$(pgfx_colormap(series.plotattributes[col]))}") + + # TODO: is this needed? + # if sp[:colorbar] == :none + # kw[:colorbar] = "false" + # else + # kw[:colorbar] = "true" + # end + # goto is needed to break out of col and series for + @goto colorbar_end + end + end + end + @label colorbar_end + + push!(axis_opt, "colorbar style" => PGFPlotsX.Options( + "title" => sp[:colorbar_title] + ) + ) axis = PGFPlotsX.Axis( axis_opt ) for series in series_list(sp) opt = series.plotattributes st = series[:seriestype] + # function args + args = if st == :contour + opt[:z].surf, opt[:x], opt[:y] + elseif is3d(st) + opt[:x], opt[:y], opt[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = opt[:x], opt[:y] + rad2deg.(theta), r + else + opt[:x], opt[:y] + end series_opt = PGFPlotsX.Options( "color" => opt[:linecolor] ) @@ -475,13 +529,11 @@ if n_calls === 0 if st == :shape segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end - # TODO: is this necessary? - # seg_args = (arg[rng] for arg in args) - # TODO: translate this - # # add fillrange - # if series[:fillrange] !== nothing && st != :shape - # push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) - # end + seg_args = (arg[rng] for arg in args) + # add fillrange + if series[:fillrange] !== nothing && st != :shape + push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + end end #include additional style if haskey(_pgfx_series_extrastyle, st) @@ -491,16 +543,13 @@ if n_calls === 0 # TODO: colorbars # TODO: gradients if is3d(series) - series_func = opt -> PGFPlotsX.Plot3(opt, - PGFPlotsX.Coordinates(series[:x],series[:y],series[:z]) - ) + series_func = PGFPlotsX.Plot3 else - series_func = opt -> PGFPlotsX.Plot(opt, - PGFPlotsX.Coordinates(series[:x],series[:y]) - ) + series_func = PGFPlotsX.Plot end series_plot = series_func( merge(series_opt, segment_opt), + PGFPlotsX.Coordinates(args...) ) # add series annotations anns = series[:series_annotations] @@ -516,8 +565,6 @@ if n_calls === 0 push!( plt.o, axis ) end end -n_calls += 1 -end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) show(io, mime, plt.o) From 1e2ea1614c5d5fc79c66e5a68f87cc38a12214bb Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 18 Nov 2019 17:16:27 +0100 Subject: [PATCH 017/184] add tests --- Project.toml | 3 ++- src/backends/pgfplotsx.jl | 4 ++++ test/runtests.jl | 2 ++ test/test_pgfplotsx.jl | 13 +++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 test/test_pgfplotsx.jl diff --git a/Project.toml b/Project.toml index 087277df..e8ffda4a 100644 --- a/Project.toml +++ b/Project.toml @@ -47,6 +47,7 @@ ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" +PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" @@ -55,4 +56,4 @@ UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92" [targets] -test = ["FileIO", "GeometryTypes", "Gtk", "ImageMagick", "Images", "LaTeXStrings", "LibGit2", "Random", "RDatasets", "StatsPlots", "Test", "UnicodePlots", "VisualRegressionTests"] +test = ["FileIO", "GeometryTypes", "Gtk", "ImageMagick", "Images", "LaTeXStrings", "LibGit2", "PGFPlotsX", "Random", "RDatasets", "StatsPlots", "Test", "UnicodePlots", "VisualRegressionTests"] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 0093e35a..2b7ea449 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -567,18 +567,22 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) + _update_plot_object(plt) show(io, mime, plt.o) end function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) + _update_plot_object(plt) show(io, mime, plt.o) end function _show(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsXBackend}) + _update_plot_object(plt) show(io, mime, plt.o) end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) + _update_plot_object(plt) PGFPlotsX.print_tex(plt.o) end diff --git a/test/runtests.jl b/test/runtests.jl index 55c7e963..16ad485f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -8,6 +8,8 @@ using Gtk using LibGit2 using GeometryTypes +include("test_pgfplotsx.jl") + reference_dir(args...) = joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...) function reference_file(backend, i, version) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl new file mode 100644 index 00000000..a46a0a35 --- /dev/null +++ b/test/test_pgfplotsx.jl @@ -0,0 +1,13 @@ +using Plots, Test +pgfplotsx() + +function create_plot( args...; kwargs... ) + pgfx_plot = plot(args..., kwargs...) + return pgfx_plot, repr("application/x-tex", pgfx_plot) +end + +@testset "PGFPlotsX" begin + pgfx_plot, pgfx_tex = create_plot(1:5) + + @test pgfx_plot.o isa PGFPlotsX.GroupPlot +end # testset From b6bd69055bf6f0b31758ede6da5c867183dcae2f Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 18 Nov 2019 19:05:49 +0100 Subject: [PATCH 018/184] tests for 3D colorbar --- src/backends/pgfplotsx.jl | 13 +++++++++++-- test/test_pgfplotsx.jl | 23 +++++++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 2b7ea449..c38f11a3 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -57,7 +57,7 @@ const _pgfx_annotation_halign = KW( function pgfx_colormap(grad::ColorGradient) join(map(grad.colors) do c @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c)) - end,", ") + end,"\n") end function pgfx_framestyle(style::Symbol) @@ -441,6 +441,8 @@ end function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsX.GroupPlot() + pushed_colormap = false + empty!(PGFPlotsX.CUSTOM_PREAMBLE) for sp in plt.subplots bb = bbox(sp) legpos = sp[:legend] @@ -477,8 +479,15 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for series in series_list(sp) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient + # TODO: fix this + # pushed_colormap || push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ + # colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, + # }""") + pushed_colormap = true push!(axis_opt, - "colormap" => "{plots}{$(pgfx_colormap(series.plotattributes[col]))}") + # "colormap" => nothing, + # "colormap name" => "plots", + ) # TODO: is this needed? # if sp[:colorbar] == :none diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index a46a0a35..a636fd91 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -2,12 +2,31 @@ using Plots, Test pgfplotsx() function create_plot( args...; kwargs... ) - pgfx_plot = plot(args..., kwargs...) + pgfx_plot = plot(args...; kwargs...) + return pgfx_plot, repr("application/x-tex", pgfx_plot) +end + +function create_plot!( args...; kwargs... ) + pgfx_plot = plot!(args...; kwargs...) return pgfx_plot, repr("application/x-tex", pgfx_plot) end @testset "PGFPlotsX" begin pgfx_plot, pgfx_tex = create_plot(1:5) - + @test pgfx_plot.o isa PGFPlotsX.GroupPlot + @testset "3D docs example" begin + n = 100 + ts = range(0, stop=8π, length=n) + x = ts .* map(cos, ts) + y = (0.1ts) .* map(sin, ts) + z = 1:n + pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5) + @show PGFPlotsX.CUSTOM_PREAMBLE + @show PGFPlotsX.CUSTOM_PREAMBLE_PATH + pgfx_plot, pgfx_tex = create_plot!(pl, zeros(n), zeros(n), 1:n, w=10) + if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colormap") == true) + @test pgfx_plot.o.contents[1]["colormap"] === nothing + end + end # testset end # testset From 4486620918f66549a9ed01353268ae96a12f3fef Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 11:30:34 +0100 Subject: [PATCH 019/184] title styling --- src/backends/pgfplotsx.jl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c38f11a3..c3e13709 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -56,7 +56,7 @@ const _pgfx_annotation_halign = KW( # TODO: maybe obsolete function pgfx_colormap(grad::ColorGradient) join(map(grad.colors) do c - @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c)) + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) end,"\n") end @@ -451,14 +451,26 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end cstr = plot_color(sp[:background_color_legend]) a = alpha(cstr) + title_cstr = plot_color(sp[:titlefontcolor]) + title_a = alpha(cstr) + # TODO: aspect ratio, legend position axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), "title" => sp[:title], + "title style" => PGFPlotsX.Options( + "font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)), + "color" => title_cstr, + "draw opacity" => title_a, + "rotate" => sp[:titlefontrotation] + ), "legend style" => PGFPlotsX.Options( - pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, - "fill" => cstr, - "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, + "fill" => cstr, + "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + ), + "axis background/.style" => PGFPlotsX.Options( + "fill" => sp[:background_color_inside] ) ) for letter in (:x, :y, :z) From 5e0d42898cc8c277755ecf7fe0c7937cd82efca0 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 11:34:21 +0100 Subject: [PATCH 020/184] claim everything --- src/backends.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index f9b7ce12..dddeea47 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -711,7 +711,9 @@ const _pgfplotsx_seriestype = [ :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, :shape ] +const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] -const _pgfplotsx_marker = _allMarkers -const _pgfplotsx_scale = [:identity, :log10] -is_marker_supported(::PGFPlotsXBackend, shape::Shape) = false +const _pgfplotsx_marker = vcat(_allMarkers, Shape) + # [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline] # +const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] +is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true From 64791017f85fce37a5c39096b931e358530967d9 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 11:35:35 +0100 Subject: [PATCH 021/184] adjust --- src/backends.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index dddeea47..89fa83eb 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -705,12 +705,12 @@ const _pgfplotsx_attr = merge_with_base_supported([ :camera, :contour_labels, ]) -const _pgfplotsx_seriestype = [ - :path, :scatter, :straightline, - :heatmap, :pie, :image, - :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, - :shape -] +# const _pgfplotsx_seriestype = [ +# :path, :scatter, :straightline, +# :heatmap, :pie, :image, +# :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, +# :shape +# ] const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _pgfplotsx_marker = vcat(_allMarkers, Shape) From 1819e3dd9966822180e8dea7a677d0222017c6c4 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 11:58:57 +0100 Subject: [PATCH 022/184] fix colorbar --- src/backends/pgfplotsx.jl | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c3e13709..82a0bded 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -492,14 +492,16 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient # TODO: fix this - # pushed_colormap || push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ - # colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, - # }""") - pushed_colormap = true - push!(axis_opt, - # "colormap" => nothing, - # "colormap name" => "plots", - ) + if !pushed_colormap + push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ + colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + pushed_colormap = true + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots", + ) + end # TODO: is this needed? # if sp[:colorbar] == :none From 3f70fdb3aaebe8053bdfc15c028fe469822dcd8e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 12:05:43 +0100 Subject: [PATCH 023/184] correct test --- test/test_pgfplotsx.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index a636fd91..4ee29dbd 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -22,11 +22,9 @@ end y = (0.1ts) .* map(sin, ts) z = 1:n pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5) - @show PGFPlotsX.CUSTOM_PREAMBLE - @show PGFPlotsX.CUSTOM_PREAMBLE_PATH pgfx_plot, pgfx_tex = create_plot!(pl, zeros(n), zeros(n), 1:n, w=10) if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colormap") == true) - @test pgfx_plot.o.contents[1]["colormap"] === nothing + @test pgfx_plot.o.contents[1]["colorbar"] === nothing end end # testset end # testset From 2d100d826172ee03743b8007aa4c1b27d9780619 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 12:08:30 +0100 Subject: [PATCH 024/184] legend position --- src/backends/pgfplotsx.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 82a0bded..8fd07e4f 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -453,7 +453,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) a = alpha(cstr) title_cstr = plot_color(sp[:titlefontcolor]) title_a = alpha(cstr) - # TODO: aspect ratio, legend position + # TODO: aspect ratio axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), @@ -464,6 +464,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) "draw opacity" => title_a, "rotate" => sp[:titlefontrotation] ), + "legend pos" => _pgfplotsx_legend_pos[sp[:legend]], "legend style" => PGFPlotsX.Options( pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, "fill" => cstr, From 1a751c7baec0640ba56cc9f2cac4ba7da4e4d8b3 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 14:47:54 +0100 Subject: [PATCH 025/184] reproduce 3D docs plot --- src/backends/pgfplotsx.jl | 23 +++++++++-------------- test/test_pgfplotsx.jl | 2 +- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 8fd07e4f..422e1c27 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,3 +1,5 @@ +PGFPlotsX.print_tex(io::IO, data::Symbol) = PGFPlotsX.print_tex(io, string(data)) + const _pgfplotsx_linestyles = KW( :solid => "solid", :dash => "dashed", @@ -445,10 +447,6 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) empty!(PGFPlotsX.CUSTOM_PREAMBLE) for sp in plt.subplots bb = bbox(sp) - legpos = sp[:legend] - if haskey(_pgfplotsx_legend_pos, legpos) - legpos = _pgfplotsx_legend_pos[legpos] - end cstr = plot_color(sp[:background_color_legend]) a = alpha(cstr) title_cstr = plot_color(sp[:titlefontcolor]) @@ -464,7 +462,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) "draw opacity" => title_a, "rotate" => sp[:titlefontrotation] ), - "legend pos" => _pgfplotsx_legend_pos[sp[:legend]], + "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), "legend style" => PGFPlotsX.Options( pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, "fill" => cstr, @@ -492,7 +490,6 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for series in series_list(sp) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient - # TODO: fix this if !pushed_colormap push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, @@ -504,12 +501,6 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) ) end - # TODO: is this needed? - # if sp[:colorbar] == :none - # kw[:colorbar] = "false" - # else - # kw[:colorbar] = "true" - # end # goto is needed to break out of col and series for @goto colorbar_end end @@ -543,8 +534,12 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) opt[:x], opt[:y] end series_opt = PGFPlotsX.Options( - "color" => opt[:linecolor] + "color" => opt[:linecolor], + "scatter" => nothing, ) + if opt[:marker_z] !== nothing + push!(series_opt, "point meta" => "explicit") + end segments = iter_segments(series) segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) @@ -573,7 +568,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end series_plot = series_func( merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(args...) + PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) ) # add series annotations anns = series[:series_annotations] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 4ee29dbd..12e3ae0e 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -23,7 +23,7 @@ end z = 1:n pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5) pgfx_plot, pgfx_tex = create_plot!(pl, zeros(n), zeros(n), 1:n, w=10) - if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colormap") == true) + if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colorbar") == true) @test pgfx_plot.o.contents[1]["colorbar"] === nothing end end # testset From b6da96fb78d36d11c59d4d6bd9389900bc5e595b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 14:58:03 +0100 Subject: [PATCH 026/184] add area legend for shapes --- src/backends/pgfplotsx.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 422e1c27..9b6dbbd5 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -537,6 +537,9 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) "color" => opt[:linecolor], "scatter" => nothing, ) + if st == :shape + push!(series_opt, "area legend" => nothing) + end if opt[:marker_z] !== nothing push!(series_opt, "point meta" => "explicit") end From fb418c87aca4901cb4c2b3bb45d702a96bc2564b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 15:06:34 +0100 Subject: [PATCH 027/184] fix pgfx_fillrange_series --- src/backends/pgfplotsx.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 9b6dbbd5..46e38136 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -256,14 +256,14 @@ function pgfx_fillrange_series(series, i, fillrange, args...) opt = PGFPlotsX.Options() push!(opt, "line width" => 0) push!(opt, "draw opacity" => 0) - push!(opt, pgfx_fillopt(series, i)) - push!(opt, pgfx_marker(series, i)) + opt = merge(opt, pgfx_fillstyle(series, i)) + opt = merge(opt, pgfx_marker(series, i)) push!(opt, "forget plot" => nothing) - if haskey(_pgfx_series_extraopt, st) + if haskey(_pgfx_series_extrastyle, st) push!(opt, _pgfx_series_extrastyle[st] => nothing) end func = is3d(series) ? PGFPlotsX.Plot3 : PGFPlotsX.Plot - return func(opt, pgfx_fillrange_args(fillrange, args...)...) + return func(opt, PGFPlotsX.Coordinates(pgfx_fillrange_args(fillrange, args...)...)) end function pgfx_fillrange_args(fillrange, x, y) From c0fc671a83ece82f7c95b0ce0c199a74a1faf9fc Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 15:31:36 +0100 Subject: [PATCH 028/184] status quo --- src/backends/pgfplotsx.jl | 5 ++++- test/test_pgfplotsx.jl | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 46e38136..1308d243 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -535,13 +535,13 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end series_opt = PGFPlotsX.Options( "color" => opt[:linecolor], - "scatter" => nothing, ) if st == :shape push!(series_opt, "area legend" => nothing) end if opt[:marker_z] !== nothing push!(series_opt, "point meta" => "explicit") + push!(series_opt, "scatter" => nothing) end segments = iter_segments(series) segment_opt = PGFPlotsX.Options() @@ -569,6 +569,9 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) else series_func = PGFPlotsX.Plot end + if st == :scatter + push!(series_opt, "only marks" => nothing) + end series_plot = series_func( merge(series_opt, segment_opt), PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 12e3ae0e..47f76ccf 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -27,4 +27,39 @@ end @test pgfx_plot.o.contents[1]["colorbar"] === nothing end end # testset + @testset "Color docs example" begin + y = rand(100) + plot(0:10:100, rand(11, 4), lab="lines", w=3, palette=:grays, fill=0, α=0.6) + scatter!(y, zcolor=abs.(y .- 0.5), m=(:heat, 0.8, Plots.stroke(1, :green)), ms=10 * abs.(y .- 0.5) .+ 4, lab="grad") + # TODO: marker size does not adjust + # TODO: marker stroke is incorrect + # TODO: fill legends + # TODO: adjust colorbar limits to data + end # testset + @testset "Plot in pieces" begin + plot(rand(100) / 3, reg=true, fill=(0, :green)) + scatter!(rand(100), markersize=6, c=:orange) + # TODO: legends should be different + end # testset + @testset "Marker types" begin + markers = filter((m->begin + m in Plots.supported_markers() + end), Plots._shape_keys) + markers = reshape(markers, 1, length(markers)) + n = length(markers) + x = (range(0, stop=10, length=n + 2))[2:end - 1] + y = repeat(reshape(reverse(x), 1, :), n, 1) + scatter(x, y, m=(8, :auto), lab=map(string, markers), bg=:linen, xlim=(0, 10), ylim=(0, 10)) + #TODO: fix markers that show up as circles + end # testset + @testset "Layout" begin + plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black]) + # TODO: add layouting + end # testset + @testset "Polar plots" begin + Θ = range(0, stop=1.5π, length=100) + r = abs.(0.1 * randn(100) + sin.(3Θ)) + plot(Θ, r, proj=:polar, m=2) + # TODO: handle polar plots + end # testset end # testset From 4902716a44c07902ae5a688403094c3f2e92eb72 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 16:30:53 +0100 Subject: [PATCH 029/184] use TikzDocument and its preamble --- src/backends/pgfplotsx.jl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 1308d243..77d75e92 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -436,15 +436,20 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) -function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) - # TODO: don't rebuild plots so often +function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) + end +function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) +end + +# TODO: don't rebuild plots so often +# IDEA: use functor to only build plot once function _update_plot_object(plt::Plot{PGFPlotsXBackend}) - plt.o = PGFPlotsX.GroupPlot() + plt.o = PGFPlotsX.TikzDocument() + push!(plt.o, PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot())) pushed_colormap = false - empty!(PGFPlotsX.CUSTOM_PREAMBLE) for sp in plt.subplots bb = bbox(sp) cstr = plot_color(sp[:background_color_legend]) @@ -491,7 +496,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient if !pushed_colormap - push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ + PGFPlotsX.push_preamble!(plt.o, """\\pgfplotsset{ colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, }""") pushed_colormap = true @@ -587,7 +592,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) ) end end - push!( plt.o, axis ) + push!( plt.o.elements[1].elements[1], axis ) end end From 408db8dc4f60737e09ea9551a15966a0c2a9ea88 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 17:30:26 +0100 Subject: [PATCH 030/184] respect layout --- src/backends/pgfplotsx.jl | 9 ++++++++- test/test_pgfplotsx.jl | 20 +++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 77d75e92..933afbfa 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -447,7 +447,14 @@ end # IDEA: use functor to only build plot once function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsX.TikzDocument() - push!(plt.o, PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot())) + cols, rows = size(plt.layout.grid) + push!(plt.o, PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot( + PGFPlotsX.Options( + "group style" => PGFPlotsX.Options( + "group size" => string(cols)*" by "*string(rows) + ) + ) + ))) pushed_colormap = false for sp in plt.subplots diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 47f76ccf..748d1739 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -54,7 +54,7 @@ end end # testset @testset "Layout" begin plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black]) - # TODO: add layouting + # TODO: no extra space for outer legends end # testset @testset "Polar plots" begin Θ = range(0, stop=1.5π, length=100) @@ -62,4 +62,22 @@ end plot(Θ, r, proj=:polar, m=2) # TODO: handle polar plots end # testset + @testset "Histogram 2D" begin + histogram2d(randn(10000), randn(10000), nbins=20) + # TODO: totally broken, errors also for pgfplots + end # testset + @testset "Contours" begin + x = 1:0.5:20 + y = 1:0.5:10 + f(x, y) = begin + (3x + y ^ 2) * abs(sin(x) + cos(y)) + end + X = repeat(reshape(x, 1, :), length(y), 1) + Y = repeat(y, 1, length(x)) + Z = map(f, X, Y) + p1 = contour(x, y, f, fill=true) + p2 = contour(x, y, Z) + plot(p1, p2) + # TODO: totally broken, also errors for pgfplots + end # testset end # testset From 91aef718911dcfb2cb58f1b6523b7275d3b83167 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 17:46:05 +0100 Subject: [PATCH 031/184] broken polar --- src/backends/pgfplotsx.jl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 933afbfa..46c90cbc 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -524,7 +524,15 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) "title" => sp[:colorbar_title] ) ) - axis = PGFPlotsX.Axis( + axisf = if sp[:projection] == :polar + # TODO: this errors for some reason + # push!(axis_opt, "xmin" => 90) + # push!(axis_opt, "xmax" => 450) + PGFPlotsX.PolarAxis + else + PGFPlotsX.Axis + end + axis = axisf( axis_opt ) for series in series_list(sp) From e14733d46017f2318621885f99e16fc70b95f286 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 18:18:08 +0100 Subject: [PATCH 032/184] ltriangle, rtriangle --- src/backends.jl | 3 +-- src/backends/pgfplotsx.jl | 12 +++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 89fa83eb..d2ae4894 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -713,7 +713,6 @@ const _pgfplotsx_attr = merge_with_base_supported([ # ] const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] -const _pgfplotsx_marker = vcat(_allMarkers, Shape) - # [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline] # +const _pgfplotsx_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :ltriangle, :rtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline, Shape] const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 46c90cbc..1d2c3587 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -16,6 +16,8 @@ const _pgfplotsx_markers = KW( :x => "x", :utriangle => "triangle*", :dtriangle => "triangle*", + :rtriangle => "triangle*", + :ltriangle => "triangle*", :circle => "*", :rect => "square*", :star5 => "star", @@ -125,7 +127,15 @@ function pgfx_marker(plotattributes, i = 1) "fill" => cstr, "fill opacity" => a, "line width" => pgfx_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i), - "rotate" => (shape == :dtriangle ? 180 : 0), + "rotate" => if shape == :dtriangle + 180 + elseif shape == :rtriangle + 270 + elseif shape == :ltriangle + 90 + else + 0 + end, get(_pgfplotsx_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid") => nothing ) ) From b66415a3383a83017fdf5b298d347379f9dd88e3 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 10:35:48 +0100 Subject: [PATCH 033/184] translate pgf_fill_legend_hack --- src/backends/pgfplotsx.jl | 140 +++++++------------------------------- 1 file changed, 26 insertions(+), 114 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 1d2c3587..7bc0aef1 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -161,106 +161,6 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) end ## -------------------------------------------------------------------------------------- # TODO: translate these if needed -function pgf_series(sp::Subplot, series::Series) - plotattributes = series.plotattributes - st = plotattributes[:seriestype] - series_collection = PGFPlotsX.Plot[] - - # function args - args = if st == :contour - plotattributes[:z].surf, plotattributes[:x], plotattributes[:y] - elseif is3d(st) - plotattributes[:x], plotattributes[:y], plotattributes[:z] - elseif st == :straightline - straightline_data(series) - elseif st == :shape - shape_data(series) - elseif ispolar(sp) - theta, r = plotattributes[:x], plotattributes[:y] - rad2deg.(theta), r - else - plotattributes[:x], plotattributes[:y] - end - - # PGFPlots can't handle non-Vector? - # args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector - # collect(a) - # else - # a - # end, args) - - if st in (:contour, :histogram2d) - style = [] - kw = KW() - push!(style, pgf_linestyle(plotattributes)) - push!(style, pgf_marker(plotattributes)) - push!(style, "forget plot") - - kw[:style] = join(style, ',') - func = if st == :histogram2d - PGFPlots.Histogram2 - else - kw[:labels] = series[:contour_labels] - kw[:levels] = series[:levels] - PGFPlots.Contour - end - push!(series_collection, func(args...; kw...)) - - else - # series segments - segments = iter_segments(series) - for (i, rng) in enumerate(segments) - style = [] - kw = KW() - push!(style, pgf_linestyle(plotattributes, i)) - push!(style, pgf_marker(plotattributes, i)) - - if st == :shape - push!(style, pgf_fillstyle(plotattributes, i)) - end - - # add to legend? - if i == 1 && sp[:legend] != :none && should_add_to_legend(series) - if plotattributes[:fillrange] !== nothing - push!(style, "forget plot") - push!(series_collection, pgf_fill_legend_hack(plotattributes, args)) - else - kw[:legendentry] = plotattributes[:label] - if st == :shape # || plotattributes[:fillrange] !== nothing - push!(style, "area legend") - end - end - else - push!(style, "forget plot") - end - - seg_args = (arg[rng] for arg in args) - - # include additional style, then add to the kw - if haskey(_pgf_series_extrastyle, st) - push!(style, _pgf_series_extrastyle[st]) - end - kw[:style] = join(style, ',') - - # add fillrange - if series[:fillrange] !== nothing && st != :shape - push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) - end - - # build/return the series object - func = if st == :path3d - PGFPlots.Linear3 - elseif st == :scatter - PGFPlots.Scatter - else - PGFPlots.Linear - end - push!(series_collection, func(seg_args...; kw...)) - end - end - series_collection -end - function pgfx_fillrange_series(series, i, fillrange, args...) st = series[:seriestype] opt = PGFPlotsX.Options() @@ -291,24 +191,21 @@ function pgfx_fillrange_args(fillrange, x, y, z) return x_fill, y_fill, z_fill end -function pgf_fill_legend_hack(plotattributes, args) - style = [] - kw = KW() - push!(style, pgf_linestyle(plotattributes, 1)) - push!(style, pgf_marker(plotattributes, 1)) - push!(style, pgf_fillstyle(plotattributes, 1)) - push!(style, "area legend") - kw[:legendentry] = plotattributes[:label] - kw[:style] = join(style, ',') +function pgfx_fill_legend_hack(plotattributes, args) + opt = PGFPlotsX.Options("area legend" => nothing) + opt = merge(opt, pgfx_linestyle(plotattributes, 1)) + opt = merge(opt, pgfx_marker(plotattributes, 1)) + opt = merge(opt, pgfx_fillstyle(plotattributes, 1)) st = plotattributes[:seriestype] func = if st == :path3d - PGFPlots.Linear3 - elseif st == :scatter - PGFPlots.Scatter + PGFPlotsX.Plot3 else - PGFPlots.Linear + PGFPlotsX.Plot end - return func(([arg[1]] for arg in args)...; kw...) + if st == :scatter + push!(opt, "only marks" => nothing) + end + return func(opt, PGFPlotsX.Coordinates(([arg[1]] for arg in args)...)) end # -------------------------------------------------------------------------------------- @@ -586,6 +483,21 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) if series[:fillrange] !== nothing && st != :shape push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) end + + # add to legend? + if i == 1 && sp[:legend] != :none && should_add_to_legend(series) + if opt[:fillrange] !== nothing + push!(segment_opt, "forget plot" => nothing) + push!(axis, pgfx_fill_legend_hack(opt, args)) + else + if st == :shape + push!(segment_opt, "area legend" => nothing) + end + end + push!( axis, PGFPlotsX.LegendEntry( opt[:label] )) + else + push!(segment_opt, "forget plot" => nothing) + end end #include additional style if haskey(_pgfx_series_extrastyle, st) From 4964eb31fa5eba5bdd67558549eabcd6897291f8 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 14:16:43 +0100 Subject: [PATCH 034/184] create plot only once --- src/backends/pgfplotsx.jl | 391 ++++++++++++++++++++------------------ 1 file changed, 208 insertions(+), 183 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 7bc0aef1..e9e49e73 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,207 @@ -PGFPlotsX.print_tex(io::IO, data::Symbol) = PGFPlotsX.print_tex(io, string(data)) +# PGFPlotsX.print_tex(io::IO, data::Symbol) = PGFPlotsX.print_tex(io, string(data)) +Base.@kwdef mutable struct PGFPlotsXPlot + is_created::Bool = false + was_shown::Bool = false + the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() +end + +function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) + show(io::IO, mime, pgfx_plot.the_plot) +end + +function Base.push!(pgfx_plot::PGFPlotsXPlot, item) + push!(pgfx_plot.the_plot, item) +end + +function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) + if !pgfx_plot.is_created + cols, rows = size(plt.layout.grid) + the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot( + PGFPlotsX.Options( + "group style" => PGFPlotsX.Options( + "group size" => string(cols)*" by "*string(rows) + ) + ) + )) + + pushed_colormap = false + for sp in plt.subplots + bb = bbox(sp) + cstr = plot_color(sp[:background_color_legend]) + a = alpha(cstr) + title_cstr = plot_color(sp[:titlefontcolor]) + title_a = alpha(cstr) + # TODO: aspect ratio + axis_opt = PGFPlotsX.Options( + "height" => string(height(bb)), + "width" => string(width(bb)), + "title" => sp[:title], + "title style" => PGFPlotsX.Options( + "font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)), + "color" => title_cstr, + "draw opacity" => title_a, + "rotate" => sp[:titlefontrotation] + ), + "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), + "legend style" => PGFPlotsX.Options( + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, + "fill" => cstr, + "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + ), + "axis background/.style" => PGFPlotsX.Options( + "fill" => sp[:background_color_inside] + ) + ) + for letter in (:x, :y, :z) + if letter != :z || is3d(sp) + pgfx_axis!(axis_opt, sp, letter) + end + end + # Search series for any gradient. In case one series uses a gradient set + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + if !pushed_colormap + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + pushed_colormap = true + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots", + ) + end + + # goto is needed to break out of col and series for + @goto colorbar_end + end + end + end + @label colorbar_end + + push!(axis_opt, "colorbar style" => PGFPlotsX.Options( + "title" => sp[:colorbar_title] + ) + ) + axisf = if sp[:projection] == :polar + # TODO: this errors for some reason + # push!(axis_opt, "xmin" => 90) + # push!(axis_opt, "xmax" => 450) + PGFPlotsX.PolarAxis + else + PGFPlotsX.Axis + end + axis = axisf( + axis_opt + ) + for series in series_list(sp) + opt = series.plotattributes + st = series[:seriestype] + # function args + args = if st == :contour + opt[:z].surf, opt[:x], opt[:y] + elseif is3d(st) + opt[:x], opt[:y], opt[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = opt[:x], opt[:y] + rad2deg.(theta), r + else + opt[:x], opt[:y] + end + series_opt = PGFPlotsX.Options( + "color" => opt[:linecolor], + ) + if st == :shape + push!(series_opt, "area legend" => nothing) + end + if opt[:marker_z] !== nothing + push!(series_opt, "point meta" => "explicit") + push!(series_opt, "scatter" => nothing) + end + segments = iter_segments(series) + segment_opt = PGFPlotsX.Options() + for (i, rng) in enumerate(segments) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + if st == :shape + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + seg_args = (arg[rng] for arg in args) + # add fillrange + if series[:fillrange] !== nothing && st != :shape + push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + end + + # add to legend? + if i == 1 && sp[:legend] != :none && should_add_to_legend(series) + if opt[:fillrange] !== nothing + push!(segment_opt, "forget plot" => nothing) + push!(axis, pgfx_fill_legend_hack(opt, args)) + else + if st == :shape + push!(segment_opt, "area legend" => nothing) + end + end + push!( axis, PGFPlotsX.LegendEntry( opt[:label] )) + else + push!(segment_opt, "forget plot" => nothing) + end + end + #include additional style + if haskey(_pgfx_series_extrastyle, st) + push!(series_opt, _pgfx_series_extrastyle[st] => nothing) + end + # TODO: different seriestypes, histogramms, contours, etc. + # TODO: colorbars + # TODO: gradients + if is3d(series) + series_func = PGFPlotsX.Plot3 + else + series_func = PGFPlotsX.Plot + end + if st == :scatter + push!(series_opt, "only marks" => nothing) + end + series_plot = series_func( + merge(series_opt, segment_opt), + PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) + ) + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) + end + push!( axis, series_plot ) + if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end + end + push!( the_plot.elements[1], axis ) + if length(plt.o.the_plot.elements) > 0 + plt.o.the_plot.elements[1] = the_plot + else + push!(plt.o, the_plot) + end + end + pgfx_plot.is_created = true + end +end + +## const _pgfplotsx_linestyles = KW( :solid => "solid", @@ -344,193 +547,15 @@ end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) - + plt.o = PGFPlotsXPlot() end -function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) +function _series_added(plt::Plot{PGFPlotsXBackend}, series::Series) + plt.o.is_created = false end -# TODO: don't rebuild plots so often -# IDEA: use functor to only build plot once function _update_plot_object(plt::Plot{PGFPlotsXBackend}) - plt.o = PGFPlotsX.TikzDocument() - cols, rows = size(plt.layout.grid) - push!(plt.o, PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot( - PGFPlotsX.Options( - "group style" => PGFPlotsX.Options( - "group size" => string(cols)*" by "*string(rows) - ) - ) - ))) - - pushed_colormap = false - for sp in plt.subplots - bb = bbox(sp) - cstr = plot_color(sp[:background_color_legend]) - a = alpha(cstr) - title_cstr = plot_color(sp[:titlefontcolor]) - title_a = alpha(cstr) - # TODO: aspect ratio - axis_opt = PGFPlotsX.Options( - "height" => string(height(bb)), - "width" => string(width(bb)), - "title" => sp[:title], - "title style" => PGFPlotsX.Options( - "font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)), - "color" => title_cstr, - "draw opacity" => title_a, - "rotate" => sp[:titlefontrotation] - ), - "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), - "legend style" => PGFPlotsX.Options( - pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, - "fill" => cstr, - "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) - ), - "axis background/.style" => PGFPlotsX.Options( - "fill" => sp[:background_color_inside] - ) - ) - for letter in (:x, :y, :z) - if letter != :z || is3d(sp) - pgfx_axis!(axis_opt, sp, letter) - end - end - # Search series for any gradient. In case one series uses a gradient set - # the colorbar and colomap. - # The reasoning behind doing this on the axis level is that pgfplots - # colorbar seems to only works on axis level and needs the proper colormap for - # correctly displaying it. - # It's also possible to assign the colormap to the series itself but - # then the colormap needs to be added twice, once for the axis and once for the - # series. - # As it is likely that all series within the same axis use the same - # colormap this should not cause any problem. - for series in series_list(sp) - for col in (:markercolor, :fillcolor, :linecolor) - if typeof(series.plotattributes[col]) == ColorGradient - if !pushed_colormap - PGFPlotsX.push_preamble!(plt.o, """\\pgfplotsset{ - colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, - }""") - pushed_colormap = true - push!(axis_opt, - "colorbar" => nothing, - "colormap name" => "plots", - ) - end - - # goto is needed to break out of col and series for - @goto colorbar_end - end - end - end - @label colorbar_end - - push!(axis_opt, "colorbar style" => PGFPlotsX.Options( - "title" => sp[:colorbar_title] - ) - ) - axisf = if sp[:projection] == :polar - # TODO: this errors for some reason - # push!(axis_opt, "xmin" => 90) - # push!(axis_opt, "xmax" => 450) - PGFPlotsX.PolarAxis - else - PGFPlotsX.Axis - end - axis = axisf( - axis_opt - ) - for series in series_list(sp) - opt = series.plotattributes - st = series[:seriestype] - # function args - args = if st == :contour - opt[:z].surf, opt[:x], opt[:y] - elseif is3d(st) - opt[:x], opt[:y], opt[:z] - elseif st == :straightline - straightline_data(series) - elseif st == :shape - shape_data(series) - elseif ispolar(sp) - theta, r = opt[:x], opt[:y] - rad2deg.(theta), r - else - opt[:x], opt[:y] - end - series_opt = PGFPlotsX.Options( - "color" => opt[:linecolor], - ) - if st == :shape - push!(series_opt, "area legend" => nothing) - end - if opt[:marker_z] !== nothing - push!(series_opt, "point meta" => "explicit") - push!(series_opt, "scatter" => nothing) - end - segments = iter_segments(series) - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - if st == :shape - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - seg_args = (arg[rng] for arg in args) - # add fillrange - if series[:fillrange] !== nothing && st != :shape - push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) - end - - # add to legend? - if i == 1 && sp[:legend] != :none && should_add_to_legend(series) - if opt[:fillrange] !== nothing - push!(segment_opt, "forget plot" => nothing) - push!(axis, pgfx_fill_legend_hack(opt, args)) - else - if st == :shape - push!(segment_opt, "area legend" => nothing) - end - end - push!( axis, PGFPlotsX.LegendEntry( opt[:label] )) - else - push!(segment_opt, "forget plot" => nothing) - end - end - #include additional style - if haskey(_pgfx_series_extrastyle, st) - push!(series_opt, _pgfx_series_extrastyle[st] => nothing) - end - # TODO: different seriestypes, histogramms, contours, etc. - # TODO: colorbars - # TODO: gradients - if is3d(series) - series_func = PGFPlotsX.Plot3 - else - series_func = PGFPlotsX.Plot - end - if st == :scatter - push!(series_opt, "only marks" => nothing) - end - series_plot = series_func( - merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) - ) - # add series annotations - anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) - pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) - end - push!( axis, series_plot ) - if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) - ) - end - end - push!( plt.o.elements[1].elements[1], axis ) - end + plt.o(plt) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) From 71720de7b2395a7ae36a357fe87abc898b7fa8a8 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 15:20:33 +0100 Subject: [PATCH 035/184] update tests --- src/backends/pgfplotsx.jl | 5 +++-- test/test_pgfplotsx.jl | 24 +++++++++++++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index e9e49e73..90b823d8 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -5,6 +5,8 @@ Base.@kwdef mutable struct PGFPlotsXPlot the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() end +pgfx_axes(pgfx_plot::PGFPlotsXPlot) = pgfx_plot.the_plot.elements[1].elements[1].contents + function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) show(io::IO, mime, pgfx_plot.the_plot) end @@ -31,7 +33,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) a = alpha(cstr) title_cstr = plot_color(sp[:titlefontcolor]) title_a = alpha(cstr) - # TODO: aspect ratio axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), @@ -575,7 +576,7 @@ end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) _update_plot_object(plt) - PGFPlotsX.print_tex(plt.o) + PGFPlotsX.print_tex(plt.o.the_plot) end function _display(plt::Plot{PGFPlotsXBackend}) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 748d1739..03e9dce2 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -12,34 +12,37 @@ function create_plot!( args...; kwargs... ) end @testset "PGFPlotsX" begin - pgfx_plot, pgfx_tex = create_plot(1:5) + pgfx_plot = plot(1:5) + Plots._update_plot_object(pgfx_plot) + @test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument - @test pgfx_plot.o isa PGFPlotsX.GroupPlot - @testset "3D docs example" begin + @testset "3D docs example" begin n = 100 ts = range(0, stop=8π, length=n) x = ts .* map(cos, ts) y = (0.1ts) .* map(sin, ts) z = 1:n pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5) - pgfx_plot, pgfx_tex = create_plot!(pl, zeros(n), zeros(n), 1:n, w=10) - if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colorbar") == true) - @test pgfx_plot.o.contents[1]["colorbar"] === nothing + pgfx_plot = plot!(pl, zeros(n), zeros(n), 1:n, w=10) + Plots._update_plot_object(pgfx_plot) + if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing end end # testset @testset "Color docs example" begin y = rand(100) plot(0:10:100, rand(11, 4), lab="lines", w=3, palette=:grays, fill=0, α=0.6) - scatter!(y, zcolor=abs.(y .- 0.5), m=(:heat, 0.8, Plots.stroke(1, :green)), ms=10 * abs.(y .- 0.5) .+ 4, lab="grad") + pl = scatter!(y, zcolor=abs.(y .- 0.5), m=(:heat, 0.8, Plots.stroke(1, :green)), ms=10 * abs.(y .- 0.5) .+ 4, lab="grad") + Plots._update_plot_object(pl) + axis = Plots.pgfx_axes(pl.o)[1] + @test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5 + @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 5 # TODO: marker size does not adjust # TODO: marker stroke is incorrect - # TODO: fill legends - # TODO: adjust colorbar limits to data end # testset @testset "Plot in pieces" begin plot(rand(100) / 3, reg=true, fill=(0, :green)) scatter!(rand(100), markersize=6, c=:orange) - # TODO: legends should be different end # testset @testset "Marker types" begin markers = filter((m->begin @@ -50,7 +53,6 @@ end x = (range(0, stop=10, length=n + 2))[2:end - 1] y = repeat(reshape(reverse(x), 1, :), n, 1) scatter(x, y, m=(8, :auto), lab=map(string, markers), bg=:linen, xlim=(0, 10), ylim=(0, 10)) - #TODO: fix markers that show up as circles end # testset @testset "Layout" begin plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black]) From 2d947f4a9779e03f14ead8b76511b1748a29c5f3 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 17:28:23 +0100 Subject: [PATCH 036/184] native fillrange --- src/backends/pgfplotsx.jl | 96 +++++++++++++++++++-------------------- test/test_pgfplotsx.jl | 12 +++-- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 90b823d8..c0c6e05e 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -88,6 +88,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end @label colorbar_end + # detect fillranges + # if any(series->series[:fillrange] != nothing, series_list(sp)) + # PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween},\n") + # end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title] @@ -125,71 +129,61 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => opt[:linecolor], ) - if st == :shape - push!(series_opt, "area legend" => nothing) - end if opt[:marker_z] !== nothing push!(series_opt, "point meta" => "explicit") push!(series_opt, "scatter" => nothing) end - segments = iter_segments(series) - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - if st == :shape - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - seg_args = (arg[rng] for arg in args) - # add fillrange - if series[:fillrange] !== nothing && st != :shape - push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) - end - - # add to legend? - if i == 1 && sp[:legend] != :none && should_add_to_legend(series) - if opt[:fillrange] !== nothing - push!(segment_opt, "forget plot" => nothing) - push!(axis, pgfx_fill_legend_hack(opt, args)) - else - if st == :shape - push!(segment_opt, "area legend" => nothing) - end - end - push!( axis, PGFPlotsX.LegendEntry( opt[:label] )) - else - push!(segment_opt, "forget plot" => nothing) - end - end - #include additional style - if haskey(_pgfx_series_extrastyle, st) - push!(series_opt, _pgfx_series_extrastyle[st] => nothing) - end - # TODO: different seriestypes, histogramms, contours, etc. - # TODO: colorbars - # TODO: gradients if is3d(series) series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot end - if st == :scatter - push!(series_opt, "only marks" => nothing) + if series[:fillrange] !== nothing + series_opt = merge(series_opt, pgfx_fillstyle(opt)) + push!(series_opt, "area legend" => nothing) end - series_plot = series_func( - merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) - ) + # include additional style + if haskey(_pgfx_series_extrastyle, st) + push!(series_opt, _pgfx_series_extrastyle[st] => nothing) + end + # treat segments + segments = iter_segments(series) + segment_opt = PGFPlotsX.Options() + # @show get_markerstrokecolor(opt, 1) + # @show get_markercolor(opt,1) + for (i, rng) in enumerate(segments) + seg_args = (arg[rng] for arg in args) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + if st == :shape || series[:fillrange] !== nothing + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + segment_plot = series_func( + merge(series_opt, segment_opt), + PGFPlotsX.Coordinates(seg_args..., + meta = if !isnothing(opt[:marker_z]) + opt[:marker_z][rng] + else + nothing + end + ), + series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + ) + push!(axis, segment_plot) + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end + end + # TODO: different seriestypes, histogramms, contours, etc. + # TODO: colorbars + # TODO: gradients # add series annotations anns = series[:series_annotations] for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end - push!( axis, series_plot ) - if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) - ) - end end push!( the_plot.elements[1], axis ) if length(plt.o.the_plot.elements) > 0 @@ -247,6 +241,8 @@ const _pgfx_series_extrastyle = KW( :sticks => "ycomb", :ysticks => "ycomb", :xsticks => "xcomb", + :scatter => "only marks", + :shape => "area legends" ) const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 03e9dce2..7a8c320a 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -36,9 +36,15 @@ end Plots._update_plot_object(pl) axis = Plots.pgfx_axes(pl.o)[1] @test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5 - @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 5 - # TODO: marker size does not adjust - # TODO: marker stroke is incorrect + @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 104 # each marker is its own plot + marker = axis.contents[5] + @test marker isa PGFPlotsX.Plot + @show marker.options.dict |> keys + @test marker.options["mark"] == "none" + @test marker.options["mark options"]["color"] == convert(RGBA{Float64}, colorant"green") + @test marker.options["mark options"]["line width"] == 1 + + # TODO: marker stroke color is incorrect end # testset @testset "Plot in pieces" begin plot(rand(100) / 3, reg=true, fill=(0, :green)) From d43e53f8961c15d13150598d5a44bbced84866b0 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 18:10:30 +0100 Subject: [PATCH 037/184] tests for marker-stroke-color --- src/backends/pgfplotsx.jl | 2 -- test/test_pgfplotsx.jl | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c0c6e05e..4995feb5 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -149,8 +149,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) # treat segments segments = iter_segments(series) segment_opt = PGFPlotsX.Options() - # @show get_markerstrokecolor(opt, 1) - # @show get_markercolor(opt,1) for (i, rng) in enumerate(segments) seg_args = (arg[rng] for arg in args) segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 7a8c320a..5ffd62c8 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -37,11 +37,10 @@ end axis = Plots.pgfx_axes(pl.o)[1] @test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5 @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 104 # each marker is its own plot - marker = axis.contents[5] + marker = axis.contents[14] @test marker isa PGFPlotsX.Plot - @show marker.options.dict |> keys - @test marker.options["mark"] == "none" - @test marker.options["mark options"]["color"] == convert(RGBA{Float64}, colorant"green") + @test marker.options["mark"] == "*" + @test marker.options["mark options"]["color"] == RGBA{Float64}( colorant"green", 0.8) @test marker.options["mark options"]["line width"] == 1 # TODO: marker stroke color is incorrect From fe7765905829c49ae685779f634571cd926ce2f4 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 11:11:05 +0100 Subject: [PATCH 038/184] remove point meta --- src/backends/pgfplotsx.jl | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4995feb5..ac088762 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -129,10 +129,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => opt[:linecolor], ) - if opt[:marker_z] !== nothing - push!(series_opt, "point meta" => "explicit") - push!(series_opt, "scatter" => nothing) - end if is3d(series) series_func = PGFPlotsX.Plot3 else @@ -158,13 +154,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end segment_plot = series_func( merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(seg_args..., - meta = if !isnothing(opt[:marker_z]) - opt[:marker_z][rng] - else - nothing - end - ), + PGFPlotsX.Coordinates(seg_args...), series[:fillrange] !== nothing ? "\\closedcycle" : "{}" ) push!(axis, segment_plot) From b6e641c035a8fa9900530ae2a9513a1e8b513ae9 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 11:31:33 +0100 Subject: [PATCH 039/184] adjust color bar limits --- src/backends/pgfplotsx.jl | 20 +++++++++++++++----- test/test_pgfplotsx.jl | 2 -- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index ac088762..53ffbfe7 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -88,13 +88,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end @label colorbar_end - # detect fillranges - # if any(series->series[:fillrange] != nothing, series_list(sp)) - # PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween},\n") - # end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( - "title" => sp[:colorbar_title] + "title" => sp[:colorbar_title], ) ) axisf = if sp[:projection] == :polar @@ -110,6 +106,20 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) for series in series_list(sp) opt = series.plotattributes + if opt[:marker_z] !== nothing + cbar_style = axis_opt["colorbar style"] + if !haskey( cbar_style.dict, "point meta max" ) + append!( axis_opt["colorbar style"], + ( + "point meta max" => maximum(opt[:marker_z]), + "point meta min" => minimum(opt[:marker_z]) + ) + ) + else + cbar_style["point meta max"] = maximum(opt[:marker_z]) + cbar_style["point meta min"] = minimum(opt[:marker_z]) + end + end st = series[:seriestype] # function args args = if st == :contour diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 5ffd62c8..21074e93 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -42,8 +42,6 @@ end @test marker.options["mark"] == "*" @test marker.options["mark options"]["color"] == RGBA{Float64}( colorant"green", 0.8) @test marker.options["mark options"]["line width"] == 1 - - # TODO: marker stroke color is incorrect end # testset @testset "Plot in pieces" begin plot(rand(100) / 3, reg=true, fill=(0, :green)) From e1e8a480f9e5fbe5b63baff7b8db47cbb87ab26b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 12:34:09 +0100 Subject: [PATCH 040/184] fix polar plots --- src/backends/pgfplotsx.jl | 31 ++++++++++++++++++++----------- test/test_pgfplotsx.jl | 1 - 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 53ffbfe7..66fc5f02 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -18,14 +18,18 @@ end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created cols, rows = size(plt.layout.grid) - the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot( - PGFPlotsX.Options( - "group style" => PGFPlotsX.Options( - "group size" => string(cols)*" by "*string(rows) + the_plot = PGFPlotsX.TikzPicture() + # the combination of groupplot and polaraxis is broken in pgfplots + if !any( sp -> ispolar(sp), plt.subplots ) + push!( the_plot, PGFPlotsX.GroupPlot( + PGFPlotsX.Options( + "group style" => PGFPlotsX.Options( + "group size" => string(cols)*" by "*string(rows) + ) + ) ) ) - )) - + end pushed_colormap = false for sp in plt.subplots bb = bbox(sp) @@ -121,6 +125,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end st = series[:seriestype] + series_opt = PGFPlotsX.Options( + "color" => opt[:linecolor], + ) # function args args = if st == :contour opt[:z].surf, opt[:x], opt[:y] @@ -136,9 +143,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else opt[:x], opt[:y] end - series_opt = PGFPlotsX.Options( - "color" => opt[:linecolor], - ) if is3d(series) series_func = PGFPlotsX.Plot3 else @@ -183,7 +187,12 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end end - push!( the_plot.elements[1], axis ) + if ispolar(sp) + axes = the_plot + else + axes = the_plot.elements[1] + end + push!( axes, axis ) if length(plt.o.the_plot.elements) > 0 plt.o.the_plot.elements[1] = the_plot else @@ -570,7 +579,7 @@ end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) _update_plot_object(plt) - PGFPlotsX.print_tex(plt.o.the_plot) + PGFPlotsX.print_tex(io, plt.o.the_plot) end function _display(plt::Plot{PGFPlotsXBackend}) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 21074e93..4eeeddf7 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -65,7 +65,6 @@ end Θ = range(0, stop=1.5π, length=100) r = abs.(0.1 * randn(100) + sin.(3Θ)) plot(Θ, r, proj=:polar, m=2) - # TODO: handle polar plots end # testset @testset "Histogram 2D" begin histogram2d(randn(10000), randn(10000), nbins=20) From 92aafb1349e583ef1c5b1629a058b1dc81ce1ad3 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 13:03:37 +0100 Subject: [PATCH 041/184] padding of grouplots --- src/backends/pgfplotsx.jl | 11 ++++++++++- test/test_pgfplotsx.jl | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 66fc5f02..0764606e 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -24,7 +24,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!( the_plot, PGFPlotsX.GroupPlot( PGFPlotsX.Options( "group style" => PGFPlotsX.Options( - "group size" => string(cols)*" by "*string(rows) + "group size" => string(cols)*" by "*string(rows), + "horizontal sep" => string(maximum(sp -> sp.minpad[1], plt.subplots)), + "vertical sep" => string(maximum(sp -> sp.minpad[2], plt.subplots)), ) ) ) @@ -550,6 +552,13 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) +# Set the (left, top, right, bottom) minimum padding around the plot area +# to fit ticks, tick labels, guides, colorbars, etc. +function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) + # TODO: make padding more intelligent + sp.minpad = (20mm, 5mm, 2mm, 10mm) +end + function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsXPlot() end diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 4eeeddf7..68002222 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -59,7 +59,6 @@ end end # testset @testset "Layout" begin plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black]) - # TODO: no extra space for outer legends end # testset @testset "Polar plots" begin Θ = range(0, stop=1.5π, length=100) From 48208998e2079d12cc222caee0416351cc654dc2 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 13:06:22 +0100 Subject: [PATCH 042/184] remove unneccesary code --- src/backends/pgfplotsx.jl | 49 --------------------------------------- 1 file changed, 49 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 0764606e..07da6b69 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -368,55 +368,6 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) "{$(val.str).};" ]) end -## -------------------------------------------------------------------------------------- -# TODO: translate these if needed -function pgfx_fillrange_series(series, i, fillrange, args...) - st = series[:seriestype] - opt = PGFPlotsX.Options() - push!(opt, "line width" => 0) - push!(opt, "draw opacity" => 0) - opt = merge(opt, pgfx_fillstyle(series, i)) - opt = merge(opt, pgfx_marker(series, i)) - push!(opt, "forget plot" => nothing) - if haskey(_pgfx_series_extrastyle, st) - push!(opt, _pgfx_series_extrastyle[st] => nothing) - end - func = is3d(series) ? PGFPlotsX.Plot3 : PGFPlotsX.Plot - return func(opt, PGFPlotsX.Coordinates(pgfx_fillrange_args(fillrange, args...)...)) -end - -function pgfx_fillrange_args(fillrange, x, y) - n = length(x) - x_fill = [x; x[n:-1:1]; x[1]] - y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] - return x_fill, y_fill -end - -function pgfx_fillrange_args(fillrange, x, y, z) - n = length(x) - x_fill = [x; x[n:-1:1]; x[1]] - y_fill = [y; y[n:-1:1]; x[1]] - z_fill = [z; _cycle(fillrange, n:-1:1); z[1]] - return x_fill, y_fill, z_fill -end - -function pgfx_fill_legend_hack(plotattributes, args) - opt = PGFPlotsX.Options("area legend" => nothing) - opt = merge(opt, pgfx_linestyle(plotattributes, 1)) - opt = merge(opt, pgfx_marker(plotattributes, 1)) - opt = merge(opt, pgfx_fillstyle(plotattributes, 1)) - st = plotattributes[:seriestype] - func = if st == :path3d - PGFPlotsX.Plot3 - else - PGFPlotsX.Plot - end - if st == :scatter - push!(opt, "only marks" => nothing) - end - return func(opt, PGFPlotsX.Coordinates(([arg[1]] for arg in args)...)) -end - # -------------------------------------------------------------------------------------- function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) axis = sp[Symbol(letter,:axis)] From 1e23b8d475a277c280b84dac5b09df9ea62a26c2 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 14:37:39 +0100 Subject: [PATCH 043/184] basic contour --- src/backends/pgfplotsx.jl | 66 ++++++++++++++++++++++----------------- test/test_pgfplotsx.jl | 9 +++++- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 07da6b69..bdb7b7f9 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,5 @@ -# PGFPlotsX.print_tex(io::IO, data::Symbol) = PGFPlotsX.print_tex(io, string(data)) +using Contour: Contour +# PGFPlotsX.print_tex(io::IO, data::ColorGradient) = write(io, pgfx_colormap(data)) Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false was_shown::Bool = false @@ -132,7 +133,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) # function args args = if st == :contour - opt[:z].surf, opt[:x], opt[:y] + opt[:x], opt[:y], opt[:z].surf' elseif is3d(st) opt[:x], opt[:y], opt[:z] elseif st == :straightline @@ -158,35 +159,44 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if haskey(_pgfx_series_extrastyle, st) push!(series_opt, _pgfx_series_extrastyle[st] => nothing) end - # treat segments - segments = iter_segments(series) - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - seg_args = (arg[rng] for arg in args) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - if st == :shape || series[:fillrange] !== nothing - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - segment_plot = series_func( - merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(seg_args...), - series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + if st == :contour + surface_opt = PGFPlotsX.Options( + "contour prepared" => nothing ) - push!(axis, segment_plot) - # add to legend? - if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + surface_plot = series_func( + # merge(series_opt, surface_opt), + surface_opt, + PGFPlotsX.Table(Contour.contours(args...)) + ) + push!(axis, surface_plot) + else + # treat segments + segments = iter_segments(series) + segment_opt = PGFPlotsX.Options() + for (i, rng) in enumerate(segments) + seg_args = (arg[rng] for arg in args) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + if st == :shape || series[:fillrange] !== nothing + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + segment_plot = series_func( + merge(series_opt, segment_opt), + PGFPlotsX.Coordinates(seg_args...), + series[:fillrange] !== nothing ? "\\closedcycle" : "{}" ) + push!(axis, segment_plot) + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end + end + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end - end - # TODO: different seriestypes, histogramms, contours, etc. - # TODO: colorbars - # TODO: gradients - # add series annotations - anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) - pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end end if ispolar(sp) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 68002222..de775c32 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -65,6 +65,13 @@ end r = abs.(0.1 * randn(100) + sin.(3Θ)) plot(Θ, r, proj=:polar, m=2) end # testset + @testset "Drawing shapes" begin + verts = [(-1.0, 1.0), (-1.28, 0.6), (-0.2, -1.4), (0.2, -1.4), (1.28, 0.6), (1.0, 1.0), (-1.0, 1.0), (-0.2, -0.6), (0.0, -0.2), (-0.4, 0.6), (1.28, 0.6), (0.2, -1.4), (-0.2, -1.4), (0.6, 0.2), (-0.2, 0.2), (0.0, -0.2), (0.2, 0.2), (-0.2, -0.6)] + x = 0.1:0.2:0.9 + y = 0.7 * rand(5) .+ 0.15 + plot(x, y, line=(3, :dash, :lightblue), marker=(Shape(verts), 30, RGBA(0, 0, 0, 0.2)), bg=:pink, fg=:darkblue, xlim=(0, 1), ylim=(0, 1), leg=false) + # TODO: draw those polygons + end # testset @testset "Histogram 2D" begin histogram2d(randn(10000), randn(10000), nbins=20) # TODO: totally broken, errors also for pgfplots @@ -78,8 +85,8 @@ end X = repeat(reshape(x, 1, :), length(y), 1) Y = repeat(y, 1, length(x)) Z = map(f, X, Y) - p1 = contour(x, y, f, fill=true) p2 = contour(x, y, Z) + p1 = contour(x, y, f, fill=true) plot(p1, p2) # TODO: totally broken, also errors for pgfplots end # testset From 31bc74e2b1b5dc7ec2c9eaf8b78d3648f11229e8 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 15:07:48 +0100 Subject: [PATCH 044/184] filled contours are difficult --- src/backends/pgfplotsx.jl | 20 ++++++++++++++++---- test/test_pgfplotsx.jl | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index bdb7b7f9..a523cc48 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -151,7 +151,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else series_func = PGFPlotsX.Plot end - if series[:fillrange] !== nothing + if series[:fillrange] !== nothing && st != :contour series_opt = merge(series_opt, pgfx_fillstyle(opt)) push!(series_opt, "area legend" => nothing) end @@ -160,13 +160,25 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!(series_opt, _pgfx_series_extrastyle[st] => nothing) end if st == :contour + if !isfilledcontour(series) surface_opt = PGFPlotsX.Options( - "contour prepared" => nothing - ) + "contour prepared" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ) + ) + else + error("PGFPlotsX backend does not support filled contours at the moment.") + surface_opt = PGFPlotsX.Options( + "contour filled" => PGFPlotsX.Options( + # "levels" => opt[:levels], + # "labels" => opt[:contour_labels], + ) + ) + end surface_plot = series_func( # merge(series_opt, surface_opt), surface_opt, - PGFPlotsX.Table(Contour.contours(args...)) + PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) ) push!(axis, surface_plot) else diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index de775c32..e0a2eacd 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -88,6 +88,6 @@ end p2 = contour(x, y, Z) p1 = contour(x, y, f, fill=true) plot(p1, p2) - # TODO: totally broken, also errors for pgfplots + # TODO: filled contours end # testset end # testset From 48c04a5a44150202557f85f1ff317c7409b54c3f Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 15:45:35 +0100 Subject: [PATCH 045/184] more than one colorbar --- src/backends/pgfplotsx.jl | 42 +++++++++++---------------------------- test/test_pgfplotsx.jl | 12 +++++++++++ 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index a523cc48..54f8b341 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,5 @@ using Contour: Contour +using StatsBase: Histogram, fit # PGFPlotsX.print_tex(io::IO, data::ColorGradient) = write(io, pgfx_colormap(data)) Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false @@ -33,7 +34,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) ) end - pushed_colormap = false for sp in plt.subplots bb = bbox(sp) cstr = plot_color(sp[:background_color_legend]) @@ -65,36 +65,16 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_axis!(axis_opt, sp, letter) end end - # Search series for any gradient. In case one series uses a gradient set - # the colorbar and colomap. - # The reasoning behind doing this on the axis level is that pgfplots - # colorbar seems to only works on axis level and needs the proper colormap for - # correctly displaying it. - # It's also possible to assign the colormap to the series itself but - # then the colormap needs to be added twice, once for the axis and once for the - # series. - # As it is likely that all series within the same axis use the same - # colormap this should not cause any problem. - for series in series_list(sp) - for col in (:markercolor, :fillcolor, :linecolor) - if typeof(series.plotattributes[col]) == ColorGradient - if !pushed_colormap - PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ - colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, - }""") - pushed_colormap = true - push!(axis_opt, - "colorbar" => nothing, - "colormap name" => "plots", - ) - end - - # goto is needed to break out of col and series for - @goto colorbar_end - end - end + if hascolorbar(sp) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + pushed_colormap = true + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots$(sp.attr[:subplot_index])", + ) end - @label colorbar_end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title], @@ -181,6 +161,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) ) push!(axis, surface_plot) + elseif st == :histogram2d + hist_ else # treat segments segments = iter_segments(series) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index e0a2eacd..3d96360d 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -90,4 +90,16 @@ end plot(p1, p2) # TODO: filled contours end # testset + @testset "Varying colors" begin + t = range(0, stop=1, length=100) + θ = (6π) .* t + x = t .* cos.(θ) + y = t .* sin.(θ) + p1 = plot(x, y, line_z=t, linewidth=3, legend=false) + p2 = scatter(x, y, marker_z=((x, y)->begin + x + y + end), color=:bluesreds, legend=false) + plot(p1, p2) + # TODO: handle gradients as color + end # testset end # testset From d47e8c0f44fe597300f4c72913af48af3450a9a8 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 16:07:08 +0100 Subject: [PATCH 046/184] simplifications --- src/backends/pgfplotsx.jl | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 54f8b341..33a2d98a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -78,6 +78,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title], + "point meta max" => get_clims(sp)[2], + "point meta min" => get_clims(sp)[1] ) ) axisf = if sp[:projection] == :polar @@ -93,20 +95,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) for series in series_list(sp) opt = series.plotattributes - if opt[:marker_z] !== nothing - cbar_style = axis_opt["colorbar style"] - if !haskey( cbar_style.dict, "point meta max" ) - append!( axis_opt["colorbar style"], - ( - "point meta max" => maximum(opt[:marker_z]), - "point meta min" => minimum(opt[:marker_z]) - ) - ) - else - cbar_style["point meta max"] = maximum(opt[:marker_z]) - cbar_style["point meta min"] = minimum(opt[:marker_z]) - end - end st = series[:seriestype] series_opt = PGFPlotsX.Options( "color" => opt[:linecolor], @@ -147,7 +135,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) ) else - error("PGFPlotsX backend does not support filled contours at the moment.") + notimpl() surface_opt = PGFPlotsX.Options( "contour filled" => PGFPlotsX.Options( # "levels" => opt[:levels], From 7bf89d86141e4f3c9629fd5138f7053755daab2d Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 16:46:15 +0100 Subject: [PATCH 047/184] subplot annotations --- src/backends/pgfplotsx.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 33a2d98a..325d1047 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -18,6 +18,7 @@ function Base.push!(pgfx_plot::PGFPlotsXPlot, item) end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) + # TODO: annotations! does not trigger _series_added ... if !pgfx_plot.is_created cols, rows = size(plt.layout.grid) the_plot = PGFPlotsX.TikzPicture() @@ -180,6 +181,11 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end end + # add subplot annotations + anns = sp.attr[:annotations] + for (xi,yi,txt) in anns + pgfx_add_annotation!(axis, xi, yi, txt) + end end if ispolar(sp) axes = the_plot From 0e94e572633074d10bdb496e4bf9db89cda18b69 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 16:52:35 +0100 Subject: [PATCH 048/184] total plot size --- src/backends/pgfplotsx.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 325d1047..267915d7 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -24,13 +24,16 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) the_plot = PGFPlotsX.TikzPicture() # the combination of groupplot and polaraxis is broken in pgfplots if !any( sp -> ispolar(sp), plt.subplots ) + pl_height, pl_width = plt.attr[:size] push!( the_plot, PGFPlotsX.GroupPlot( PGFPlotsX.Options( "group style" => PGFPlotsX.Options( "group size" => string(cols)*" by "*string(rows), "horizontal sep" => string(maximum(sp -> sp.minpad[1], plt.subplots)), "vertical sep" => string(maximum(sp -> sp.minpad[2], plt.subplots)), - ) + ), + "height" => pl_height > 0 ? string(pl_height)*"px" : "{}", + "width" => pl_width > 0 ? string(pl_width)*"px" : "{}", ) ) ) From 4dd4d5eb5f0a490813192d0f78d24c7d4f588abb Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 19:10:58 +0100 Subject: [PATCH 049/184] working heatmap --- src/backends.jl | 2 +- src/backends/pgfplotsx.jl | 75 ++++++++++++++++++++++++++++++++------- test/test_pgfplotsx.jl | 15 +++++++- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index d2ae4894..87f4dda8 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -711,7 +711,7 @@ const _pgfplotsx_attr = merge_with_base_supported([ # :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, # :shape # ] -const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] +const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :heatmap, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _pgfplotsx_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :ltriangle, :rtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline, Shape] const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 267915d7..81cabf23 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -9,6 +9,19 @@ end pgfx_axes(pgfx_plot::PGFPlotsXPlot) = pgfx_plot.the_plot.elements[1].elements[1].contents +function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) + a = Array(s) + xn = Vector{eltype(x)}(undef, length(a)) + yn = Vector{eltype(y)}(undef, length(a)) + zn = Vector{eltype(s)}(undef, length(a)) + for (n, (i, j)) in enumerate(Tuple.(CartesianIndices(a))) + xn[n] = x[j] + yn[n] = y[i] + zn[n] = a[i,j] + end + return xn, yn, zn +end + function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) show(io::IO, mime, pgfx_plot.the_plot) end @@ -69,16 +82,32 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_axis!(axis_opt, sp, letter) end end - if hascolorbar(sp) - PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ - colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, - }""") - pushed_colormap = true - push!(axis_opt, - "colorbar" => nothing, - "colormap name" => "plots$(sp.attr[:subplot_index])", - ) - end + # Search series for any gradient. In case one series uses a gradient set + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots$(sp.attr[:subplot_index])", + ) + # goto is needed to break out of col and series for + @goto colorbar_end + end + end + end + @label colorbar_end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title], @@ -101,11 +130,13 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) opt = series.plotattributes st = series[:seriestype] series_opt = PGFPlotsX.Options( - "color" => opt[:linecolor], + "color" => single_color(opt[:linecolor]), ) # function args args = if st == :contour opt[:x], opt[:y], opt[:z].surf' + elseif st == :heatmap + surface_to_vecs(opt[:x], opt[:y], opt[:z]) elseif is3d(st) opt[:x], opt[:y], opt[:z] elseif st == :straightline @@ -153,8 +184,21 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) ) push!(axis, surface_plot) - elseif st == :histogram2d - hist_ + elseif st == :heatmap + # TODO: global view setting + push!(axis.options, + "view" => "{0}{90}", + "shader" => "flat corner", + ) + heatmap_opt = PGFPlotsX.Options( + "surf" => nothing, + "mesh/rows" => length(opt[:x]) + ) + heatmap_plot = PGFPlotsX.Plot3( + merge(series_opt, heatmap_opt), + PGFPlotsX.Table(args) + ) + push!(axis, heatmap_plot) else # treat segments segments = iter_segments(series) @@ -273,6 +317,11 @@ function pgfx_colormap(grad::ColorGradient) @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) end,"\n") end +function pgfx_colormap(grad::Vector{<:Colorant}) + join(map(grad) do c + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) + end,"\n") +end function pgfx_framestyle(style::Symbol) if style in _pgfx_framestyles diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 3d96360d..aa21ef71 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -74,7 +74,20 @@ end end # testset @testset "Histogram 2D" begin histogram2d(randn(10000), randn(10000), nbins=20) - # TODO: totally broken, errors also for pgfplots + # TODO: should work, when heatmaps works? + end # testset + @testset "Heatmap" begin + xs = [string("x", i) for i = 1:10] + ys = [string("y", i) for i = 1:4] + z = float((1:4) * reshape(1:10, 1, :)) + pgfx_plot = heatmap(xs, ys, z, aspect_ratio=1) + Plots._update_plot_object(pgfx_plot) + if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" + end + # TODO: wrong colors + # TODO: lines instead of patches end # testset @testset "Contours" begin x = 1:0.5:20 From 5694ce53f65b12994d70b40c142f315f3cbe37c8 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 22:28:36 +0100 Subject: [PATCH 050/184] 3D view --- src/backends/pgfplotsx.jl | 4 ++++ test/test_pgfplotsx.jl | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 81cabf23..e2c08795 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -115,6 +115,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "point meta min" => get_clims(sp)[1] ) ) + if is3d(sp) + azim, elev = sp[:camera] + push!( axis_opt, "view" => (azim, elev) ) + end axisf = if sp[:projection] == :polar # TODO: this errors for some reason # push!(axis_opt, "xmin" => 90) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index aa21ef71..125ee529 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -86,8 +86,6 @@ end @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" end - # TODO: wrong colors - # TODO: lines instead of patches end # testset @testset "Contours" begin x = 1:0.5:20 From e2306868512525674fa29baa3d160ea9ee1a9779 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 22:34:14 +0100 Subject: [PATCH 051/184] fix gradient scatter plot --- src/backends/pgfplotsx.jl | 2 +- test/test_pgfplotsx.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index e2c08795..560b559a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -364,7 +364,7 @@ end function pgfx_linestyle(plotattributes, i = 1) lw = pgfx_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i) - lc = get_linecolor(plotattributes, i) + lc = single_color(get_linecolor(plotattributes, i)) la = get_linealpha(plotattributes, i) ls = get_linestyle(plotattributes, i) return pgfx_linestyle(lw, lc, la, ls) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 125ee529..a2a96681 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -111,6 +111,6 @@ end x + y end), color=:bluesreds, legend=false) plot(p1, p2) - # TODO: handle gradients as color + # TODO: questionable tiling end # testset end # testset From 04e5ff7ebacb156443e183768a5e8642100dc672 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 00:23:47 +0100 Subject: [PATCH 052/184] quiver plots --- src/backends/pgfplotsx.jl | 44 ++++++++++++++++++++++++++++++++++++--- test/test_pgfplotsx.jl | 12 +++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 560b559a..616c2756 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -5,6 +5,11 @@ Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false was_shown::Bool = false the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() + function PGFPlotsXPlot(is_created, was_shown, the_plot) + pgfx_plot = new(is_created, was_shown, the_plot) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}") + pgfx_plot + end end pgfx_axes(pgfx_plot::PGFPlotsXPlot) = pgfx_plot.the_plot.elements[1].elements[1].contents @@ -214,9 +219,21 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if st == :shape || series[:fillrange] !== nothing segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end + x, y = collect(seg_args) + coordinates = if opt[:quiver] !== nothing + push!(segment_opt, "quiver" => PGFPlotsX.Options( + "u" => "\\thisrow{u}", + "v" => "\\thisrow{v}", + pgfx_arrow(opt[:arrow]) => nothing + ), + ) + PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) + else + PGFPlotsX.Coordinates(seg_args...) + end segment_plot = series_func( merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(seg_args...), + coordinates, series[:fillrange] !== nothing ? "\\closedcycle" : "{}" ) push!(axis, segment_plot) @@ -255,7 +272,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end ## - const _pgfplotsx_linestyles = KW( :solid => "solid", :dash => "dashed", @@ -316,6 +332,27 @@ const _pgfx_annotation_halign = KW( ## -------------------------------------------------------------------------------------- # Generates a colormap for pgfplots based on a ColorGradient # TODO: maybe obsolete +pgfx_arrow(::Nothing) = "-" +function pgfx_arrow( arr::Arrow ) + components = String[] + head = String[] + push!(head, "{stealth[length = $(arr.headlength)pt, width = $(arr.headwidth)pt") + if arr.style == :open + push!(head, ", open") + end + push!(head, "]}") + head = join(head, "") + if arr.side == :both || arr.side == :tail + push!( components, head ) + end + push!(components, "-") + if arr.side == :both || arr.side == :head + push!( components, head ) + end + components = join( components, "" ) + return "every arrow/.append style={$(components)}" +end + function pgfx_colormap(grad::ColorGradient) join(map(grad.colors) do c @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) @@ -561,7 +598,8 @@ end # to fit ticks, tick labels, guides, colorbars, etc. function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) # TODO: make padding more intelligent - sp.minpad = (20mm, 5mm, 2mm, 10mm) + # order: right, top, left, bottom + sp.minpad = (20mm, 12mm, 2mm, 10mm) end function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index a2a96681..35a1b05f 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -113,4 +113,16 @@ end plot(p1, p2) # TODO: questionable tiling end # testset + @testset "Framestyles" begin + scatter(fill(randn(10), 6), fill(randn(10), 6), framestyle=[:box :semi :origin :zerolines :grid :none], title=[":box" ":semi" ":origin" ":zerolines" ":grid" ":none"], color=permutedims(1:6), layout=6, label="", markerstrokewidth=0, ticks=-2:2) + # TODO: support :semi + end # testset + @testset "Quiver" begin + x = -2pi:0.2:2*pi + y = sin.(x) + + u = ones(length(x)) + v = cos.(x) + plot( x, y, quiver = (u, v), arrow = true ) + end # testset end # testset From 5482cfac3f2b789075360bb8b2b86ccd9068256b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 00:45:14 +0100 Subject: [PATCH 053/184] extra styles for 3dTypes --- src/backends.jl | 13 ++++++------- src/backends/pgfplotsx.jl | 6 +++++- test/test_pgfplotsx.jl | 1 + 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 87f4dda8..1d4b3482 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -705,13 +705,12 @@ const _pgfplotsx_attr = merge_with_base_supported([ :camera, :contour_labels, ]) -# const _pgfplotsx_seriestype = [ -# :path, :scatter, :straightline, -# :heatmap, :pie, :image, -# :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, -# :shape -# ] -const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :heatmap, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] +const _pgfplotsx_seriestype = + [:path, :scatter, :straightline, + :path3d, :scatter3d, :surface, :wireframe, :volume, + :heatmap, :contour, :histogram2d, + :shape, + :steppre, :stepmid, :steppost, :ysticks, :xsticks] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _pgfplotsx_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :ltriangle, :rtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline, Shape] const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 616c2756..af67917b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -316,7 +316,11 @@ const _pgfx_series_extrastyle = KW( :ysticks => "ycomb", :xsticks => "xcomb", :scatter => "only marks", - :shape => "area legends" + :shape => "area legends", + :scatter3D => "only marks" + :surface => "surf", + :wireframe => "mesh", + :volume => "patch" ) const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 35a1b05f..5af30606 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -124,5 +124,6 @@ end u = ones(length(x)) v = cos.(x) plot( x, y, quiver = (u, v), arrow = true ) + # TODO: could adjust limits to fit arrows if too long, but how? end # testset end # testset From 3b56977c498697e241b206acaba4a1403cbc9e30 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 00:54:16 +0100 Subject: [PATCH 054/184] fix arrow = false --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index af67917b..f97f6e4a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -336,7 +336,7 @@ const _pgfx_annotation_halign = KW( ## -------------------------------------------------------------------------------------- # Generates a colormap for pgfplots based on a ColorGradient # TODO: maybe obsolete -pgfx_arrow(::Nothing) = "-" +pgfx_arrow(::Nothing) = "every arrow/.append style={-}" function pgfx_arrow( arr::Arrow ) components = String[] head = String[] From e176c6c315c377842212821d8acd30ebdd27ccc7 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 00:58:03 +0100 Subject: [PATCH 055/184] add patchlibrary --- src/backends/pgfplotsx.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index f97f6e4a..90d97d35 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -8,6 +8,7 @@ Base.@kwdef mutable struct PGFPlotsXPlot function PGFPlotsXPlot(is_created, was_shown, the_plot) pgfx_plot = new(is_created, was_shown, the_plot) PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}") pgfx_plot end end From fa324561dacbcf2178f82714123b3326dbaccd6e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 13:50:18 +0100 Subject: [PATCH 056/184] restructure --- src/backends/pgfplotsx.jl | 232 ++++++++++++++++++++++---------------- test/test_pgfplotsx.jl | 6 + 2 files changed, 138 insertions(+), 100 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 90d97d35..17129cbd 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -142,24 +142,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => single_color(opt[:linecolor]), ) - # function args - args = if st == :contour - opt[:x], opt[:y], opt[:z].surf' - elseif st == :heatmap - surface_to_vecs(opt[:x], opt[:y], opt[:z]) - elseif is3d(st) - opt[:x], opt[:y], opt[:z] - elseif st == :straightline - straightline_data(series) - elseif st == :shape - shape_data(series) - elseif ispolar(sp) - theta, r = opt[:x], opt[:y] - rad2deg.(theta), r - else - opt[:x], opt[:y] - end - if is3d(series) + if is3d(series) || st == :heatmap series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot @@ -168,82 +151,56 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = merge(series_opt, pgfx_fillstyle(opt)) push!(series_opt, "area legend" => nothing) end - # include additional style - if haskey(_pgfx_series_extrastyle, st) - push!(series_opt, _pgfx_series_extrastyle[st] => nothing) - end - if st == :contour - if !isfilledcontour(series) - surface_opt = PGFPlotsX.Options( - "contour prepared" => PGFPlotsX.Options( - "labels" => opt[:contour_labels], - ) - ) - else - notimpl() - surface_opt = PGFPlotsX.Options( - "contour filled" => PGFPlotsX.Options( - # "levels" => opt[:levels], - # "labels" => opt[:contour_labels], - ) - ) - end - surface_plot = series_func( - # merge(series_opt, surface_opt), - surface_opt, - PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) - ) - push!(axis, surface_plot) - elseif st == :heatmap - # TODO: global view setting + if st == :heatmap push!(axis.options, "view" => "{0}{90}", "shader" => "flat corner", ) - heatmap_opt = PGFPlotsX.Options( - "surf" => nothing, - "mesh/rows" => length(opt[:x]) - ) - heatmap_plot = PGFPlotsX.Plot3( - merge(series_opt, heatmap_opt), - PGFPlotsX.Table(args) - ) - push!(axis, heatmap_plot) - else - # treat segments - segments = iter_segments(series) - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - seg_args = (arg[rng] for arg in args) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + end + # treat segments + segments = if iscontour(series) || st == :heatmap + iter_segments(series[:x], series[:y]) + else + iter_segments(series) + end + segment_opt = PGFPlotsX.Options() + for (i, rng) in enumerate(segments) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + if !iscontour(series) && !(st == :heatmap) segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - if st == :shape || series[:fillrange] !== nothing - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - x, y = collect(seg_args) - coordinates = if opt[:quiver] !== nothing - push!(segment_opt, "quiver" => PGFPlotsX.Options( - "u" => "\\thisrow{u}", - "v" => "\\thisrow{v}", - pgfx_arrow(opt[:arrow]) => nothing - ), - ) - PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) - else - PGFPlotsX.Coordinates(seg_args...) - end - segment_plot = series_func( - merge(series_opt, segment_opt), - coordinates, - series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + end + if st == :shape || series[:fillrange] !== nothing + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + if iscontour(series) + if !isfilledcontour(series) + push!(series_opt, + "contour prepared" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ) ) - push!(axis, segment_plot) - # add to legend? - if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + else + notimpl() + push!(series_opt, + "contour filled" => PGFPlotsX.Options( + # "levels" => opt[:levels], + # "labels" => opt[:contour_labels], + ) ) end end + coordinates = pgfx_series_coordinates!( sp, st, segment_opt, opt, rng ) + segment_plot = series_func( + merge(series_opt, segment_opt), + coordinates, + series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + ) + push!(axis, segment_plot) + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end # add series annotations anns = series[:series_annotations] for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) @@ -271,6 +228,96 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_plot.is_created = true end end +## seriestype specifics +@inline function pgfx_series_coordinates!(sp, st, segment_opt, opt, rng) + # function args + args = if st == :contour + opt[:x], opt[:y], opt[:z].surf' + elseif st == :heatmap + surface_to_vecs(opt[:x], opt[:y], opt[:z]) + elseif is3d(st) + opt[:x], opt[:y], opt[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = opt[:x], opt[:y] + rad2deg.(theta), r + else + opt[:x], opt[:y] + end + seg_args = if st == :contour || st == :heatmap + args + else + (arg[rng] for arg in args) + end + if opt[:quiver] !== nothing + push!(segment_opt, "quiver" => PGFPlotsX.Options( + "u" => "\\thisrow{u}", + "v" => "\\thisrow{v}", + pgfx_arrow(opt[:arrow]) => nothing + ), + ) + x, y = collect(seg_args) + return PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) + else + pgfx_series_coordinates!(Val(st), segment_opt, opt, seg_args) + end +end +function pgfx_series_coordinates!(st_val::Union{Val{:path}, Val{:path3d}}, segment_opt, opt, args) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Union{Val{:scatter}, Val{:scatter3d}}, segment_opt, opt, args) + push!( segment_opt, "only marks" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) + push!(segment_opt, + "surf" => nothing, + "mesh/rows" => length(opt[:x]) + ) + return PGFPlotsX.Table(args...) +end +function pgfx_series_coordinates!(st_val::Val{:stepre}, segment_opt, opt, args) + push!( segment_opt, "const plot mark right" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:stepmid}, segment_opt, opt, args) + push!( segment_opt, "const plot mark mid" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:steppost}, segment_opt, opt, args) + push!( segment_opt, "const plot" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Union{Val{:ysticks},Val{:sticks}}, segment_opt, opt, args) + push!( segment_opt, "ycomb" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) + push!( segment_opt, "xcomb" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) + push!( segment_opt, "surf" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:volume}, segment_opt, opt, args) + push!( segment_opt, "patch" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, args) + push!( segment_opt, "mesh" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) + push!( segment_opt, "area legends" => nothing, "patch" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:contour}, segment_opt, opt, args) + return PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) +end ## const _pgfplotsx_linestyles = KW( @@ -309,21 +356,6 @@ const _pgfplotsx_legend_pos = KW( :outertopright => "outer north east", ) -const _pgfx_series_extrastyle = KW( - :steppre => "const plot mark right", - :stepmid => "const plot mark mid", - :steppost => "const plot", - :sticks => "ycomb", - :ysticks => "ycomb", - :xsticks => "xcomb", - :scatter => "only marks", - :shape => "area legends", - :scatter3D => "only marks" - :surface => "surf", - :wireframe => "mesh", - :volume => "patch" -) - const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] const _pgfx_framestyle_defaults = Dict(:semi => :box) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 5af30606..b8f6b146 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -126,4 +126,10 @@ end plot( x, y, quiver = (u, v), arrow = true ) # TODO: could adjust limits to fit arrows if too long, but how? end # testset + @testset "Annotations" begin + y = rand(10) + plot(y, annotations=(3, y[3], Plots.text("this is \\#3", :left)), leg=false) + annotate!([(5, y[5], Plots.text("this is \\#5", 16, :red, :center)), (10, y[10], Plots.text("this is \\#10", :right, 20, "courier"))]) + scatter!(range(2, stop=8, length=6), rand(6), marker=(50, 0.2, :orange), series_annotations=["series", "annotations", "map", "to", "series", Plots.text("data", :green)]) + end # testset end # testset From 229f74e370b304ae7babf9dd3fc58b99c906549c Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 14:05:34 +0100 Subject: [PATCH 057/184] surface plots --- src/backends/pgfplotsx.jl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 17129cbd..ecf0833a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -166,7 +166,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - if !iscontour(series) && !(st == :heatmap) + if opt[:markershape] != :none #|| !iscontour(series) && !(st == :heatmap) segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end if st == :shape || series[:fillrange] !== nothing @@ -233,7 +233,10 @@ end # function args args = if st == :contour opt[:x], opt[:y], opt[:z].surf' - elseif st == :heatmap + elseif st == :heatmap || st == :surface + @show opt[:x] + @show opt[:y] + @show opt[:z] surface_to_vecs(opt[:x], opt[:y], opt[:z]) elseif is3d(st) opt[:x], opt[:y], opt[:z] @@ -300,7 +303,9 @@ function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) - push!( segment_opt, "surf" => nothing ) + push!( segment_opt, "surf" => nothing, + "mesh/rows" => length(opt[:x]) + ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:volume}, segment_opt, opt, args) From 1c854519c87a78d932565ecb03c379853c6327b7 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 14:08:45 +0100 Subject: [PATCH 058/184] wireframes --- src/backends/pgfplotsx.jl | 9 ++++----- test/test_pgfplotsx.jl | 5 ++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index ecf0833a..c2b1ef51 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -233,10 +233,7 @@ end # function args args = if st == :contour opt[:x], opt[:y], opt[:z].surf' - elseif st == :heatmap || st == :surface - @show opt[:x] - @show opt[:y] - @show opt[:z] + elseif st in (:heatmap, :surface, :wireframe) surface_to_vecs(opt[:x], opt[:y], opt[:z]) elseif is3d(st) opt[:x], opt[:y], opt[:z] @@ -313,7 +310,9 @@ function pgfx_series_coordinates!(st_val::Val{:volume}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, args) - push!( segment_opt, "mesh" => nothing ) + push!( segment_opt, "mesh" => nothing, + "mesh/rows" => length(opt[:x]) + ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index b8f6b146..70f51a72 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -76,7 +76,7 @@ end histogram2d(randn(10000), randn(10000), nbins=20) # TODO: should work, when heatmaps works? end # testset - @testset "Heatmap" begin + @testset "Heatmap-like" begin xs = [string("x", i) for i = 1:10] ys = [string("y", i) for i = 1:4] z = float((1:4) * reshape(1:10, 1, :)) @@ -86,6 +86,9 @@ end @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" end + + pgfx_plot = wireframe(xs, ys, z, aspect_ratio=1) + # TODO: clims are wrong end # testset @testset "Contours" begin x = 1:0.5:20 From d50c28ebe7ce8c61f9adce1266c13f2c78879b75 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 14:11:43 +0100 Subject: [PATCH 059/184] straightline --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c2b1ef51..f9b9c9a9 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -265,7 +265,7 @@ end pgfx_series_coordinates!(Val(st), segment_opt, opt, seg_args) end end -function pgfx_series_coordinates!(st_val::Union{Val{:path}, Val{:path3d}}, segment_opt, opt, args) +function pgfx_series_coordinates!(st_val::Union{Val{:path}, Val{:path3d}, Val{:straightline}}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Union{Val{:scatter}, Val{:scatter3d}}, segment_opt, opt, args) From 20f6d559c374810aa357e724e8290efee839a6fa Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sat, 23 Nov 2019 20:10:08 +0100 Subject: [PATCH 060/184] free shapes --- src/backends/pgfplotsx.jl | 77 ++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index f9b9c9a9..e3441d0b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -89,31 +89,31 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end # Search series for any gradient. In case one series uses a gradient set - # the colorbar and colomap. - # The reasoning behind doing this on the axis level is that pgfplots - # colorbar seems to only works on axis level and needs the proper colormap for - # correctly displaying it. - # It's also possible to assign the colormap to the series itself but - # then the colormap needs to be added twice, once for the axis and once for the - # series. - # As it is likely that all series within the same axis use the same - # colormap this should not cause any problem. - for series in series_list(sp) - for col in (:markercolor, :fillcolor, :linecolor) - if typeof(series.plotattributes[col]) == ColorGradient - PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ - colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, - }""") - push!(axis_opt, - "colorbar" => nothing, - "colormap name" => "plots$(sp.attr[:subplot_index])", - ) - # goto is needed to break out of col and series for - @goto colorbar_end - end + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots$(sp.attr[:subplot_index])", + ) + # goto is needed to break out of col and series for + @goto colorbar_end end end - @label colorbar_end + end + @label colorbar_end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title], @@ -158,8 +158,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) end # treat segments - segments = if iscontour(series) || st == :heatmap - iter_segments(series[:x], series[:y]) + segments = if st in (:wireframe, :heatmap, :contour, :surface) + iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) else iter_segments(series) end @@ -167,6 +167,21 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) for (i, rng) in enumerate(segments) segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) if opt[:markershape] != :none #|| !iscontour(series) && !(st == :heatmap) + marker = opt[:markershape] + if marker isa Shape + x = marker.x + y = marker.y + scale_factor = 0.025 + mark_size = opt[:markersize] * scale_factor + path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, + """ + \\pgfdeclareplotmark{PlotsShape}{ + \\draw $path; + } + """ + ) + end segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end if st == :shape || series[:fillrange] !== nothing @@ -300,8 +315,11 @@ function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) + @show collect(args)[3] |> length + @show args push!( segment_opt, "surf" => nothing, - "mesh/rows" => length(opt[:x]) + "mesh/rows" => length(opt[:x]), + "mesh/cols" => length(opt[:y]), ) return PGFPlotsX.Coordinates(args...) end @@ -316,7 +334,7 @@ function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, arg return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) - push!( segment_opt, "area legends" => nothing, "patch" => nothing ) + push!( segment_opt, "area legends" => nothing ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:contour}, segment_opt, opt, args) @@ -459,9 +477,10 @@ function pgfx_marker(plotattributes, i = 1) a = alpha(cstr) cstr_stroke = plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)) a_stroke = alpha(cstr_stroke) + mark_size = pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i) return PGFPlotsX.Options( - "mark" => get(_pgfplotsx_markers, shape, "*"), - "mark size" => pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i), + "mark" => shape isa Shape ? "PlotsShape" : get(_pgfplotsx_markers, shape, "*"), + "mark size" => "$mark_size pt", "mark options" => PGFPlotsX.Options( "color" => cstr_stroke, "draw opacity" => a_stroke, From 8553bef132fb76699d8cb9f7c765ec42ee66db33 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sat, 23 Nov 2019 20:45:21 +0100 Subject: [PATCH 061/184] filled contour, histogram2d --- src/backends.jl | 2 +- src/backends/pgfplotsx.jl | 11 ----------- test/test_pgfplotsx.jl | 3 --- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 1d4b3482..9bf596fd 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -707,7 +707,7 @@ const _pgfplotsx_attr = merge_with_base_supported([ ]) const _pgfplotsx_seriestype = [:path, :scatter, :straightline, - :path3d, :scatter3d, :surface, :wireframe, :volume, + :path3d, :scatter3d, :surface, :wireframe, :heatmap, :contour, :histogram2d, :shape, :steppre, :stepmid, :steppost, :ysticks, :xsticks] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index e3441d0b..c7a3889b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -37,7 +37,6 @@ function Base.push!(pgfx_plot::PGFPlotsXPlot, item) end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) - # TODO: annotations! does not trigger _series_added ... if !pgfx_plot.is_created cols, rows = size(plt.layout.grid) the_plot = PGFPlotsX.TikzPicture() @@ -126,7 +125,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!( axis_opt, "view" => (azim, elev) ) end axisf = if sp[:projection] == :polar - # TODO: this errors for some reason # push!(axis_opt, "xmin" => 90) # push!(axis_opt, "xmax" => 450) PGFPlotsX.PolarAxis @@ -194,14 +192,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "labels" => opt[:contour_labels], ) ) - else - notimpl() - push!(series_opt, - "contour filled" => PGFPlotsX.Options( - # "levels" => opt[:levels], - # "labels" => opt[:contour_labels], - ) - ) end end coordinates = pgfx_series_coordinates!( sp, st, segment_opt, opt, rng ) @@ -390,7 +380,6 @@ const _pgfx_annotation_halign = KW( ) ## -------------------------------------------------------------------------------------- # Generates a colormap for pgfplots based on a ColorGradient -# TODO: maybe obsolete pgfx_arrow(::Nothing) = "every arrow/.append style={-}" function pgfx_arrow( arr::Arrow ) components = String[] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 70f51a72..4192e354 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -70,11 +70,9 @@ end x = 0.1:0.2:0.9 y = 0.7 * rand(5) .+ 0.15 plot(x, y, line=(3, :dash, :lightblue), marker=(Shape(verts), 30, RGBA(0, 0, 0, 0.2)), bg=:pink, fg=:darkblue, xlim=(0, 1), ylim=(0, 1), leg=false) - # TODO: draw those polygons end # testset @testset "Histogram 2D" begin histogram2d(randn(10000), randn(10000), nbins=20) - # TODO: should work, when heatmaps works? end # testset @testset "Heatmap-like" begin xs = [string("x", i) for i = 1:10] @@ -102,7 +100,6 @@ end p2 = contour(x, y, Z) p1 = contour(x, y, f, fill=true) plot(p1, p2) - # TODO: filled contours end # testset @testset "Varying colors" begin t = range(0, stop=1, length=100) From 8cb32b1f14fb39cd6cae30feb06e47eab1c65cb5 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 16:46:20 +0100 Subject: [PATCH 062/184] filled contour (really) --- src/backends.jl | 4 +- src/backends/pgfplotsx.jl | 85 ++++++++++++++++++++++++++------------- test/test_pgfplotsx.jl | 1 + 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 9bf596fd..623a057c 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -707,8 +707,8 @@ const _pgfplotsx_attr = merge_with_base_supported([ ]) const _pgfplotsx_seriestype = [:path, :scatter, :straightline, - :path3d, :scatter3d, :surface, :wireframe, - :heatmap, :contour, :histogram2d, + :path3d, :scatter3d, :surface, :wireframe, + :heatmap, :contour, :contour3d, :histogram2d, :shape, :steppre, :stepmid, :steppost, :ysticks, :xsticks] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c7a3889b..c6efba0e 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,5 +1,4 @@ using Contour: Contour -using StatsBase: Histogram, fit # PGFPlotsX.print_tex(io::IO, data::ColorGradient) = write(io, pgfx_colormap(data)) Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false @@ -140,13 +139,18 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => single_color(opt[:linecolor]), ) - if is3d(series) || st == :heatmap + if is3d(series) || st == :heatmap #|| isfilledcontour(series) series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot end - if series[:fillrange] !== nothing && st != :contour - series_opt = merge(series_opt, pgfx_fillstyle(opt)) + if isfilledcontour(series) + # push!(series_opt, "contour filled" => nothing) + # st = :surface + # axis_opt["view"] = (0, 90) + # push!(series_opt, "shader" => "interp") + end + if series[:fillrange] !== nothing && !isfilledcontour(series) push!(series_opt, "area legend" => nothing) end if st == :heatmap @@ -156,7 +160,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) end # treat segments - segments = if st in (:wireframe, :heatmap, :contour, :surface) + segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) else iter_segments(series) @@ -164,7 +168,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - if opt[:markershape] != :none #|| !iscontour(series) && !(st == :heatmap) + if opt[:markershape] != :none marker = opt[:markershape] if marker isa Shape x = marker.x @@ -182,23 +186,17 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end - if st == :shape || series[:fillrange] !== nothing + if st == :shape || + (series[:fillrange] !== nothing && !isfilledcontour(series)) segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end - if iscontour(series) - if !isfilledcontour(series) - push!(series_opt, - "contour prepared" => PGFPlotsX.Options( - "labels" => opt[:contour_labels], - ) - ) - end - end - coordinates = pgfx_series_coordinates!( sp, st, segment_opt, opt, rng ) + coordinates = pgfx_series_coordinates!( sp, + isfilledcontour(series) ? :filledcontour : st, + segment_opt, opt, rng ) segment_plot = series_func( merge(series_opt, segment_opt), coordinates, - series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + (series[:fillrange] !== nothing && !isfilledcontour(series)) ? "\\closedcycle" : "{}" ) push!(axis, segment_plot) # add to legend? @@ -236,10 +234,10 @@ end ## seriestype specifics @inline function pgfx_series_coordinates!(sp, st, segment_opt, opt, rng) # function args - args = if st == :contour - opt[:x], opt[:y], opt[:z].surf' + args = if st in (:contour, :contour3d, :filledcontour) + opt[:x], opt[:y], Array(opt[:z])' elseif st in (:heatmap, :surface, :wireframe) - surface_to_vecs(opt[:x], opt[:y], opt[:z]) + surface_to_vecs(opt[:x], opt[:y], opt[:z]) elseif is3d(st) opt[:x], opt[:y], opt[:z] elseif st == :straightline @@ -252,7 +250,7 @@ end else opt[:x], opt[:y] end - seg_args = if st == :contour || st == :heatmap + seg_args = if st in (:contour, :contour3d, :heatmap, :filledcontour) args else (arg[rng] for arg in args) @@ -305,8 +303,6 @@ function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) - @show collect(args)[3] |> length - @show args push!( segment_opt, "surf" => nothing, "mesh/rows" => length(opt[:x]), "mesh/cols" => length(opt[:y]), @@ -327,10 +323,42 @@ function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) push!( segment_opt, "area legends" => nothing ) return PGFPlotsX.Coordinates(args...) end -function pgfx_series_coordinates!(st_val::Val{:contour}, segment_opt, opt, args) +function pgfx_series_coordinates!(st_val::Union{Val{:contour}, Val{:contour3d}}, segment_opt, opt, args) + push!(segment_opt, + "contour prepared" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ), + ) return PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) end +function pgfx_series_coordinates!(st_val::Val{:filledcontour}, segment_opt, opt, args) + xs, ys, zs = collect(args) + push!(segment_opt, + "contour filled" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ), + "point meta" => "explicit", + "shader" => "flat" + ) + if opt[:levels] isa Number + push!(segment_opt["contour filled"], + "number" => opt[:levels], + ) + elseif opt[:levels] isa AVec + push!(segment_opt["contour filled"], + "levels" => opt[:levels], + ) + end + cs = join([ + join(["($x, $y) [$(zs[j, i])]" for (j, x) in enumerate(xs)], " ") for (i, y) in enumerate(ys)], "\n\n" + ) + """ +coordinates { +$cs +}; + """ +end ## const _pgfplotsx_linestyles = KW( :solid => "solid", @@ -428,10 +456,9 @@ pgfx_thickness_scaling(series) = pgfx_thickness_scaling(series[:subplot]) function pgfx_fillstyle(plotattributes, i = 1) cstr = get_fillcolor(plotattributes, i) - a = alpha(cstr) - fa = get_fillalpha(plotattributes, i) - if fa !== nothing - a = fa + a = get_fillalpha(plotattributes, i) + if a === nothing + a = alpha(single_color(cstr)) end PGFPlotsX.Options("fill" => cstr, "fill opacity" => a) end diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 4192e354..f38b115b 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -100,6 +100,7 @@ end p2 = contour(x, y, Z) p1 = contour(x, y, f, fill=true) plot(p1, p2) + # TODO: colorbar for filled contours end # testset @testset "Varying colors" begin t = range(0, stop=1, length=100) From e2a4b0eb30d3940470e4d75a87293f2036219c10 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:03:08 +0100 Subject: [PATCH 063/184] rely on recipe for histogram2d --- src/backends.jl | 2 +- src/backends/pgfplotsx.jl | 27 +++++++++++++-------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 623a057c..9bcba334 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -708,7 +708,7 @@ const _pgfplotsx_attr = merge_with_base_supported([ const _pgfplotsx_seriestype = [:path, :scatter, :straightline, :path3d, :scatter3d, :surface, :wireframe, - :heatmap, :contour, :contour3d, :histogram2d, + :heatmap, :contour, :contour3d, :shape, :steppre, :stepmid, :steppost, :ysticks, :xsticks] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c6efba0e..684253de 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,5 +1,4 @@ using Contour: Contour -# PGFPlotsX.print_tex(io::IO, data::ColorGradient) = write(io, pgfx_colormap(data)) Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false was_shown::Bool = false @@ -250,7 +249,8 @@ end else opt[:x], opt[:y] end - seg_args = if st in (:contour, :contour3d, :heatmap, :filledcontour) + seg_args = if st in (:contour, :contour3d, :filledcontour) + args else (arg[rng] for arg in args) @@ -278,10 +278,12 @@ end function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) push!(segment_opt, "surf" => nothing, - "mesh/rows" => length(opt[:x]) + "mesh/rows" => length(opt[:x]), + "mesh/cols" => length(opt[:y]) ) return PGFPlotsX.Table(args...) end + function pgfx_series_coordinates!(st_val::Val{:stepre}, segment_opt, opt, args) push!( segment_opt, "const plot mark right" => nothing ) return PGFPlotsX.Coordinates(args...) @@ -354,9 +356,9 @@ function pgfx_series_coordinates!(st_val::Val{:filledcontour}, segment_opt, opt, join(["($x, $y) [$(zs[j, i])]" for (j, x) in enumerate(xs)], " ") for (i, y) in enumerate(ys)], "\n\n" ) """ -coordinates { -$cs -}; + coordinates { + $cs + }; """ end ## @@ -590,14 +592,11 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # limits - # TODO: support zlims - if letter != :z - lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) - push!( opt, - string(letter,:min) => lims[1], - string(letter,:max) => lims[2] - ) - end + lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) + push!( opt, + string(letter,:min) => lims[1], + string(letter,:max) => lims[2] + ) if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none ticks = get_ticks(sp, axis) From 44341d1ff54f64bd8c24d3c23aa8342871eacccb Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:04:13 +0100 Subject: [PATCH 064/184] fix steppre --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 684253de..4d2921da 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -284,7 +284,7 @@ function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) return PGFPlotsX.Table(args...) end -function pgfx_series_coordinates!(st_val::Val{:stepre}, segment_opt, opt, args) +function pgfx_series_coordinates!(st_val::Val{:steppre}, segment_opt, opt, args) push!( segment_opt, "const plot mark right" => nothing ) return PGFPlotsX.Coordinates(args...) end From a9cbe354c14228e3f4fa22b4c7b1d87d5031a09c Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:10:34 +0100 Subject: [PATCH 065/184] fix bar --- src/backends/pgfplotsx.jl | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4d2921da..373d9ca3 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -143,12 +143,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else series_func = PGFPlotsX.Plot end - if isfilledcontour(series) - # push!(series_opt, "contour filled" => nothing) - # st = :surface - # axis_opt["view"] = (0, 90) - # push!(series_opt, "shader" => "interp") - end if series[:fillrange] !== nothing && !isfilledcontour(series) push!(series_opt, "area legend" => nothing) end @@ -189,9 +183,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) (series[:fillrange] !== nothing && !isfilledcontour(series)) segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end - coordinates = pgfx_series_coordinates!( sp, - isfilledcontour(series) ? :filledcontour : st, - segment_opt, opt, rng ) + coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) segment_plot = series_func( merge(series_opt, segment_opt), coordinates, @@ -231,9 +223,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end ## seriestype specifics -@inline function pgfx_series_coordinates!(sp, st, segment_opt, opt, rng) +@inline function pgfx_series_coordinates!(sp, series, segment_opt, opt, rng) + st = series[:seriestype] # function args - args = if st in (:contour, :contour3d, :filledcontour) + args = if st in (:contour, :contour3d) opt[:x], opt[:y], Array(opt[:z])' elseif st in (:heatmap, :surface, :wireframe) surface_to_vecs(opt[:x], opt[:y], opt[:z]) @@ -249,8 +242,7 @@ end else opt[:x], opt[:y] end - seg_args = if st in (:contour, :contour3d, :filledcontour) - + seg_args = if st in (:contour, :contour3d) args else (arg[rng] for arg in args) @@ -265,6 +257,9 @@ end x, y = collect(seg_args) return PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) else + if isfilledcontour(series) + st = :filledcontour + end pgfx_series_coordinates!(Val(st), segment_opt, opt, seg_args) end end @@ -322,7 +317,7 @@ function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, arg return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) - push!( segment_opt, "area legends" => nothing ) + # push!( segment_opt, "area legend" => nothing ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Union{Val{:contour}, Val{:contour3d}}, segment_opt, opt, args) From 077f1ddb84fbee5689b2cabf5cebf26211ff588b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:11:52 +0100 Subject: [PATCH 066/184] fix bar2 --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 373d9ca3..2be8ec56 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -317,7 +317,7 @@ function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, arg return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) - # push!( segment_opt, "area legend" => nothing ) + push!( segment_opt, "area legend" => nothing ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Union{Val{:contour}, Val{:contour3d}}, segment_opt, opt, args) From c600cb0294b9ce5a26060d91964c30f7f1727571 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:18:10 +0100 Subject: [PATCH 067/184] fix display --- src/backends/pgfplotsx.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 2be8ec56..27067035 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -26,6 +26,7 @@ function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) return xn, yn, zn end +Base.display(pgfx_plot::PGFPlotsXPlot) = display(pgfx_plot.the_plot) function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) show(io::IO, mime, pgfx_plot.the_plot) end @@ -705,8 +706,5 @@ function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend end function _display(plt::Plot{PGFPlotsXBackend}) - # fn = string(tempname(),".svg") - # PGFPlotsX.pgfsave(fn, plt.o) - # open_browser_window(fn) plt.o end From d409ad22a0e3a9fcb39b4b68c7d849d6e11156f7 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 19:12:31 +0100 Subject: [PATCH 068/184] filled custom marker --- src/backends/pgfplotsx.jl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 27067035..8e21ebcb 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -133,7 +133,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) axis = axisf( axis_opt ) - for series in series_list(sp) + for (series_index, series) in enumerate(series_list(sp)) opt = series.plotattributes st = series[:seriestype] series_opt = PGFPlotsX.Options( @@ -170,10 +170,13 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) scale_factor = 0.025 mark_size = opt[:markersize] * scale_factor path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") + c = get_markercolor(series, i) + a = get_markeralpha(series, i) PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """ - \\pgfdeclareplotmark{PlotsShape}{ - \\draw $path; + \\pgfdeclareplotmark{PlotsShape$(series_index)}{ + \\filldraw + $path; } """ ) @@ -493,7 +496,7 @@ function pgfx_marker(plotattributes, i = 1) a_stroke = alpha(cstr_stroke) mark_size = pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i) return PGFPlotsX.Options( - "mark" => shape isa Shape ? "PlotsShape" : get(_pgfplotsx_markers, shape, "*"), + "mark" => shape isa Shape ? "PlotsShape$i" : get(_pgfplotsx_markers, shape, "*"), "mark size" => "$mark_size pt", "mark options" => PGFPlotsX.Options( "color" => cstr_stroke, From 33390a2c2d8db0fa9ac0293ae829e27a57e0515a Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 19:18:45 +0100 Subject: [PATCH 069/184] increase right padding --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 8e21ebcb..54393377 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -673,7 +673,7 @@ end function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) # TODO: make padding more intelligent # order: right, top, left, bottom - sp.minpad = (20mm, 12mm, 2mm, 10mm) + sp.minpad = (22mm, 12mm, 2mm, 10mm) end function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) From 024a11f35b0f2602cd833af4b24507abfd7306e4 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 12:21:12 +0100 Subject: [PATCH 070/184] robust pgfx_axes --- src/backends/pgfplotsx.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 54393377..52fbe121 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -11,7 +11,11 @@ Base.@kwdef mutable struct PGFPlotsXPlot end end -pgfx_axes(pgfx_plot::PGFPlotsXPlot) = pgfx_plot.the_plot.elements[1].elements[1].contents +function pgfx_axes(pgfx_plot::PGFPlotsXPlot) + gp = pgfx_plot.the_plot.elements[1] + return gp isa PGFPlotsX.GroupPlot ? gp.elements[1].contents : gp +end + function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) a = Array(s) From c056f8525d80a6868e07d475853106b15865c309 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 12:38:54 +0100 Subject: [PATCH 071/184] add background_color_outside --- src/backends/pgfplotsx.jl | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 52fbe121..fd276505 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -5,7 +5,26 @@ Base.@kwdef mutable struct PGFPlotsXPlot the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() function PGFPlotsXPlot(is_created, was_shown, the_plot) pgfx_plot = new(is_created, was_shown, the_plot) + # tikz libraries PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{backgrounds}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, + """ + \\pgfkeys{/tikz/.cd, + background color/.initial=white, + background color/.get=\\backcol, + background color/.store in=\\backcol, + } + \\tikzset{background rectangle/.style={ + fill=\\backcol, + }, + use background/.style={ + show background rectangle + } + } + """ + ) + # pgfplots libraries PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}") pgfx_plot end @@ -41,8 +60,19 @@ end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created + the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) cols, rows = size(plt.layout.grid) - the_plot = PGFPlotsX.TikzPicture() + bgc = plt.attr[:background_color_outside] + if bgc isa Colors.Colorant + cstr = plot_color(bgc) + a = alpha(cstr) + push!(the_plot.options, + "draw opacity" => a, + "background color" => cstr, + "use background" => nothing, + ) + end + # the combination of groupplot and polaraxis is broken in pgfplots if !any( sp -> ispolar(sp), plt.subplots ) pl_height, pl_width = plt.attr[:size] From eb7ac6ea3dd4bf8eaa8798adc845d0192b4da5db Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 14:18:25 +0100 Subject: [PATCH 072/184] add ribbons --- src/backends/pgfplotsx.jl | 266 ++++++++++++++++++++++---------------- 1 file changed, 156 insertions(+), 110 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index fd276505..47b9fa9a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -26,6 +26,7 @@ Base.@kwdef mutable struct PGFPlotsXPlot ) # pgfplots libraries PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween}") pgfx_plot end end @@ -147,116 +148,122 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end @label colorbar_end - push!(axis_opt, "colorbar style" => PGFPlotsX.Options( - "title" => sp[:colorbar_title], - "point meta max" => get_clims(sp)[2], - "point meta min" => get_clims(sp)[1] - ) - ) - if is3d(sp) - azim, elev = sp[:camera] - push!( axis_opt, "view" => (azim, elev) ) - end - axisf = if sp[:projection] == :polar - # push!(axis_opt, "xmin" => 90) - # push!(axis_opt, "xmax" => 450) - PGFPlotsX.PolarAxis - else - PGFPlotsX.Axis - end - axis = axisf( - axis_opt - ) - for (series_index, series) in enumerate(series_list(sp)) - opt = series.plotattributes - st = series[:seriestype] - series_opt = PGFPlotsX.Options( - "color" => single_color(opt[:linecolor]), - ) - if is3d(series) || st == :heatmap #|| isfilledcontour(series) - series_func = PGFPlotsX.Plot3 - else - series_func = PGFPlotsX.Plot - end - if series[:fillrange] !== nothing && !isfilledcontour(series) - push!(series_opt, "area legend" => nothing) - end - if st == :heatmap - push!(axis.options, - "view" => "{0}{90}", - "shader" => "flat corner", - ) - end - # treat segments - segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) - iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) - else - iter_segments(series) - end - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - if opt[:markershape] != :none - marker = opt[:markershape] - if marker isa Shape - x = marker.x - y = marker.y - scale_factor = 0.025 - mark_size = opt[:markersize] * scale_factor - path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") - c = get_markercolor(series, i) - a = get_markeralpha(series, i) - PGFPlotsX.push_preamble!(pgfx_plot.the_plot, - """ - \\pgfdeclareplotmark{PlotsShape$(series_index)}{ - \\filldraw - $path; - } - """ - ) - end - segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - end - if st == :shape || - (series[:fillrange] !== nothing && !isfilledcontour(series)) - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) - segment_plot = series_func( - merge(series_opt, segment_opt), - coordinates, - (series[:fillrange] !== nothing && !isfilledcontour(series)) ? "\\closedcycle" : "{}" - ) - push!(axis, segment_plot) - # add to legend? - if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) - ) - end - # add series annotations - anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) - pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) - end - end - # add subplot annotations - anns = sp.attr[:annotations] - for (xi,yi,txt) in anns - pgfx_add_annotation!(axis, xi, yi, txt) - end - end - if ispolar(sp) - axes = the_plot - else - axes = the_plot.elements[1] - end - push!( axes, axis ) - if length(plt.o.the_plot.elements) > 0 - plt.o.the_plot.elements[1] = the_plot - else - push!(plt.o, the_plot) - end - end + push!(axis_opt, "colorbar style" => PGFPlotsX.Options( + "title" => sp[:colorbar_title], + "point meta max" => get_clims(sp)[2], + "point meta min" => get_clims(sp)[1] + ) + ) + if is3d(sp) + azim, elev = sp[:camera] + push!( axis_opt, "view" => (azim, elev) ) + end + axisf = if sp[:projection] == :polar + # push!(axis_opt, "xmin" => 90) + # push!(axis_opt, "xmax" => 450) + PGFPlotsX.PolarAxis + else + PGFPlotsX.Axis + end + axis = axisf( + axis_opt + ) + for (series_index, series) in enumerate(series_list(sp)) + opt = series.plotattributes + st = series[:seriestype] + series_opt = PGFPlotsX.Options( + "color" => single_color(opt[:linecolor]), + ) + if is3d(series) || st == :heatmap #|| isfilledcontour(series) + series_func = PGFPlotsX.Plot3 + else + series_func = PGFPlotsX.Plot + end + if series[:fillrange] !== nothing && !isfilledcontour(series) + push!(series_opt, "area legend" => nothing) + end + if st == :heatmap + push!(axis.options, + "view" => "{0}{90}", + "shader" => "flat corner", + ) + end + # treat segments + segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) + iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) + else + iter_segments(series) + end + segment_opt = PGFPlotsX.Options() + for (i, rng) in enumerate(segments) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + if opt[:markershape] != :none + marker = opt[:markershape] + if marker isa Shape + x = marker.x + y = marker.y + scale_factor = 0.025 + mark_size = opt[:markersize] * scale_factor + path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") + c = get_markercolor(series, i) + a = get_markeralpha(series, i) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, + """ + \\pgfdeclareplotmark{PlotsShape$(series_index)}{ + \\filldraw + $path; + } + """ + ) + end + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + end + if st == :shape || + (series[:fillrange] !== nothing && !isfilledcontour(series)) && + series[:ribbon] === nothing + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) + segment_plot = series_func( + merge(series_opt, segment_opt), + coordinates, + (series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing) ? "\\closedcycle" : "{}" + ) + push!(axis, segment_plot) + # add ribbons? + ribbon = series[:ribbon] + if ribbon !== nothing + pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) + end + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) + end + end + # add subplot annotations + anns = sp.attr[:annotations] + for (xi,yi,txt) in anns + pgfx_add_annotation!(axis, xi, yi, txt) + end + end + if ispolar(sp) + axes = the_plot + else + axes = the_plot.elements[1] + end + push!( axes, axis ) + if length(plt.o.the_plot.elements) > 0 + plt.o.the_plot.elements[1] = the_plot + else + push!(plt.o, the_plot) + end + end pgfx_plot.is_created = true end end @@ -570,6 +577,45 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) "{$(val.str).};" ]) end + +function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) + ribbon = series[:ribbon] + opt = series.plotattributes + ribbon_n = length(opt[:y]) ÷ length(ribbon) + ribbon_y = repeat(ribbon, outer = ribbon_n) + # upper ribbon + ribbon_name_plus = "plots_rib_p$series_index" + ribbon_opt_plus = merge(segment_plot.options, PGFPlotsX.Options( + "name path" => ribbon_name_plus, + "color" => opt[:fillcolor], + "draw opacity" => opt[:fillalpha] + )) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] + ribbon_y) + ribbon_plot_plus = series_func( + ribbon_opt_plus, + coordinates_plus + ) + push!(axis, ribbon_plot_plus) + # lower ribbon + ribbon_name_minus = "plots_rib_m$series_index" + ribbon_opt_minus = merge(segment_plot.options, PGFPlotsX.Options( + "name path" => ribbon_name_minus, + "color" => opt[:fillcolor], + "draw opacity" => opt[:fillalpha] + )) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] - ribbon_y) + ribbon_plot_plus = series_func( + ribbon_opt_minus, + coordinates_plus + ) + push!(axis, ribbon_plot_plus) + # fill + push!(axis, series_func( + pgfx_fillstyle(opt, series_index), + "fill between [of=$(ribbon_name_plus) and $(ribbon_name_minus)]" + )) + return axis +end # -------------------------------------------------------------------------------------- function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) axis = sp[Symbol(letter,:axis)] From ab8b57ed490fa5f52c052c8a1d343443be0fcf3e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 14:37:48 +0100 Subject: [PATCH 073/184] fix scalar ribbons --- src/backends/pgfplotsx.jl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 47b9fa9a..012b2dfd 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -579,10 +579,12 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) end function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) - ribbon = series[:ribbon] + ribbon_y = series[:ribbon] opt = series.plotattributes - ribbon_n = length(opt[:y]) ÷ length(ribbon) - ribbon_y = repeat(ribbon, outer = ribbon_n) + if ribbon_y isa AVec + ribbon_n = length(opt[:y]) ÷ length(ribbon) + ribbon_y = repeat(ribbon, outer = ribbon_n) + end # upper ribbon ribbon_name_plus = "plots_rib_p$series_index" ribbon_opt_plus = merge(segment_plot.options, PGFPlotsX.Options( @@ -590,7 +592,7 @@ function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_inde "color" => opt[:fillcolor], "draw opacity" => opt[:fillalpha] )) - coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] + ribbon_y) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] .+ ribbon_y) ribbon_plot_plus = series_func( ribbon_opt_plus, coordinates_plus @@ -603,7 +605,7 @@ function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_inde "color" => opt[:fillcolor], "draw opacity" => opt[:fillalpha] )) - coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] - ribbon_y) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] .- ribbon_y) ribbon_plot_plus = series_func( ribbon_opt_minus, coordinates_plus From 3272f72df00c71443c5ec9ef6942537fe8624e87 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 14:51:53 +0100 Subject: [PATCH 074/184] arbitrary legend position --- src/backends/pgfplotsx.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 012b2dfd..09fc06bc 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -106,7 +106,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "draw opacity" => title_a, "rotate" => sp[:titlefontrotation] ), - "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), "legend style" => PGFPlotsX.Options( pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, "fill" => cstr, @@ -116,6 +115,14 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "fill" => sp[:background_color_inside] ) ) + # legend position + if sp[:legend] isa Tuple + x, y = sp[:legend] + push!(axis_opt["legend style"], "at={($x, $y)}" ) + else + push!(axis_opt, "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), + ) + end for letter in (:x, :y, :z) if letter != :z || is3d(sp) pgfx_axis!(axis_opt, sp, letter) From 7fc7471f81669d76e04debb344e07e649738c75d Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 15:49:25 +0100 Subject: [PATCH 075/184] respect user margins --- src/backends/pgfplotsx.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 09fc06bc..66dfe4e5 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -762,7 +762,10 @@ end function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) # TODO: make padding more intelligent # order: right, top, left, bottom - sp.minpad = (22mm, 12mm, 2mm, 10mm) + sp.minpad = (22mm + sp[:right_margin], + 12mm + sp[:top_margin], + 2mm + sp[:left_margin], + 10mm + sp[:bottom_margin]) end function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) From 26905b18ac0b34c9fd824866652ee32581005a99 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 17:44:25 +0100 Subject: [PATCH 076/184] respect standalone flag --- src/backends/pgfplotsx.jl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 66dfe4e5..b13125fe 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -36,6 +36,14 @@ function pgfx_axes(pgfx_plot::PGFPlotsXPlot) return gp isa PGFPlotsX.GroupPlot ? gp.elements[1].contents : gp end +function pgfx_preample(pgfx_plot::Plots.Plot{Plots.PGFPlotsXBackend}) + old_flag = pgfx_plot.attr[:tex_output_standalone] + pgfx_plot.attr[:tex_output_standalone] = true + fulltext = String(repr("application/x-tex", pgfx_plot)) + preamble = fulltext[1:first(findfirst("\\begin{document}", fulltext)) - 1] + pgfx_plot.attr[:tex_output_standalone] = old_flag + preamble +end function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) a = Array(s) @@ -797,7 +805,7 @@ end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) _update_plot_object(plt) - PGFPlotsX.print_tex(io, plt.o.the_plot) + PGFPlotsX.print_tex(io, plt.o.the_plot, include_preamble = plt.attr[:tex_output_standalone]) end function _display(plt::Plot{PGFPlotsXBackend}) From d796812161cb65b042ffd06883004f4333f646e1 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 18:56:20 +0100 Subject: [PATCH 077/184] line legend for ribbon plots --- src/backends/pgfplotsx.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index b13125fe..09496a67 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -194,7 +194,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else series_func = PGFPlotsX.Plot end - if series[:fillrange] !== nothing && !isfilledcontour(series) + if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing push!(series_opt, "area legend" => nothing) end if st == :heatmap @@ -252,8 +252,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end # add to legend? if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) - ) + push!( axis, PGFPlotsX.LegendEntry(opt[:label]) ) end # add series annotations anns = series[:series_annotations] From 0c5e561eace1b2687f7931ce32003925d2295120 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 20:10:09 +0100 Subject: [PATCH 078/184] legend opacity --- src/backends/pgfplotsx.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 09496a67..94a76b3b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -102,8 +102,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) bb = bbox(sp) cstr = plot_color(sp[:background_color_legend]) a = alpha(cstr) + fg_alpha = alpha(plot_color(sp[:foreground_color_legend])) title_cstr = plot_color(sp[:titlefontcolor]) - title_a = alpha(cstr) + title_a = alpha(title_cstr) axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), @@ -115,8 +116,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "rotate" => sp[:titlefontrotation] ), "legend style" => PGFPlotsX.Options( - pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid") => nothing, "fill" => cstr, + "fill opacity" => a, + "text opacity" => alpha(plot_color(sp[:legendfontcolor])), "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) ), "axis background/.style" => PGFPlotsX.Options( From 568c4a02285b658007534bab55c220ebb1734c72 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 23:05:27 +0100 Subject: [PATCH 079/184] fix background color --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 94a76b3b..2e210ab3 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -71,7 +71,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) cols, rows = size(plt.layout.grid) - bgc = plt.attr[:background_color_outside] + bgc = plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : plt.attr[:background_color] if bgc isa Colors.Colorant cstr = plot_color(bgc) a = alpha(cstr) From ce5c36ded5e5b1974c90265dea57cf7142ec9f0a Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 23:12:20 +0100 Subject: [PATCH 080/184] fix pgfx_axes --- src/backends/pgfplotsx.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 2e210ab3..056405eb 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -32,8 +32,8 @@ Base.@kwdef mutable struct PGFPlotsXPlot end function pgfx_axes(pgfx_plot::PGFPlotsXPlot) - gp = pgfx_plot.the_plot.elements[1] - return gp isa PGFPlotsX.GroupPlot ? gp.elements[1].contents : gp + gp = pgfx_plot.the_plot.elements[1].elements[1] + return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp end function pgfx_preample(pgfx_plot::Plots.Plot{Plots.PGFPlotsXBackend}) From 1e216291ab99fc5e0587dcf62be1e45f8222c3ec Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 00:07:45 +0100 Subject: [PATCH 081/184] direct colormap access --- src/backends/pgfplotsx.jl | 13 +++++++------ test/test_pgfplotsx.jl | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 056405eb..ec210aab 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -158,6 +158,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!(axis_opt, "colorbar" => nothing, "colormap name" => "plots$(sp.attr[:subplot_index])", + "colormap access" => "direct", ) # goto is needed to break out of col and series for @goto colorbar_end @@ -167,10 +168,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) @label colorbar_end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( - "title" => sp[:colorbar_title], - "point meta max" => get_clims(sp)[2], - "point meta min" => get_clims(sp)[1] - ) + "title" => sp[:colorbar_title], + "point meta max" => get_clims(sp)[2], + "point meta min" => get_clims(sp)[1] + ) ) if is3d(sp) azim, elev = sp[:camera] @@ -192,7 +193,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => single_color(opt[:linecolor]), ) - if is3d(series) || st == :heatmap #|| isfilledcontour(series) + if is3d(series) || st == :heatmap series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot @@ -336,7 +337,7 @@ function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) push!(segment_opt, "surf" => nothing, "mesh/rows" => length(opt[:x]), - "mesh/cols" => length(opt[:y]) + "mesh/cols" => length(opt[:y]), ) return PGFPlotsX.Table(args...) end diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index f38b115b..4c62ef4f 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -80,7 +80,8 @@ end z = float((1:4) * reshape(1:10, 1, :)) pgfx_plot = heatmap(xs, ys, z, aspect_ratio=1) Plots._update_plot_object(pgfx_plot) - if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) + if + @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" end From e29edc9e97cfaf57d120eec590ef2554c742b4be Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 00:15:54 +0100 Subject: [PATCH 082/184] flip layout --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index ec210aab..4ae9370f 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -70,7 +70,7 @@ end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) - cols, rows = size(plt.layout.grid) + rows, cols = size(plt.layout.grid) bgc = plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : plt.attr[:background_color] if bgc isa Colors.Colorant cstr = plot_color(bgc) From 7de8d302fa83e0fbce1d24038e77862b3601ce20 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 00:28:11 +0100 Subject: [PATCH 083/184] fix framestyle error --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4ae9370f..82ca9e32 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -646,7 +646,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) ) # set to supported framestyle - framestyle = pgfx_framestyle(sp[:framestyle]) + framestyle = pgfx_framestyle(sp[:framestyle] == false ? :none : sp[:framestyle]) # axis label position labelpos = "" From a37d9768a04fc22b3aeb499fdc633d98f109faff Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 01:41:54 +0100 Subject: [PATCH 084/184] add quiver bug test --- test/test_pgfplotsx.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 4c62ef4f..289a5c93 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -15,6 +15,7 @@ end pgfx_plot = plot(1:5) Plots._update_plot_object(pgfx_plot) @test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument + @test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing @testset "3D docs example" begin n = 100 @@ -80,8 +81,7 @@ end z = float((1:4) * reshape(1:10, 1, :)) pgfx_plot = heatmap(xs, ys, z, aspect_ratio=1) Plots._update_plot_object(pgfx_plot) - if - @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) + if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" end From 9cdc72662f946fdbfb143493dbee036fdbb0b3d3 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 13:22:37 +0100 Subject: [PATCH 085/184] fifty shades of show --- src/backends/pgfplotsx.jl | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 82ca9e32..9dbfb1a1 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -59,6 +59,7 @@ function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) end Base.display(pgfx_plot::PGFPlotsXPlot) = display(pgfx_plot.the_plot) + function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) show(io::IO, mime, pgfx_plot.the_plot) end @@ -284,6 +285,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end pgfx_plot.is_created = true end + return pgfx_plot end ## seriestype specifics @inline function pgfx_series_coordinates!(sp, series, segment_opt, opt, rng) @@ -791,26 +793,21 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o(plt) end -function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) - _update_plot_object(plt) - show(io, mime, plt.o) +for mime in ("application/pdf", "image/png", "image/svg+xml") + @eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{PGFPlotsXBackend}) + show(io, mime, plt.o.the_plot) + end end -function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) - _update_plot_object(plt) - show(io, mime, plt.o) -end - -function _show(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsXBackend}) - _update_plot_object(plt) - show(io, mime, plt.o) -end - -function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) - _update_plot_object(plt) +function _show(io::IO, mime::MIME{Symbol("application/x-tex")}, plt::Plot{PGFPlotsXBackend}) PGFPlotsX.print_tex(io, plt.o.the_plot, include_preamble = plt.attr[:tex_output_standalone]) end -function _display(plt::Plot{PGFPlotsXBackend}) - plt.o +Base.show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot{PGFPlotsXBackend}) = show(io, plt) + +function Base.show(io::IO, plt::Plot{PGFPlotsXBackend}) display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) +end + +function _display(plt::Plot{PGFPlotsXBackend}) + display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) end From 0b71f55b29cb435ec783e0ff72ade04b7a013162 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 13:30:04 +0100 Subject: [PATCH 086/184] fix typo --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 9dbfb1a1..172c4470 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -36,7 +36,7 @@ function pgfx_axes(pgfx_plot::PGFPlotsXPlot) return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp end -function pgfx_preample(pgfx_plot::Plots.Plot{Plots.PGFPlotsXBackend}) +function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend}) old_flag = pgfx_plot.attr[:tex_output_standalone] pgfx_plot.attr[:tex_output_standalone] = true fulltext = String(repr("application/x-tex", pgfx_plot)) From 0d2ccfddfb2c1da658cba03414ea722bafe745f8 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 18:55:44 +0100 Subject: [PATCH 087/184] fix show --- src/backends/pgfplotsx.jl | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 172c4470..b3007bc7 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -31,6 +31,7 @@ Base.@kwdef mutable struct PGFPlotsXPlot end end +## end user utility functions function pgfx_axes(pgfx_plot::PGFPlotsXPlot) gp = pgfx_plot.the_plot.elements[1].elements[1] return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp @@ -44,6 +45,7 @@ function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend}) pgfx_plot.attr[:tex_output_standalone] = old_flag preamble end +## function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) a = Array(s) @@ -58,12 +60,6 @@ function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) return xn, yn, zn end -Base.display(pgfx_plot::PGFPlotsXPlot) = display(pgfx_plot.the_plot) - -function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) - show(io::IO, mime, pgfx_plot.the_plot) -end - function Base.push!(pgfx_plot::PGFPlotsXPlot, item) push!(pgfx_plot.the_plot, item) end @@ -803,11 +799,6 @@ function _show(io::IO, mime::MIME{Symbol("application/x-tex")}, plt::Plot{PGFPlo PGFPlotsX.print_tex(io, plt.o.the_plot, include_preamble = plt.attr[:tex_output_standalone]) end -Base.show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot{PGFPlotsXBackend}) = show(io, plt) - -function Base.show(io::IO, plt::Plot{PGFPlotsXBackend}) display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) -end - function _display(plt::Plot{PGFPlotsXBackend}) display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) end From be5cd7de2e4eb2e5e267bf3d3ea8a5d6666351dd Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 19:10:25 +0100 Subject: [PATCH 088/184] improved fillrange --- src/backends/pgfplotsx.jl | 57 ++++++++++++++++++++++++++++++++++----- test/test_pgfplotsx.jl | 1 - 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index b3007bc7..4cc09fc4 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -210,8 +210,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else iter_segments(series) end - segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) + segment_opt = PGFPlotsX.Options() segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) if opt[:markershape] != :none marker = opt[:markershape] @@ -235,15 +235,28 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end if st == :shape || - (series[:fillrange] !== nothing && !isfilledcontour(series)) && - series[:ribbon] === nothing + isfilledcontour(series) || + series[:ribbon] !== nothing segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end + # add fillrange + if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing + pgfx_fillrange_series!( axis, series, series_func, i, _cycle(series[:fillrange], rng), rng) + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + io = IOBuffer() + PGFPlotsX.print_tex(io, pgfx_fillstyle(opt, i)) + style = strip(String(take!(io)),['[',']', ' ']) + push!( segment_opt, "legend image code/.code" => """{ + \\draw[##1,/tikz/.cd, $style] (0cm,-0.1cm) rectangle (0.6cm,0.1cm); + }""" ) + end + end + # series coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) segment_plot = series_func( - merge(series_opt, segment_opt), - coordinates, - (series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing) ? "\\closedcycle" : "{}" + merge(series_opt, segment_opt), + coordinates, ) push!(axis, segment_plot) # add ribbons? @@ -253,7 +266,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end # add to legend? if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry(opt[:label]) ) + legend = PGFPlotsX.LegendEntry(PGFPlotsX.Options(), opt[:label], true) + push!( axis, legend ) end # add series annotations anns = series[:series_annotations] @@ -634,6 +648,35 @@ function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_inde )) return axis end + +function pgfx_fillrange_series!(axis, series, series_func, i, fillrange, rng) + fillrange_opt = PGFPlotsX.Options( + "line width" => "0", + "draw opacity" => "0", + ) + fillrange_opt = merge( fillrange_opt, pgfx_fillstyle(series, i) ) + fillrange_opt = merge( fillrange_opt, pgfx_marker(series, i) ) + push!( fillrange_opt, "forget plot" => nothing ) + opt = series.plotattributes + args = is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) : (opt[:x][rng], opt[:y][rng]) + push!(axis, PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...))) + return axis +end + +function pgfx_fillrange_args(fillrange, x, y) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] + return PGFPlotsX.Coordinates(x_fill, y_fill) +end + +function pgfx_fillrange_args(fillrange, x, y, z) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; y[n:-1:1]; x[1]] + z_fill = [z; _cycle(fillrange, n:-1:1); z[1]] + return PGFPlotsX.Coordiantes(x_fill, y_fill, z_fill) +end # -------------------------------------------------------------------------------------- function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) axis = sp[Symbol(letter,:axis)] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 289a5c93..fc27f0e8 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -113,7 +113,6 @@ end x + y end), color=:bluesreds, legend=false) plot(p1, p2) - # TODO: questionable tiling end # testset @testset "Framestyles" begin scatter(fill(randn(10), 6), fill(randn(10), 6), framestyle=[:box :semi :origin :zerolines :grid :none], title=[":box" ":semi" ":origin" ":zerolines" ":grid" ":none"], color=permutedims(1:6), layout=6, label="", markerstrokewidth=0, ticks=-2:2) From cc4750688e35d47a4f3f571551fc3885de79a6a1 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 21:28:15 +0100 Subject: [PATCH 089/184] improve annotations --- src/backends/pgfplotsx.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4cc09fc4..c7e8e7e1 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -278,7 +278,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) # add subplot annotations anns = sp.attr[:annotations] for (xi,yi,txt) in anns - pgfx_add_annotation!(axis, xi, yi, txt) + pgfx_add_annotation!(axis, xi, yi, txt, pgfx_thickness_scaling(sp)) end end if ispolar(sp) @@ -604,7 +604,7 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) ), " at ", PGFPlotsX.Coordinate(x, y), - "{$(val.str).};" + "{$(val.str)};" ]) end From cc2e8ed5136e0a214e325bf3f47dcdcbac32bb5b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 27 Nov 2019 12:23:39 +0100 Subject: [PATCH 090/184] axis cs for annotations --- src/backends/pgfplotsx.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c7e8e7e1..5f487c8c 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -591,20 +591,17 @@ end function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) # Construct the style string. - # Currently supports color and orientation cstr = val.font.color a = alpha(cstr) push!(o, ["\\node", PGFPlotsX.Options( - get(_pgfx_annotation_halign,val.font.halign,"") => nothing, + get(_pgfx_annotation_halign, val.font.halign, "") => nothing, "color" => cstr, "draw opacity" => convert(Float16, a), "rotate" => val.font.rotation, "font" => pgfx_font(val.font.pointsize, thickness_scaling) ), - " at ", - PGFPlotsX.Coordinate(x, y), - "{$(val.str)};" + " at (axis cs:$x, $y) {$(val.str)};" ]) end From bf2e5d3fdc140f5734ef25a7243a6663b66f4e22 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 28 Nov 2019 12:12:32 +0100 Subject: [PATCH 091/184] fix matching background colors --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 5f487c8c..4dfa71ff 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -68,7 +68,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) rows, cols = size(plt.layout.grid) - bgc = plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : plt.attr[:background_color] + bgc = plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : plt.attr[:background_color_outside] if bgc isa Colors.Colorant cstr = plot_color(bgc) a = alpha(cstr) From 0821ad3c0315044c495ac1cbf5d4255517a08a48 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 12 Nov 2019 16:03:54 +0100 Subject: [PATCH 092/184] create stub --- Project.toml | 1 + src/backends.jl | 55 +++++++++++++++++++++++++++++++++++++++ src/backends/pgfplotsx.jl | 13 +++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/backends/pgfplotsx.jl diff --git a/Project.toml b/Project.toml index 6b6c0284..9c172eb9 100644 --- a/Project.toml +++ b/Project.toml @@ -15,6 +15,7 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e" NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043" diff --git a/src/backends.jl b/src/backends.jl index 26f01c91..d8074d35 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -252,6 +252,7 @@ end @init_backend PlotlyJS @init_backend GR @init_backend PGFPlots +@init_backend PGFPlotsX @init_backend InspectDR @init_backend HDF5 @@ -661,3 +662,57 @@ const _inspectdr_marker = Symbol[ ] const _inspectdr_scale = [:identity, :ln, :log2, :log10] +# ------------------------------------------------------------------------------ +# pgfplotsx + +const _pgfplotsx_attr = merge_with_base_supported([ + :annotations, + :background_color_legend, :background_color_inside, :background_color_outside, + :foreground_color_legend, :foreground_color_grid, :foreground_color_axis, + :foreground_color_text, :foreground_color_border, + :label, + :seriescolor, :seriesalpha, + :linecolor, :linestyle, :linewidth, :linealpha, + :markershape, :markercolor, :markersize, :markeralpha, + :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, + :fillrange, :fillcolor, :fillalpha, + :bins, + :layout, + :title, :window_title, + :guide, :lims, :ticks, :scale, :flip, + :match_dimensions, + :titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign, + :titlefontrotation, :titlefontcolor, + :legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign, + :legendfontrotation, :legendfontcolor, + :tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign, + :tickfontrotation, :tickfontcolor, + :guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign, + :guidefontrotation, :guidefontcolor, + :grid, :gridalpha, :gridstyle, :gridlinewidth, + :legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry, + :fill_z, :line_z, :marker_z, :levels, + :ribbon, :quiver, + :orientation, + :overwrite_figure, + :polar, + :aspect_ratio, + :normalize, :weights, + :inset_subplots, + :bar_width, + :arrow, + :framestyle, + :tick_direction, + :camera, + :contour_labels, +]) +const _pgfplotsx_seriestype = [ + :path, :scatter, :straightline, + :heatmap, :pie, :image, + :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, + :shape +] +const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] +const _pgfplotsx_marker = _allMarkers +const _pgfplotsx_scale = [:identity, :log10] +is_marker_supported(::PGFPlotsXBackend, shape::Shape) = false diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl new file mode 100644 index 00000000..27122d8b --- /dev/null +++ b/src/backends/pgfplotsx.jl @@ -0,0 +1,13 @@ +# -------------------------------------------------------------------------------------- +function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) +end + +function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) +end + +function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) +end + +function _display(plt::Plot{PGFPlotsXBackend}) + +end From 91d4e9dbe2ab8bab90b65b64fe736f788c778f31 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 12 Nov 2019 16:27:27 +0100 Subject: [PATCH 093/184] create display methods --- src/backends/pgfplotsx.jl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 27122d8b..19522d8e 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,13 +1,25 @@ # -------------------------------------------------------------------------------------- +# display calls this and then _display +function _update_plot_object(plt::Plot{PGFPlotsXBackend}) + plt.o = PGFPlotsX.Axis() +end + function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) + plt.o end function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) + show(io, mime, plt.o) +end + +function _show(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsXBackend}) + display("image/png", plt.o) end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) + PGFPlotsX.print_tex(plt.o) end function _display(plt::Plot{PGFPlotsXBackend}) - + plt.o end From 37ff1a73edc9cbbb52ce4d1d8d11cfe6773e8e30 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 12 Nov 2019 16:55:13 +0100 Subject: [PATCH 094/184] not displaying in Juno --- src/backends/pgfplotsx.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 19522d8e..e85e0933 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,11 +1,13 @@ +using PGFPlotsX: PGFPlotsX # -------------------------------------------------------------------------------------- # display calls this and then _display function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsX.Axis() + push!( plt.o, PGFPlotsX.Plot(PGFPlotsX.Coordinates(1:5,1:5)) ) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) - plt.o + show(io, mime, plt.o) end function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) @@ -13,7 +15,7 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) end function _show(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsXBackend}) - display("image/png", plt.o) + show(io, mime, plt.o) end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) From eddf523d084328fbebe16375bc503525f5eb1b4d Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 13 Nov 2019 12:12:31 +0100 Subject: [PATCH 095/184] fix display --- src/backends/pgfplotsx.jl | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index e85e0933..a62f2317 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,9 +1,18 @@ using PGFPlotsX: PGFPlotsX # -------------------------------------------------------------------------------------- -# display calls this and then _display +# display calls this and then _display, its called 3 times for plot(1:5) function _update_plot_object(plt::Plot{PGFPlotsXBackend}) - plt.o = PGFPlotsX.Axis() - push!( plt.o, PGFPlotsX.Plot(PGFPlotsX.Coordinates(1:5,1:5)) ) + plt.o = PGFPlotsX.GroupPlot() + + local axis + for sp in plt.subplots + axis = PGFPlotsX.Axis() + for series in series_list(sp) + series_plot = PGFPlotsX.Plot(PGFPlotsX.Coordinates(series[:x],series[:y])) + push!( axis, series_plot ) + end + end + push!( plt.o, axis ) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) @@ -23,5 +32,8 @@ function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend end function _display(plt::Plot{PGFPlotsXBackend}) + # fn = string(tempname(),".svg") + # PGFPlotsX.pgfsave(fn, plt.o) + # open_browser_window(fn) plt.o end From 9324123b4d298dd1712f809a64d183de7265e383 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 13 Nov 2019 16:00:50 +0100 Subject: [PATCH 096/184] axes labels, legend entries, line color, marker shapes --- src/backends/pgfplotsx.jl | 60 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index a62f2317..44ac5994 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,38 @@ using PGFPlotsX: PGFPlotsX + +const _pgfplotsx_linestyles = KW( + :solid => "solid", + :dash => "dashed", + :dot => "dotted", + :dashdot => "dashdotted", + :dashdotdot => "dashdotdotted", +) + +const _pgfplotsx_markers = KW( + :none => "none", + :cross => "+", + :xcross => "x", + :+ => "+", + :x => "x", + :utriangle => "triangle*", + :dtriangle => "triangle*", + :circle => "*", + :rect => "square*", + :star5 => "star", + :star6 => "asterisk", + :diamond => "diamond*", + :pentagon => "pentagon*", + :hline => "-", + :vline => "|" +) + +const _pgfplotsx_legend_pos = KW( + :bottomleft => "south west", + :bottomright => "south east", + :topright => "north east", + :topleft => "north west", + :outertopright => "outer north east", +) # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) function _update_plot_object(plt::Plot{PGFPlotsXBackend}) @@ -6,10 +40,32 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) local axis for sp in plt.subplots - axis = PGFPlotsX.Axis() + bb = bbox(sp) + axis = PGFPlotsX.@pgf PGFPlotsX.Axis( + { + xlabel = sp.attr[:xaxis][:guide], + ylabel = sp.attr[:yaxis][:guide], + height = string(height(bb)), + width = string(width(bb)), + title = sp[:title], + }, + ) for series in series_list(sp) - series_plot = PGFPlotsX.Plot(PGFPlotsX.Coordinates(series[:x],series[:y])) + opt = series.plotattributes + series_plot = PGFPlotsX.@pgf PGFPlotsX.Plot( + { + color = opt[:linecolor], + mark = _pgfplotsx_markers[opt[:markershape]], + # TODO: how to do nested options? + # "mark options" = "{color = $(opt[:markercolor])}", + }, + PGFPlotsX.Coordinates(series[:x],series[:y]) + ) push!( axis, series_plot ) + if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end end end push!( plt.o, axis ) From 1ef4cfb86a61b98a989650ca2e3b5e24cfb7a260 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 14 Nov 2019 07:37:21 +0100 Subject: [PATCH 097/184] markercolor --- src/backends/pgfplotsx.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 44ac5994..d2fc8622 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -56,8 +56,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) { color = opt[:linecolor], mark = _pgfplotsx_markers[opt[:markershape]], - # TODO: how to do nested options? - # "mark options" = "{color = $(opt[:markercolor])}", + mark_options = {color = opt[:markercolor]}, }, PGFPlotsX.Coordinates(series[:x],series[:y]) ) From 046643f7437f679bdeff51ccb33f91f315fb98aa Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 14 Nov 2019 16:45:31 +0100 Subject: [PATCH 098/184] fix code loading --- Project.toml | 1 - src/backends.jl | 1 - 2 files changed, 2 deletions(-) diff --git a/Project.toml b/Project.toml index 9c172eb9..6b6c0284 100644 --- a/Project.toml +++ b/Project.toml @@ -15,7 +15,6 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e" NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043" diff --git a/src/backends.jl b/src/backends.jl index d8074d35..f9b7ce12 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -37,7 +37,6 @@ macro init_backend(s) _backendType[Symbol($str)] = $T _backendSymbol[$T] = Symbol($str) _backend_packages[Symbol($str)] = Symbol($package_str) - # include("backends/" * $str * ".jl") end) end From 10868ef5651eb446a668af079e6f23b8eaecf7da Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 14 Nov 2019 22:31:22 +0100 Subject: [PATCH 099/184] options translation part 1, use Options instead of @pgf --- src/backends/pgfplotsx.jl | 420 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 400 insertions(+), 20 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index d2fc8622..455f61cc 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,5 +1,3 @@ -using PGFPlotsX: PGFPlotsX - const _pgfplotsx_linestyles = KW( :solid => "solid", :dash => "dashed", @@ -33,41 +31,423 @@ const _pgfplotsx_legend_pos = KW( :topleft => "north west", :outertopright => "outer north east", ) + +const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] +const _pgfx_framestyle_defaults = Dict(:semi => :box) +## -------------------------------------------------------------------------------------- +function pgfx_framestyle(style::Symbol) + if style in _pgfx_framestyles + return style + else + default_style = get(_pgfx_framestyle_defaults, style, :axes) + @warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.") + default_style + end +end + +pgfx_thickness_scaling(plt::Plot) = plt[:thickness_scaling] +pgfx_thickness_scaling(sp::Subplot) = pgfx_thickness_scaling(sp.plt) +pgfx_thickness_scaling(series) = pgfx_thickness_scaling(series[:subplot]) + +function pgfx_fillstyle(plotattributes, i = 1) + cstr = get_fillcolor(plotattributes, i) + a = alpha(cstr) + fa = get_fillalpha(plotattributes, i) + if fa !== nothing + a = fa + end + fill => cstr, fill_opacity => a +end + +function pgfx_linestyle(linewidth::Real, color, α = 1, linestyle = "solid") + cstr = plot_color(color, α) + a = alpha(cstr) + return PGFPlotsX.Options( + "color" => cstr, + "draw opacity" => a, + "line width" => linewidth, + get(_pgfplotsx_linestyles, linestyle, "solid") => nothing + ) +end + +function pgfx_linestyle(plotattributes, i = 1) + lw = pgfx_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i) + lc = get_linecolor(plotattributes, i) + la = get_linealpha(plotattributes, i) + ls = get_linestyle(plotattributes, i) + return pgfx_linestyle(lw, lc, la, ls) +end + +function pgfx_font(fontsize, thickness_scaling = 1, font = "\\selectfont") + fs = fontsize * thickness_scaling + return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}") +end + +function pgfx_marker(plotattributes, i = 1) + shape = _cycle(plotattributes[:markershape], i) + cstr = plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)) + a = alpha(cstr) + cstr_stroke = plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)) + a_stroke = alpha(cstr_stroke) + return PGFPlotsX.Options( + "mark" => get(_pgfplotsx_markers, shape, "*"), + "mark size" => pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i), + "mark options" => PGFPlotsX.Options( + "color" => cstr_stroke, + "draw opacity" => a_stroke, + "fill" => cstr, + "fill opacity" => a, + "line width" => pgfx_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i), + "rotate" => (shape == :dtriangle ? 180 : 0), + get(_pgfplotsx_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid") => nothing + ) + ) +end + +function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) + # Construct the style string. + # Currently supports color and orientation + cstr = val.font.color + a = alpha(cstr) + #TODO: translate this + push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text + x, y, + style=""" + $(get(_pgfx_annotation_halign,val.font.halign,"")), + color=$cstr, draw opacity=$(convert(Float16,a)), + rotate=$(val.font.rotation), + font=$(pgfx_font(val.font.pointsize, thickness_scaling)) + """)) +end +## -------------------------------------------------------------------------------------- +# TODO: translate these if needed +function pgf_series(sp::Subplot, series::Series) + plotattributes = series.plotattributes + st = plotattributes[:seriestype] + series_collection = PGFPlots.Plot[] + + # function args + args = if st == :contour + plotattributes[:z].surf, plotattributes[:x], plotattributes[:y] + elseif is3d(st) + plotattributes[:x], plotattributes[:y], plotattributes[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = plotattributes[:x], plotattributes[:y] + rad2deg.(theta), r + else + plotattributes[:x], plotattributes[:y] + end + + # PGFPlots can't handle non-Vector? + args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector + collect(a) + else + a + end, args) + + if st in (:contour, :histogram2d) + style = [] + kw = KW() + push!(style, pgf_linestyle(plotattributes)) + push!(style, pgf_marker(plotattributes)) + push!(style, "forget plot") + + kw[:style] = join(style, ',') + func = if st == :histogram2d + PGFPlots.Histogram2 + else + kw[:labels] = series[:contour_labels] + kw[:levels] = series[:levels] + PGFPlots.Contour + end + push!(series_collection, func(args...; kw...)) + + else + # series segments + segments = iter_segments(series) + for (i, rng) in enumerate(segments) + style = [] + kw = KW() + push!(style, pgf_linestyle(plotattributes, i)) + push!(style, pgf_marker(plotattributes, i)) + + if st == :shape + push!(style, pgf_fillstyle(plotattributes, i)) + end + + # add to legend? + if i == 1 && sp[:legend] != :none && should_add_to_legend(series) + if plotattributes[:fillrange] !== nothing + push!(style, "forget plot") + push!(series_collection, pgf_fill_legend_hack(plotattributes, args)) + else + kw[:legendentry] = plotattributes[:label] + if st == :shape # || plotattributes[:fillrange] !== nothing + push!(style, "area legend") + end + end + else + push!(style, "forget plot") + end + + seg_args = (arg[rng] for arg in args) + + # include additional style, then add to the kw + if haskey(_pgf_series_extrastyle, st) + push!(style, _pgf_series_extrastyle[st]) + end + kw[:style] = join(style, ',') + + # add fillrange + if series[:fillrange] !== nothing && st != :shape + push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + end + + # build/return the series object + func = if st == :path3d + PGFPlots.Linear3 + elseif st == :scatter + PGFPlots.Scatter + else + PGFPlots.Linear + end + push!(series_collection, func(seg_args...; kw...)) + end + end + series_collection +end + +function pgf_fillrange_series(series, i, fillrange, args...) + st = series[:seriestype] + style = [] + kw = KW() + push!(style, "line width = 0") + push!(style, "draw opacity = 0") + push!(style, pgf_fillstyle(series, i)) + push!(style, pgf_marker(series, i)) + push!(style, "forget plot") + if haskey(_pgf_series_extrastyle, st) + push!(style, _pgf_series_extrastyle[st]) + end + kw[:style] = join(style, ',') + func = is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear + return func(pgf_fillrange_args(fillrange, args...)...; kw...) +end + +function pgf_fillrange_args(fillrange, x, y) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] + return x_fill, y_fill +end + +function pgf_fillrange_args(fillrange, x, y, z) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; y[n:-1:1]; x[1]] + z_fill = [z; _cycle(fillrange, n:-1:1); z[1]] + return x_fill, y_fill, z_fill +end + +function pgf_fill_legend_hack(plotattributes, args) + style = [] + kw = KW() + push!(style, pgf_linestyle(plotattributes, 1)) + push!(style, pgf_marker(plotattributes, 1)) + push!(style, pgf_fillstyle(plotattributes, 1)) + push!(style, "area legend") + kw[:legendentry] = plotattributes[:label] + kw[:style] = join(style, ',') + st = plotattributes[:seriestype] + func = if st == :path3d + PGFPlots.Linear3 + elseif st == :scatter + PGFPlots.Scatter + else + PGFPlots.Linear + end + return func(([arg[1]] for arg in args)...; kw...) +end + +# -------------------------------------------------------------------------------------- +function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) + axis = sp[Symbol(letter,:axis)] + + # turn off scaled ticks + push!(opt, "scaled $(letter) ticks" => "false", + string(letter,:label) => axis[:guide], + ) + + # set to supported framestyle + framestyle = pgfx_framestyle(sp[:framestyle]) + + # axis label position + labelpos = "" + if letter == :x && axis[:guide_position] == :top + labelpos = "at={(0.5,1)},above," + elseif letter == :y && axis[:guide_position] == :right + labelpos = "at={(1,0.5)},below," + end + + # Add label font + cstr = plot_color(axis[:guidefontcolor]) + α = alpha(cstr) + push!(opt, string(letter, "label style") => PGFPlotsX.Options( + labelpos => nothing, + "font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)), + "color" => cstr, + "draw opacity" => α, + "rotate" => axis[:guidefontrotation], + ) + ) + + # flip/reverse? + axis[:flip] && push!(opt, "$letter dir" => "reverse") + + # scale + scale = axis[:scale] + if scale in (:log2, :ln, :log10) + push!(opt, string(letter,:mode) => "log") + scale == :ln || push!(opt, "log basis $letter" => "$(scale == :log2 ? 2 : 10)") + end + + # ticks on or off + if axis[:ticks] in (nothing, false, :none) || framestyle == :none + push!(opt, "$(letter)majorticks" => "false") + end + + # grid on or off + if axis[:grid] && framestyle != :none + push!(opt, "$(letter)majorgrids" => "true") + else + push!(opt, "$(letter)majorgrids" => "false") + end + + # limits + # TODO: support zlims + if letter != :z + lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) + push!( opt, + string(letter,:min) => lims[1], + string(letter,:max) => lims[2] + ) + end + + if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none + ticks = get_ticks(sp, axis) + #pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values + tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1] + push!(opt, string(letter, "tick") => string("{", join(tick_values,","), "}")) + if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto + # wrap the power part of label with } + tick_labels = Vector{String}(undef, length(ticks[2])) + for (i, label) in enumerate(ticks[2]) + base, power = split(label, "^") + power = string("{", power, "}") + tick_labels[i] = string(base, "^", power) + end + push!(opt, string(letter, "ticklabels") => string("{\$", join(tick_labels,"\$,\$"), "\$}")) + elseif axis[:showaxis] + tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2] + if axis[:formatter] in (:scientific, :auto) + tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$") + tick_labels = replace.(tick_labels, Ref("×" => "\\times")) + end + push!(opt, string(letter, "ticklabels") => string("{", join(tick_labels,","), "}")) + else + push!(opt, string(letter, "ticklabels") => "{}") + end + push!(opt, string(letter, "tick align") => (axis[:tick_direction] == :out ? "outside" : "inside")) + cstr = plot_color(axis[:tickfontcolor]) + α = alpha(cstr) + push!(opt, string(letter, "ticklabel style") => PGFPlotsX.Options( + "font" => pgfx_font(axis[:tickfontsize], pgfx_thickness_scaling(sp)), + "color" => cstr, + "draw opacity" => α, + "rotate" => axis[:tickfontrotation] + ) + ) + push!(opt, string(letter, " grid style") => pgfx_linestyle(pgfx_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle]) + ) + end + + # framestyle + if framestyle in (:axes, :origin) + axispos = framestyle == :axes ? "left" : "middle" + if axis[:draw_arrow] + push!(opt, string("axis ", letter, " line") => axispos) + else + # the * after line disables the arrow at the axis + push!(opt, string("axis ", letter, " line*") => axispos) + end + end + + if framestyle == :zerolines + push!(opt, string("extra ", letter, " ticks") => "0") + push!(opt, string("extra ", letter, " tick labels") => "") + push!(opt, string("extra ", letter, " tick style") => PGFPlotsX.Options( + "grid" => "major", + "major grid style" => pgfx_linestyle(pgfx_thickness_scaling(sp), axis[:foreground_color_border], 1.0) + ) + ) + end + + if !axis[:showaxis] + push!(opt, "separate axis lines") + end + if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none) + push!(opt, string(letter, " axis line style") => "{draw opacity = 0}") + else + push!(opt, string(letter, " axis line style") => pgfx_linestyle(pgfx_thickness_scaling(sp), axis[:foreground_color_border], 1.0) + ) + end +end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsX.GroupPlot() - local axis for sp in plt.subplots bb = bbox(sp) - axis = PGFPlotsX.@pgf PGFPlotsX.Axis( - { - xlabel = sp.attr[:xaxis][:guide], - ylabel = sp.attr[:yaxis][:guide], - height = string(height(bb)), - width = string(width(bb)), - title = sp[:title], - }, + axis_opt = PGFPlotsX.Options( + "height" => string(height(bb)), + "width" => string(width(bb)), + "title" => sp[:title], + ) + for letter in (:x, :y, :z) + if letter != :z || is3d(sp) + pgfx_axis!(axis_opt, sp, letter) + end + end + axis = PGFPlotsX.Axis( + axis_opt ) for series in series_list(sp) opt = series.plotattributes - series_plot = PGFPlotsX.@pgf PGFPlotsX.Plot( - { - color = opt[:linecolor], - mark = _pgfplotsx_markers[opt[:markershape]], - mark_options = {color = opt[:markercolor]}, - }, - PGFPlotsX.Coordinates(series[:x],series[:y]) + segments = iter_segments(series) + for (i, rng) in enumerate(segments) + series_plot = PGFPlotsX.Plot( + merge( + PGFPlotsX.Options( + "color" => opt[:linecolor] + ), + pgfx_marker(opt, i) + ), + PGFPlotsX.Coordinates(series[:x],series[:y]) ) - push!( axis, series_plot ) + push!( axis, series_plot ) + end if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) ) end end + push!( plt.o, axis ) end - push!( plt.o, axis ) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) From 914d3cac448fc9cec3feb9feda90a292339feb5b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 08:52:56 +0100 Subject: [PATCH 100/184] legend styling --- src/backends/pgfplotsx.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 455f61cc..0a1f58f6 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -413,10 +413,21 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for sp in plt.subplots bb = bbox(sp) + legpos = sp[:legend] + if haskey(_pgfplotsx_legend_pos, legpos) + legpos = _pgfplotsx_legend_pos[legpos] + end + cstr = plot_color(sp[:background_color_legend]) + a = alpha(cstr) axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), "title" => sp[:title], + "legend style" => PGFPlotsX.Options( + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, + "fill" => cstr, + "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + ) ) for letter in (:x, :y, :z) if letter != :z || is3d(sp) From bc42001b75b6f16db68cd22f7a4fd636fe8e9fef Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 09:42:05 +0100 Subject: [PATCH 101/184] translate pgf_add_aanotation! --- src/backends/pgfplotsx.jl | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 0a1f58f6..fd1decac 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -34,6 +34,14 @@ const _pgfplotsx_legend_pos = KW( const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] const _pgfx_framestyle_defaults = Dict(:semi => :box) + +# we use the anchors to define orientations for example to align left +# one needs to use the right edge as anchor +const _pgfx_annotation_halign = KW( + :center => "", + :left => "right", + :right => "left" +) ## -------------------------------------------------------------------------------------- function pgfx_framestyle(style::Symbol) if style in _pgfx_framestyles @@ -109,15 +117,18 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) # Currently supports color and orientation cstr = val.font.color a = alpha(cstr) - #TODO: translate this - push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text - x, y, - style=""" - $(get(_pgfx_annotation_halign,val.font.halign,"")), - color=$cstr, draw opacity=$(convert(Float16,a)), - rotate=$(val.font.rotation), - font=$(pgfx_font(val.font.pointsize, thickness_scaling)) - """)) + push!(o, ["\\node", + PGFPlotsX.Options( + get(_pgfx_annotation_halign,val.font.halign,"") => nothing, + "color" => cstr, + "draw opacity" => convert(Float16, a), + "rotate" => val.font.rotation, + "font" => pgfx_font(val.font.pointsize, thickness_scaling) + ), + " at ", + PGFPlotsX.Coordinate(x, y), + "{$(val.str).};" + ]) end ## -------------------------------------------------------------------------------------- # TODO: translate these if needed From 32d712ce29500a041417e1dfb50dc2bb1f2921c7 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 13:47:04 +0100 Subject: [PATCH 102/184] apply annotations --- src/backends/pgfplotsx.jl | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index fd1decac..becb538a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -135,7 +135,7 @@ end function pgf_series(sp::Subplot, series::Series) plotattributes = series.plotattributes st = plotattributes[:seriestype] - series_collection = PGFPlots.Plot[] + series_collection = PGFPlotsX.Plot[] # function args args = if st == :contour @@ -154,11 +154,11 @@ function pgf_series(sp::Subplot, series::Series) end # PGFPlots can't handle non-Vector? - args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector - collect(a) - else - a - end, args) + # args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector + # collect(a) + # else + # a + # end, args) if st in (:contour, :histogram2d) style = [] @@ -452,17 +452,24 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) opt = series.plotattributes segments = iter_segments(series) for (i, rng) in enumerate(segments) - series_plot = PGFPlotsX.Plot( - merge( - PGFPlotsX.Options( - "color" => opt[:linecolor] - ), - pgfx_marker(opt, i) - ), - PGFPlotsX.Coordinates(series[:x],series[:y]) - ) - push!( axis, series_plot ) + # TODO: make segmented series end + # TODO: different seriestypes, histogramms, contours, etc. + series_plot = PGFPlotsX.Plot( + merge( + PGFPlotsX.Options( + "color" => opt[:linecolor] + ), + pgfx_marker(opt, i) + ), + PGFPlotsX.Coordinates(series[:x],series[:y]) + ) + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) + end + push!( axis, series_plot ) if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) ) From e34570e307bf0e2c84e726b6b41286c0c246e92e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 15:47:36 +0100 Subject: [PATCH 103/184] basic 3D --- src/backends/pgfplotsx.jl | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index becb538a..b094a4e8 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -451,18 +451,29 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for series in series_list(sp) opt = series.plotattributes segments = iter_segments(series) + segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) - # TODO: make segmented series + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end # TODO: different seriestypes, histogramms, contours, etc. - series_plot = PGFPlotsX.Plot( + # TODO: colorbars + # TOOD: gradients + if is3d(series) + series_func = opt -> PGFPlotsX.Plot3(opt, + PGFPlotsX.Coordinates(series[:x],series[:y],series[:z]) + ) + else + series_func = opt -> PGFPlotsX.Plot(opt, + PGFPlotsX.Coordinates(series[:x],series[:y]) + ) + end + series_plot = series_func( merge( PGFPlotsX.Options( "color" => opt[:linecolor] ), - pgfx_marker(opt, i) + segment_opt ), - PGFPlotsX.Coordinates(series[:x],series[:y]) ) # add series annotations anns = series[:series_annotations] From 9fb6b8059fcd6e2f6081924041bf3496dba43df0 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 16:13:54 +0100 Subject: [PATCH 104/184] translate pgf_fillrange_series --- src/backends/pgfplotsx.jl | 62 ++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index b094a4e8..d7e8c3ea 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -32,6 +32,15 @@ const _pgfplotsx_legend_pos = KW( :outertopright => "outer north east", ) +const _pgfx_series_extrastyle = KW( + :steppre => "const plot mark right", + :stepmid => "const plot mark mid", + :steppost => "const plot", + :sticks => "ycomb", + :ysticks => "ycomb", + :xsticks => "xcomb", +) + const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] const _pgfx_framestyle_defaults = Dict(:semi => :box) @@ -64,7 +73,7 @@ function pgfx_fillstyle(plotattributes, i = 1) if fa !== nothing a = fa end - fill => cstr, fill_opacity => a + PGFPlotsX.Options("fill" => cstr, "fill opacity" => a) end function pgfx_linestyle(linewidth::Real, color, α = 1, linestyle = "solid") @@ -232,21 +241,18 @@ function pgf_series(sp::Subplot, series::Series) series_collection end -function pgf_fillrange_series(series, i, fillrange, args...) +function pgfx_fillrange_series!(opt, series, i, fillrange, args...) st = series[:seriestype] - style = [] - kw = KW() - push!(style, "line width = 0") - push!(style, "draw opacity = 0") - push!(style, pgf_fillstyle(series, i)) - push!(style, pgf_marker(series, i)) - push!(style, "forget plot") - if haskey(_pgf_series_extrastyle, st) - push!(style, _pgf_series_extrastyle[st]) + push!(opt, "line width" => 0) + push!(opt, "draw opacity" => 0) + push!(opt, pgfx_fillopt(series, i)) + push!(opt, pgfx_marker(series, i)) + push!(opt, "forget plot" => nothing) + if haskey(_pgfx_series_extraopt, st) + push!(opt, _pgfx_series_extrastyle[st] => nothing) end - kw[:style] = join(style, ',') - func = is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear - return func(pgf_fillrange_args(fillrange, args...)...; kw...) + # TODO: what are those fillrange_args about? + # return func(pgf_fillrange_args(fillrange, args...)...; kw...) end function pgf_fillrange_args(fillrange, x, y) @@ -450,14 +456,33 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) ) for series in series_list(sp) opt = series.plotattributes + st = series[:seriestype] + series_opt = PGFPlotsX.Options( + "color" => opt[:linecolor] + ) segments = iter_segments(series) segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + if st == :shape + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + # TODO: is this necessary? + # seg_args = (arg[rng] for arg in args) + # TODO: translate this + # # add fillrange + # if series[:fillrange] !== nothing && st != :shape + # push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + # end + end + #include additional style + if haskey(_pgfx_series_extrastyle, st) + push!(series_opt, _pgfx_series_extrastyle[st] => nothing) end # TODO: different seriestypes, histogramms, contours, etc. # TODO: colorbars - # TOOD: gradients + # TODO: gradients if is3d(series) series_func = opt -> PGFPlotsX.Plot3(opt, PGFPlotsX.Coordinates(series[:x],series[:y],series[:z]) @@ -468,12 +493,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) ) end series_plot = series_func( - merge( - PGFPlotsX.Options( - "color" => opt[:linecolor] - ), - segment_opt - ), + merge(series_opt, segment_opt), ) # add series annotations anns = series[:series_annotations] From 7f1863f3b937833cd86f2e68a47c792d54740b0b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 15 Nov 2019 16:41:47 +0100 Subject: [PATCH 105/184] add guard against overexecution --- src/backends/pgfplotsx.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index d7e8c3ea..f6c539f5 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -425,7 +425,13 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) +let n_calls = 0 +function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) + n_calls = 0 +end + function _update_plot_object(plt::Plot{PGFPlotsXBackend}) +if n_calls === 0 plt.o = PGFPlotsX.GroupPlot() for sp in plt.subplots @@ -509,6 +515,8 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) push!( plt.o, axis ) end end +n_calls += 1 +end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) show(io, mime, plt.o) From fc6dfb8dcb725baceb216093709cabe51b7cbf17 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 18 Nov 2019 11:51:03 +0100 Subject: [PATCH 106/184] translated pgf_fillrange_series --- src/backends/pgfplotsx.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index f6c539f5..9f8678c8 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -241,8 +241,9 @@ function pgf_series(sp::Subplot, series::Series) series_collection end -function pgfx_fillrange_series!(opt, series, i, fillrange, args...) +function pgfx_fillrange_series(series, i, fillrange, args...) st = series[:seriestype] + opt = PGFPlotsX.Options() push!(opt, "line width" => 0) push!(opt, "draw opacity" => 0) push!(opt, pgfx_fillopt(series, i)) @@ -251,18 +252,18 @@ function pgfx_fillrange_series!(opt, series, i, fillrange, args...) if haskey(_pgfx_series_extraopt, st) push!(opt, _pgfx_series_extrastyle[st] => nothing) end - # TODO: what are those fillrange_args about? - # return func(pgf_fillrange_args(fillrange, args...)...; kw...) + func = is3d(series) ? PGFPlotsX.Plot3 : PGFPlotsX.Plot + return func(opt, pgfx_fillrange_args(fillrange, args...)...) end -function pgf_fillrange_args(fillrange, x, y) +function pgfx_fillrange_args(fillrange, x, y) n = length(x) x_fill = [x; x[n:-1:1]; x[1]] y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] return x_fill, y_fill end -function pgf_fillrange_args(fillrange, x, y, z) +function pgfx_fillrange_args(fillrange, x, y, z) n = length(x) x_fill = [x; x[n:-1:1]; x[1]] y_fill = [y; y[n:-1:1]; x[1]] From 7954adedf3e41a630ead77414ef9caacfb2ddbfa Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 18 Nov 2019 16:13:56 +0100 Subject: [PATCH 107/184] translation of pgf_colormap --- src/backends/pgfplotsx.jl | 83 ++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 9f8678c8..0093e35a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -52,6 +52,14 @@ const _pgfx_annotation_halign = KW( :right => "left" ) ## -------------------------------------------------------------------------------------- +# Generates a colormap for pgfplots based on a ColorGradient +# TODO: maybe obsolete +function pgfx_colormap(grad::ColorGradient) + join(map(grad.colors) do c + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c)) + end,", ") +end + function pgfx_framestyle(style::Symbol) if style in _pgfx_framestyles return style @@ -426,13 +434,11 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) -let n_calls = 0 function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) - n_calls = 0 + # TODO: don't rebuild plots so often end function _update_plot_object(plt::Plot{PGFPlotsXBackend}) -if n_calls === 0 plt.o = PGFPlotsX.GroupPlot() for sp in plt.subplots @@ -458,12 +464,60 @@ if n_calls === 0 pgfx_axis!(axis_opt, sp, letter) end end + # Search series for any gradient. In case one series uses a gradient set + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + push!(axis_opt, + "colormap" => "{plots}{$(pgfx_colormap(series.plotattributes[col]))}") + + # TODO: is this needed? + # if sp[:colorbar] == :none + # kw[:colorbar] = "false" + # else + # kw[:colorbar] = "true" + # end + # goto is needed to break out of col and series for + @goto colorbar_end + end + end + end + @label colorbar_end + + push!(axis_opt, "colorbar style" => PGFPlotsX.Options( + "title" => sp[:colorbar_title] + ) + ) axis = PGFPlotsX.Axis( axis_opt ) for series in series_list(sp) opt = series.plotattributes st = series[:seriestype] + # function args + args = if st == :contour + opt[:z].surf, opt[:x], opt[:y] + elseif is3d(st) + opt[:x], opt[:y], opt[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = opt[:x], opt[:y] + rad2deg.(theta), r + else + opt[:x], opt[:y] + end series_opt = PGFPlotsX.Options( "color" => opt[:linecolor] ) @@ -475,13 +529,11 @@ if n_calls === 0 if st == :shape segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end - # TODO: is this necessary? - # seg_args = (arg[rng] for arg in args) - # TODO: translate this - # # add fillrange - # if series[:fillrange] !== nothing && st != :shape - # push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) - # end + seg_args = (arg[rng] for arg in args) + # add fillrange + if series[:fillrange] !== nothing && st != :shape + push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + end end #include additional style if haskey(_pgfx_series_extrastyle, st) @@ -491,16 +543,13 @@ if n_calls === 0 # TODO: colorbars # TODO: gradients if is3d(series) - series_func = opt -> PGFPlotsX.Plot3(opt, - PGFPlotsX.Coordinates(series[:x],series[:y],series[:z]) - ) + series_func = PGFPlotsX.Plot3 else - series_func = opt -> PGFPlotsX.Plot(opt, - PGFPlotsX.Coordinates(series[:x],series[:y]) - ) + series_func = PGFPlotsX.Plot end series_plot = series_func( merge(series_opt, segment_opt), + PGFPlotsX.Coordinates(args...) ) # add series annotations anns = series[:series_annotations] @@ -516,8 +565,6 @@ if n_calls === 0 push!( plt.o, axis ) end end -n_calls += 1 -end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) show(io, mime, plt.o) From 6d3e8fcb81f4a6360d383a0b3e9ec7fbd3824cc6 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 18 Nov 2019 17:16:27 +0100 Subject: [PATCH 108/184] add tests --- Project.toml | 3 ++- src/backends/pgfplotsx.jl | 4 ++++ test/runtests.jl | 2 ++ test/test_pgfplotsx.jl | 13 +++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 test/test_pgfplotsx.jl diff --git a/Project.toml b/Project.toml index 6b6c0284..b87f0ffd 100644 --- a/Project.toml +++ b/Project.toml @@ -56,6 +56,7 @@ ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" +PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" @@ -64,4 +65,4 @@ UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92" [targets] -test = ["FileIO", "GeometryTypes", "Gtk", "ImageMagick", "Images", "LaTeXStrings", "LibGit2", "Random", "RDatasets", "StatsPlots", "Test", "UnicodePlots", "VisualRegressionTests"] +test = ["FileIO", "GeometryTypes", "Gtk", "ImageMagick", "Images", "LaTeXStrings", "LibGit2", "PGFPlotsX", "Random", "RDatasets", "StatsPlots", "Test", "UnicodePlots", "VisualRegressionTests"] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 0093e35a..2b7ea449 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -567,18 +567,22 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) + _update_plot_object(plt) show(io, mime, plt.o) end function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) + _update_plot_object(plt) show(io, mime, plt.o) end function _show(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsXBackend}) + _update_plot_object(plt) show(io, mime, plt.o) end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) + _update_plot_object(plt) PGFPlotsX.print_tex(plt.o) end diff --git a/test/runtests.jl b/test/runtests.jl index 55c7e963..16ad485f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -8,6 +8,8 @@ using Gtk using LibGit2 using GeometryTypes +include("test_pgfplotsx.jl") + reference_dir(args...) = joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...) function reference_file(backend, i, version) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl new file mode 100644 index 00000000..a46a0a35 --- /dev/null +++ b/test/test_pgfplotsx.jl @@ -0,0 +1,13 @@ +using Plots, Test +pgfplotsx() + +function create_plot( args...; kwargs... ) + pgfx_plot = plot(args..., kwargs...) + return pgfx_plot, repr("application/x-tex", pgfx_plot) +end + +@testset "PGFPlotsX" begin + pgfx_plot, pgfx_tex = create_plot(1:5) + + @test pgfx_plot.o isa PGFPlotsX.GroupPlot +end # testset From c2c1c9d7386772d48f56d0e79aaf1abaa7e29fcb Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 18 Nov 2019 19:05:49 +0100 Subject: [PATCH 109/184] tests for 3D colorbar --- src/backends/pgfplotsx.jl | 13 +++++++++++-- test/test_pgfplotsx.jl | 23 +++++++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 2b7ea449..c38f11a3 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -57,7 +57,7 @@ const _pgfx_annotation_halign = KW( function pgfx_colormap(grad::ColorGradient) join(map(grad.colors) do c @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c)) - end,", ") + end,"\n") end function pgfx_framestyle(style::Symbol) @@ -441,6 +441,8 @@ end function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsX.GroupPlot() + pushed_colormap = false + empty!(PGFPlotsX.CUSTOM_PREAMBLE) for sp in plt.subplots bb = bbox(sp) legpos = sp[:legend] @@ -477,8 +479,15 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for series in series_list(sp) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient + # TODO: fix this + # pushed_colormap || push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ + # colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, + # }""") + pushed_colormap = true push!(axis_opt, - "colormap" => "{plots}{$(pgfx_colormap(series.plotattributes[col]))}") + # "colormap" => nothing, + # "colormap name" => "plots", + ) # TODO: is this needed? # if sp[:colorbar] == :none diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index a46a0a35..a636fd91 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -2,12 +2,31 @@ using Plots, Test pgfplotsx() function create_plot( args...; kwargs... ) - pgfx_plot = plot(args..., kwargs...) + pgfx_plot = plot(args...; kwargs...) + return pgfx_plot, repr("application/x-tex", pgfx_plot) +end + +function create_plot!( args...; kwargs... ) + pgfx_plot = plot!(args...; kwargs...) return pgfx_plot, repr("application/x-tex", pgfx_plot) end @testset "PGFPlotsX" begin pgfx_plot, pgfx_tex = create_plot(1:5) - + @test pgfx_plot.o isa PGFPlotsX.GroupPlot + @testset "3D docs example" begin + n = 100 + ts = range(0, stop=8π, length=n) + x = ts .* map(cos, ts) + y = (0.1ts) .* map(sin, ts) + z = 1:n + pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5) + @show PGFPlotsX.CUSTOM_PREAMBLE + @show PGFPlotsX.CUSTOM_PREAMBLE_PATH + pgfx_plot, pgfx_tex = create_plot!(pl, zeros(n), zeros(n), 1:n, w=10) + if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colormap") == true) + @test pgfx_plot.o.contents[1]["colormap"] === nothing + end + end # testset end # testset From ce1276bcbdf2ba7fadffe391c991b4d4d8a64714 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 11:30:34 +0100 Subject: [PATCH 110/184] title styling --- src/backends/pgfplotsx.jl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c38f11a3..c3e13709 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -56,7 +56,7 @@ const _pgfx_annotation_halign = KW( # TODO: maybe obsolete function pgfx_colormap(grad::ColorGradient) join(map(grad.colors) do c - @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c)) + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) end,"\n") end @@ -451,14 +451,26 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end cstr = plot_color(sp[:background_color_legend]) a = alpha(cstr) + title_cstr = plot_color(sp[:titlefontcolor]) + title_a = alpha(cstr) + # TODO: aspect ratio, legend position axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), "title" => sp[:title], + "title style" => PGFPlotsX.Options( + "font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)), + "color" => title_cstr, + "draw opacity" => title_a, + "rotate" => sp[:titlefontrotation] + ), "legend style" => PGFPlotsX.Options( - pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, - "fill" => cstr, - "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, + "fill" => cstr, + "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + ), + "axis background/.style" => PGFPlotsX.Options( + "fill" => sp[:background_color_inside] ) ) for letter in (:x, :y, :z) From 0dd970fc6bae2e771735c1b2efe68bd06a633017 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 11:34:21 +0100 Subject: [PATCH 111/184] claim everything --- src/backends.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index f9b7ce12..dddeea47 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -711,7 +711,9 @@ const _pgfplotsx_seriestype = [ :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, :shape ] +const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] -const _pgfplotsx_marker = _allMarkers -const _pgfplotsx_scale = [:identity, :log10] -is_marker_supported(::PGFPlotsXBackend, shape::Shape) = false +const _pgfplotsx_marker = vcat(_allMarkers, Shape) + # [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline] # +const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] +is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true From cb1d32422a3b2957e76fb757a3e69431ce8ec223 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 11:35:35 +0100 Subject: [PATCH 112/184] adjust --- src/backends.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index dddeea47..89fa83eb 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -705,12 +705,12 @@ const _pgfplotsx_attr = merge_with_base_supported([ :camera, :contour_labels, ]) -const _pgfplotsx_seriestype = [ - :path, :scatter, :straightline, - :heatmap, :pie, :image, - :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, - :shape -] +# const _pgfplotsx_seriestype = [ +# :path, :scatter, :straightline, +# :heatmap, :pie, :image, +# :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, +# :shape +# ] const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _pgfplotsx_marker = vcat(_allMarkers, Shape) From abc212b0391d8f5eef0864d3304af0d877334392 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 11:58:57 +0100 Subject: [PATCH 113/184] fix colorbar --- src/backends/pgfplotsx.jl | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c3e13709..82a0bded 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -492,14 +492,16 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient # TODO: fix this - # pushed_colormap || push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ - # colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, - # }""") - pushed_colormap = true - push!(axis_opt, - # "colormap" => nothing, - # "colormap name" => "plots", - ) + if !pushed_colormap + push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ + colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + pushed_colormap = true + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots", + ) + end # TODO: is this needed? # if sp[:colorbar] == :none From a117bbc04bf6734951b1e6ae12aa44b07890ebc0 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 12:05:43 +0100 Subject: [PATCH 114/184] correct test --- test/test_pgfplotsx.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index a636fd91..4ee29dbd 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -22,11 +22,9 @@ end y = (0.1ts) .* map(sin, ts) z = 1:n pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5) - @show PGFPlotsX.CUSTOM_PREAMBLE - @show PGFPlotsX.CUSTOM_PREAMBLE_PATH pgfx_plot, pgfx_tex = create_plot!(pl, zeros(n), zeros(n), 1:n, w=10) if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colormap") == true) - @test pgfx_plot.o.contents[1]["colormap"] === nothing + @test pgfx_plot.o.contents[1]["colorbar"] === nothing end end # testset end # testset From f2f647c6428f471c9ea82c053cf5f6f67ef2cdf7 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 12:08:30 +0100 Subject: [PATCH 115/184] legend position --- src/backends/pgfplotsx.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 82a0bded..8fd07e4f 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -453,7 +453,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) a = alpha(cstr) title_cstr = plot_color(sp[:titlefontcolor]) title_a = alpha(cstr) - # TODO: aspect ratio, legend position + # TODO: aspect ratio axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), @@ -464,6 +464,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) "draw opacity" => title_a, "rotate" => sp[:titlefontrotation] ), + "legend pos" => _pgfplotsx_legend_pos[sp[:legend]], "legend style" => PGFPlotsX.Options( pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, "fill" => cstr, From c0e68af63ff58146de15beeb1996451326ee0c69 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 14:47:54 +0100 Subject: [PATCH 116/184] reproduce 3D docs plot --- src/backends/pgfplotsx.jl | 23 +++++++++-------------- test/test_pgfplotsx.jl | 2 +- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 8fd07e4f..422e1c27 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,3 +1,5 @@ +PGFPlotsX.print_tex(io::IO, data::Symbol) = PGFPlotsX.print_tex(io, string(data)) + const _pgfplotsx_linestyles = KW( :solid => "solid", :dash => "dashed", @@ -445,10 +447,6 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) empty!(PGFPlotsX.CUSTOM_PREAMBLE) for sp in plt.subplots bb = bbox(sp) - legpos = sp[:legend] - if haskey(_pgfplotsx_legend_pos, legpos) - legpos = _pgfplotsx_legend_pos[legpos] - end cstr = plot_color(sp[:background_color_legend]) a = alpha(cstr) title_cstr = plot_color(sp[:titlefontcolor]) @@ -464,7 +462,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) "draw opacity" => title_a, "rotate" => sp[:titlefontrotation] ), - "legend pos" => _pgfplotsx_legend_pos[sp[:legend]], + "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), "legend style" => PGFPlotsX.Options( pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, "fill" => cstr, @@ -492,7 +490,6 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for series in series_list(sp) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient - # TODO: fix this if !pushed_colormap push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, @@ -504,12 +501,6 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) ) end - # TODO: is this needed? - # if sp[:colorbar] == :none - # kw[:colorbar] = "false" - # else - # kw[:colorbar] = "true" - # end # goto is needed to break out of col and series for @goto colorbar_end end @@ -543,8 +534,12 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) opt[:x], opt[:y] end series_opt = PGFPlotsX.Options( - "color" => opt[:linecolor] + "color" => opt[:linecolor], + "scatter" => nothing, ) + if opt[:marker_z] !== nothing + push!(series_opt, "point meta" => "explicit") + end segments = iter_segments(series) segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) @@ -573,7 +568,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end series_plot = series_func( merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(args...) + PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) ) # add series annotations anns = series[:series_annotations] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 4ee29dbd..12e3ae0e 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -23,7 +23,7 @@ end z = 1:n pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5) pgfx_plot, pgfx_tex = create_plot!(pl, zeros(n), zeros(n), 1:n, w=10) - if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colormap") == true) + if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colorbar") == true) @test pgfx_plot.o.contents[1]["colorbar"] === nothing end end # testset From 57db8095c404ef503de1bab2d5a987a84276967a Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 14:58:03 +0100 Subject: [PATCH 117/184] add area legend for shapes --- src/backends/pgfplotsx.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 422e1c27..9b6dbbd5 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -537,6 +537,9 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) "color" => opt[:linecolor], "scatter" => nothing, ) + if st == :shape + push!(series_opt, "area legend" => nothing) + end if opt[:marker_z] !== nothing push!(series_opt, "point meta" => "explicit") end From 424b98e1a1fdf0a5a6ec9d5d54523c339c9c9ae4 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 15:06:34 +0100 Subject: [PATCH 118/184] fix pgfx_fillrange_series --- src/backends/pgfplotsx.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 9b6dbbd5..46e38136 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -256,14 +256,14 @@ function pgfx_fillrange_series(series, i, fillrange, args...) opt = PGFPlotsX.Options() push!(opt, "line width" => 0) push!(opt, "draw opacity" => 0) - push!(opt, pgfx_fillopt(series, i)) - push!(opt, pgfx_marker(series, i)) + opt = merge(opt, pgfx_fillstyle(series, i)) + opt = merge(opt, pgfx_marker(series, i)) push!(opt, "forget plot" => nothing) - if haskey(_pgfx_series_extraopt, st) + if haskey(_pgfx_series_extrastyle, st) push!(opt, _pgfx_series_extrastyle[st] => nothing) end func = is3d(series) ? PGFPlotsX.Plot3 : PGFPlotsX.Plot - return func(opt, pgfx_fillrange_args(fillrange, args...)...) + return func(opt, PGFPlotsX.Coordinates(pgfx_fillrange_args(fillrange, args...)...)) end function pgfx_fillrange_args(fillrange, x, y) From 3c9a7193fd78f7dd9be39f4626752cf3710be059 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 15:31:36 +0100 Subject: [PATCH 119/184] status quo --- src/backends/pgfplotsx.jl | 5 ++++- test/test_pgfplotsx.jl | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 46e38136..1308d243 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -535,13 +535,13 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end series_opt = PGFPlotsX.Options( "color" => opt[:linecolor], - "scatter" => nothing, ) if st == :shape push!(series_opt, "area legend" => nothing) end if opt[:marker_z] !== nothing push!(series_opt, "point meta" => "explicit") + push!(series_opt, "scatter" => nothing) end segments = iter_segments(series) segment_opt = PGFPlotsX.Options() @@ -569,6 +569,9 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) else series_func = PGFPlotsX.Plot end + if st == :scatter + push!(series_opt, "only marks" => nothing) + end series_plot = series_func( merge(series_opt, segment_opt), PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 12e3ae0e..47f76ccf 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -27,4 +27,39 @@ end @test pgfx_plot.o.contents[1]["colorbar"] === nothing end end # testset + @testset "Color docs example" begin + y = rand(100) + plot(0:10:100, rand(11, 4), lab="lines", w=3, palette=:grays, fill=0, α=0.6) + scatter!(y, zcolor=abs.(y .- 0.5), m=(:heat, 0.8, Plots.stroke(1, :green)), ms=10 * abs.(y .- 0.5) .+ 4, lab="grad") + # TODO: marker size does not adjust + # TODO: marker stroke is incorrect + # TODO: fill legends + # TODO: adjust colorbar limits to data + end # testset + @testset "Plot in pieces" begin + plot(rand(100) / 3, reg=true, fill=(0, :green)) + scatter!(rand(100), markersize=6, c=:orange) + # TODO: legends should be different + end # testset + @testset "Marker types" begin + markers = filter((m->begin + m in Plots.supported_markers() + end), Plots._shape_keys) + markers = reshape(markers, 1, length(markers)) + n = length(markers) + x = (range(0, stop=10, length=n + 2))[2:end - 1] + y = repeat(reshape(reverse(x), 1, :), n, 1) + scatter(x, y, m=(8, :auto), lab=map(string, markers), bg=:linen, xlim=(0, 10), ylim=(0, 10)) + #TODO: fix markers that show up as circles + end # testset + @testset "Layout" begin + plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black]) + # TODO: add layouting + end # testset + @testset "Polar plots" begin + Θ = range(0, stop=1.5π, length=100) + r = abs.(0.1 * randn(100) + sin.(3Θ)) + plot(Θ, r, proj=:polar, m=2) + # TODO: handle polar plots + end # testset end # testset From 10e7cb8ebab4bb3c1c60de8043486a4231a1cbcf Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 16:30:53 +0100 Subject: [PATCH 120/184] use TikzDocument and its preamble --- src/backends/pgfplotsx.jl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 1308d243..77d75e92 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -436,15 +436,20 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) -function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) - # TODO: don't rebuild plots so often +function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) + end +function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) +end + +# TODO: don't rebuild plots so often +# IDEA: use functor to only build plot once function _update_plot_object(plt::Plot{PGFPlotsXBackend}) - plt.o = PGFPlotsX.GroupPlot() + plt.o = PGFPlotsX.TikzDocument() + push!(plt.o, PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot())) pushed_colormap = false - empty!(PGFPlotsX.CUSTOM_PREAMBLE) for sp in plt.subplots bb = bbox(sp) cstr = plot_color(sp[:background_color_legend]) @@ -491,7 +496,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient if !pushed_colormap - push!(PGFPlotsX.CUSTOM_PREAMBLE, """\\pgfplotsset{ + PGFPlotsX.push_preamble!(plt.o, """\\pgfplotsset{ colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, }""") pushed_colormap = true @@ -587,7 +592,7 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) ) end end - push!( plt.o, axis ) + push!( plt.o.elements[1].elements[1], axis ) end end From 66e8f6615e49daccea059b606268d11391d1872e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 17:30:26 +0100 Subject: [PATCH 121/184] respect layout --- src/backends/pgfplotsx.jl | 9 ++++++++- test/test_pgfplotsx.jl | 20 +++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 77d75e92..933afbfa 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -447,7 +447,14 @@ end # IDEA: use functor to only build plot once function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsX.TikzDocument() - push!(plt.o, PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot())) + cols, rows = size(plt.layout.grid) + push!(plt.o, PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot( + PGFPlotsX.Options( + "group style" => PGFPlotsX.Options( + "group size" => string(cols)*" by "*string(rows) + ) + ) + ))) pushed_colormap = false for sp in plt.subplots diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 47f76ccf..748d1739 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -54,7 +54,7 @@ end end # testset @testset "Layout" begin plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black]) - # TODO: add layouting + # TODO: no extra space for outer legends end # testset @testset "Polar plots" begin Θ = range(0, stop=1.5π, length=100) @@ -62,4 +62,22 @@ end plot(Θ, r, proj=:polar, m=2) # TODO: handle polar plots end # testset + @testset "Histogram 2D" begin + histogram2d(randn(10000), randn(10000), nbins=20) + # TODO: totally broken, errors also for pgfplots + end # testset + @testset "Contours" begin + x = 1:0.5:20 + y = 1:0.5:10 + f(x, y) = begin + (3x + y ^ 2) * abs(sin(x) + cos(y)) + end + X = repeat(reshape(x, 1, :), length(y), 1) + Y = repeat(y, 1, length(x)) + Z = map(f, X, Y) + p1 = contour(x, y, f, fill=true) + p2 = contour(x, y, Z) + plot(p1, p2) + # TODO: totally broken, also errors for pgfplots + end # testset end # testset From 1fcd06f903bb96ba06229d4cfb2d39a5f0e15f34 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 17:46:05 +0100 Subject: [PATCH 122/184] broken polar --- src/backends/pgfplotsx.jl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 933afbfa..46c90cbc 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -524,7 +524,15 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) "title" => sp[:colorbar_title] ) ) - axis = PGFPlotsX.Axis( + axisf = if sp[:projection] == :polar + # TODO: this errors for some reason + # push!(axis_opt, "xmin" => 90) + # push!(axis_opt, "xmax" => 450) + PGFPlotsX.PolarAxis + else + PGFPlotsX.Axis + end + axis = axisf( axis_opt ) for series in series_list(sp) From 59ad0d830b702b61f197795da6c6a5b87a2cc509 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 19 Nov 2019 18:18:08 +0100 Subject: [PATCH 123/184] ltriangle, rtriangle --- src/backends.jl | 3 +-- src/backends/pgfplotsx.jl | 12 +++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 89fa83eb..d2ae4894 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -713,7 +713,6 @@ const _pgfplotsx_attr = merge_with_base_supported([ # ] const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] -const _pgfplotsx_marker = vcat(_allMarkers, Shape) - # [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline] # +const _pgfplotsx_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :ltriangle, :rtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline, Shape] const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 46c90cbc..1d2c3587 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -16,6 +16,8 @@ const _pgfplotsx_markers = KW( :x => "x", :utriangle => "triangle*", :dtriangle => "triangle*", + :rtriangle => "triangle*", + :ltriangle => "triangle*", :circle => "*", :rect => "square*", :star5 => "star", @@ -125,7 +127,15 @@ function pgfx_marker(plotattributes, i = 1) "fill" => cstr, "fill opacity" => a, "line width" => pgfx_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i), - "rotate" => (shape == :dtriangle ? 180 : 0), + "rotate" => if shape == :dtriangle + 180 + elseif shape == :rtriangle + 270 + elseif shape == :ltriangle + 90 + else + 0 + end, get(_pgfplotsx_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid") => nothing ) ) From 1ba5ad0e909378a42be8a287d0e72bfc9c5ad345 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 10:35:48 +0100 Subject: [PATCH 124/184] translate pgf_fill_legend_hack --- src/backends/pgfplotsx.jl | 140 +++++++------------------------------- 1 file changed, 26 insertions(+), 114 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 1d2c3587..7bc0aef1 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -161,106 +161,6 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) end ## -------------------------------------------------------------------------------------- # TODO: translate these if needed -function pgf_series(sp::Subplot, series::Series) - plotattributes = series.plotattributes - st = plotattributes[:seriestype] - series_collection = PGFPlotsX.Plot[] - - # function args - args = if st == :contour - plotattributes[:z].surf, plotattributes[:x], plotattributes[:y] - elseif is3d(st) - plotattributes[:x], plotattributes[:y], plotattributes[:z] - elseif st == :straightline - straightline_data(series) - elseif st == :shape - shape_data(series) - elseif ispolar(sp) - theta, r = plotattributes[:x], plotattributes[:y] - rad2deg.(theta), r - else - plotattributes[:x], plotattributes[:y] - end - - # PGFPlots can't handle non-Vector? - # args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector - # collect(a) - # else - # a - # end, args) - - if st in (:contour, :histogram2d) - style = [] - kw = KW() - push!(style, pgf_linestyle(plotattributes)) - push!(style, pgf_marker(plotattributes)) - push!(style, "forget plot") - - kw[:style] = join(style, ',') - func = if st == :histogram2d - PGFPlots.Histogram2 - else - kw[:labels] = series[:contour_labels] - kw[:levels] = series[:levels] - PGFPlots.Contour - end - push!(series_collection, func(args...; kw...)) - - else - # series segments - segments = iter_segments(series) - for (i, rng) in enumerate(segments) - style = [] - kw = KW() - push!(style, pgf_linestyle(plotattributes, i)) - push!(style, pgf_marker(plotattributes, i)) - - if st == :shape - push!(style, pgf_fillstyle(plotattributes, i)) - end - - # add to legend? - if i == 1 && sp[:legend] != :none && should_add_to_legend(series) - if plotattributes[:fillrange] !== nothing - push!(style, "forget plot") - push!(series_collection, pgf_fill_legend_hack(plotattributes, args)) - else - kw[:legendentry] = plotattributes[:label] - if st == :shape # || plotattributes[:fillrange] !== nothing - push!(style, "area legend") - end - end - else - push!(style, "forget plot") - end - - seg_args = (arg[rng] for arg in args) - - # include additional style, then add to the kw - if haskey(_pgf_series_extrastyle, st) - push!(style, _pgf_series_extrastyle[st]) - end - kw[:style] = join(style, ',') - - # add fillrange - if series[:fillrange] !== nothing && st != :shape - push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) - end - - # build/return the series object - func = if st == :path3d - PGFPlots.Linear3 - elseif st == :scatter - PGFPlots.Scatter - else - PGFPlots.Linear - end - push!(series_collection, func(seg_args...; kw...)) - end - end - series_collection -end - function pgfx_fillrange_series(series, i, fillrange, args...) st = series[:seriestype] opt = PGFPlotsX.Options() @@ -291,24 +191,21 @@ function pgfx_fillrange_args(fillrange, x, y, z) return x_fill, y_fill, z_fill end -function pgf_fill_legend_hack(plotattributes, args) - style = [] - kw = KW() - push!(style, pgf_linestyle(plotattributes, 1)) - push!(style, pgf_marker(plotattributes, 1)) - push!(style, pgf_fillstyle(plotattributes, 1)) - push!(style, "area legend") - kw[:legendentry] = plotattributes[:label] - kw[:style] = join(style, ',') +function pgfx_fill_legend_hack(plotattributes, args) + opt = PGFPlotsX.Options("area legend" => nothing) + opt = merge(opt, pgfx_linestyle(plotattributes, 1)) + opt = merge(opt, pgfx_marker(plotattributes, 1)) + opt = merge(opt, pgfx_fillstyle(plotattributes, 1)) st = plotattributes[:seriestype] func = if st == :path3d - PGFPlots.Linear3 - elseif st == :scatter - PGFPlots.Scatter + PGFPlotsX.Plot3 else - PGFPlots.Linear + PGFPlotsX.Plot end - return func(([arg[1]] for arg in args)...; kw...) + if st == :scatter + push!(opt, "only marks" => nothing) + end + return func(opt, PGFPlotsX.Coordinates(([arg[1]] for arg in args)...)) end # -------------------------------------------------------------------------------------- @@ -586,6 +483,21 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) if series[:fillrange] !== nothing && st != :shape push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) end + + # add to legend? + if i == 1 && sp[:legend] != :none && should_add_to_legend(series) + if opt[:fillrange] !== nothing + push!(segment_opt, "forget plot" => nothing) + push!(axis, pgfx_fill_legend_hack(opt, args)) + else + if st == :shape + push!(segment_opt, "area legend" => nothing) + end + end + push!( axis, PGFPlotsX.LegendEntry( opt[:label] )) + else + push!(segment_opt, "forget plot" => nothing) + end end #include additional style if haskey(_pgfx_series_extrastyle, st) From faf905a9328251e32ff55be43558914e870edbda Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 14:16:43 +0100 Subject: [PATCH 125/184] create plot only once --- src/backends/pgfplotsx.jl | 391 ++++++++++++++++++++------------------ 1 file changed, 208 insertions(+), 183 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 7bc0aef1..e9e49e73 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,207 @@ -PGFPlotsX.print_tex(io::IO, data::Symbol) = PGFPlotsX.print_tex(io, string(data)) +# PGFPlotsX.print_tex(io::IO, data::Symbol) = PGFPlotsX.print_tex(io, string(data)) +Base.@kwdef mutable struct PGFPlotsXPlot + is_created::Bool = false + was_shown::Bool = false + the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() +end + +function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) + show(io::IO, mime, pgfx_plot.the_plot) +end + +function Base.push!(pgfx_plot::PGFPlotsXPlot, item) + push!(pgfx_plot.the_plot, item) +end + +function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) + if !pgfx_plot.is_created + cols, rows = size(plt.layout.grid) + the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot( + PGFPlotsX.Options( + "group style" => PGFPlotsX.Options( + "group size" => string(cols)*" by "*string(rows) + ) + ) + )) + + pushed_colormap = false + for sp in plt.subplots + bb = bbox(sp) + cstr = plot_color(sp[:background_color_legend]) + a = alpha(cstr) + title_cstr = plot_color(sp[:titlefontcolor]) + title_a = alpha(cstr) + # TODO: aspect ratio + axis_opt = PGFPlotsX.Options( + "height" => string(height(bb)), + "width" => string(width(bb)), + "title" => sp[:title], + "title style" => PGFPlotsX.Options( + "font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)), + "color" => title_cstr, + "draw opacity" => title_a, + "rotate" => sp[:titlefontrotation] + ), + "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), + "legend style" => PGFPlotsX.Options( + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, + "fill" => cstr, + "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + ), + "axis background/.style" => PGFPlotsX.Options( + "fill" => sp[:background_color_inside] + ) + ) + for letter in (:x, :y, :z) + if letter != :z || is3d(sp) + pgfx_axis!(axis_opt, sp, letter) + end + end + # Search series for any gradient. In case one series uses a gradient set + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + if !pushed_colormap + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + pushed_colormap = true + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots", + ) + end + + # goto is needed to break out of col and series for + @goto colorbar_end + end + end + end + @label colorbar_end + + push!(axis_opt, "colorbar style" => PGFPlotsX.Options( + "title" => sp[:colorbar_title] + ) + ) + axisf = if sp[:projection] == :polar + # TODO: this errors for some reason + # push!(axis_opt, "xmin" => 90) + # push!(axis_opt, "xmax" => 450) + PGFPlotsX.PolarAxis + else + PGFPlotsX.Axis + end + axis = axisf( + axis_opt + ) + for series in series_list(sp) + opt = series.plotattributes + st = series[:seriestype] + # function args + args = if st == :contour + opt[:z].surf, opt[:x], opt[:y] + elseif is3d(st) + opt[:x], opt[:y], opt[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = opt[:x], opt[:y] + rad2deg.(theta), r + else + opt[:x], opt[:y] + end + series_opt = PGFPlotsX.Options( + "color" => opt[:linecolor], + ) + if st == :shape + push!(series_opt, "area legend" => nothing) + end + if opt[:marker_z] !== nothing + push!(series_opt, "point meta" => "explicit") + push!(series_opt, "scatter" => nothing) + end + segments = iter_segments(series) + segment_opt = PGFPlotsX.Options() + for (i, rng) in enumerate(segments) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + if st == :shape + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + seg_args = (arg[rng] for arg in args) + # add fillrange + if series[:fillrange] !== nothing && st != :shape + push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + end + + # add to legend? + if i == 1 && sp[:legend] != :none && should_add_to_legend(series) + if opt[:fillrange] !== nothing + push!(segment_opt, "forget plot" => nothing) + push!(axis, pgfx_fill_legend_hack(opt, args)) + else + if st == :shape + push!(segment_opt, "area legend" => nothing) + end + end + push!( axis, PGFPlotsX.LegendEntry( opt[:label] )) + else + push!(segment_opt, "forget plot" => nothing) + end + end + #include additional style + if haskey(_pgfx_series_extrastyle, st) + push!(series_opt, _pgfx_series_extrastyle[st] => nothing) + end + # TODO: different seriestypes, histogramms, contours, etc. + # TODO: colorbars + # TODO: gradients + if is3d(series) + series_func = PGFPlotsX.Plot3 + else + series_func = PGFPlotsX.Plot + end + if st == :scatter + push!(series_opt, "only marks" => nothing) + end + series_plot = series_func( + merge(series_opt, segment_opt), + PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) + ) + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) + end + push!( axis, series_plot ) + if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end + end + push!( the_plot.elements[1], axis ) + if length(plt.o.the_plot.elements) > 0 + plt.o.the_plot.elements[1] = the_plot + else + push!(plt.o, the_plot) + end + end + pgfx_plot.is_created = true + end +end + +## const _pgfplotsx_linestyles = KW( :solid => "solid", @@ -344,193 +547,15 @@ end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) - + plt.o = PGFPlotsXPlot() end -function _series_updated(plt::Plot{PGFPlotsXBackend}, series::Series) +function _series_added(plt::Plot{PGFPlotsXBackend}, series::Series) + plt.o.is_created = false end -# TODO: don't rebuild plots so often -# IDEA: use functor to only build plot once function _update_plot_object(plt::Plot{PGFPlotsXBackend}) - plt.o = PGFPlotsX.TikzDocument() - cols, rows = size(plt.layout.grid) - push!(plt.o, PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot( - PGFPlotsX.Options( - "group style" => PGFPlotsX.Options( - "group size" => string(cols)*" by "*string(rows) - ) - ) - ))) - - pushed_colormap = false - for sp in plt.subplots - bb = bbox(sp) - cstr = plot_color(sp[:background_color_legend]) - a = alpha(cstr) - title_cstr = plot_color(sp[:titlefontcolor]) - title_a = alpha(cstr) - # TODO: aspect ratio - axis_opt = PGFPlotsX.Options( - "height" => string(height(bb)), - "width" => string(width(bb)), - "title" => sp[:title], - "title style" => PGFPlotsX.Options( - "font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)), - "color" => title_cstr, - "draw opacity" => title_a, - "rotate" => sp[:titlefontrotation] - ), - "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), - "legend style" => PGFPlotsX.Options( - pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, - "fill" => cstr, - "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) - ), - "axis background/.style" => PGFPlotsX.Options( - "fill" => sp[:background_color_inside] - ) - ) - for letter in (:x, :y, :z) - if letter != :z || is3d(sp) - pgfx_axis!(axis_opt, sp, letter) - end - end - # Search series for any gradient. In case one series uses a gradient set - # the colorbar and colomap. - # The reasoning behind doing this on the axis level is that pgfplots - # colorbar seems to only works on axis level and needs the proper colormap for - # correctly displaying it. - # It's also possible to assign the colormap to the series itself but - # then the colormap needs to be added twice, once for the axis and once for the - # series. - # As it is likely that all series within the same axis use the same - # colormap this should not cause any problem. - for series in series_list(sp) - for col in (:markercolor, :fillcolor, :linecolor) - if typeof(series.plotattributes[col]) == ColorGradient - if !pushed_colormap - PGFPlotsX.push_preamble!(plt.o, """\\pgfplotsset{ - colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, - }""") - pushed_colormap = true - push!(axis_opt, - "colorbar" => nothing, - "colormap name" => "plots", - ) - end - - # goto is needed to break out of col and series for - @goto colorbar_end - end - end - end - @label colorbar_end - - push!(axis_opt, "colorbar style" => PGFPlotsX.Options( - "title" => sp[:colorbar_title] - ) - ) - axisf = if sp[:projection] == :polar - # TODO: this errors for some reason - # push!(axis_opt, "xmin" => 90) - # push!(axis_opt, "xmax" => 450) - PGFPlotsX.PolarAxis - else - PGFPlotsX.Axis - end - axis = axisf( - axis_opt - ) - for series in series_list(sp) - opt = series.plotattributes - st = series[:seriestype] - # function args - args = if st == :contour - opt[:z].surf, opt[:x], opt[:y] - elseif is3d(st) - opt[:x], opt[:y], opt[:z] - elseif st == :straightline - straightline_data(series) - elseif st == :shape - shape_data(series) - elseif ispolar(sp) - theta, r = opt[:x], opt[:y] - rad2deg.(theta), r - else - opt[:x], opt[:y] - end - series_opt = PGFPlotsX.Options( - "color" => opt[:linecolor], - ) - if st == :shape - push!(series_opt, "area legend" => nothing) - end - if opt[:marker_z] !== nothing - push!(series_opt, "point meta" => "explicit") - push!(series_opt, "scatter" => nothing) - end - segments = iter_segments(series) - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - if st == :shape - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - seg_args = (arg[rng] for arg in args) - # add fillrange - if series[:fillrange] !== nothing && st != :shape - push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) - end - - # add to legend? - if i == 1 && sp[:legend] != :none && should_add_to_legend(series) - if opt[:fillrange] !== nothing - push!(segment_opt, "forget plot" => nothing) - push!(axis, pgfx_fill_legend_hack(opt, args)) - else - if st == :shape - push!(segment_opt, "area legend" => nothing) - end - end - push!( axis, PGFPlotsX.LegendEntry( opt[:label] )) - else - push!(segment_opt, "forget plot" => nothing) - end - end - #include additional style - if haskey(_pgfx_series_extrastyle, st) - push!(series_opt, _pgfx_series_extrastyle[st] => nothing) - end - # TODO: different seriestypes, histogramms, contours, etc. - # TODO: colorbars - # TODO: gradients - if is3d(series) - series_func = PGFPlotsX.Plot3 - else - series_func = PGFPlotsX.Plot - end - if st == :scatter - push!(series_opt, "only marks" => nothing) - end - series_plot = series_func( - merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) - ) - # add series annotations - anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) - pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) - end - push!( axis, series_plot ) - if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) - ) - end - end - push!( plt.o.elements[1].elements[1], axis ) - end + plt.o(plt) end function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) From a2bdc4c3ef8e16b8a6e657460a0534d6a4a754fc Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 15:20:33 +0100 Subject: [PATCH 126/184] update tests --- src/backends/pgfplotsx.jl | 5 +++-- test/test_pgfplotsx.jl | 24 +++++++++++++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index e9e49e73..90b823d8 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -5,6 +5,8 @@ Base.@kwdef mutable struct PGFPlotsXPlot the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() end +pgfx_axes(pgfx_plot::PGFPlotsXPlot) = pgfx_plot.the_plot.elements[1].elements[1].contents + function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) show(io::IO, mime, pgfx_plot.the_plot) end @@ -31,7 +33,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) a = alpha(cstr) title_cstr = plot_color(sp[:titlefontcolor]) title_a = alpha(cstr) - # TODO: aspect ratio axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), @@ -575,7 +576,7 @@ end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) _update_plot_object(plt) - PGFPlotsX.print_tex(plt.o) + PGFPlotsX.print_tex(plt.o.the_plot) end function _display(plt::Plot{PGFPlotsXBackend}) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 748d1739..03e9dce2 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -12,34 +12,37 @@ function create_plot!( args...; kwargs... ) end @testset "PGFPlotsX" begin - pgfx_plot, pgfx_tex = create_plot(1:5) + pgfx_plot = plot(1:5) + Plots._update_plot_object(pgfx_plot) + @test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument - @test pgfx_plot.o isa PGFPlotsX.GroupPlot - @testset "3D docs example" begin + @testset "3D docs example" begin n = 100 ts = range(0, stop=8π, length=n) x = ts .* map(cos, ts) y = (0.1ts) .* map(sin, ts) z = 1:n pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5) - pgfx_plot, pgfx_tex = create_plot!(pl, zeros(n), zeros(n), 1:n, w=10) - if @test_nowarn(haskey(pgfx_plot.o.contents[1].options.dict, "colorbar") == true) - @test pgfx_plot.o.contents[1]["colorbar"] === nothing + pgfx_plot = plot!(pl, zeros(n), zeros(n), 1:n, w=10) + Plots._update_plot_object(pgfx_plot) + if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing end end # testset @testset "Color docs example" begin y = rand(100) plot(0:10:100, rand(11, 4), lab="lines", w=3, palette=:grays, fill=0, α=0.6) - scatter!(y, zcolor=abs.(y .- 0.5), m=(:heat, 0.8, Plots.stroke(1, :green)), ms=10 * abs.(y .- 0.5) .+ 4, lab="grad") + pl = scatter!(y, zcolor=abs.(y .- 0.5), m=(:heat, 0.8, Plots.stroke(1, :green)), ms=10 * abs.(y .- 0.5) .+ 4, lab="grad") + Plots._update_plot_object(pl) + axis = Plots.pgfx_axes(pl.o)[1] + @test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5 + @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 5 # TODO: marker size does not adjust # TODO: marker stroke is incorrect - # TODO: fill legends - # TODO: adjust colorbar limits to data end # testset @testset "Plot in pieces" begin plot(rand(100) / 3, reg=true, fill=(0, :green)) scatter!(rand(100), markersize=6, c=:orange) - # TODO: legends should be different end # testset @testset "Marker types" begin markers = filter((m->begin @@ -50,7 +53,6 @@ end x = (range(0, stop=10, length=n + 2))[2:end - 1] y = repeat(reshape(reverse(x), 1, :), n, 1) scatter(x, y, m=(8, :auto), lab=map(string, markers), bg=:linen, xlim=(0, 10), ylim=(0, 10)) - #TODO: fix markers that show up as circles end # testset @testset "Layout" begin plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black]) From fc0a12ac361bd332d8683c8f0de6c5e3791f7c3d Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 17:28:23 +0100 Subject: [PATCH 127/184] native fillrange --- src/backends/pgfplotsx.jl | 96 +++++++++++++++++++-------------------- test/test_pgfplotsx.jl | 12 +++-- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 90b823d8..c0c6e05e 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -88,6 +88,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end @label colorbar_end + # detect fillranges + # if any(series->series[:fillrange] != nothing, series_list(sp)) + # PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween},\n") + # end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title] @@ -125,71 +129,61 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => opt[:linecolor], ) - if st == :shape - push!(series_opt, "area legend" => nothing) - end if opt[:marker_z] !== nothing push!(series_opt, "point meta" => "explicit") push!(series_opt, "scatter" => nothing) end - segments = iter_segments(series) - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - if st == :shape - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - seg_args = (arg[rng] for arg in args) - # add fillrange - if series[:fillrange] !== nothing && st != :shape - push!(axis, pgfx_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) - end - - # add to legend? - if i == 1 && sp[:legend] != :none && should_add_to_legend(series) - if opt[:fillrange] !== nothing - push!(segment_opt, "forget plot" => nothing) - push!(axis, pgfx_fill_legend_hack(opt, args)) - else - if st == :shape - push!(segment_opt, "area legend" => nothing) - end - end - push!( axis, PGFPlotsX.LegendEntry( opt[:label] )) - else - push!(segment_opt, "forget plot" => nothing) - end - end - #include additional style - if haskey(_pgfx_series_extrastyle, st) - push!(series_opt, _pgfx_series_extrastyle[st] => nothing) - end - # TODO: different seriestypes, histogramms, contours, etc. - # TODO: colorbars - # TODO: gradients if is3d(series) series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot end - if st == :scatter - push!(series_opt, "only marks" => nothing) + if series[:fillrange] !== nothing + series_opt = merge(series_opt, pgfx_fillstyle(opt)) + push!(series_opt, "area legend" => nothing) end - series_plot = series_func( - merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(args..., meta = opt[:marker_z]) - ) + # include additional style + if haskey(_pgfx_series_extrastyle, st) + push!(series_opt, _pgfx_series_extrastyle[st] => nothing) + end + # treat segments + segments = iter_segments(series) + segment_opt = PGFPlotsX.Options() + # @show get_markerstrokecolor(opt, 1) + # @show get_markercolor(opt,1) + for (i, rng) in enumerate(segments) + seg_args = (arg[rng] for arg in args) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + if st == :shape || series[:fillrange] !== nothing + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + segment_plot = series_func( + merge(series_opt, segment_opt), + PGFPlotsX.Coordinates(seg_args..., + meta = if !isnothing(opt[:marker_z]) + opt[:marker_z][rng] + else + nothing + end + ), + series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + ) + push!(axis, segment_plot) + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end + end + # TODO: different seriestypes, histogramms, contours, etc. + # TODO: colorbars + # TODO: gradients # add series annotations anns = series[:series_annotations] for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end - push!( axis, series_plot ) - if opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) - ) - end end push!( the_plot.elements[1], axis ) if length(plt.o.the_plot.elements) > 0 @@ -247,6 +241,8 @@ const _pgfx_series_extrastyle = KW( :sticks => "ycomb", :ysticks => "ycomb", :xsticks => "xcomb", + :scatter => "only marks", + :shape => "area legends" ) const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 03e9dce2..7a8c320a 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -36,9 +36,15 @@ end Plots._update_plot_object(pl) axis = Plots.pgfx_axes(pl.o)[1] @test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5 - @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 5 - # TODO: marker size does not adjust - # TODO: marker stroke is incorrect + @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 104 # each marker is its own plot + marker = axis.contents[5] + @test marker isa PGFPlotsX.Plot + @show marker.options.dict |> keys + @test marker.options["mark"] == "none" + @test marker.options["mark options"]["color"] == convert(RGBA{Float64}, colorant"green") + @test marker.options["mark options"]["line width"] == 1 + + # TODO: marker stroke color is incorrect end # testset @testset "Plot in pieces" begin plot(rand(100) / 3, reg=true, fill=(0, :green)) From 642bb9aeadd1e5c120a9565a468c4828326d3b74 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 20 Nov 2019 18:10:30 +0100 Subject: [PATCH 128/184] tests for marker-stroke-color --- src/backends/pgfplotsx.jl | 2 -- test/test_pgfplotsx.jl | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c0c6e05e..4995feb5 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -149,8 +149,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) # treat segments segments = iter_segments(series) segment_opt = PGFPlotsX.Options() - # @show get_markerstrokecolor(opt, 1) - # @show get_markercolor(opt,1) for (i, rng) in enumerate(segments) seg_args = (arg[rng] for arg in args) segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 7a8c320a..5ffd62c8 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -37,11 +37,10 @@ end axis = Plots.pgfx_axes(pl.o)[1] @test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5 @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 104 # each marker is its own plot - marker = axis.contents[5] + marker = axis.contents[14] @test marker isa PGFPlotsX.Plot - @show marker.options.dict |> keys - @test marker.options["mark"] == "none" - @test marker.options["mark options"]["color"] == convert(RGBA{Float64}, colorant"green") + @test marker.options["mark"] == "*" + @test marker.options["mark options"]["color"] == RGBA{Float64}( colorant"green", 0.8) @test marker.options["mark options"]["line width"] == 1 # TODO: marker stroke color is incorrect From 2cfd1838ca8b3d8d784178d03c9562252178fa9a Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 11:11:05 +0100 Subject: [PATCH 129/184] remove point meta --- src/backends/pgfplotsx.jl | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4995feb5..ac088762 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -129,10 +129,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => opt[:linecolor], ) - if opt[:marker_z] !== nothing - push!(series_opt, "point meta" => "explicit") - push!(series_opt, "scatter" => nothing) - end if is3d(series) series_func = PGFPlotsX.Plot3 else @@ -158,13 +154,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end segment_plot = series_func( merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(seg_args..., - meta = if !isnothing(opt[:marker_z]) - opt[:marker_z][rng] - else - nothing - end - ), + PGFPlotsX.Coordinates(seg_args...), series[:fillrange] !== nothing ? "\\closedcycle" : "{}" ) push!(axis, segment_plot) From 242d8b290d2661fe964c0e310c5a9ecbe1e78e27 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 11:31:33 +0100 Subject: [PATCH 130/184] adjust color bar limits --- src/backends/pgfplotsx.jl | 20 +++++++++++++++----- test/test_pgfplotsx.jl | 2 -- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index ac088762..53ffbfe7 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -88,13 +88,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end @label colorbar_end - # detect fillranges - # if any(series->series[:fillrange] != nothing, series_list(sp)) - # PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween},\n") - # end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( - "title" => sp[:colorbar_title] + "title" => sp[:colorbar_title], ) ) axisf = if sp[:projection] == :polar @@ -110,6 +106,20 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) for series in series_list(sp) opt = series.plotattributes + if opt[:marker_z] !== nothing + cbar_style = axis_opt["colorbar style"] + if !haskey( cbar_style.dict, "point meta max" ) + append!( axis_opt["colorbar style"], + ( + "point meta max" => maximum(opt[:marker_z]), + "point meta min" => minimum(opt[:marker_z]) + ) + ) + else + cbar_style["point meta max"] = maximum(opt[:marker_z]) + cbar_style["point meta min"] = minimum(opt[:marker_z]) + end + end st = series[:seriestype] # function args args = if st == :contour diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 5ffd62c8..21074e93 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -42,8 +42,6 @@ end @test marker.options["mark"] == "*" @test marker.options["mark options"]["color"] == RGBA{Float64}( colorant"green", 0.8) @test marker.options["mark options"]["line width"] == 1 - - # TODO: marker stroke color is incorrect end # testset @testset "Plot in pieces" begin plot(rand(100) / 3, reg=true, fill=(0, :green)) From 1f14a4d4c6fd7e7ff59efcf06219f07f771a081e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 12:34:09 +0100 Subject: [PATCH 131/184] fix polar plots --- src/backends/pgfplotsx.jl | 31 ++++++++++++++++++++----------- test/test_pgfplotsx.jl | 1 - 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 53ffbfe7..66fc5f02 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -18,14 +18,18 @@ end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created cols, rows = size(plt.layout.grid) - the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.GroupPlot( - PGFPlotsX.Options( - "group style" => PGFPlotsX.Options( - "group size" => string(cols)*" by "*string(rows) + the_plot = PGFPlotsX.TikzPicture() + # the combination of groupplot and polaraxis is broken in pgfplots + if !any( sp -> ispolar(sp), plt.subplots ) + push!( the_plot, PGFPlotsX.GroupPlot( + PGFPlotsX.Options( + "group style" => PGFPlotsX.Options( + "group size" => string(cols)*" by "*string(rows) + ) + ) ) ) - )) - + end pushed_colormap = false for sp in plt.subplots bb = bbox(sp) @@ -121,6 +125,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end st = series[:seriestype] + series_opt = PGFPlotsX.Options( + "color" => opt[:linecolor], + ) # function args args = if st == :contour opt[:z].surf, opt[:x], opt[:y] @@ -136,9 +143,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else opt[:x], opt[:y] end - series_opt = PGFPlotsX.Options( - "color" => opt[:linecolor], - ) if is3d(series) series_func = PGFPlotsX.Plot3 else @@ -183,7 +187,12 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end end - push!( the_plot.elements[1], axis ) + if ispolar(sp) + axes = the_plot + else + axes = the_plot.elements[1] + end + push!( axes, axis ) if length(plt.o.the_plot.elements) > 0 plt.o.the_plot.elements[1] = the_plot else @@ -570,7 +579,7 @@ end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) _update_plot_object(plt) - PGFPlotsX.print_tex(plt.o.the_plot) + PGFPlotsX.print_tex(io, plt.o.the_plot) end function _display(plt::Plot{PGFPlotsXBackend}) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 21074e93..4eeeddf7 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -65,7 +65,6 @@ end Θ = range(0, stop=1.5π, length=100) r = abs.(0.1 * randn(100) + sin.(3Θ)) plot(Θ, r, proj=:polar, m=2) - # TODO: handle polar plots end # testset @testset "Histogram 2D" begin histogram2d(randn(10000), randn(10000), nbins=20) From 4c6b96e38a806d7f2c2e8a234be12b878a147d58 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 13:03:37 +0100 Subject: [PATCH 132/184] padding of grouplots --- src/backends/pgfplotsx.jl | 11 ++++++++++- test/test_pgfplotsx.jl | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 66fc5f02..0764606e 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -24,7 +24,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!( the_plot, PGFPlotsX.GroupPlot( PGFPlotsX.Options( "group style" => PGFPlotsX.Options( - "group size" => string(cols)*" by "*string(rows) + "group size" => string(cols)*" by "*string(rows), + "horizontal sep" => string(maximum(sp -> sp.minpad[1], plt.subplots)), + "vertical sep" => string(maximum(sp -> sp.minpad[2], plt.subplots)), ) ) ) @@ -550,6 +552,13 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # -------------------------------------------------------------------------------------- # display calls this and then _display, its called 3 times for plot(1:5) +# Set the (left, top, right, bottom) minimum padding around the plot area +# to fit ticks, tick labels, guides, colorbars, etc. +function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) + # TODO: make padding more intelligent + sp.minpad = (20mm, 5mm, 2mm, 10mm) +end + function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) plt.o = PGFPlotsXPlot() end diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 4eeeddf7..68002222 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -59,7 +59,6 @@ end end # testset @testset "Layout" begin plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black]) - # TODO: no extra space for outer legends end # testset @testset "Polar plots" begin Θ = range(0, stop=1.5π, length=100) From 74001a555bd1719734123f187afd060e29f36837 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 13:06:22 +0100 Subject: [PATCH 133/184] remove unneccesary code --- src/backends/pgfplotsx.jl | 49 --------------------------------------- 1 file changed, 49 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 0764606e..07da6b69 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -368,55 +368,6 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) "{$(val.str).};" ]) end -## -------------------------------------------------------------------------------------- -# TODO: translate these if needed -function pgfx_fillrange_series(series, i, fillrange, args...) - st = series[:seriestype] - opt = PGFPlotsX.Options() - push!(opt, "line width" => 0) - push!(opt, "draw opacity" => 0) - opt = merge(opt, pgfx_fillstyle(series, i)) - opt = merge(opt, pgfx_marker(series, i)) - push!(opt, "forget plot" => nothing) - if haskey(_pgfx_series_extrastyle, st) - push!(opt, _pgfx_series_extrastyle[st] => nothing) - end - func = is3d(series) ? PGFPlotsX.Plot3 : PGFPlotsX.Plot - return func(opt, PGFPlotsX.Coordinates(pgfx_fillrange_args(fillrange, args...)...)) -end - -function pgfx_fillrange_args(fillrange, x, y) - n = length(x) - x_fill = [x; x[n:-1:1]; x[1]] - y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] - return x_fill, y_fill -end - -function pgfx_fillrange_args(fillrange, x, y, z) - n = length(x) - x_fill = [x; x[n:-1:1]; x[1]] - y_fill = [y; y[n:-1:1]; x[1]] - z_fill = [z; _cycle(fillrange, n:-1:1); z[1]] - return x_fill, y_fill, z_fill -end - -function pgfx_fill_legend_hack(plotattributes, args) - opt = PGFPlotsX.Options("area legend" => nothing) - opt = merge(opt, pgfx_linestyle(plotattributes, 1)) - opt = merge(opt, pgfx_marker(plotattributes, 1)) - opt = merge(opt, pgfx_fillstyle(plotattributes, 1)) - st = plotattributes[:seriestype] - func = if st == :path3d - PGFPlotsX.Plot3 - else - PGFPlotsX.Plot - end - if st == :scatter - push!(opt, "only marks" => nothing) - end - return func(opt, PGFPlotsX.Coordinates(([arg[1]] for arg in args)...)) -end - # -------------------------------------------------------------------------------------- function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) axis = sp[Symbol(letter,:axis)] From e3a166f04cc22d8a7a1d5338f5beda9d1590fd31 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 14:37:39 +0100 Subject: [PATCH 134/184] basic contour --- src/backends/pgfplotsx.jl | 66 ++++++++++++++++++++++----------------- test/test_pgfplotsx.jl | 9 +++++- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 07da6b69..bdb7b7f9 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,5 @@ -# PGFPlotsX.print_tex(io::IO, data::Symbol) = PGFPlotsX.print_tex(io, string(data)) +using Contour: Contour +# PGFPlotsX.print_tex(io::IO, data::ColorGradient) = write(io, pgfx_colormap(data)) Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false was_shown::Bool = false @@ -132,7 +133,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) # function args args = if st == :contour - opt[:z].surf, opt[:x], opt[:y] + opt[:x], opt[:y], opt[:z].surf' elseif is3d(st) opt[:x], opt[:y], opt[:z] elseif st == :straightline @@ -158,35 +159,44 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if haskey(_pgfx_series_extrastyle, st) push!(series_opt, _pgfx_series_extrastyle[st] => nothing) end - # treat segments - segments = iter_segments(series) - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - seg_args = (arg[rng] for arg in args) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - if st == :shape || series[:fillrange] !== nothing - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - segment_plot = series_func( - merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(seg_args...), - series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + if st == :contour + surface_opt = PGFPlotsX.Options( + "contour prepared" => nothing ) - push!(axis, segment_plot) - # add to legend? - if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + surface_plot = series_func( + # merge(series_opt, surface_opt), + surface_opt, + PGFPlotsX.Table(Contour.contours(args...)) + ) + push!(axis, surface_plot) + else + # treat segments + segments = iter_segments(series) + segment_opt = PGFPlotsX.Options() + for (i, rng) in enumerate(segments) + seg_args = (arg[rng] for arg in args) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + if st == :shape || series[:fillrange] !== nothing + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + segment_plot = series_func( + merge(series_opt, segment_opt), + PGFPlotsX.Coordinates(seg_args...), + series[:fillrange] !== nothing ? "\\closedcycle" : "{}" ) + push!(axis, segment_plot) + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end + end + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end - end - # TODO: different seriestypes, histogramms, contours, etc. - # TODO: colorbars - # TODO: gradients - # add series annotations - anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) - pgfx_add_annotation!(series_plot, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end end if ispolar(sp) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 68002222..de775c32 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -65,6 +65,13 @@ end r = abs.(0.1 * randn(100) + sin.(3Θ)) plot(Θ, r, proj=:polar, m=2) end # testset + @testset "Drawing shapes" begin + verts = [(-1.0, 1.0), (-1.28, 0.6), (-0.2, -1.4), (0.2, -1.4), (1.28, 0.6), (1.0, 1.0), (-1.0, 1.0), (-0.2, -0.6), (0.0, -0.2), (-0.4, 0.6), (1.28, 0.6), (0.2, -1.4), (-0.2, -1.4), (0.6, 0.2), (-0.2, 0.2), (0.0, -0.2), (0.2, 0.2), (-0.2, -0.6)] + x = 0.1:0.2:0.9 + y = 0.7 * rand(5) .+ 0.15 + plot(x, y, line=(3, :dash, :lightblue), marker=(Shape(verts), 30, RGBA(0, 0, 0, 0.2)), bg=:pink, fg=:darkblue, xlim=(0, 1), ylim=(0, 1), leg=false) + # TODO: draw those polygons + end # testset @testset "Histogram 2D" begin histogram2d(randn(10000), randn(10000), nbins=20) # TODO: totally broken, errors also for pgfplots @@ -78,8 +85,8 @@ end X = repeat(reshape(x, 1, :), length(y), 1) Y = repeat(y, 1, length(x)) Z = map(f, X, Y) - p1 = contour(x, y, f, fill=true) p2 = contour(x, y, Z) + p1 = contour(x, y, f, fill=true) plot(p1, p2) # TODO: totally broken, also errors for pgfplots end # testset From 567d3688e84e217a1b6047c0849bf1f56648c191 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 15:07:48 +0100 Subject: [PATCH 135/184] filled contours are difficult --- src/backends/pgfplotsx.jl | 20 ++++++++++++++++---- test/test_pgfplotsx.jl | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index bdb7b7f9..a523cc48 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -151,7 +151,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else series_func = PGFPlotsX.Plot end - if series[:fillrange] !== nothing + if series[:fillrange] !== nothing && st != :contour series_opt = merge(series_opt, pgfx_fillstyle(opt)) push!(series_opt, "area legend" => nothing) end @@ -160,13 +160,25 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!(series_opt, _pgfx_series_extrastyle[st] => nothing) end if st == :contour + if !isfilledcontour(series) surface_opt = PGFPlotsX.Options( - "contour prepared" => nothing - ) + "contour prepared" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ) + ) + else + error("PGFPlotsX backend does not support filled contours at the moment.") + surface_opt = PGFPlotsX.Options( + "contour filled" => PGFPlotsX.Options( + # "levels" => opt[:levels], + # "labels" => opt[:contour_labels], + ) + ) + end surface_plot = series_func( # merge(series_opt, surface_opt), surface_opt, - PGFPlotsX.Table(Contour.contours(args...)) + PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) ) push!(axis, surface_plot) else diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index de775c32..e0a2eacd 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -88,6 +88,6 @@ end p2 = contour(x, y, Z) p1 = contour(x, y, f, fill=true) plot(p1, p2) - # TODO: totally broken, also errors for pgfplots + # TODO: filled contours end # testset end # testset From c9c4de37e68ae72fc577d0f29cca83e95cf7dc5f Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 15:45:35 +0100 Subject: [PATCH 136/184] more than one colorbar --- src/backends/pgfplotsx.jl | 42 +++++++++++---------------------------- test/test_pgfplotsx.jl | 12 +++++++++++ 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index a523cc48..54f8b341 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,5 @@ using Contour: Contour +using StatsBase: Histogram, fit # PGFPlotsX.print_tex(io::IO, data::ColorGradient) = write(io, pgfx_colormap(data)) Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false @@ -33,7 +34,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) ) end - pushed_colormap = false for sp in plt.subplots bb = bbox(sp) cstr = plot_color(sp[:background_color_legend]) @@ -65,36 +65,16 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_axis!(axis_opt, sp, letter) end end - # Search series for any gradient. In case one series uses a gradient set - # the colorbar and colomap. - # The reasoning behind doing this on the axis level is that pgfplots - # colorbar seems to only works on axis level and needs the proper colormap for - # correctly displaying it. - # It's also possible to assign the colormap to the series itself but - # then the colormap needs to be added twice, once for the axis and once for the - # series. - # As it is likely that all series within the same axis use the same - # colormap this should not cause any problem. - for series in series_list(sp) - for col in (:markercolor, :fillcolor, :linecolor) - if typeof(series.plotattributes[col]) == ColorGradient - if !pushed_colormap - PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ - colormap={plots}{$(pgfx_colormap(series.plotattributes[col]))}, - }""") - pushed_colormap = true - push!(axis_opt, - "colorbar" => nothing, - "colormap name" => "plots", - ) - end - - # goto is needed to break out of col and series for - @goto colorbar_end - end - end + if hascolorbar(sp) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + pushed_colormap = true + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots$(sp.attr[:subplot_index])", + ) end - @label colorbar_end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title], @@ -181,6 +161,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) ) push!(axis, surface_plot) + elseif st == :histogram2d + hist_ else # treat segments segments = iter_segments(series) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index e0a2eacd..3d96360d 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -90,4 +90,16 @@ end plot(p1, p2) # TODO: filled contours end # testset + @testset "Varying colors" begin + t = range(0, stop=1, length=100) + θ = (6π) .* t + x = t .* cos.(θ) + y = t .* sin.(θ) + p1 = plot(x, y, line_z=t, linewidth=3, legend=false) + p2 = scatter(x, y, marker_z=((x, y)->begin + x + y + end), color=:bluesreds, legend=false) + plot(p1, p2) + # TODO: handle gradients as color + end # testset end # testset From f5cbb1e341e64f98b35a8528d854e06adb473bab Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 16:07:08 +0100 Subject: [PATCH 137/184] simplifications --- src/backends/pgfplotsx.jl | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 54f8b341..33a2d98a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -78,6 +78,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title], + "point meta max" => get_clims(sp)[2], + "point meta min" => get_clims(sp)[1] ) ) axisf = if sp[:projection] == :polar @@ -93,20 +95,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) for series in series_list(sp) opt = series.plotattributes - if opt[:marker_z] !== nothing - cbar_style = axis_opt["colorbar style"] - if !haskey( cbar_style.dict, "point meta max" ) - append!( axis_opt["colorbar style"], - ( - "point meta max" => maximum(opt[:marker_z]), - "point meta min" => minimum(opt[:marker_z]) - ) - ) - else - cbar_style["point meta max"] = maximum(opt[:marker_z]) - cbar_style["point meta min"] = minimum(opt[:marker_z]) - end - end st = series[:seriestype] series_opt = PGFPlotsX.Options( "color" => opt[:linecolor], @@ -147,7 +135,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) ) else - error("PGFPlotsX backend does not support filled contours at the moment.") + notimpl() surface_opt = PGFPlotsX.Options( "contour filled" => PGFPlotsX.Options( # "levels" => opt[:levels], From 6378f88ba973af3b942ff2f3dba12f6f6c363e79 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 16:46:15 +0100 Subject: [PATCH 138/184] subplot annotations --- src/backends/pgfplotsx.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 33a2d98a..325d1047 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -18,6 +18,7 @@ function Base.push!(pgfx_plot::PGFPlotsXPlot, item) end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) + # TODO: annotations! does not trigger _series_added ... if !pgfx_plot.is_created cols, rows = size(plt.layout.grid) the_plot = PGFPlotsX.TikzPicture() @@ -180,6 +181,11 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end end + # add subplot annotations + anns = sp.attr[:annotations] + for (xi,yi,txt) in anns + pgfx_add_annotation!(axis, xi, yi, txt) + end end if ispolar(sp) axes = the_plot From faa401f0e5a9403270fb882d6bf3249d1f07eed9 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 16:52:35 +0100 Subject: [PATCH 139/184] total plot size --- src/backends/pgfplotsx.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 325d1047..267915d7 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -24,13 +24,16 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) the_plot = PGFPlotsX.TikzPicture() # the combination of groupplot and polaraxis is broken in pgfplots if !any( sp -> ispolar(sp), plt.subplots ) + pl_height, pl_width = plt.attr[:size] push!( the_plot, PGFPlotsX.GroupPlot( PGFPlotsX.Options( "group style" => PGFPlotsX.Options( "group size" => string(cols)*" by "*string(rows), "horizontal sep" => string(maximum(sp -> sp.minpad[1], plt.subplots)), "vertical sep" => string(maximum(sp -> sp.minpad[2], plt.subplots)), - ) + ), + "height" => pl_height > 0 ? string(pl_height)*"px" : "{}", + "width" => pl_width > 0 ? string(pl_width)*"px" : "{}", ) ) ) From a03ae0be10f9707417e95f52d4b004fecff9843b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 19:10:58 +0100 Subject: [PATCH 140/184] working heatmap --- src/backends.jl | 2 +- src/backends/pgfplotsx.jl | 75 ++++++++++++++++++++++++++++++++------- test/test_pgfplotsx.jl | 15 +++++++- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index d2ae4894..87f4dda8 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -711,7 +711,7 @@ const _pgfplotsx_attr = merge_with_base_supported([ # :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, # :shape # ] -const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] +const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :heatmap, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _pgfplotsx_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :ltriangle, :rtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline, Shape] const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 267915d7..81cabf23 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -9,6 +9,19 @@ end pgfx_axes(pgfx_plot::PGFPlotsXPlot) = pgfx_plot.the_plot.elements[1].elements[1].contents +function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) + a = Array(s) + xn = Vector{eltype(x)}(undef, length(a)) + yn = Vector{eltype(y)}(undef, length(a)) + zn = Vector{eltype(s)}(undef, length(a)) + for (n, (i, j)) in enumerate(Tuple.(CartesianIndices(a))) + xn[n] = x[j] + yn[n] = y[i] + zn[n] = a[i,j] + end + return xn, yn, zn +end + function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) show(io::IO, mime, pgfx_plot.the_plot) end @@ -69,16 +82,32 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_axis!(axis_opt, sp, letter) end end - if hascolorbar(sp) - PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ - colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, - }""") - pushed_colormap = true - push!(axis_opt, - "colorbar" => nothing, - "colormap name" => "plots$(sp.attr[:subplot_index])", - ) - end + # Search series for any gradient. In case one series uses a gradient set + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots$(sp.attr[:subplot_index])", + ) + # goto is needed to break out of col and series for + @goto colorbar_end + end + end + end + @label colorbar_end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title], @@ -101,11 +130,13 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) opt = series.plotattributes st = series[:seriestype] series_opt = PGFPlotsX.Options( - "color" => opt[:linecolor], + "color" => single_color(opt[:linecolor]), ) # function args args = if st == :contour opt[:x], opt[:y], opt[:z].surf' + elseif st == :heatmap + surface_to_vecs(opt[:x], opt[:y], opt[:z]) elseif is3d(st) opt[:x], opt[:y], opt[:z] elseif st == :straightline @@ -153,8 +184,21 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) ) push!(axis, surface_plot) - elseif st == :histogram2d - hist_ + elseif st == :heatmap + # TODO: global view setting + push!(axis.options, + "view" => "{0}{90}", + "shader" => "flat corner", + ) + heatmap_opt = PGFPlotsX.Options( + "surf" => nothing, + "mesh/rows" => length(opt[:x]) + ) + heatmap_plot = PGFPlotsX.Plot3( + merge(series_opt, heatmap_opt), + PGFPlotsX.Table(args) + ) + push!(axis, heatmap_plot) else # treat segments segments = iter_segments(series) @@ -273,6 +317,11 @@ function pgfx_colormap(grad::ColorGradient) @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) end,"\n") end +function pgfx_colormap(grad::Vector{<:Colorant}) + join(map(grad) do c + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) + end,"\n") +end function pgfx_framestyle(style::Symbol) if style in _pgfx_framestyles diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 3d96360d..aa21ef71 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -74,7 +74,20 @@ end end # testset @testset "Histogram 2D" begin histogram2d(randn(10000), randn(10000), nbins=20) - # TODO: totally broken, errors also for pgfplots + # TODO: should work, when heatmaps works? + end # testset + @testset "Heatmap" begin + xs = [string("x", i) for i = 1:10] + ys = [string("y", i) for i = 1:4] + z = float((1:4) * reshape(1:10, 1, :)) + pgfx_plot = heatmap(xs, ys, z, aspect_ratio=1) + Plots._update_plot_object(pgfx_plot) + if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" + end + # TODO: wrong colors + # TODO: lines instead of patches end # testset @testset "Contours" begin x = 1:0.5:20 From d6bd10a937afbcfecc352391f988eea60e2bc53a Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 22:28:36 +0100 Subject: [PATCH 141/184] 3D view --- src/backends/pgfplotsx.jl | 4 ++++ test/test_pgfplotsx.jl | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 81cabf23..e2c08795 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -115,6 +115,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "point meta min" => get_clims(sp)[1] ) ) + if is3d(sp) + azim, elev = sp[:camera] + push!( axis_opt, "view" => (azim, elev) ) + end axisf = if sp[:projection] == :polar # TODO: this errors for some reason # push!(axis_opt, "xmin" => 90) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index aa21ef71..125ee529 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -86,8 +86,6 @@ end @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" end - # TODO: wrong colors - # TODO: lines instead of patches end # testset @testset "Contours" begin x = 1:0.5:20 From 311ace523dd4db5a725e8b748d793d4b2a6237a7 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 21 Nov 2019 22:34:14 +0100 Subject: [PATCH 142/184] fix gradient scatter plot --- src/backends/pgfplotsx.jl | 2 +- test/test_pgfplotsx.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index e2c08795..560b559a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -364,7 +364,7 @@ end function pgfx_linestyle(plotattributes, i = 1) lw = pgfx_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i) - lc = get_linecolor(plotattributes, i) + lc = single_color(get_linecolor(plotattributes, i)) la = get_linealpha(plotattributes, i) ls = get_linestyle(plotattributes, i) return pgfx_linestyle(lw, lc, la, ls) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 125ee529..a2a96681 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -111,6 +111,6 @@ end x + y end), color=:bluesreds, legend=false) plot(p1, p2) - # TODO: handle gradients as color + # TODO: questionable tiling end # testset end # testset From 6d737dea7b4b983575a1b02a9af8e4fcfc2474ad Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 00:23:47 +0100 Subject: [PATCH 143/184] quiver plots --- src/backends/pgfplotsx.jl | 44 ++++++++++++++++++++++++++++++++++++--- test/test_pgfplotsx.jl | 12 +++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 560b559a..616c2756 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -5,6 +5,11 @@ Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false was_shown::Bool = false the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() + function PGFPlotsXPlot(is_created, was_shown, the_plot) + pgfx_plot = new(is_created, was_shown, the_plot) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}") + pgfx_plot + end end pgfx_axes(pgfx_plot::PGFPlotsXPlot) = pgfx_plot.the_plot.elements[1].elements[1].contents @@ -214,9 +219,21 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if st == :shape || series[:fillrange] !== nothing segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end + x, y = collect(seg_args) + coordinates = if opt[:quiver] !== nothing + push!(segment_opt, "quiver" => PGFPlotsX.Options( + "u" => "\\thisrow{u}", + "v" => "\\thisrow{v}", + pgfx_arrow(opt[:arrow]) => nothing + ), + ) + PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) + else + PGFPlotsX.Coordinates(seg_args...) + end segment_plot = series_func( merge(series_opt, segment_opt), - PGFPlotsX.Coordinates(seg_args...), + coordinates, series[:fillrange] !== nothing ? "\\closedcycle" : "{}" ) push!(axis, segment_plot) @@ -255,7 +272,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end ## - const _pgfplotsx_linestyles = KW( :solid => "solid", :dash => "dashed", @@ -316,6 +332,27 @@ const _pgfx_annotation_halign = KW( ## -------------------------------------------------------------------------------------- # Generates a colormap for pgfplots based on a ColorGradient # TODO: maybe obsolete +pgfx_arrow(::Nothing) = "-" +function pgfx_arrow( arr::Arrow ) + components = String[] + head = String[] + push!(head, "{stealth[length = $(arr.headlength)pt, width = $(arr.headwidth)pt") + if arr.style == :open + push!(head, ", open") + end + push!(head, "]}") + head = join(head, "") + if arr.side == :both || arr.side == :tail + push!( components, head ) + end + push!(components, "-") + if arr.side == :both || arr.side == :head + push!( components, head ) + end + components = join( components, "" ) + return "every arrow/.append style={$(components)}" +end + function pgfx_colormap(grad::ColorGradient) join(map(grad.colors) do c @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) @@ -561,7 +598,8 @@ end # to fit ticks, tick labels, guides, colorbars, etc. function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) # TODO: make padding more intelligent - sp.minpad = (20mm, 5mm, 2mm, 10mm) + # order: right, top, left, bottom + sp.minpad = (20mm, 12mm, 2mm, 10mm) end function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index a2a96681..35a1b05f 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -113,4 +113,16 @@ end plot(p1, p2) # TODO: questionable tiling end # testset + @testset "Framestyles" begin + scatter(fill(randn(10), 6), fill(randn(10), 6), framestyle=[:box :semi :origin :zerolines :grid :none], title=[":box" ":semi" ":origin" ":zerolines" ":grid" ":none"], color=permutedims(1:6), layout=6, label="", markerstrokewidth=0, ticks=-2:2) + # TODO: support :semi + end # testset + @testset "Quiver" begin + x = -2pi:0.2:2*pi + y = sin.(x) + + u = ones(length(x)) + v = cos.(x) + plot( x, y, quiver = (u, v), arrow = true ) + end # testset end # testset From ced201700ef90fb012b2843ce72c67b0823480bb Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 00:45:14 +0100 Subject: [PATCH 144/184] extra styles for 3dTypes --- src/backends.jl | 13 ++++++------- src/backends/pgfplotsx.jl | 6 +++++- test/test_pgfplotsx.jl | 1 + 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 87f4dda8..1d4b3482 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -705,13 +705,12 @@ const _pgfplotsx_attr = merge_with_base_supported([ :camera, :contour_labels, ]) -# const _pgfplotsx_seriestype = [ -# :path, :scatter, :straightline, -# :heatmap, :pie, :image, -# :contour, :path3d, :scatter3d, :surface, :wireframe, :volume, -# :shape -# ] -const _pgfplotsx_seriestype = [:path, :path3d, :scatter, :steppre, :heatmap, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] +const _pgfplotsx_seriestype = + [:path, :scatter, :straightline, + :path3d, :scatter3d, :surface, :wireframe, :volume, + :heatmap, :contour, :histogram2d, + :shape, + :steppre, :stepmid, :steppost, :ysticks, :xsticks] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _pgfplotsx_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :ltriangle, :rtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline, Shape] const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 616c2756..af67917b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -316,7 +316,11 @@ const _pgfx_series_extrastyle = KW( :ysticks => "ycomb", :xsticks => "xcomb", :scatter => "only marks", - :shape => "area legends" + :shape => "area legends", + :scatter3D => "only marks" + :surface => "surf", + :wireframe => "mesh", + :volume => "patch" ) const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 35a1b05f..5af30606 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -124,5 +124,6 @@ end u = ones(length(x)) v = cos.(x) plot( x, y, quiver = (u, v), arrow = true ) + # TODO: could adjust limits to fit arrows if too long, but how? end # testset end # testset From b2852802db417340b7057db6b41d8b542818cb8c Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 00:54:16 +0100 Subject: [PATCH 145/184] fix arrow = false --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index af67917b..f97f6e4a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -336,7 +336,7 @@ const _pgfx_annotation_halign = KW( ## -------------------------------------------------------------------------------------- # Generates a colormap for pgfplots based on a ColorGradient # TODO: maybe obsolete -pgfx_arrow(::Nothing) = "-" +pgfx_arrow(::Nothing) = "every arrow/.append style={-}" function pgfx_arrow( arr::Arrow ) components = String[] head = String[] From b9b69158558148475ebfdd9e1f79b60bcea6346f Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 00:58:03 +0100 Subject: [PATCH 146/184] add patchlibrary --- src/backends/pgfplotsx.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index f97f6e4a..90d97d35 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -8,6 +8,7 @@ Base.@kwdef mutable struct PGFPlotsXPlot function PGFPlotsXPlot(is_created, was_shown, the_plot) pgfx_plot = new(is_created, was_shown, the_plot) PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}") pgfx_plot end end From 42e88225c5791163a38787a2bf4740474c565b98 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 13:50:18 +0100 Subject: [PATCH 147/184] restructure --- src/backends/pgfplotsx.jl | 232 ++++++++++++++++++++++---------------- test/test_pgfplotsx.jl | 6 + 2 files changed, 138 insertions(+), 100 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 90d97d35..17129cbd 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -142,24 +142,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => single_color(opt[:linecolor]), ) - # function args - args = if st == :contour - opt[:x], opt[:y], opt[:z].surf' - elseif st == :heatmap - surface_to_vecs(opt[:x], opt[:y], opt[:z]) - elseif is3d(st) - opt[:x], opt[:y], opt[:z] - elseif st == :straightline - straightline_data(series) - elseif st == :shape - shape_data(series) - elseif ispolar(sp) - theta, r = opt[:x], opt[:y] - rad2deg.(theta), r - else - opt[:x], opt[:y] - end - if is3d(series) + if is3d(series) || st == :heatmap series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot @@ -168,82 +151,56 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = merge(series_opt, pgfx_fillstyle(opt)) push!(series_opt, "area legend" => nothing) end - # include additional style - if haskey(_pgfx_series_extrastyle, st) - push!(series_opt, _pgfx_series_extrastyle[st] => nothing) - end - if st == :contour - if !isfilledcontour(series) - surface_opt = PGFPlotsX.Options( - "contour prepared" => PGFPlotsX.Options( - "labels" => opt[:contour_labels], - ) - ) - else - notimpl() - surface_opt = PGFPlotsX.Options( - "contour filled" => PGFPlotsX.Options( - # "levels" => opt[:levels], - # "labels" => opt[:contour_labels], - ) - ) - end - surface_plot = series_func( - # merge(series_opt, surface_opt), - surface_opt, - PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) - ) - push!(axis, surface_plot) - elseif st == :heatmap - # TODO: global view setting + if st == :heatmap push!(axis.options, "view" => "{0}{90}", "shader" => "flat corner", ) - heatmap_opt = PGFPlotsX.Options( - "surf" => nothing, - "mesh/rows" => length(opt[:x]) - ) - heatmap_plot = PGFPlotsX.Plot3( - merge(series_opt, heatmap_opt), - PGFPlotsX.Table(args) - ) - push!(axis, heatmap_plot) - else - # treat segments - segments = iter_segments(series) - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - seg_args = (arg[rng] for arg in args) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + end + # treat segments + segments = if iscontour(series) || st == :heatmap + iter_segments(series[:x], series[:y]) + else + iter_segments(series) + end + segment_opt = PGFPlotsX.Options() + for (i, rng) in enumerate(segments) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + if !iscontour(series) && !(st == :heatmap) segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - if st == :shape || series[:fillrange] !== nothing - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - x, y = collect(seg_args) - coordinates = if opt[:quiver] !== nothing - push!(segment_opt, "quiver" => PGFPlotsX.Options( - "u" => "\\thisrow{u}", - "v" => "\\thisrow{v}", - pgfx_arrow(opt[:arrow]) => nothing - ), - ) - PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) - else - PGFPlotsX.Coordinates(seg_args...) - end - segment_plot = series_func( - merge(series_opt, segment_opt), - coordinates, - series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + end + if st == :shape || series[:fillrange] !== nothing + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + if iscontour(series) + if !isfilledcontour(series) + push!(series_opt, + "contour prepared" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ) ) - push!(axis, segment_plot) - # add to legend? - if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + else + notimpl() + push!(series_opt, + "contour filled" => PGFPlotsX.Options( + # "levels" => opt[:levels], + # "labels" => opt[:contour_labels], + ) ) end end + coordinates = pgfx_series_coordinates!( sp, st, segment_opt, opt, rng ) + segment_plot = series_func( + merge(series_opt, segment_opt), + coordinates, + series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + ) + push!(axis, segment_plot) + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end # add series annotations anns = series[:series_annotations] for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) @@ -271,6 +228,96 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_plot.is_created = true end end +## seriestype specifics +@inline function pgfx_series_coordinates!(sp, st, segment_opt, opt, rng) + # function args + args = if st == :contour + opt[:x], opt[:y], opt[:z].surf' + elseif st == :heatmap + surface_to_vecs(opt[:x], opt[:y], opt[:z]) + elseif is3d(st) + opt[:x], opt[:y], opt[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = opt[:x], opt[:y] + rad2deg.(theta), r + else + opt[:x], opt[:y] + end + seg_args = if st == :contour || st == :heatmap + args + else + (arg[rng] for arg in args) + end + if opt[:quiver] !== nothing + push!(segment_opt, "quiver" => PGFPlotsX.Options( + "u" => "\\thisrow{u}", + "v" => "\\thisrow{v}", + pgfx_arrow(opt[:arrow]) => nothing + ), + ) + x, y = collect(seg_args) + return PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) + else + pgfx_series_coordinates!(Val(st), segment_opt, opt, seg_args) + end +end +function pgfx_series_coordinates!(st_val::Union{Val{:path}, Val{:path3d}}, segment_opt, opt, args) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Union{Val{:scatter}, Val{:scatter3d}}, segment_opt, opt, args) + push!( segment_opt, "only marks" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) + push!(segment_opt, + "surf" => nothing, + "mesh/rows" => length(opt[:x]) + ) + return PGFPlotsX.Table(args...) +end +function pgfx_series_coordinates!(st_val::Val{:stepre}, segment_opt, opt, args) + push!( segment_opt, "const plot mark right" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:stepmid}, segment_opt, opt, args) + push!( segment_opt, "const plot mark mid" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:steppost}, segment_opt, opt, args) + push!( segment_opt, "const plot" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Union{Val{:ysticks},Val{:sticks}}, segment_opt, opt, args) + push!( segment_opt, "ycomb" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) + push!( segment_opt, "xcomb" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) + push!( segment_opt, "surf" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:volume}, segment_opt, opt, args) + push!( segment_opt, "patch" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, args) + push!( segment_opt, "mesh" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) + push!( segment_opt, "area legends" => nothing, "patch" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:contour}, segment_opt, opt, args) + return PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) +end ## const _pgfplotsx_linestyles = KW( @@ -309,21 +356,6 @@ const _pgfplotsx_legend_pos = KW( :outertopright => "outer north east", ) -const _pgfx_series_extrastyle = KW( - :steppre => "const plot mark right", - :stepmid => "const plot mark mid", - :steppost => "const plot", - :sticks => "ycomb", - :ysticks => "ycomb", - :xsticks => "xcomb", - :scatter => "only marks", - :shape => "area legends", - :scatter3D => "only marks" - :surface => "surf", - :wireframe => "mesh", - :volume => "patch" -) - const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] const _pgfx_framestyle_defaults = Dict(:semi => :box) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 5af30606..b8f6b146 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -126,4 +126,10 @@ end plot( x, y, quiver = (u, v), arrow = true ) # TODO: could adjust limits to fit arrows if too long, but how? end # testset + @testset "Annotations" begin + y = rand(10) + plot(y, annotations=(3, y[3], Plots.text("this is \\#3", :left)), leg=false) + annotate!([(5, y[5], Plots.text("this is \\#5", 16, :red, :center)), (10, y[10], Plots.text("this is \\#10", :right, 20, "courier"))]) + scatter!(range(2, stop=8, length=6), rand(6), marker=(50, 0.2, :orange), series_annotations=["series", "annotations", "map", "to", "series", Plots.text("data", :green)]) + end # testset end # testset From c39a6d8ec32117f8d1a2b32d8e999aa8ec1a72b2 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 14:05:34 +0100 Subject: [PATCH 148/184] surface plots --- src/backends/pgfplotsx.jl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 17129cbd..ecf0833a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -166,7 +166,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - if !iscontour(series) && !(st == :heatmap) + if opt[:markershape] != :none #|| !iscontour(series) && !(st == :heatmap) segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end if st == :shape || series[:fillrange] !== nothing @@ -233,7 +233,10 @@ end # function args args = if st == :contour opt[:x], opt[:y], opt[:z].surf' - elseif st == :heatmap + elseif st == :heatmap || st == :surface + @show opt[:x] + @show opt[:y] + @show opt[:z] surface_to_vecs(opt[:x], opt[:y], opt[:z]) elseif is3d(st) opt[:x], opt[:y], opt[:z] @@ -300,7 +303,9 @@ function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) - push!( segment_opt, "surf" => nothing ) + push!( segment_opt, "surf" => nothing, + "mesh/rows" => length(opt[:x]) + ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:volume}, segment_opt, opt, args) From 195c6d601c546f20cdd3dd9080575d13aabdb701 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 14:08:45 +0100 Subject: [PATCH 149/184] wireframes --- src/backends/pgfplotsx.jl | 9 ++++----- test/test_pgfplotsx.jl | 5 ++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index ecf0833a..c2b1ef51 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -233,10 +233,7 @@ end # function args args = if st == :contour opt[:x], opt[:y], opt[:z].surf' - elseif st == :heatmap || st == :surface - @show opt[:x] - @show opt[:y] - @show opt[:z] + elseif st in (:heatmap, :surface, :wireframe) surface_to_vecs(opt[:x], opt[:y], opt[:z]) elseif is3d(st) opt[:x], opt[:y], opt[:z] @@ -313,7 +310,9 @@ function pgfx_series_coordinates!(st_val::Val{:volume}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, args) - push!( segment_opt, "mesh" => nothing ) + push!( segment_opt, "mesh" => nothing, + "mesh/rows" => length(opt[:x]) + ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index b8f6b146..70f51a72 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -76,7 +76,7 @@ end histogram2d(randn(10000), randn(10000), nbins=20) # TODO: should work, when heatmaps works? end # testset - @testset "Heatmap" begin + @testset "Heatmap-like" begin xs = [string("x", i) for i = 1:10] ys = [string("y", i) for i = 1:4] z = float((1:4) * reshape(1:10, 1, :)) @@ -86,6 +86,9 @@ end @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" end + + pgfx_plot = wireframe(xs, ys, z, aspect_ratio=1) + # TODO: clims are wrong end # testset @testset "Contours" begin x = 1:0.5:20 From 607640ce73210d167ea3e84c41e4cdac3be629e0 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 22 Nov 2019 14:11:43 +0100 Subject: [PATCH 150/184] straightline --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c2b1ef51..f9b9c9a9 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -265,7 +265,7 @@ end pgfx_series_coordinates!(Val(st), segment_opt, opt, seg_args) end end -function pgfx_series_coordinates!(st_val::Union{Val{:path}, Val{:path3d}}, segment_opt, opt, args) +function pgfx_series_coordinates!(st_val::Union{Val{:path}, Val{:path3d}, Val{:straightline}}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Union{Val{:scatter}, Val{:scatter3d}}, segment_opt, opt, args) From 2bbaf9d50401a3ffd0f0b2195591fa7a8b7c3879 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sat, 23 Nov 2019 20:10:08 +0100 Subject: [PATCH 151/184] free shapes --- src/backends/pgfplotsx.jl | 77 ++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index f9b9c9a9..e3441d0b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -89,31 +89,31 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end # Search series for any gradient. In case one series uses a gradient set - # the colorbar and colomap. - # The reasoning behind doing this on the axis level is that pgfplots - # colorbar seems to only works on axis level and needs the proper colormap for - # correctly displaying it. - # It's also possible to assign the colormap to the series itself but - # then the colormap needs to be added twice, once for the axis and once for the - # series. - # As it is likely that all series within the same axis use the same - # colormap this should not cause any problem. - for series in series_list(sp) - for col in (:markercolor, :fillcolor, :linecolor) - if typeof(series.plotattributes[col]) == ColorGradient - PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ - colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, - }""") - push!(axis_opt, - "colorbar" => nothing, - "colormap name" => "plots$(sp.attr[:subplot_index])", - ) - # goto is needed to break out of col and series for - @goto colorbar_end - end + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots$(sp.attr[:subplot_index])", + ) + # goto is needed to break out of col and series for + @goto colorbar_end end end - @label colorbar_end + end + @label colorbar_end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( "title" => sp[:colorbar_title], @@ -158,8 +158,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) end # treat segments - segments = if iscontour(series) || st == :heatmap - iter_segments(series[:x], series[:y]) + segments = if st in (:wireframe, :heatmap, :contour, :surface) + iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) else iter_segments(series) end @@ -167,6 +167,21 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) for (i, rng) in enumerate(segments) segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) if opt[:markershape] != :none #|| !iscontour(series) && !(st == :heatmap) + marker = opt[:markershape] + if marker isa Shape + x = marker.x + y = marker.y + scale_factor = 0.025 + mark_size = opt[:markersize] * scale_factor + path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, + """ + \\pgfdeclareplotmark{PlotsShape}{ + \\draw $path; + } + """ + ) + end segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end if st == :shape || series[:fillrange] !== nothing @@ -300,8 +315,11 @@ function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) + @show collect(args)[3] |> length + @show args push!( segment_opt, "surf" => nothing, - "mesh/rows" => length(opt[:x]) + "mesh/rows" => length(opt[:x]), + "mesh/cols" => length(opt[:y]), ) return PGFPlotsX.Coordinates(args...) end @@ -316,7 +334,7 @@ function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, arg return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) - push!( segment_opt, "area legends" => nothing, "patch" => nothing ) + push!( segment_opt, "area legends" => nothing ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:contour}, segment_opt, opt, args) @@ -459,9 +477,10 @@ function pgfx_marker(plotattributes, i = 1) a = alpha(cstr) cstr_stroke = plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)) a_stroke = alpha(cstr_stroke) + mark_size = pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i) return PGFPlotsX.Options( - "mark" => get(_pgfplotsx_markers, shape, "*"), - "mark size" => pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i), + "mark" => shape isa Shape ? "PlotsShape" : get(_pgfplotsx_markers, shape, "*"), + "mark size" => "$mark_size pt", "mark options" => PGFPlotsX.Options( "color" => cstr_stroke, "draw opacity" => a_stroke, From 6ba1607bb14b383b32abd909ce23016f18fe720e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sat, 23 Nov 2019 20:45:21 +0100 Subject: [PATCH 152/184] filled contour, histogram2d --- src/backends.jl | 2 +- src/backends/pgfplotsx.jl | 11 ----------- test/test_pgfplotsx.jl | 3 --- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 1d4b3482..9bf596fd 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -707,7 +707,7 @@ const _pgfplotsx_attr = merge_with_base_supported([ ]) const _pgfplotsx_seriestype = [:path, :scatter, :straightline, - :path3d, :scatter3d, :surface, :wireframe, :volume, + :path3d, :scatter3d, :surface, :wireframe, :heatmap, :contour, :histogram2d, :shape, :steppre, :stepmid, :steppost, :ysticks, :xsticks] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index e3441d0b..c7a3889b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -37,7 +37,6 @@ function Base.push!(pgfx_plot::PGFPlotsXPlot, item) end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) - # TODO: annotations! does not trigger _series_added ... if !pgfx_plot.is_created cols, rows = size(plt.layout.grid) the_plot = PGFPlotsX.TikzPicture() @@ -126,7 +125,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!( axis_opt, "view" => (azim, elev) ) end axisf = if sp[:projection] == :polar - # TODO: this errors for some reason # push!(axis_opt, "xmin" => 90) # push!(axis_opt, "xmax" => 450) PGFPlotsX.PolarAxis @@ -194,14 +192,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "labels" => opt[:contour_labels], ) ) - else - notimpl() - push!(series_opt, - "contour filled" => PGFPlotsX.Options( - # "levels" => opt[:levels], - # "labels" => opt[:contour_labels], - ) - ) end end coordinates = pgfx_series_coordinates!( sp, st, segment_opt, opt, rng ) @@ -390,7 +380,6 @@ const _pgfx_annotation_halign = KW( ) ## -------------------------------------------------------------------------------------- # Generates a colormap for pgfplots based on a ColorGradient -# TODO: maybe obsolete pgfx_arrow(::Nothing) = "every arrow/.append style={-}" function pgfx_arrow( arr::Arrow ) components = String[] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 70f51a72..4192e354 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -70,11 +70,9 @@ end x = 0.1:0.2:0.9 y = 0.7 * rand(5) .+ 0.15 plot(x, y, line=(3, :dash, :lightblue), marker=(Shape(verts), 30, RGBA(0, 0, 0, 0.2)), bg=:pink, fg=:darkblue, xlim=(0, 1), ylim=(0, 1), leg=false) - # TODO: draw those polygons end # testset @testset "Histogram 2D" begin histogram2d(randn(10000), randn(10000), nbins=20) - # TODO: should work, when heatmaps works? end # testset @testset "Heatmap-like" begin xs = [string("x", i) for i = 1:10] @@ -102,7 +100,6 @@ end p2 = contour(x, y, Z) p1 = contour(x, y, f, fill=true) plot(p1, p2) - # TODO: filled contours end # testset @testset "Varying colors" begin t = range(0, stop=1, length=100) From 95a29f9cbe664d7634e7ec4477aca573da9b81c4 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 16:46:20 +0100 Subject: [PATCH 153/184] filled contour (really) --- src/backends.jl | 4 +- src/backends/pgfplotsx.jl | 85 ++++++++++++++++++++++++++------------- test/test_pgfplotsx.jl | 1 + 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 9bf596fd..623a057c 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -707,8 +707,8 @@ const _pgfplotsx_attr = merge_with_base_supported([ ]) const _pgfplotsx_seriestype = [:path, :scatter, :straightline, - :path3d, :scatter3d, :surface, :wireframe, - :heatmap, :contour, :histogram2d, + :path3d, :scatter3d, :surface, :wireframe, + :heatmap, :contour, :contour3d, :histogram2d, :shape, :steppre, :stepmid, :steppost, :ysticks, :xsticks] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c7a3889b..c6efba0e 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,5 +1,4 @@ using Contour: Contour -using StatsBase: Histogram, fit # PGFPlotsX.print_tex(io::IO, data::ColorGradient) = write(io, pgfx_colormap(data)) Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false @@ -140,13 +139,18 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => single_color(opt[:linecolor]), ) - if is3d(series) || st == :heatmap + if is3d(series) || st == :heatmap #|| isfilledcontour(series) series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot end - if series[:fillrange] !== nothing && st != :contour - series_opt = merge(series_opt, pgfx_fillstyle(opt)) + if isfilledcontour(series) + # push!(series_opt, "contour filled" => nothing) + # st = :surface + # axis_opt["view"] = (0, 90) + # push!(series_opt, "shader" => "interp") + end + if series[:fillrange] !== nothing && !isfilledcontour(series) push!(series_opt, "area legend" => nothing) end if st == :heatmap @@ -156,7 +160,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) ) end # treat segments - segments = if st in (:wireframe, :heatmap, :contour, :surface) + segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) else iter_segments(series) @@ -164,7 +168,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - if opt[:markershape] != :none #|| !iscontour(series) && !(st == :heatmap) + if opt[:markershape] != :none marker = opt[:markershape] if marker isa Shape x = marker.x @@ -182,23 +186,17 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end - if st == :shape || series[:fillrange] !== nothing + if st == :shape || + (series[:fillrange] !== nothing && !isfilledcontour(series)) segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end - if iscontour(series) - if !isfilledcontour(series) - push!(series_opt, - "contour prepared" => PGFPlotsX.Options( - "labels" => opt[:contour_labels], - ) - ) - end - end - coordinates = pgfx_series_coordinates!( sp, st, segment_opt, opt, rng ) + coordinates = pgfx_series_coordinates!( sp, + isfilledcontour(series) ? :filledcontour : st, + segment_opt, opt, rng ) segment_plot = series_func( merge(series_opt, segment_opt), coordinates, - series[:fillrange] !== nothing ? "\\closedcycle" : "{}" + (series[:fillrange] !== nothing && !isfilledcontour(series)) ? "\\closedcycle" : "{}" ) push!(axis, segment_plot) # add to legend? @@ -236,10 +234,10 @@ end ## seriestype specifics @inline function pgfx_series_coordinates!(sp, st, segment_opt, opt, rng) # function args - args = if st == :contour - opt[:x], opt[:y], opt[:z].surf' + args = if st in (:contour, :contour3d, :filledcontour) + opt[:x], opt[:y], Array(opt[:z])' elseif st in (:heatmap, :surface, :wireframe) - surface_to_vecs(opt[:x], opt[:y], opt[:z]) + surface_to_vecs(opt[:x], opt[:y], opt[:z]) elseif is3d(st) opt[:x], opt[:y], opt[:z] elseif st == :straightline @@ -252,7 +250,7 @@ end else opt[:x], opt[:y] end - seg_args = if st == :contour || st == :heatmap + seg_args = if st in (:contour, :contour3d, :heatmap, :filledcontour) args else (arg[rng] for arg in args) @@ -305,8 +303,6 @@ function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) - @show collect(args)[3] |> length - @show args push!( segment_opt, "surf" => nothing, "mesh/rows" => length(opt[:x]), "mesh/cols" => length(opt[:y]), @@ -327,10 +323,42 @@ function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) push!( segment_opt, "area legends" => nothing ) return PGFPlotsX.Coordinates(args...) end -function pgfx_series_coordinates!(st_val::Val{:contour}, segment_opt, opt, args) +function pgfx_series_coordinates!(st_val::Union{Val{:contour}, Val{:contour3d}}, segment_opt, opt, args) + push!(segment_opt, + "contour prepared" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ), + ) return PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) end +function pgfx_series_coordinates!(st_val::Val{:filledcontour}, segment_opt, opt, args) + xs, ys, zs = collect(args) + push!(segment_opt, + "contour filled" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ), + "point meta" => "explicit", + "shader" => "flat" + ) + if opt[:levels] isa Number + push!(segment_opt["contour filled"], + "number" => opt[:levels], + ) + elseif opt[:levels] isa AVec + push!(segment_opt["contour filled"], + "levels" => opt[:levels], + ) + end + cs = join([ + join(["($x, $y) [$(zs[j, i])]" for (j, x) in enumerate(xs)], " ") for (i, y) in enumerate(ys)], "\n\n" + ) + """ +coordinates { +$cs +}; + """ +end ## const _pgfplotsx_linestyles = KW( :solid => "solid", @@ -428,10 +456,9 @@ pgfx_thickness_scaling(series) = pgfx_thickness_scaling(series[:subplot]) function pgfx_fillstyle(plotattributes, i = 1) cstr = get_fillcolor(plotattributes, i) - a = alpha(cstr) - fa = get_fillalpha(plotattributes, i) - if fa !== nothing - a = fa + a = get_fillalpha(plotattributes, i) + if a === nothing + a = alpha(single_color(cstr)) end PGFPlotsX.Options("fill" => cstr, "fill opacity" => a) end diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 4192e354..f38b115b 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -100,6 +100,7 @@ end p2 = contour(x, y, Z) p1 = contour(x, y, f, fill=true) plot(p1, p2) + # TODO: colorbar for filled contours end # testset @testset "Varying colors" begin t = range(0, stop=1, length=100) From 35e24fef2a821d52af5467fbd26670539302ded8 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:03:08 +0100 Subject: [PATCH 154/184] rely on recipe for histogram2d --- src/backends.jl | 2 +- src/backends/pgfplotsx.jl | 27 +++++++++++++-------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 623a057c..9bcba334 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -708,7 +708,7 @@ const _pgfplotsx_attr = merge_with_base_supported([ const _pgfplotsx_seriestype = [:path, :scatter, :straightline, :path3d, :scatter3d, :surface, :wireframe, - :heatmap, :contour, :contour3d, :histogram2d, + :heatmap, :contour, :contour3d, :shape, :steppre, :stepmid, :steppost, :ysticks, :xsticks] const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c6efba0e..684253de 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,5 +1,4 @@ using Contour: Contour -# PGFPlotsX.print_tex(io::IO, data::ColorGradient) = write(io, pgfx_colormap(data)) Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false was_shown::Bool = false @@ -250,7 +249,8 @@ end else opt[:x], opt[:y] end - seg_args = if st in (:contour, :contour3d, :heatmap, :filledcontour) + seg_args = if st in (:contour, :contour3d, :filledcontour) + args else (arg[rng] for arg in args) @@ -278,10 +278,12 @@ end function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) push!(segment_opt, "surf" => nothing, - "mesh/rows" => length(opt[:x]) + "mesh/rows" => length(opt[:x]), + "mesh/cols" => length(opt[:y]) ) return PGFPlotsX.Table(args...) end + function pgfx_series_coordinates!(st_val::Val{:stepre}, segment_opt, opt, args) push!( segment_opt, "const plot mark right" => nothing ) return PGFPlotsX.Coordinates(args...) @@ -354,9 +356,9 @@ function pgfx_series_coordinates!(st_val::Val{:filledcontour}, segment_opt, opt, join(["($x, $y) [$(zs[j, i])]" for (j, x) in enumerate(xs)], " ") for (i, y) in enumerate(ys)], "\n\n" ) """ -coordinates { -$cs -}; + coordinates { + $cs + }; """ end ## @@ -590,14 +592,11 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # limits - # TODO: support zlims - if letter != :z - lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) - push!( opt, - string(letter,:min) => lims[1], - string(letter,:max) => lims[2] - ) - end + lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) + push!( opt, + string(letter,:min) => lims[1], + string(letter,:max) => lims[2] + ) if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none ticks = get_ticks(sp, axis) From 92814e71c76b98c7d8e64c9824394b15a480162c Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:04:13 +0100 Subject: [PATCH 155/184] fix steppre --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 684253de..4d2921da 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -284,7 +284,7 @@ function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) return PGFPlotsX.Table(args...) end -function pgfx_series_coordinates!(st_val::Val{:stepre}, segment_opt, opt, args) +function pgfx_series_coordinates!(st_val::Val{:steppre}, segment_opt, opt, args) push!( segment_opt, "const plot mark right" => nothing ) return PGFPlotsX.Coordinates(args...) end From 903fb84af06ecf8b3b72c152e8a34564caa77736 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:10:34 +0100 Subject: [PATCH 156/184] fix bar --- src/backends/pgfplotsx.jl | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4d2921da..373d9ca3 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -143,12 +143,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else series_func = PGFPlotsX.Plot end - if isfilledcontour(series) - # push!(series_opt, "contour filled" => nothing) - # st = :surface - # axis_opt["view"] = (0, 90) - # push!(series_opt, "shader" => "interp") - end if series[:fillrange] !== nothing && !isfilledcontour(series) push!(series_opt, "area legend" => nothing) end @@ -189,9 +183,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) (series[:fillrange] !== nothing && !isfilledcontour(series)) segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end - coordinates = pgfx_series_coordinates!( sp, - isfilledcontour(series) ? :filledcontour : st, - segment_opt, opt, rng ) + coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) segment_plot = series_func( merge(series_opt, segment_opt), coordinates, @@ -231,9 +223,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end end ## seriestype specifics -@inline function pgfx_series_coordinates!(sp, st, segment_opt, opt, rng) +@inline function pgfx_series_coordinates!(sp, series, segment_opt, opt, rng) + st = series[:seriestype] # function args - args = if st in (:contour, :contour3d, :filledcontour) + args = if st in (:contour, :contour3d) opt[:x], opt[:y], Array(opt[:z])' elseif st in (:heatmap, :surface, :wireframe) surface_to_vecs(opt[:x], opt[:y], opt[:z]) @@ -249,8 +242,7 @@ end else opt[:x], opt[:y] end - seg_args = if st in (:contour, :contour3d, :filledcontour) - + seg_args = if st in (:contour, :contour3d) args else (arg[rng] for arg in args) @@ -265,6 +257,9 @@ end x, y = collect(seg_args) return PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) else + if isfilledcontour(series) + st = :filledcontour + end pgfx_series_coordinates!(Val(st), segment_opt, opt, seg_args) end end @@ -322,7 +317,7 @@ function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, arg return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) - push!( segment_opt, "area legends" => nothing ) + # push!( segment_opt, "area legend" => nothing ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Union{Val{:contour}, Val{:contour3d}}, segment_opt, opt, args) From f11d5b1e635a2be59bb69dc775c5844073b44fd1 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:11:52 +0100 Subject: [PATCH 157/184] fix bar2 --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 373d9ca3..2be8ec56 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -317,7 +317,7 @@ function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, arg return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) - # push!( segment_opt, "area legend" => nothing ) + push!( segment_opt, "area legend" => nothing ) return PGFPlotsX.Coordinates(args...) end function pgfx_series_coordinates!(st_val::Union{Val{:contour}, Val{:contour3d}}, segment_opt, opt, args) From 8636718c88871fd567b0a965d6f4e1c4259afda5 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 18:18:10 +0100 Subject: [PATCH 158/184] fix display --- src/backends/pgfplotsx.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 2be8ec56..27067035 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -26,6 +26,7 @@ function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) return xn, yn, zn end +Base.display(pgfx_plot::PGFPlotsXPlot) = display(pgfx_plot.the_plot) function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) show(io::IO, mime, pgfx_plot.the_plot) end @@ -705,8 +706,5 @@ function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend end function _display(plt::Plot{PGFPlotsXBackend}) - # fn = string(tempname(),".svg") - # PGFPlotsX.pgfsave(fn, plt.o) - # open_browser_window(fn) plt.o end From c034d7bf1bc197415c9bb393f38860f8f7ffd224 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 19:12:31 +0100 Subject: [PATCH 159/184] filled custom marker --- src/backends/pgfplotsx.jl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 27067035..8e21ebcb 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -133,7 +133,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) axis = axisf( axis_opt ) - for series in series_list(sp) + for (series_index, series) in enumerate(series_list(sp)) opt = series.plotattributes st = series[:seriestype] series_opt = PGFPlotsX.Options( @@ -170,10 +170,13 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) scale_factor = 0.025 mark_size = opt[:markersize] * scale_factor path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") + c = get_markercolor(series, i) + a = get_markeralpha(series, i) PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """ - \\pgfdeclareplotmark{PlotsShape}{ - \\draw $path; + \\pgfdeclareplotmark{PlotsShape$(series_index)}{ + \\filldraw + $path; } """ ) @@ -493,7 +496,7 @@ function pgfx_marker(plotattributes, i = 1) a_stroke = alpha(cstr_stroke) mark_size = pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i) return PGFPlotsX.Options( - "mark" => shape isa Shape ? "PlotsShape" : get(_pgfplotsx_markers, shape, "*"), + "mark" => shape isa Shape ? "PlotsShape$i" : get(_pgfplotsx_markers, shape, "*"), "mark size" => "$mark_size pt", "mark options" => PGFPlotsX.Options( "color" => cstr_stroke, From 02b54e72a6ce5d720b6bbae7af63c340711c3a45 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 24 Nov 2019 19:18:45 +0100 Subject: [PATCH 160/184] increase right padding --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 8e21ebcb..54393377 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -673,7 +673,7 @@ end function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) # TODO: make padding more intelligent # order: right, top, left, bottom - sp.minpad = (20mm, 12mm, 2mm, 10mm) + sp.minpad = (22mm, 12mm, 2mm, 10mm) end function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) From aaaedcab1ae42c772dd38c062ce694ee8b1e83de Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 12:21:12 +0100 Subject: [PATCH 161/184] robust pgfx_axes --- src/backends/pgfplotsx.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 54393377..52fbe121 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -11,7 +11,11 @@ Base.@kwdef mutable struct PGFPlotsXPlot end end -pgfx_axes(pgfx_plot::PGFPlotsXPlot) = pgfx_plot.the_plot.elements[1].elements[1].contents +function pgfx_axes(pgfx_plot::PGFPlotsXPlot) + gp = pgfx_plot.the_plot.elements[1] + return gp isa PGFPlotsX.GroupPlot ? gp.elements[1].contents : gp +end + function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) a = Array(s) From f53b070d79d295c42929ec3e2f174c10d7cbf81c Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 12:38:54 +0100 Subject: [PATCH 162/184] add background_color_outside --- src/backends/pgfplotsx.jl | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 52fbe121..fd276505 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -5,7 +5,26 @@ Base.@kwdef mutable struct PGFPlotsXPlot the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() function PGFPlotsXPlot(is_created, was_shown, the_plot) pgfx_plot = new(is_created, was_shown, the_plot) + # tikz libraries PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{backgrounds}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, + """ + \\pgfkeys{/tikz/.cd, + background color/.initial=white, + background color/.get=\\backcol, + background color/.store in=\\backcol, + } + \\tikzset{background rectangle/.style={ + fill=\\backcol, + }, + use background/.style={ + show background rectangle + } + } + """ + ) + # pgfplots libraries PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}") pgfx_plot end @@ -41,8 +60,19 @@ end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created + the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) cols, rows = size(plt.layout.grid) - the_plot = PGFPlotsX.TikzPicture() + bgc = plt.attr[:background_color_outside] + if bgc isa Colors.Colorant + cstr = plot_color(bgc) + a = alpha(cstr) + push!(the_plot.options, + "draw opacity" => a, + "background color" => cstr, + "use background" => nothing, + ) + end + # the combination of groupplot and polaraxis is broken in pgfplots if !any( sp -> ispolar(sp), plt.subplots ) pl_height, pl_width = plt.attr[:size] From acf4cb4e5b213f252de72adc29c90f6689e8b1f1 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 14:18:25 +0100 Subject: [PATCH 163/184] add ribbons --- src/backends/pgfplotsx.jl | 266 ++++++++++++++++++++++---------------- 1 file changed, 156 insertions(+), 110 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index fd276505..47b9fa9a 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -26,6 +26,7 @@ Base.@kwdef mutable struct PGFPlotsXPlot ) # pgfplots libraries PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween}") pgfx_plot end end @@ -147,116 +148,122 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end @label colorbar_end - push!(axis_opt, "colorbar style" => PGFPlotsX.Options( - "title" => sp[:colorbar_title], - "point meta max" => get_clims(sp)[2], - "point meta min" => get_clims(sp)[1] - ) - ) - if is3d(sp) - azim, elev = sp[:camera] - push!( axis_opt, "view" => (azim, elev) ) - end - axisf = if sp[:projection] == :polar - # push!(axis_opt, "xmin" => 90) - # push!(axis_opt, "xmax" => 450) - PGFPlotsX.PolarAxis - else - PGFPlotsX.Axis - end - axis = axisf( - axis_opt - ) - for (series_index, series) in enumerate(series_list(sp)) - opt = series.plotattributes - st = series[:seriestype] - series_opt = PGFPlotsX.Options( - "color" => single_color(opt[:linecolor]), - ) - if is3d(series) || st == :heatmap #|| isfilledcontour(series) - series_func = PGFPlotsX.Plot3 - else - series_func = PGFPlotsX.Plot - end - if series[:fillrange] !== nothing && !isfilledcontour(series) - push!(series_opt, "area legend" => nothing) - end - if st == :heatmap - push!(axis.options, - "view" => "{0}{90}", - "shader" => "flat corner", - ) - end - # treat segments - segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) - iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) - else - iter_segments(series) - end - segment_opt = PGFPlotsX.Options() - for (i, rng) in enumerate(segments) - segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) - if opt[:markershape] != :none - marker = opt[:markershape] - if marker isa Shape - x = marker.x - y = marker.y - scale_factor = 0.025 - mark_size = opt[:markersize] * scale_factor - path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") - c = get_markercolor(series, i) - a = get_markeralpha(series, i) - PGFPlotsX.push_preamble!(pgfx_plot.the_plot, - """ - \\pgfdeclareplotmark{PlotsShape$(series_index)}{ - \\filldraw - $path; - } - """ - ) - end - segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) - end - if st == :shape || - (series[:fillrange] !== nothing && !isfilledcontour(series)) - segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) - end - coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) - segment_plot = series_func( - merge(series_opt, segment_opt), - coordinates, - (series[:fillrange] !== nothing && !isfilledcontour(series)) ? "\\closedcycle" : "{}" - ) - push!(axis, segment_plot) - # add to legend? - if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) - ) - end - # add series annotations - anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) - pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) - end - end - # add subplot annotations - anns = sp.attr[:annotations] - for (xi,yi,txt) in anns - pgfx_add_annotation!(axis, xi, yi, txt) - end - end - if ispolar(sp) - axes = the_plot - else - axes = the_plot.elements[1] - end - push!( axes, axis ) - if length(plt.o.the_plot.elements) > 0 - plt.o.the_plot.elements[1] = the_plot - else - push!(plt.o, the_plot) - end - end + push!(axis_opt, "colorbar style" => PGFPlotsX.Options( + "title" => sp[:colorbar_title], + "point meta max" => get_clims(sp)[2], + "point meta min" => get_clims(sp)[1] + ) + ) + if is3d(sp) + azim, elev = sp[:camera] + push!( axis_opt, "view" => (azim, elev) ) + end + axisf = if sp[:projection] == :polar + # push!(axis_opt, "xmin" => 90) + # push!(axis_opt, "xmax" => 450) + PGFPlotsX.PolarAxis + else + PGFPlotsX.Axis + end + axis = axisf( + axis_opt + ) + for (series_index, series) in enumerate(series_list(sp)) + opt = series.plotattributes + st = series[:seriestype] + series_opt = PGFPlotsX.Options( + "color" => single_color(opt[:linecolor]), + ) + if is3d(series) || st == :heatmap #|| isfilledcontour(series) + series_func = PGFPlotsX.Plot3 + else + series_func = PGFPlotsX.Plot + end + if series[:fillrange] !== nothing && !isfilledcontour(series) + push!(series_opt, "area legend" => nothing) + end + if st == :heatmap + push!(axis.options, + "view" => "{0}{90}", + "shader" => "flat corner", + ) + end + # treat segments + segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) + iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) + else + iter_segments(series) + end + segment_opt = PGFPlotsX.Options() + for (i, rng) in enumerate(segments) + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + if opt[:markershape] != :none + marker = opt[:markershape] + if marker isa Shape + x = marker.x + y = marker.y + scale_factor = 0.025 + mark_size = opt[:markersize] * scale_factor + path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") + c = get_markercolor(series, i) + a = get_markeralpha(series, i) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, + """ + \\pgfdeclareplotmark{PlotsShape$(series_index)}{ + \\filldraw + $path; + } + """ + ) + end + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + end + if st == :shape || + (series[:fillrange] !== nothing && !isfilledcontour(series)) && + series[:ribbon] === nothing + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) + segment_plot = series_func( + merge(series_opt, segment_opt), + coordinates, + (series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing) ? "\\closedcycle" : "{}" + ) + push!(axis, segment_plot) + # add ribbons? + ribbon = series[:ribbon] + if ribbon !== nothing + pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) + end + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) + ) + end + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) + end + end + # add subplot annotations + anns = sp.attr[:annotations] + for (xi,yi,txt) in anns + pgfx_add_annotation!(axis, xi, yi, txt) + end + end + if ispolar(sp) + axes = the_plot + else + axes = the_plot.elements[1] + end + push!( axes, axis ) + if length(plt.o.the_plot.elements) > 0 + plt.o.the_plot.elements[1] = the_plot + else + push!(plt.o, the_plot) + end + end pgfx_plot.is_created = true end end @@ -570,6 +577,45 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) "{$(val.str).};" ]) end + +function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) + ribbon = series[:ribbon] + opt = series.plotattributes + ribbon_n = length(opt[:y]) ÷ length(ribbon) + ribbon_y = repeat(ribbon, outer = ribbon_n) + # upper ribbon + ribbon_name_plus = "plots_rib_p$series_index" + ribbon_opt_plus = merge(segment_plot.options, PGFPlotsX.Options( + "name path" => ribbon_name_plus, + "color" => opt[:fillcolor], + "draw opacity" => opt[:fillalpha] + )) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] + ribbon_y) + ribbon_plot_plus = series_func( + ribbon_opt_plus, + coordinates_plus + ) + push!(axis, ribbon_plot_plus) + # lower ribbon + ribbon_name_minus = "plots_rib_m$series_index" + ribbon_opt_minus = merge(segment_plot.options, PGFPlotsX.Options( + "name path" => ribbon_name_minus, + "color" => opt[:fillcolor], + "draw opacity" => opt[:fillalpha] + )) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] - ribbon_y) + ribbon_plot_plus = series_func( + ribbon_opt_minus, + coordinates_plus + ) + push!(axis, ribbon_plot_plus) + # fill + push!(axis, series_func( + pgfx_fillstyle(opt, series_index), + "fill between [of=$(ribbon_name_plus) and $(ribbon_name_minus)]" + )) + return axis +end # -------------------------------------------------------------------------------------- function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) axis = sp[Symbol(letter,:axis)] From 3eafc67654d1222331650ceac83b475d0a6f633e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 14:37:48 +0100 Subject: [PATCH 164/184] fix scalar ribbons --- src/backends/pgfplotsx.jl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 47b9fa9a..012b2dfd 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -579,10 +579,12 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) end function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) - ribbon = series[:ribbon] + ribbon_y = series[:ribbon] opt = series.plotattributes - ribbon_n = length(opt[:y]) ÷ length(ribbon) - ribbon_y = repeat(ribbon, outer = ribbon_n) + if ribbon_y isa AVec + ribbon_n = length(opt[:y]) ÷ length(ribbon) + ribbon_y = repeat(ribbon, outer = ribbon_n) + end # upper ribbon ribbon_name_plus = "plots_rib_p$series_index" ribbon_opt_plus = merge(segment_plot.options, PGFPlotsX.Options( @@ -590,7 +592,7 @@ function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_inde "color" => opt[:fillcolor], "draw opacity" => opt[:fillalpha] )) - coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] + ribbon_y) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] .+ ribbon_y) ribbon_plot_plus = series_func( ribbon_opt_plus, coordinates_plus @@ -603,7 +605,7 @@ function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_inde "color" => opt[:fillcolor], "draw opacity" => opt[:fillalpha] )) - coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] - ribbon_y) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] .- ribbon_y) ribbon_plot_plus = series_func( ribbon_opt_minus, coordinates_plus From 7b2be59b7b9be91fe5f619da57d78ccd8a46e675 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 14:51:53 +0100 Subject: [PATCH 165/184] arbitrary legend position --- src/backends/pgfplotsx.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 012b2dfd..09fc06bc 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -106,7 +106,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "draw opacity" => title_a, "rotate" => sp[:titlefontrotation] ), - "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), "legend style" => PGFPlotsX.Options( pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, "fill" => cstr, @@ -116,6 +115,14 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "fill" => sp[:background_color_inside] ) ) + # legend position + if sp[:legend] isa Tuple + x, y = sp[:legend] + push!(axis_opt["legend style"], "at={($x, $y)}" ) + else + push!(axis_opt, "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), + ) + end for letter in (:x, :y, :z) if letter != :z || is3d(sp) pgfx_axis!(axis_opt, sp, letter) From 5335159203f19a72827634d681b45631ced60550 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 15:49:25 +0100 Subject: [PATCH 166/184] respect user margins --- src/backends/pgfplotsx.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 09fc06bc..66dfe4e5 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -762,7 +762,10 @@ end function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) # TODO: make padding more intelligent # order: right, top, left, bottom - sp.minpad = (22mm, 12mm, 2mm, 10mm) + sp.minpad = (22mm + sp[:right_margin], + 12mm + sp[:top_margin], + 2mm + sp[:left_margin], + 10mm + sp[:bottom_margin]) end function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) From 3d735911784029174d706c1e1c426a497121902c Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 17:44:25 +0100 Subject: [PATCH 167/184] respect standalone flag --- src/backends/pgfplotsx.jl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 66dfe4e5..b13125fe 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -36,6 +36,14 @@ function pgfx_axes(pgfx_plot::PGFPlotsXPlot) return gp isa PGFPlotsX.GroupPlot ? gp.elements[1].contents : gp end +function pgfx_preample(pgfx_plot::Plots.Plot{Plots.PGFPlotsXBackend}) + old_flag = pgfx_plot.attr[:tex_output_standalone] + pgfx_plot.attr[:tex_output_standalone] = true + fulltext = String(repr("application/x-tex", pgfx_plot)) + preamble = fulltext[1:first(findfirst("\\begin{document}", fulltext)) - 1] + pgfx_plot.attr[:tex_output_standalone] = old_flag + preamble +end function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) a = Array(s) @@ -797,7 +805,7 @@ end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) _update_plot_object(plt) - PGFPlotsX.print_tex(io, plt.o.the_plot) + PGFPlotsX.print_tex(io, plt.o.the_plot, include_preamble = plt.attr[:tex_output_standalone]) end function _display(plt::Plot{PGFPlotsXBackend}) From 7ea1eebc9e01e16c7c02a406e205ccd4f9fb151b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 18:56:20 +0100 Subject: [PATCH 168/184] line legend for ribbon plots --- src/backends/pgfplotsx.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index b13125fe..09496a67 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -194,7 +194,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else series_func = PGFPlotsX.Plot end - if series[:fillrange] !== nothing && !isfilledcontour(series) + if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing push!(series_opt, "area legend" => nothing) end if st == :heatmap @@ -252,8 +252,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end # add to legend? if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry( opt[:label] ) - ) + push!( axis, PGFPlotsX.LegendEntry(opt[:label]) ) end # add series annotations anns = series[:series_annotations] From c4354c86c009334b934415bea63dbb05f83316f6 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 20:10:09 +0100 Subject: [PATCH 169/184] legend opacity --- src/backends/pgfplotsx.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 09496a67..94a76b3b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -102,8 +102,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) bb = bbox(sp) cstr = plot_color(sp[:background_color_legend]) a = alpha(cstr) + fg_alpha = alpha(plot_color(sp[:foreground_color_legend])) title_cstr = plot_color(sp[:titlefontcolor]) - title_a = alpha(cstr) + title_a = alpha(title_cstr) axis_opt = PGFPlotsX.Options( "height" => string(height(bb)), "width" => string(width(bb)), @@ -115,8 +116,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "rotate" => sp[:titlefontrotation] ), "legend style" => PGFPlotsX.Options( - pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid") => nothing, + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid") => nothing, "fill" => cstr, + "fill opacity" => a, + "text opacity" => alpha(plot_color(sp[:legendfontcolor])), "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) ), "axis background/.style" => PGFPlotsX.Options( From fe07fe0a7b5c66d0fb555a7d0c8f7146bfecea84 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 23:05:27 +0100 Subject: [PATCH 170/184] fix background color --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 94a76b3b..2e210ab3 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -71,7 +71,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) cols, rows = size(plt.layout.grid) - bgc = plt.attr[:background_color_outside] + bgc = plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : plt.attr[:background_color] if bgc isa Colors.Colorant cstr = plot_color(bgc) a = alpha(cstr) From f2af1216612e6d48934a2b79ad487d1b2479a8a3 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Mon, 25 Nov 2019 23:12:20 +0100 Subject: [PATCH 171/184] fix pgfx_axes --- src/backends/pgfplotsx.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 2e210ab3..056405eb 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -32,8 +32,8 @@ Base.@kwdef mutable struct PGFPlotsXPlot end function pgfx_axes(pgfx_plot::PGFPlotsXPlot) - gp = pgfx_plot.the_plot.elements[1] - return gp isa PGFPlotsX.GroupPlot ? gp.elements[1].contents : gp + gp = pgfx_plot.the_plot.elements[1].elements[1] + return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp end function pgfx_preample(pgfx_plot::Plots.Plot{Plots.PGFPlotsXBackend}) From 091ca327ba4a1363f4d511e23ca74bb7cd7acf4f Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 00:07:45 +0100 Subject: [PATCH 172/184] direct colormap access --- src/backends/pgfplotsx.jl | 13 +++++++------ test/test_pgfplotsx.jl | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 056405eb..ec210aab 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -158,6 +158,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) push!(axis_opt, "colorbar" => nothing, "colormap name" => "plots$(sp.attr[:subplot_index])", + "colormap access" => "direct", ) # goto is needed to break out of col and series for @goto colorbar_end @@ -167,10 +168,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) @label colorbar_end push!(axis_opt, "colorbar style" => PGFPlotsX.Options( - "title" => sp[:colorbar_title], - "point meta max" => get_clims(sp)[2], - "point meta min" => get_clims(sp)[1] - ) + "title" => sp[:colorbar_title], + "point meta max" => get_clims(sp)[2], + "point meta min" => get_clims(sp)[1] + ) ) if is3d(sp) azim, elev = sp[:camera] @@ -192,7 +193,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) series_opt = PGFPlotsX.Options( "color" => single_color(opt[:linecolor]), ) - if is3d(series) || st == :heatmap #|| isfilledcontour(series) + if is3d(series) || st == :heatmap series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot @@ -336,7 +337,7 @@ function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) push!(segment_opt, "surf" => nothing, "mesh/rows" => length(opt[:x]), - "mesh/cols" => length(opt[:y]) + "mesh/cols" => length(opt[:y]), ) return PGFPlotsX.Table(args...) end diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index f38b115b..4c62ef4f 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -80,7 +80,8 @@ end z = float((1:4) * reshape(1:10, 1, :)) pgfx_plot = heatmap(xs, ys, z, aspect_ratio=1) Plots._update_plot_object(pgfx_plot) - if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) + if + @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" end From 9488176a2d8e05ed4b7e441088c71e8014864a1d Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 00:15:54 +0100 Subject: [PATCH 173/184] flip layout --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index ec210aab..4ae9370f 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -70,7 +70,7 @@ end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) - cols, rows = size(plt.layout.grid) + rows, cols = size(plt.layout.grid) bgc = plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : plt.attr[:background_color] if bgc isa Colors.Colorant cstr = plot_color(bgc) From 47900b1a8014a8ad7dd63c1953d793126afd2e34 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 00:28:11 +0100 Subject: [PATCH 174/184] fix framestyle error --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4ae9370f..82ca9e32 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -646,7 +646,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) ) # set to supported framestyle - framestyle = pgfx_framestyle(sp[:framestyle]) + framestyle = pgfx_framestyle(sp[:framestyle] == false ? :none : sp[:framestyle]) # axis label position labelpos = "" From f9ea9cd999bee5871fe13a03284a3aec243fb461 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 01:41:54 +0100 Subject: [PATCH 175/184] add quiver bug test --- test/test_pgfplotsx.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 4c62ef4f..289a5c93 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -15,6 +15,7 @@ end pgfx_plot = plot(1:5) Plots._update_plot_object(pgfx_plot) @test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument + @test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing @testset "3D docs example" begin n = 100 @@ -80,8 +81,7 @@ end z = float((1:4) * reshape(1:10, 1, :)) pgfx_plot = heatmap(xs, ys, z, aspect_ratio=1) Plots._update_plot_object(pgfx_plot) - if - @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) + if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true) @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" end From 39cb3733db1ba013982545aa72297171ba26f61f Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 13:22:37 +0100 Subject: [PATCH 176/184] fifty shades of show --- src/backends/pgfplotsx.jl | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 82ca9e32..9dbfb1a1 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -59,6 +59,7 @@ function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) end Base.display(pgfx_plot::PGFPlotsXPlot) = display(pgfx_plot.the_plot) + function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) show(io::IO, mime, pgfx_plot.the_plot) end @@ -284,6 +285,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end pgfx_plot.is_created = true end + return pgfx_plot end ## seriestype specifics @inline function pgfx_series_coordinates!(sp, series, segment_opt, opt, rng) @@ -791,26 +793,21 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) plt.o(plt) end -function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsXBackend}) - _update_plot_object(plt) - show(io, mime, plt.o) +for mime in ("application/pdf", "image/png", "image/svg+xml") + @eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{PGFPlotsXBackend}) + show(io, mime, plt.o.the_plot) + end end -function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsXBackend}) - _update_plot_object(plt) - show(io, mime, plt.o) -end - -function _show(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsXBackend}) - _update_plot_object(plt) - show(io, mime, plt.o) -end - -function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsXBackend}) - _update_plot_object(plt) +function _show(io::IO, mime::MIME{Symbol("application/x-tex")}, plt::Plot{PGFPlotsXBackend}) PGFPlotsX.print_tex(io, plt.o.the_plot, include_preamble = plt.attr[:tex_output_standalone]) end -function _display(plt::Plot{PGFPlotsXBackend}) - plt.o +Base.show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot{PGFPlotsXBackend}) = show(io, plt) + +function Base.show(io::IO, plt::Plot{PGFPlotsXBackend}) display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) +end + +function _display(plt::Plot{PGFPlotsXBackend}) + display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) end From e3239bf31200770d081fc3c5e66bb4261ed21091 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 13:30:04 +0100 Subject: [PATCH 177/184] fix typo --- src/backends/pgfplotsx.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 9dbfb1a1..172c4470 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -36,7 +36,7 @@ function pgfx_axes(pgfx_plot::PGFPlotsXPlot) return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp end -function pgfx_preample(pgfx_plot::Plots.Plot{Plots.PGFPlotsXBackend}) +function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend}) old_flag = pgfx_plot.attr[:tex_output_standalone] pgfx_plot.attr[:tex_output_standalone] = true fulltext = String(repr("application/x-tex", pgfx_plot)) From 985d43bf4ca293b98a39fd60461d6826e40ef228 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 18:55:44 +0100 Subject: [PATCH 178/184] fix show --- src/backends/pgfplotsx.jl | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 172c4470..b3007bc7 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -31,6 +31,7 @@ Base.@kwdef mutable struct PGFPlotsXPlot end end +## end user utility functions function pgfx_axes(pgfx_plot::PGFPlotsXPlot) gp = pgfx_plot.the_plot.elements[1].elements[1] return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp @@ -44,6 +45,7 @@ function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend}) pgfx_plot.attr[:tex_output_standalone] = old_flag preamble end +## function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) a = Array(s) @@ -58,12 +60,6 @@ function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) return xn, yn, zn end -Base.display(pgfx_plot::PGFPlotsXPlot) = display(pgfx_plot.the_plot) - -function Base.show(io::IO, mime::MIME, pgfx_plot::PGFPlotsXPlot) - show(io::IO, mime, pgfx_plot.the_plot) -end - function Base.push!(pgfx_plot::PGFPlotsXPlot, item) push!(pgfx_plot.the_plot, item) end @@ -803,11 +799,6 @@ function _show(io::IO, mime::MIME{Symbol("application/x-tex")}, plt::Plot{PGFPlo PGFPlotsX.print_tex(io, plt.o.the_plot, include_preamble = plt.attr[:tex_output_standalone]) end -Base.show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot{PGFPlotsXBackend}) = show(io, plt) - -function Base.show(io::IO, plt::Plot{PGFPlotsXBackend}) display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) -end - function _display(plt::Plot{PGFPlotsXBackend}) display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) end From 68b29f63a6ca395579b9ffbf8d8e52a94ea6362e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 19:10:25 +0100 Subject: [PATCH 179/184] improved fillrange --- src/backends/pgfplotsx.jl | 57 ++++++++++++++++++++++++++++++++++----- test/test_pgfplotsx.jl | 1 - 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index b3007bc7..4cc09fc4 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -210,8 +210,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else iter_segments(series) end - segment_opt = PGFPlotsX.Options() for (i, rng) in enumerate(segments) + segment_opt = PGFPlotsX.Options() segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) if opt[:markershape] != :none marker = opt[:markershape] @@ -235,15 +235,28 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) end if st == :shape || - (series[:fillrange] !== nothing && !isfilledcontour(series)) && - series[:ribbon] === nothing + isfilledcontour(series) || + series[:ribbon] !== nothing segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end + # add fillrange + if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing + pgfx_fillrange_series!( axis, series, series_func, i, _cycle(series[:fillrange], rng), rng) + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + io = IOBuffer() + PGFPlotsX.print_tex(io, pgfx_fillstyle(opt, i)) + style = strip(String(take!(io)),['[',']', ' ']) + push!( segment_opt, "legend image code/.code" => """{ + \\draw[##1,/tikz/.cd, $style] (0cm,-0.1cm) rectangle (0.6cm,0.1cm); + }""" ) + end + end + # series coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) segment_plot = series_func( - merge(series_opt, segment_opt), - coordinates, - (series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing) ? "\\closedcycle" : "{}" + merge(series_opt, segment_opt), + coordinates, ) push!(axis, segment_plot) # add ribbons? @@ -253,7 +266,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) end # add to legend? if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) - push!( axis, PGFPlotsX.LegendEntry(opt[:label]) ) + legend = PGFPlotsX.LegendEntry(PGFPlotsX.Options(), opt[:label], true) + push!( axis, legend ) end # add series annotations anns = series[:series_annotations] @@ -634,6 +648,35 @@ function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_inde )) return axis end + +function pgfx_fillrange_series!(axis, series, series_func, i, fillrange, rng) + fillrange_opt = PGFPlotsX.Options( + "line width" => "0", + "draw opacity" => "0", + ) + fillrange_opt = merge( fillrange_opt, pgfx_fillstyle(series, i) ) + fillrange_opt = merge( fillrange_opt, pgfx_marker(series, i) ) + push!( fillrange_opt, "forget plot" => nothing ) + opt = series.plotattributes + args = is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) : (opt[:x][rng], opt[:y][rng]) + push!(axis, PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...))) + return axis +end + +function pgfx_fillrange_args(fillrange, x, y) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] + return PGFPlotsX.Coordinates(x_fill, y_fill) +end + +function pgfx_fillrange_args(fillrange, x, y, z) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; y[n:-1:1]; x[1]] + z_fill = [z; _cycle(fillrange, n:-1:1); z[1]] + return PGFPlotsX.Coordiantes(x_fill, y_fill, z_fill) +end # -------------------------------------------------------------------------------------- function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) axis = sp[Symbol(letter,:axis)] diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 289a5c93..fc27f0e8 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -113,7 +113,6 @@ end x + y end), color=:bluesreds, legend=false) plot(p1, p2) - # TODO: questionable tiling end # testset @testset "Framestyles" begin scatter(fill(randn(10), 6), fill(randn(10), 6), framestyle=[:box :semi :origin :zerolines :grid :none], title=[":box" ":semi" ":origin" ":zerolines" ":grid" ":none"], color=permutedims(1:6), layout=6, label="", markerstrokewidth=0, ticks=-2:2) From 58cf8e471e40bd454f4af701c8c86d22840cd3e2 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Tue, 26 Nov 2019 21:28:15 +0100 Subject: [PATCH 180/184] improve annotations --- src/backends/pgfplotsx.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4cc09fc4..c7e8e7e1 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -278,7 +278,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) # add subplot annotations anns = sp.attr[:annotations] for (xi,yi,txt) in anns - pgfx_add_annotation!(axis, xi, yi, txt) + pgfx_add_annotation!(axis, xi, yi, txt, pgfx_thickness_scaling(sp)) end end if ispolar(sp) @@ -604,7 +604,7 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) ), " at ", PGFPlotsX.Coordinate(x, y), - "{$(val.str).};" + "{$(val.str)};" ]) end From 68b344e7c3afe594c168c41578f8a29f867bdeb9 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Wed, 27 Nov 2019 12:23:39 +0100 Subject: [PATCH 181/184] axis cs for annotations --- src/backends/pgfplotsx.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index c7e8e7e1..5f487c8c 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -591,20 +591,17 @@ end function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) # Construct the style string. - # Currently supports color and orientation cstr = val.font.color a = alpha(cstr) push!(o, ["\\node", PGFPlotsX.Options( - get(_pgfx_annotation_halign,val.font.halign,"") => nothing, + get(_pgfx_annotation_halign, val.font.halign, "") => nothing, "color" => cstr, "draw opacity" => convert(Float16, a), "rotate" => val.font.rotation, "font" => pgfx_font(val.font.pointsize, thickness_scaling) ), - " at ", - PGFPlotsX.Coordinate(x, y), - "{$(val.str)};" + " at (axis cs:$x, $y) {$(val.str)};" ]) end From 899c8b36340d71d7bb413e469227ae2d7d59d339 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 29 Nov 2019 11:53:35 +0100 Subject: [PATCH 182/184] add require --- src/init.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/init.jl b/src/init.jl index 2e1a3404..ee629f73 100644 --- a/src/init.jl +++ b/src/init.jl @@ -46,6 +46,12 @@ function __init__() @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) end + @require PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" begin + fn = joinpath(@__DIR__, "backends", "pgfplotsx.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end + @require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" begin fn = joinpath(@__DIR__, "backends", "plotlyjs.jl") include(fn) From 715181585ab9589a1fc61acebd602ed8a77e64c1 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 29 Nov 2019 16:06:00 +0100 Subject: [PATCH 183/184] trigger CI --- src/backends/pgfplotsx.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 4dfa71ff..cc8d7013 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1,4 +1,5 @@ using Contour: Contour + Base.@kwdef mutable struct PGFPlotsXPlot is_created::Bool = false was_shown::Bool = false From 39e93f40c26c526725b36744001b970e8e2b7e1f Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 29 Nov 2019 16:38:40 +0100 Subject: [PATCH 184/184] fix tests --- test/test_pgfplotsx.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index fc27f0e8..ca033a52 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -37,8 +37,8 @@ end Plots._update_plot_object(pl) axis = Plots.pgfx_axes(pl.o)[1] @test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5 - @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 104 # each marker is its own plot - marker = axis.contents[14] + @test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 108 # each marker is its own plot, fillranges create 2 plot-objects + marker = axis.contents[15] @test marker isa PGFPlotsX.Plot @test marker.options["mark"] == "*" @test marker.options["mark options"]["color"] == RGBA{Float64}( colorant"green", 0.8)