Ordered color palette

I want to use a palette that is ordered rather than nominal or continuous. If I don’t specify a palette, I get nominal. If I specify a continuous one, I get an error. visual(Scatter, colormap=:viridis) doesn’t change anything.

using AlgebraOfGraphics, CategoricalArrays, CairoMakie
let n = 100
d = data((x=rand(n), y=rand(n), c=rand(CategoricalArray(1:13, ordered=true), n)))
v = visual(Scatter)
m = mapping(:x, :y, color=:c)
p = d * v * m
draw(p, )
end

using AlgebraOfGraphics, CategoricalArrays, CairoMakie
let n = 100
k = 13
d = data((x=rand(n), y=rand(n), c=rand(CategoricalArray(1:k, ordered=true), n)))
v = visual(Scatter) 
m = mapping(:x, :y, color=:c) 
p = d * v * m
draw(p, palettes=(color=:cividis))
end


ERROR: LoadError: MethodError: no method matching merge(::NamedTuple{(:layout,), Tuple{AlgebraOfGraphics.Wrap}}, ::NamedTuple{(:color, :marker, :linestyle, :patchcolor, :side), Tuple{Vector{ColorTypes.RGB{Float64}}, Vector{Symbol}, Vector{Symbol}, Vector{ColorTypes.RGB{Float64}}, Vector{Symbol}}}, ::Symbol)
Closest candidates are:
  merge(::NamedTuple{an, T} where T<:Tuple, ::NamedTuple{bn, T} where T<:Tuple) where {an, bn} at namedtuple.jl:242
  merge(::NamedTuple, ::NamedTuple, ::NamedTuple...) at namedtuple.jl:263
  merge(::NamedTuple, ::Any) at namedtuple.jl:277
  ...
Stacktrace:
 [1] compute_axes_grid(fig::Figure, s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, palettes::Symbol)
   @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:74
 [2] plot!(fig::Figure, s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, palettes::Symbol)
   @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:150
 [3] plot(s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, figure::NamedTuple{(), Tuple{}}, palettes::Symbol)
   @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:158
 [4] draw(s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, figure::NamedTuple{(), Tuple{}}, palettes::Symbol)
   @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:173
 [5] top-level scope

1 Like

First of all you’re passing the color incorrectly, you’re not making a named tuple. Either do (;color = :cividis) or (color = :cividis,).

Then the colors will probably look wrong because you’ll take the first n colors from cividis, while you want n colors spanning all of cividis.

You probably have to construct that map yourself, maybe cgrad(:cividis, n, categorical = true) will work as colormap argument?

2 Likes

Something is wrong still. Using ; color= raises an error

using AlgebraOfGraphics, CategoricalArrays, CairoMakie
let
    n = 100
    k = 13
    d = data((x=rand(n), y=rand(n), c=rand(CategoricalArray(1:k, ordered=true), n)))
    v = visual(Scatter)
    m = mapping(:x, :y, color=:c)
    p = d * v * m
    draw(p, palettes=(; color=cgrad(:cividis, n, categorical=true)))
end

ERROR: LoadError: MethodError: objects of type PlotUtils.CategoricalColorGradient are not callable
Stacktrace:
  [1] iterate
    @ ./generator.jl:47 [inlined]
  [2] _collect
    @ ./array.jl:691 [inlined]
  [3] collect_similar
    @ ./array.jl:606 [inlined]
  [4] map
    @ ./abstractarray.jl:2294 [inlined]
  [5] apply_palette
    @ ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/scales.jl:11 [inlined]
  [6] fitscale(c::AlgebraOfGraphics.CategoricalScale{Vector{CategoricalValue{Int64, UInt32}}, Nothing, PlotUtils.CategoricalColorGradient})
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/scales.jl:38
  [7] map!(f::typeof(AlgebraOfGraphics.fitscale), iter::Base.ValueIterator{Dict{Union{Int64, Symbol}, Any}})
    @ Base ./dict.jl:723
  [8] compute_axes_grid(fig::Figure, s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, palettes::NamedTuple{(:color,), Tuple{PlotUtils.CategoricalColorGradient}})
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:80
  [9] plot!(fig::Figure, s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, palettes::NamedTuple{(:color,), Tuple{PlotUtils.CategoricalColorGradient}})
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:150
 [10] plot(s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, figure::NamedTuple{(), Tuple{}}, palettes::NamedTuple{(:color,), Tuple{PlotUtils.CategoricalColorGradient}})
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:158
 [11] draw(s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, figure::NamedTuple{(), Tuple{}}, palettes::NamedTuple{(:color,), Tuple{PlotUtils.CategoricalColorGradient}})
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:173
 [12] top-level scope

and ; colormap= doesn’t use cividis.

let
           n = 100
           k = 13
           d = data((x=rand(n), y=rand(n), c=rand(CategoricalArray(1:k, ordered=true), n)))
           v = visual(Scatter)
           m = mapping(:x, :y, color=:c)
           p = d * v * m
           save("/tmp/plot.pdf", draw(p, palettes=(; colormap=cgrad(:cividis, n, categorical=true))))
       end

At the moment palettes wants lists of values for the attributes, so you should do

color_list = collect(cgrad(:cividis, n, categorical=true))
palettes=(color=color_list,)

That being said, this looks like something that could be done automatically on the AoG side, so that just passing color = :cividis would work. (At least making collect not required should be completely straightforward.)

2 Likes