Merge pull request #2354 from BeastyBlacksmith/pgfplotsx

@JuliaRegistrator register()
This commit is contained in:
Simon Christ 2020-01-10 22:26:19 +01:00 committed by GitHub
commit dd70192de4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 177 additions and 156 deletions

View File

@ -1,7 +1,7 @@
name = "Plots" name = "Plots"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
author = ["Tom Breloff (@tbreloff)"] author = ["Tom Breloff (@tbreloff)"]
version = "0.28.4" version = "0.28.5"
[deps] [deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

View File

@ -786,7 +786,6 @@ function processFillArg(plotattributes::KW, arg)
plotattributes[:fillrange] = arg plotattributes[:fillrange] = arg
elseif !handleColors!(plotattributes, arg, :fillcolor) elseif !handleColors!(plotattributes, arg, :fillcolor)
plotattributes[:fillrange] = arg plotattributes[:fillrange] = arg
end end
# plotattributes[:fillrange] = fr # plotattributes[:fillrange] = fr

View File

@ -34,6 +34,7 @@ function pgfx_axes(pgfx_plot::PGFPlotsXPlot)
return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp
end end
pgfx_preamble() = pgfx_preamble(current())
function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend}) function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend})
old_flag = pgfx_plot.attr[:tex_output_standalone] old_flag = pgfx_plot.attr[:tex_output_standalone]
pgfx_plot.attr[:tex_output_standalone] = true pgfx_plot.attr[:tex_output_standalone] = true
@ -82,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)
@ -139,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]))},
}""") }""")
@ -158,141 +158,160 @@ 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 sf = series[:fillrange]
series_func = PGFPlotsX.Plot3 series_opt = PGFPlotsX.Options(
else "color" => single_color(opt[:linecolor]),
series_func = PGFPlotsX.Plot "name path" => string(series_id)
end )
if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing if is3d(series) || st == :heatmap
push!(series_opt, "area legend" => nothing) series_func = PGFPlotsX.Plot3
end else
if st == :heatmap series_func = PGFPlotsX.Plot
push!(axis.options, end
"view" => "{0}{90}", if sf !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
) push!(series_opt, "area legend" => nothing)
end end
# treat segments if st == :heatmap
segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) push!(axis.options,
iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) "view" => "{0}{90}",
else )
iter_segments(series) end
end # treat segments
for (i, rng) in enumerate(segments) segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d)
segment_opt = PGFPlotsX.Options() iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...)
segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) else
if opt[:markershape] != :none iter_segments(series)
marker = opt[:markershape] end
if marker isa Shape for (i, rng) in enumerate(segments)
x = marker.x segment_opt = PGFPlotsX.Options()
y = marker.y segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) )
scale_factor = 0.025 if opt[:markershape] != :none
mark_size = opt[:markersize] * scale_factor marker = opt[:markershape]
path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") if marker isa Shape
c = get_markercolor(series, i) x = marker.x
a = get_markeralpha(series, i) y = marker.y
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, scale_factor = 0.025
""" mark_size = opt[:markersize] * scale_factor
\\pgfdeclareplotmark{PlotsShape$(series_index)}{ path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ")
\\filldraw c = get_markercolor(series, i)
$path; a = get_markeralpha(series, i)
} PGFPlotsX.push_preamble!(pgfx_plot.the_plot,
""" """
) \\pgfdeclareplotmark{PlotsShape$(series_index)}{
end \\filldraw
segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) $path;
end }
if st == :shape || """
isfilledcontour(series) )
segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) end
end segment_opt = merge( segment_opt, pgfx_marker(opt, i) )
# add fillrange end
if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing if st == :shape ||
pgfx_fillrange_series!( axis, series, series_func, i, _cycle(series[:fillrange], rng), rng) isfilledcontour(series)
if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) )
pgfx_filllegend!(series_opt, opt) end
end # add fillrange
end if sf !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
# series if sf isa Number || sf isa AVec
# pgfx_fillrange_series!( axis, series, series_func, i, _cycle(sf, rng), rng)
coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) end
segment_plot = series_func( if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series)
merge(series_opt, segment_opt), pgfx_filllegend!(series_opt, opt)
coordinates, end
) end
push!(axis, segment_plot) # series
# add ribbons? #
ribbon = series[:ribbon] coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng )
if ribbon !== nothing segment_plot = series_func(
pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) merge(series_opt, segment_opt),
end coordinates,
# add to legend? )
if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) push!(axis, segment_plot)
leg_opt = PGFPlotsX.Options() # fill between functions
if ribbon !== nothing if sf isa Tuple && series[:ribbon] === nothing
pgfx_filllegend!(axis.contents[end-3].options, opt) sf1, sf2 = sf
end @assert sf1 == series_index "First index of the tuple has to match the current series index."
legend = PGFPlotsX.LegendEntry(leg_opt, opt[:label], false) push!(axis, series_func(
push!( axis, legend ) merge(pgfx_fillstyle(opt, series_index), PGFPlotsX.Options("forget plot" => nothing)),
end "fill between [of=$series_id and $(_pgfplotsx_series_ids[Symbol(string(sf2))])]"
# add series annotations ))
anns = series[:series_annotations] end
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) # add ribbons?
pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) ribbon = series[:ribbon]
end if ribbon !== nothing
end pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index )
# add subplot annotations end
anns = sp.attr[:annotations] # add to legend?
for (xi,yi,txt) in anns if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series)
pgfx_add_annotation!(axis, xi, yi, txt, pgfx_thickness_scaling(sp)) leg_opt = PGFPlotsX.Options()
end if ribbon !== nothing
end pgfx_filllegend!(axis.contents[end-3].options, opt)
if ispolar(sp) end
axes = the_plot legend = PGFPlotsX.LegendEntry(leg_opt, opt[:label], false)
else push!( axis, legend )
axes = the_plot.elements[1] end
end # add series annotations
push!( axes, axis ) anns = series[:series_annotations]
if length(plt.o.the_plot.elements) > 0 for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
plt.o.the_plot.elements[1] = the_plot pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series))
else end
push!(plt.o, the_plot) end
end # add subplot annotations
end for ann in sp[:annotations]
pgfx_add_annotation!(axis, locate_annotation(sp, ann...)..., pgfx_thickness_scaling(sp))
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
@ -438,6 +457,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 => "+",
@ -524,7 +545,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

View File

@ -13,6 +13,7 @@ const DataPoint = Union{MaybeNumber, MaybeString}
prepareSeriesData(x) = error("Cannot convert $(typeof(x)) to series data for plotting") prepareSeriesData(x) = error("Cannot convert $(typeof(x)) to series data for plotting")
prepareSeriesData(::Nothing) = nothing prepareSeriesData(::Nothing) = nothing
prepareSeriesData(t::Tuple{T, T}) where {T<:Number} = t
prepareSeriesData(f::Function) = f prepareSeriesData(f::Function) = f
prepareSeriesData(a::AbstractArray{<:MaybeNumber}) = replace!( prepareSeriesData(a::AbstractArray{<:MaybeNumber}) = replace!(
x -> ismissing(x) || isinf(x) ? NaN : x, x -> ismissing(x) || isinf(x) ? NaN : x,