implement fill between functions

This commit is contained in:
Simon Christ 2020-01-03 21:04:47 +01:00
parent f20582e528
commit 7fb1a6a517

View File

@ -83,17 +83,16 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
if !any( sp -> ispolar(sp), plt.subplots ) if !any( sp -> ispolar(sp), plt.subplots )
pl_height, pl_width = plt.attr[:size] pl_height, pl_width = plt.attr[:size]
push!( the_plot, PGFPlotsX.GroupPlot( push!( the_plot, PGFPlotsX.GroupPlot(
PGFPlotsX.Options( PGFPlotsX.Options(
"group style" => 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)), "horizontal sep" => string(maximum(sp -> sp.minpad[1], plt.subplots)),
"vertical sep" => string(maximum(sp -> sp.minpad[2], plt.subplots)), "vertical sep" => string(maximum(sp -> sp.minpad[2], plt.subplots)),
), ),
"height" => pl_height > 0 ? string(pl_height * px) : "{}", "height" => pl_height > 0 ? string(pl_height * px) : "{}",
"width" => pl_width > 0 ? string(pl_width * px) : "{}", "width" => pl_width > 0 ? string(pl_width * px) : "{}",
)
) )
) ))
end end
for sp in plt.subplots for sp in plt.subplots
bb = bbox(sp) bb = bbox(sp)
@ -140,18 +139,18 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
end end
end end
# Search series for any gradient. In case one series uses a gradient set # Search series for any gradient. In case one series uses a gradient set
# the colorbar and colomap. # the colorbar and colomap.
# The reasoning behind doing this on the axis level is that pgfplots # 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 # colorbar seems to only works on axis level and needs the proper colormap for
# correctly displaying it. # correctly displaying it.
# It's also possible to assign the colormap to the series itself but # 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 # then the colormap needs to be added twice, once for the axis and once for the
# series. # series.
# As it is likely that all series within the same axis use the same # As it is likely that all series within the same axis use the same
# colormap this should not cause any problem. # colormap this should not cause any problem.
for series in series_list(sp) for series in series_list(sp)
for col in (:markercolor, :fillcolor, :linecolor) for col in (:markercolor, :fillcolor, :linecolor)
if typeof(series.plotattributes[col]) == ColorGradient if typeof(series.plotattributes[col]) == ColorGradient
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{
colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))},
}""") }""")
@ -159,141 +158,157 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
"colorbar" => nothing, "colorbar" => nothing,
"colormap name" => "plots$(sp.attr[:subplot_index])", "colormap name" => "plots$(sp.attr[:subplot_index])",
) )
# goto is needed to break out of col and series for # goto is needed to break out of col and series for
@goto colorbar_end @goto colorbar_end
end end
end end
end end
@label colorbar_end @label colorbar_end
push!(axis_opt, "colorbar style" => PGFPlotsX.Options( push!(axis_opt, "colorbar style" => PGFPlotsX.Options(
"title" => sp[:colorbar_title], "title" => sp[:colorbar_title],
"point meta max" => get_clims(sp)[2], "point meta max" => get_clims(sp)[2],
"point meta min" => get_clims(sp)[1] "point meta min" => get_clims(sp)[1]
) )
) )
if is3d(sp) if is3d(sp)
azim, elev = sp[:camera] azim, elev = sp[:camera]
push!( axis_opt, "view" => (azim, elev) ) push!( axis_opt, "view" => (azim, elev) )
end end
axisf = if sp[:projection] == :polar axisf = if sp[:projection] == :polar
# push!(axis_opt, "xmin" => 90) # push!(axis_opt, "xmin" => 90)
# push!(axis_opt, "xmax" => 450) # push!(axis_opt, "xmax" => 450)
PGFPlotsX.PolarAxis PGFPlotsX.PolarAxis
else else
PGFPlotsX.Axis PGFPlotsX.Axis
end end
axis = axisf( axis = axisf(
axis_opt axis_opt
) )
for (series_index, series) in enumerate(series_list(sp)) for (series_index, series) in enumerate(series_list(sp))
opt = series.plotattributes # give each series a uuid for fillbetween
st = series[:seriestype] series_id = uuid4()
series_opt = PGFPlotsX.Options( _pgfplotsx_series_ids[Symbol("$series_index")] = series_id
"color" => single_color(opt[:linecolor]), opt = series.plotattributes
) st = series[:seriestype]
if is3d(series) || st == :heatmap series_opt = PGFPlotsX.Options(
series_func = PGFPlotsX.Plot3 "color" => single_color(opt[:linecolor]),
else "name path" => string(series_id)
series_func = PGFPlotsX.Plot )
end if is3d(series) || st == :heatmap
if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing series_func = PGFPlotsX.Plot3
push!(series_opt, "area legend" => nothing) else
end series_func = PGFPlotsX.Plot
if st == :heatmap end
push!(axis.options, if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
"view" => "{0}{90}", push!(series_opt, "area legend" => nothing)
) end
end if st == :heatmap
# treat segments push!(axis.options,
segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) "view" => "{0}{90}",
iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) )
else end
iter_segments(series) # treat segments
end segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d)
for (i, rng) in enumerate(segments) iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...)
segment_opt = PGFPlotsX.Options() else
segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) iter_segments(series)
if opt[:markershape] != :none end
marker = opt[:markershape] for (i, rng) in enumerate(segments)
if marker isa Shape segment_opt = PGFPlotsX.Options()
x = marker.x segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) )
y = marker.y if opt[:markershape] != :none
scale_factor = 0.025 marker = opt[:markershape]
mark_size = opt[:markersize] * scale_factor if marker isa Shape
path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") x = marker.x
c = get_markercolor(series, i) y = marker.y
a = get_markeralpha(series, i) scale_factor = 0.025
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, mark_size = opt[:markersize] * scale_factor
""" path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ")
\\pgfdeclareplotmark{PlotsShape$(series_index)}{ c = get_markercolor(series, i)
\\filldraw a = get_markeralpha(series, i)
$path; PGFPlotsX.push_preamble!(pgfx_plot.the_plot,
} """
""" \\pgfdeclareplotmark{PlotsShape$(series_index)}{
) \\filldraw
end $path;
segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) }
end """
if st == :shape || )
isfilledcontour(series) end
segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) segment_opt = merge( segment_opt, pgfx_marker(opt, i) )
end end
# add fillrange if st == :shape ||
if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing isfilledcontour(series)
pgfx_fillrange_series!( axis, series, series_func, i, _cycle(series[:fillrange], rng), rng) segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) )
if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) end
pgfx_filllegend!(series_opt, opt) # add fillrange
end if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
end if series[:fillrange] == 0
# series pgfx_fillrange_series!( axis, series, series_func, i, _cycle(series[:fillrange], rng), rng)
# end
coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series)
segment_plot = series_func( pgfx_filllegend!(series_opt, opt)
merge(series_opt, segment_opt), end
coordinates, end
) # series
push!(axis, segment_plot) #
# add ribbons? coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng )
ribbon = series[:ribbon] segment_plot = series_func(
if ribbon !== nothing merge(series_opt, segment_opt),
pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) coordinates,
end )
# add to legend? push!(axis, segment_plot)
if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) # fill between functions
leg_opt = PGFPlotsX.Options() if series[:fillrange] !== nothing && series[:fillrange] != 0
if ribbon !== nothing push!(axis, series_func(
pgfx_filllegend!(axis.contents[end-3].options, opt) merge(pgfx_fillstyle(opt, series_index), PGFPlotsX.Options("forget plot" => nothing)),
end "fill between [of=$series_id and $(_pgfplotsx_series_ids[Symbol(string(series[:fillrange]))])]"
legend = PGFPlotsX.LegendEntry(leg_opt, opt[:label], false) ))
push!( axis, legend ) end
end # add ribbons?
# add series annotations ribbon = series[:ribbon]
anns = series[:series_annotations] if ribbon !== nothing
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index )
pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) end
end # add to legend?
end if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series)
# add subplot annotations leg_opt = PGFPlotsX.Options()
anns = sp.attr[:annotations] if ribbon !== nothing
for (xi,yi,txt) in anns pgfx_filllegend!(axis.contents[end-3].options, opt)
pgfx_add_annotation!(axis, xi, yi, txt, pgfx_thickness_scaling(sp)) end
end legend = PGFPlotsX.LegendEntry(leg_opt, opt[:label], false)
end push!( axis, legend )
if ispolar(sp) end
axes = the_plot # add series annotations
else anns = series[:series_annotations]
axes = the_plot.elements[1] for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
end pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series))
push!( axes, axis ) end
if length(plt.o.the_plot.elements) > 0 end
plt.o.the_plot.elements[1] = the_plot # add subplot annotations
else for ann in sp[:annotations]
push!(plt.o, the_plot) pgfx_add_annotation!(axis, locate_annotation(sp, ann...)..., pgfx_thickness_scaling(sp))
end end
end # anns = sp.attr[:annotations]
# for (xi,yi,txt) in anns
# pgfx_add_annotation!(axis, xi, yi, txt, pgfx_thickness_scaling(sp))
# end
end # for series
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 # for subplots
pgfx_plot.is_created = true pgfx_plot.is_created = true
end end # if
return pgfx_plot return pgfx_plot
end end
## seriestype specifics ## seriestype specifics
@ -439,6 +454,8 @@ const _pgfplotsx_linestyles = KW(
:dashdotdot => "dashdotdotted", :dashdotdot => "dashdotdotted",
) )
const _pgfplotsx_series_ids = KW()
const _pgfplotsx_markers = KW( const _pgfplotsx_markers = KW(
:none => "none", :none => "none",
:cross => "+", :cross => "+",
@ -525,7 +542,7 @@ function pgfx_framestyle(style::Symbol)
return style return style
else else
default_style = get(_pgfx_framestyle_defaults, style, :axes) default_style = get(_pgfx_framestyle_defaults, style, :axes)
@warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.") @warn("Framestyle :$style is not (yet) supported by the PGFPlotsX backend. :$default_style was cosen instead.")
default_style default_style
end end
end end