implement ColorSchemes integration in PlotUtils

This commit is contained in:
Daniel Schwabeneder 2020-04-10 13:04:38 +02:00
parent 39b10f05b9
commit 66d2e4746a
7 changed files with 50 additions and 53 deletions

View File

@ -245,7 +245,7 @@ end
const CURRENT_BACKEND = CurrentBackend(:none) const CURRENT_BACKEND = CurrentBackend(:none)
include("precompile.jl") # include("precompile.jl")
_precompile_() # _precompile_()
end # module end # module

View File

@ -481,10 +481,7 @@ is_default_attribute(k) = k in _internal_args || k in _all_args || is_axis_attr_
makeplural(s::Symbol) = Symbol(string(s,"s")) makeplural(s::Symbol) = Symbol(string(s,"s"))
autopick(arr::AVec, idx::Integer) = arr[mod1(idx,length(arr))] autopick_ignore_none_auto(arr::AVec, idx::Integer) = _cycle(setdiff(arr, [:none, :auto]), idx)
autopick(notarr, idx::Integer) = notarr
autopick_ignore_none_auto(arr::AVec, idx::Integer) = autopick(setdiff(arr, [:none, :auto]), idx)
autopick_ignore_none_auto(notarr, idx::Integer) = notarr autopick_ignore_none_auto(notarr, idx::Integer) = notarr
function aliasesAndAutopick(plotattributes::AKW, sym::Symbol, aliases::Dict{Symbol,Symbol}, options::AVec, plotIndex::Int) function aliasesAndAutopick(plotattributes::AKW, sym::Symbol, aliases::Dict{Symbol,Symbol}, options::AVec, plotIndex::Int)
@ -1410,8 +1407,7 @@ end
function _update_subplot_colors(sp::Subplot) function _update_subplot_colors(sp::Subplot)
# background colors # background colors
color_or_nothing!(sp.attr, :background_color_subplot) color_or_nothing!(sp.attr, :background_color_subplot)
bg = plot_color(sp[:background_color_subplot]) sp.attr[:color_palette] = get_color_palette(sp.attr[:color_palette], 30)
sp.attr[:color_palette] = get_color_palette(sp.attr[:color_palette], bg, 30)
color_or_nothing!(sp.attr, :background_color_legend) color_or_nothing!(sp.attr, :background_color_legend)
color_or_nothing!(sp.attr, :background_color_inside) color_or_nothing!(sp.attr, :background_color_inside)
@ -1514,9 +1510,9 @@ end
# and assigns a color automatically # and assigns a color automatically
function get_series_color(c, sp::Subplot, n::Int, seriestype) function get_series_color(c, sp::Subplot, n::Int, seriestype)
if c == :auto if c == :auto
c = like_surface(seriestype) ? cgrad() : autopick(sp[:color_palette], n) c = like_surface(seriestype) ? cgrad() : _cycle(sp[:color_palette], n)
elseif isa(c, Int) elseif isa(c, Int)
c = autopick(sp[:color_palette], c) c = _cycle(sp[:color_palette], c)
end end
plot_color(c) plot_color(c)
end end
@ -1526,7 +1522,7 @@ function get_series_color(c::AbstractArray, sp::Subplot, n::Int, seriestype)
end end
function ensure_gradient!(plotattributes::AKW, csym::Symbol, asym::Symbol) function ensure_gradient!(plotattributes::AKW, csym::Symbol, asym::Symbol)
if !isa(plotattributes[csym], ColorGradient) if typeof(plotattributes[csym]) (ColorGradient, ColorPalette)
plotattributes[csym] = typeof(plotattributes[asym]) <: AbstractVector ? cgrad() : cgrad(alpha = plotattributes[asym]) plotattributes[csym] = typeof(plotattributes[asym]) <: AbstractVector ? cgrad() : cgrad(alpha = plotattributes[asym])
end end
end end

View File

@ -1661,34 +1661,29 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :heatmap elseif st == :heatmap
zmin, zmax = clims zmin, zmax = clims
fillgrad = _as_gradient(series[:fillcolor])
colors = plot_color.(nan_get(fillgrad, z, clims), series[:fillalpha])
rgba = gr_color.(colors)
if !ispolar(sp) if !ispolar(sp)
GR.setspace(zmin, zmax, 0, 90) GR.setspace(clims..., 0, 90)
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale], series[:y], sp[:yaxis][:scale], size(series[:z])) x, y = heatmap_edges(series[:x], sp[:xaxis][:scale], series[:y], sp[:yaxis][:scale], size(series[:z]))
w, h = length(x) - 1, length(y) - 1 w, h = length(x) - 1, length(y) - 1
z_normalized = map(x -> GR.jlgr.normalize_color(x, zmin, zmax), z)
if is_uniformly_spaced(x) && is_uniformly_spaced(y) if is_uniformly_spaced(x) && is_uniformly_spaced(y)
# For uniformly spaced data use GR.drawimage, which can be # For uniformly spaced data use GR.drawimage, which can be
# much faster than GR.nonuniformcellarray, especially for # much faster than GR.nonuniformcellarray, especially for
# pdf output, and also supports alpha values. # pdf output, and also supports alpha values.
# Note that drawimage draws uniformly spaced data correctly # Note that drawimage draws uniformly spaced data correctly
# even on log scales, where it is visually non-uniform. # even on log scales, where it is visually non-uniform.
fillgrad = _as_gradient(series[:fillcolor])
colors = plot_color.(fillgrad[z_normalized], series[:fillalpha])
colors[isnan.(z_normalized)] .= RGBA(0,0,0,0)
rgba = gr_color.(colors)
GR.drawimage(first(x), last(x), last(y), first(y), w, h, rgba) GR.drawimage(first(x), last(x), last(y), first(y), w, h, rgba)
else else
(something(series[:fillalpha],1) < 1 || any(_gr_gradient_alpha .< 1)) && @warn( if something(series[:fillalpha],1) < 1 || any(_gr_gradient_alpha .< 1)
"GR: transparency not supported in non-uniform heatmaps. Alpha values ignored.") @warn "GR: transparency not supported in non-uniform heatmaps. Alpha values ignored."
z_normalized = map(x -> isnan(x) ? 256/255 : x, z_normalized) # results in color index = 1256 -> transparent end
colors = Int32[round(Int32, 1000 + _i * 255) for _i in z_normalized] GR.nonuniformcellarray(x, y, w, h, rgba)
GR.nonuniformcellarray(x, y, w, h, colors)
end end
else else
phimin, phimax = 0.0, 360.0 # nonuniform polar array is not yet supported in GR.jl phimin, phimax = 0.0, 360.0 # nonuniform polar array is not yet supported in GR.jl
nx, ny = length(series[:x]), length(series[:y]) nx, ny = length(series[:x]), length(series[:y])
z_normalized = map(x -> GR.jlgr.normalize_color(x, zmin, zmax), z)
colors = Int32[round(Int32, 1000 + _i * 255) for _i in z_normalized]
xmin, xmax, ymin, ymax = xy_lims xmin, xmax, ymin, ymax = xy_lims
rmax = data_lims[4] rmax = data_lims[4]
GR.setwindow(-rmax, rmax, -rmax, rmax) GR.setwindow(-rmax, rmax, -rmax, rmax)

View File

@ -677,8 +677,8 @@ function pgfx_filllegend!(series_opt, opt)
}""") }""")
end end
function pgfx_colormap(grad::ColorGradient) function pgfx_colormap(grad::Union{ColorGradient, ColorPalette})
join(map(grad.colors) do c join(map(color_list(grad)) do c
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c))
end, "\n") end, "\n")
end end

View File

@ -14,25 +14,15 @@ function _theme(s::Symbol, defaults::AKW; kw...)
# Set the theme's gradient as default # Set the theme's gradient as default
if haskey(defaults, :colorgradient) if haskey(defaults, :colorgradient)
PlotUtils.clibrary(:misc) PlotUtils.default_cgrad(pop!(defaults, :colorgradient))
PlotUtils.default_cgrad(default = :sequential, sequential = PlotThemes.gradient_name(s))
pop!(defaults, :colorgradient)
else else
PlotUtils.clibrary(:Plots) PlotUtils.default_cgrad(:default)
PlotUtils.default_cgrad(default = :sequential, sequential = :inferno)
end end
# maybe overwrite the theme's gradient # maybe overwrite the theme's gradient
kw = KW(kw) kw = KW(kw)
if haskey(kw, :colorgradient) if haskey(kw, :colorgradient)
kwgrad = pop!(kw, :colorgradient) PlotUtils.default_cgrad(pop!(kw, :colorgradient))
for clib in clibraries()
if kwgrad in cgradients(clib)
PlotUtils.clibrary(clib)
PlotUtils.default_cgrad(default = :sequential, sequential = kwgrad)
break
end
end
end end
# Set the theme's defaults # Set the theme's defaults
@ -57,12 +47,12 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
defaults = PlotThemes._themes[thm].defaults defaults = PlotThemes._themes[thm].defaults
# get the gradient # get the gradient
gradient_colors = get(defaults, :colorgradient, cgrad(:inferno).colors) gradient_colors = color_list(cgrad(get(defaults, :colorgradient, :default)))
colorgradient = cgrad(cfunc.(RGB.(gradient_colors))) colorgradient = cgrad(cfunc.(RGB.(gradient_colors)))
# get the palette # get the palette
palette = get(defaults, :palette, get_color_palette(:auto, plot_color(:white), 17)) cp = color_list(palette(get(defaults, :palette, :default)))
palette = cfunc.(RGB.(palette)) cp = cfunc.(RGB.(cp))
# apply the theme # apply the theme
for k in keys(defaults) for k in keys(defaults)
@ -89,7 +79,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
for j in 1:4 for j in 1:4
@series begin @series begin
subplot := 1 subplot := 1
palette := palette color_palette := cp
seriestype := :path seriestype := :path
cumsum(randn(50)) cumsum(randn(50))
end end
@ -97,7 +87,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
@series begin @series begin
subplot := 2 subplot := 2
seriestype := :scatter seriestype := :scatter
palette := palette color_palette := cp
marker := (:circle, :diamond, :star5, :square)[j] marker := (:circle, :diamond, :star5, :square)[j]
randn(10), randn(10) randn(10), randn(10)
end end
@ -106,7 +96,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
@series begin @series begin
subplot := 3 subplot := 3
seriestype := :histogram seriestype := :histogram
palette := palette color_palette := cp
randn(1000) .+ (0:2:4)' randn(1000) .+ (0:2:4)'
end end

View File

@ -130,10 +130,12 @@ _cycle(v::AVec, indices::AVec{Int}) = map(i -> _cycle(v,i), indices)
_cycle(v::AMat, indices::AVec{Int}) = map(i -> _cycle(v,i), indices) _cycle(v::AMat, indices::AVec{Int}) = map(i -> _cycle(v,i), indices)
_cycle(v, indices::AVec{Int}) = fill(v, length(indices)) _cycle(v, indices::AVec{Int}) = fill(v, length(indices))
_cycle(grad::ColorGradient, idx::Int) = _cycle(grad.colors, idx) _cycle(cg::ColorGradient, idx::Int) = cg[mod1(idx, end)]
_cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices) _cycle(cg::ColorGradient, idx::AVec{Int}) = cg[mod1.(idx, end)]
_cycle(cp::ColorPalette, idx::Int) = cp[mod1(idx, end)]
_cycle(cp::ColorPalette, idx::AVec{Int}) = cp[mod1.(idx, end)]
_as_gradient(grad::ColorGradient) = grad _as_gradient(grad) = grad
_as_gradient(c::Colorant) = ColorGradient([c,c]) _as_gradient(c::Colorant) = ColorGradient([c,c])
makevec(v::AVec) = v makevec(v::AVec) = v
@ -521,8 +523,7 @@ for comp in (:line, :fill, :marker)
if z === nothing if z === nothing
isa(c, ColorGradient) ? c : plot_color(_cycle(c, i)) isa(c, ColorGradient) ? c : plot_color(_cycle(c, i))
else else
grad = isa(c, ColorGradient) ? c : cgrad() nan_get(get_gradient(c), z[i], (cmin, cmax))
grad[clamp((_cycle(z, i) - cmin) / (cmax - cmin), 0, 1)]
end end
end end
@ -543,6 +544,21 @@ end
single_color(c, v = 0.5) = c single_color(c, v = 0.5) = c
single_color(grad::ColorGradient, v = 0.5) = grad[v] single_color(grad::ColorGradient, v = 0.5) = grad[v]
get_gradient(c) = cgrad()
get_gradient(cg::ColorGradient) = cg
get_gradient(cp::ColorPalette) = cp
nan_get(cs, x, range) = isfinite(x) ? plot_color(get(cs, x, range)) : invisible()
function nan_get(cs, v::AbstractVector, range)
colors = fill(invisible(), length(v))
for (i, x) in enumerate(v)
if isfinite(x)
colors[i] = get(cs, x, range)
end
end
return colors
end
function get_linewidth(series, i::Int = 1) function get_linewidth(series, i::Int = 1)
_cycle(series[:linewidth], i) _cycle(series[:linewidth], i)
end end

View File

@ -71,7 +71,7 @@ end
pl = scatter!( pl = scatter!(
y, y,
zcolor = abs.(y .- 0.5), zcolor = abs.(y .- 0.5),
m = (:heat, 0.8, Plots.stroke(1, :green)), m = (:hot, 0.8, Plots.stroke(1, :green)),
ms = 10 * abs.(y .- 0.5) .+ 4, ms = 10 * abs.(y .- 0.5) .+ 4,
lab = ["grad", "", "ient"], lab = ["grad", "", "ient"],
) )
@ -122,7 +122,7 @@ end
plot( plot(
Plots.fakedata(100, 10), Plots.fakedata(100, 10),
layout = 4, layout = 4,
palette = [:grays :blues :heat :lightrainbow], palette = [:grays :blues :hot :rainbow],
bg_inside = [:orange :pink :darkblue :black], bg_inside = [:orange :pink :darkblue :black],
) )
end # testset end # testset
@ -211,7 +211,7 @@ end
marker_z = ((x, y) -> begin marker_z = ((x, y) -> begin
x + y x + y
end), end),
color = :bluesreds, color = :bwr,
legend = false, legend = false,
) )
plot(p1, p2) plot(p1, p2)