diff --git a/src/args.jl b/src/args.jl index 88b1638c..3b779f07 100644 --- a/src/args.jl +++ b/src/args.jl @@ -281,6 +281,7 @@ const _series_defaults = KW( # one logical series to be broken up (path and markers, for example) :hover => nothing, # text to display when hovering over the data points :stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride. + :extra_kwargs => Dict() ) @@ -292,7 +293,7 @@ const _plot_defaults = KW( :fontfamily => "sans-serif", :size => (600,400), :pos => (0,0), - :window_title => "Plots.jl", + :window_title => "Plots.jl", :show => false, :layout => 1, :link => :none, @@ -304,8 +305,9 @@ const _plot_defaults = KW( :dpi => DPI, # dots per inch for images, etc :thickness_scaling => 1, :display_type => :auto, - :extra_kwargs => KW(), :warn_on_unsupported => true, + :extra_plot_kwargs => Dict(), + :extra_kwargs => :series, # directs collection of extra_kwargs ) @@ -354,6 +356,7 @@ const _subplot_defaults = KW( :colorbar_title => "", :framestyle => :axes, :camera => (30,30), + :extra_kwargs => Dict() ) const _axis_defaults = KW( @@ -656,7 +659,7 @@ function default(k::Symbol) return _axis_defaults_byletter[letter][key] end k == :letter && return k # for type recipe processing - k in _suppress_warnings || error("Unknown key: ", k) + return missing end function default(k::Symbol, v) @@ -1121,26 +1124,29 @@ const _already_warned = Dict{Symbol,Set{Symbol}}() const _to_warn = Set{Symbol}() function warn_on_unsupported_args(pkg::AbstractBackend, plotattributes) - if !get(plotattributes, :warn_on_unsupported, _plot_defaults[:warn_on_unsupported]) - return - end empty!(_to_warn) bend = backend_name(pkg) already_warned = get!(_already_warned, bend, Set{Symbol}()) + extra_kwargs = Dict{Symbol,Any}() for k in keys(plotattributes) is_attr_supported(pkg, k) && continue k in _suppress_warnings && continue - if plotattributes[k] != default(k) + default_value = default(k) + if ismissing(default_value) + extra_kwargs[k] = pop_kw!(plotattributes, k) + elseif plotattributes[k] != default(k) k in already_warned || push!(_to_warn, k) end end - if !isempty(_to_warn) + if !isempty(_to_warn) && + !get(plotattributes, :warn_on_unsupported, _plot_defaults[:warn_on_unsupported]) for k in sort(collect(_to_warn)) push!(already_warned, k) @warn("Keyword argument $k not supported with $pkg. Choose from: $(supported_attrs(pkg))") end end + return extra_kwargs end # _markershape_supported(pkg::AbstractBackend, shape::Symbol) = shape in supported_markers(pkg) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index f66c517c..4486330c 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -86,7 +86,16 @@ end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created || pgfx_plot.was_shown pgfx_sanitize_plot!(plt) - the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) + # extract extra kwargs + extra_plot_opt = plt[:extra_plot_kwargs] + extra_plot = nothing + if haskey(extra_plot_opt, :add) + extra_plot = wraptuple(pop!(extra_plot_opt,:add)) + end + the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options(extra_plot_opt...)) + if extra_plot !== nothing + push!(the_plot, extra_plot...) + end bgc = plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : plt.attr[:background_color_outside] if bgc isa Colors.Colorant @@ -243,7 +252,15 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) else PGFPlotsX.Axis end - axis = axisf(axis_opt) + extra_sp_opt = sp[:extra_kwargs] + extra_sp = nothing + if haskey(extra_sp_opt, :add) + extra_sp = wraptuple(pop!(extra_sp_opt,:add)) + end + axis = axisf(merge(axis_opt, PGFPlotsX.Options(extra_sp_opt...))) + if extra_sp !== nothing + push!(axis, extra_sp...) + end if sp[:legendtitle] !== nothing push!(axis, PGFPlotsX.Options("\\addlegendimage{empty legend}" => nothing)) push!( @@ -265,6 +282,12 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "color" => single_color(opt[:linecolor]), "name path" => string(series_id), ) + extra_series_opt = series[:extra_kwargs] + extra_series = nothing + if haskey(extra_series_opt, :add) + extra_series = wraptuple(pop!(extra_series_opt,:add)) + end + series_opt = merge(series_opt, PGFPlotsX.Options(extra_series_opt...)) if RecipesPipeline.is3d(series) || st == :heatmap series_func = PGFPlotsX.Plot3 else @@ -344,6 +367,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) pgfx_series_coordinates!(sp, series, segment_opt, opt, rng) segment_plot = series_func(merge(series_opt, segment_opt), coordinates) + if extra_series !== nothing + push!(segment_plot, extra_series...) + end push!(axis, segment_plot) # fill between functions if sf isa Tuple && series[:ribbon] === nothing diff --git a/src/pipeline.jl b/src/pipeline.jl index 4865b257..c595a80e 100644 --- a/src/pipeline.jl +++ b/src/pipeline.jl @@ -341,7 +341,20 @@ function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol) end function _add_the_series(plt, sp, plotattributes) - warn_on_unsupported_args(plt.backend, plotattributes) + extra_kwargs = warn_on_unsupported_args(plt.backend, plotattributes) + if (kw = plt[:extra_kwargs]) isa AbstractDict + plt[:extra_plot_kwargs] = get(kw,:plot,KW()) + sp[:extra_kwargs] = get(kw,:subplot, KW()) + plotattributes[:extra_kwargs] = get(kw,:series,KW()) + elseif plt[:extra_kwargs] == :plot + plt[:extra_plot_kwargs] = extra_kwargs + elseif plt[:extra_kwargs] == :subplot + sp[:extra_kwargs] = extra_kwargs + elseif plt[:extra_kwargs] == :series + plotattributes[:extra_kwargs] = extra_kwargs + else + ArgumentError("Unsupported type for extra keyword arguments") + end warn_on_unsupported(plt.backend, plotattributes) series = Series(plotattributes) push!(plt.series_list, series) diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index a21ed191..302d4fb2 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -326,3 +326,23 @@ end # end end # testset end # testset + +@testset "Extra kwargs" begin + pl = plot(1:5, test = "me") + @test pl[1][1].plotattributes[:extra_kwargs][:test] == "me" + pl = plot(1:5, test = "me", extra_kwargs = :subplot) + @test pl[1].attr[:extra_kwargs][:test] == "me" + pl = plot(1:5, test = "me", extra_kwargs = :plot) + @test pl.attr[:extra_plot_kwargs][:test] == "me" + pl = plot(1:5, extra_kwargs = Dict(:plot => Dict(:test => "me"), :series => Dict(:and => "me too"))) + @test pl.attr[:extra_plot_kwargs][:test] == "me" + @test pl[1][1].plotattributes[:extra_kwargs][:and] == "me too" + pl = plot( + plot(1:5, title="Line"), + scatter(1:5, title="Scatter", extra_kwargs=Dict(:subplot=>Dict("axis line shift" => "10pt"))) + ) + Plots._update_plot_object(pl) + axes = Plots.pgfx_axes(pl.o) + @test !haskey(axes[1].options.dict, "axis line shift") + @test haskey(axes[2].options.dict, "axis line shift") +end # testset diff --git a/tmpplotsave.hdf5 b/tmpplotsave.hdf5 new file mode 100644 index 00000000..66f7bab5 Binary files /dev/null and b/tmpplotsave.hdf5 differ