diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index bb946042..fb7a9e3b 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -1488,65 +1488,82 @@ function py_add_legend(plt::Plot, sp::Subplot, ax) if should_add_to_legend(series) clims = get_clims(sp, series) # add a line/marker and a label - push!( - handles, - if series[:seriestype] == :shape || series[:fillrange] !== nothing - fs = get_fillstyle(series) - has_fs = !isnothing(fs) - lc = get_linecolor(series, clims) - la = get_linealpha(series) - fc = get_fillcolor(series, clims) - fa = get_fillalpha(series) + if series[:seriestype] == :shape || series[:fillrange] !== nothing + lc = get_linecolor(series, clims) + la = get_linealpha(series) + ls = get_linestyle(series) + fc = get_fillcolor(series, clims) + fa = get_fillalpha(series) + fs = get_fillstyle(series) + has_fs = !isnothing(fs) - pypatches."Patch"( - # hatch color/alpha controlled by edge (not face) color/alpha - # if has_fs, set edge color/alpha <- fill color/alpha and face alpha <- 0 - edgecolor = has_fs ? py_color(single_color(fc), fa) : py_color(single_color(lc), la), - facecolor = py_color(single_color(fc), has_fs ? 0 : fa), + # line (and potentially solid fill) + line_handle = pypatches."Patch"( + edgecolor = py_color(single_color(lc), la), + facecolor = py_color(single_color(fc), has_fs ? 0 : fa), + linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)), + linestyle = py_linestyle(series[:seriestype], ls), + capstyle = "butt", + ) + + # hatched fill + # hatch color/alpha are controlled by edge (not face) color/alpha + if has_fs + fill_handle = pypatches."Patch"( + edgecolor = py_color(single_color(fc), fa), + facecolor = py_color(single_color(fc), 0), # don't fill with solid background hatch = py_fillstyle(fs), - linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)), - linestyle = py_linestyle(series[:seriestype], get_linestyle(series)), - capstyle = "butt" - ) - elseif series[:seriestype] in - (:path, :straightline, :scatter, :steppre, :stepmid, :steppost) - hasline = get_linewidth(series) > 0 - PyPlot.plt."Line2D"( - (0, 1), - (0, 0), - color = py_color( - single_color(get_linecolor(series, clims)), - get_linealpha(series), - ), - linewidth = py_thickness_scale( - plt, - hasline * sp[:legendfontsize] / 8, - ), - linestyle = py_linestyle(:path, get_linestyle(series)), - solid_capstyle = "butt", - solid_joinstyle = "miter", - dash_capstyle = "butt", - dash_joinstyle = "miter", - marker = py_marker(_cycle(series[:markershape], 1)), - markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]), - markeredgecolor = py_color( - single_color(get_markerstrokecolor(series)), - get_markerstrokealpha(series), - ), - markerfacecolor = py_color( - single_color(get_markercolor(series, clims)), - get_markeralpha(series), - ), - markeredgewidth = py_thickness_scale( - plt, - 0.8 * get_markerstrokewidth(series) * sp[:legendfontsize] / - first(series[:markersize]), - ), # retain the markersize/markerstroke ratio from the markers on the plot + linewidth = 0, # don't replot shape outline (doesn't affect hatch linewidth) + linestyle = py_linestyle(series[:seriestype], ls), + capstyle = "butt", ) + + # plot two handles on top of each other by passing in a tuple + # https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html + push!(handles, (line_handle, fill_handle)) else - series[:serieshandle][1] - end, - ) + # plot line handle (which includes solid fill) only + push!(handles, line_handle) + end + elseif series[:seriestype] in + (:path, :straightline, :scatter, :steppre, :stepmid, :steppost) + hasline = get_linewidth(series) > 0 + handle = PyPlot.plt."Line2D"( + (0, 1), + (0, 0), + color = py_color( + single_color(get_linecolor(series, clims)), + get_linealpha(series), + ), + linewidth = py_thickness_scale( + plt, + hasline * sp[:legendfontsize] / 8, + ), + linestyle = py_linestyle(:path, get_linestyle(series)), + solid_capstyle = "butt", + solid_joinstyle = "miter", + dash_capstyle = "butt", + dash_joinstyle = "miter", + marker = py_marker(_cycle(series[:markershape], 1)), + markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]), + markeredgecolor = py_color( + single_color(get_markerstrokecolor(series)), + get_markerstrokealpha(series), + ), + markerfacecolor = py_color( + single_color(get_markercolor(series, clims)), + get_markeralpha(series), + ), + markeredgewidth = py_thickness_scale( + plt, + 0.8 * get_markerstrokewidth(series) * sp[:legendfontsize] / + first(series[:markersize]), + ), # retain the markersize/markerstroke ratio from the markers on the plot + ) + push!(handles, handle) + else + push!(handles, series[:serieshandle][1]) + end push!(labels, series[:label]) end end