From eb0e6c7ed15da90512c84ab3bb77500023b0e412 Mon Sep 17 00:00:00 2001 From: Pearl Li Date: Tue, 27 Oct 2020 22:38:16 -0700 Subject: [PATCH] Start fillstyle for GR and PyPlot --- src/arg_desc.jl | 1 + src/args.jl | 3 +++ src/backends/gr.jl | 31 ++++++++++++++++++++++++++++--- src/backends/pyplot.jl | 37 ++++++++++++++++++++++++++++++------- src/utils.jl | 5 +++++ 5 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/arg_desc.jl b/src/arg_desc.jl index 9adad50b..521512dc 100644 --- a/src/arg_desc.jl +++ b/src/arg_desc.jl @@ -13,6 +13,7 @@ const _arg_desc = KW( :fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.", :fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.", :fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.", +:fillstyle => "Symbol. Style of the fill area. `nothing` (the default) means solid fill. Choose from :/, :\\, :|, :-, :+, :x", :markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).", :markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.", :markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.", diff --git a/src/args.jl b/src/args.jl index 519fea3c..c640ed39 100644 --- a/src/args.jl +++ b/src/args.jl @@ -285,6 +285,7 @@ const _series_defaults = KW( :fillrange => nothing, # ribbons, areas, etc :fillcolor => :match, :fillalpha => nothing, + :fillstyle => nothing, :markershape => :none, :markercolor => :match, :markeralpha => nothing, @@ -805,6 +806,7 @@ function processLineArg(plotattributes::AKW, arg) arg.size === nothing || (plotattributes[:fillrange] = arg.size) arg.color === nothing || (plotattributes[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color)) arg.alpha === nothing || (plotattributes[:fillalpha] = arg.alpha) + arg.style === nothing || (plotattributes[:fillstyle] = arg.style) elseif typeof(arg) <: Arrow || arg in (:arrow, :arrows) plotattributes[:arrow] = arg @@ -871,6 +873,7 @@ function processFillArg(plotattributes::AKW, arg) arg.size === nothing || (plotattributes[:fillrange] = arg.size) arg.color === nothing || (plotattributes[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color)) arg.alpha === nothing || (plotattributes[:fillalpha] = arg.alpha) + arg.style === nothing || (plotattributes[:fillstyle] = arg.style) elseif typeof(arg) <: Bool plotattributes[:fillrange] = arg ? 0 : nothing diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 372c2baa..04feae22 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -110,6 +110,7 @@ end gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(_cycle(c,1))) gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(_cycle(c,1))) + gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(_cycle(c,1))) gr_set_bordercolor(c) = GR.setbordercolorind(gr_getcolorind(_cycle(c,1))) gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(_cycle(c,1))) @@ -133,6 +134,24 @@ gr_set_arrowstyle(s::Symbol) = GR.setarrowstyle(get( 1, )) +gr_set_fillstyle(::Nothing) = GR.setfillintstyle(GR.INTSTYLE_SOLID) +function gr_set_fillstyle(s::Symbol) + GR.setfillintstyle(GR.INTSTYLE_HATCH) + GR.setfillstyle(get( + ( + / = 9, + \ = 10, + | = 7, + - = 8, + + = 11, + x = 6, + ), + s, + 9), + ) +end + + # -------------------------------------------------------------------------------------- @@ -914,7 +933,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) gr_update_viewport_ratio!(viewport_plotarea, sp) leg = gr_get_legend_geometry(viewport_plotarea, sp) gr_update_viewport_legend!(viewport_plotarea, sp, leg) - + # fill in the plot area background gr_fill_plotarea(sp, viewport_plotarea) @@ -998,6 +1017,8 @@ function gr_add_legend(sp, leg, viewport_plotarea) if (st == :shape || series[:fillrange] !== nothing) && series[:ribbon] === nothing fc = get_fillcolor(series, clims) gr_set_fill(fc) #, series[:fillalpha]) + fs = get_fillstyle(series, i) + gr_set_fillstyle(fs) l, r = xpos - leg.width_factor * 3.5, xpos - leg.width_factor / 2 b, t = ypos - 0.4 * leg.dy, ypos + 0.4 * leg.dy x = [l, r, r, l, l] @@ -1468,10 +1489,10 @@ function gr_label_axis_3d(sp, letter) if ax[:guide] != "" near_letter = letter in (:x, :z) ? :y : :x far_letter = letter in (:x, :y) ? :z : :x - + nax = sp[Symbol(near_letter, :axis)] fax = sp[Symbol(far_letter, :axis)] - + amin, amax = axis_limits(sp, letter) namin, namax = axis_limits(sp, near_letter) famin, famax = axis_limits(sp, far_letter) @@ -1629,6 +1650,8 @@ function gr_draw_segments(series, x, y, fillrange, clims) for (i, rng) in enumerate(segments) fc = get_fillcolor(series, clims, i) gr_set_fillcolor(fc) + fs = get_fillstyle(series, i) + gr_set_fillstyle(fs) fx = _cycle(x, vcat(rng, reverse(rng))) fy = vcat(_cycle(fr_from, rng), _cycle(fr_to, reverse(rng))) gr_set_transparency(fc, get_fillalpha(series, i)) @@ -1709,6 +1732,8 @@ function gr_draw_shapes(series, x, y, clims) # draw the interior fc = get_fillcolor(series, clims, i) gr_set_fill(fc) + fs = get_fillstyle(series, i) + gr_set_fillstyle(fs) gr_set_transparency(fc, get_fillalpha(series, i)) GR.fillarea(xseg, yseg) diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 8a62292f..927612f8 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -162,6 +162,9 @@ function py_fillstepstyle(seriestype::Symbol) return nothing end +py_fillstyle(::Nothing) = nothing +py_fillstyle(fillstyle::Symbol) = string(fillstyle) + # # untested... return a FontProperties object from a Plots.Font # function py_font(font::Font) # pyfont["FontProperties"]( @@ -484,11 +487,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) y[rng], x[rng], z[rng] else y[rng], x[rng] - end + end else if RecipesPipeline.is3d(sp) x[rng], y[rng], z[rng] - else + else x[rng], y[rng] end end @@ -672,13 +675,19 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) handle = [] for (i, rng) in enumerate(iter_segments(series)) if length(rng) > 1 + fillstyle = get_fillstyle(series, i) + has_fillstyle = !isnothing(fillstyle) + linecolor = get_linecolor(series, clims, i) + fillcolor = get_fillcolor(series, clims, i) + path = pypath."Path"(hcat(x[rng], y[rng])) patches = pypatches."PathPatch"( path; label = series[:label], zorder = series[:series_plotindex], - edgecolor = py_color(get_linecolor(series, clims, i), get_linealpha(series, i)), - facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)), + edgecolor = py_color(has_fillstyle ? fillcolor : linecolor, get_linealpha(series, i)), + facecolor = py_color(fillcolor, has_fillstyle ? 0 : get_fillalpha(series, i)), + hatch = py_fillstyle(fillstyle), linewidth = py_thickness_scale(plt, get_linewidth(series, i)), linestyle = py_linestyle(st, get_linestyle(series, i)), fill = true @@ -710,9 +719,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) dim1, _cycle(fillrange[1], rng), _cycle(fillrange[2], rng) end + fillstyle = get_fillstyle(series, i) + has_fillstyle = !isnothing(fillstyle) + linecolor = get_linecolor(series, clims, i) + fillcolor = get_fillcolor(series, clims, i) + handle = getproperty(ax, f)(args..., trues(n), false, py_fillstepstyle(st); zorder = series[:series_plotindex], - facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)), + edgecolor = py_color(fillcolor, get_linealpha(series, i)), + facecolor = py_color(fillcolor, has_fillstyle ? 0 : get_fillalpha(series, i)), + hatch = py_fillstyle(fillstyle), linewidths = 0 ) push!(handles, handle) @@ -1295,9 +1311,16 @@ function py_add_legend(plt::Plot, sp::Subplot, ax) # add a line/marker and a label push!(handles, if series[:seriestype] == :shape || series[:fillrange] !== nothing + + fillstyle = get_fillstyle(series) + has_fillstyle = !isnothing(fillstyle) + linecolor = get_linecolor(series, clims) + fillcolor = get_fillcolor(series, clims) + pypatches."Patch"( - edgecolor = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)), - facecolor = py_color(single_color(get_fillcolor(series, clims)), get_fillalpha(series)), + edgecolor = py_color(single_color(has_fillstyle ? fillcolor : linecolor), get_linealpha(series)), + facecolor = py_color(single_color(fillcolor), has_fillstyle ? 0 : get_fillalpha(series)), + hatch = py_fillstyle(fillstyle), linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)), linestyle = py_linestyle(series[:seriestype], get_linestyle(series)), capstyle = "butt" diff --git a/src/utils.jl b/src/utils.jl index 81779dd3..0bba4422 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -557,6 +557,10 @@ function get_linestyle(series, i::Int = 1) _cycle(series[:linestyle], i) end +function get_fillstyle(series, i::Int = 1) + _cycle(series[:fillstyle], i) +end + function get_markerstrokecolor(series, i::Int = 1) msc = series[:markerstrokecolor] isa(msc, ColorGradient) ? msc : _cycle(msc, i) @@ -592,6 +596,7 @@ function has_attribute_segments(series::Series) :linestyle, :fillcolor, :fillalpha, + :fillstyle, :markercolor, :markeralpha, :markersize,