Support for CategoricalValue in StatsPlots

Hi I am following the walkthrough for StatsPlots at:

Using Julia Version 1.4.1

Got into problems when trying the violin plot:

singers = RDatasets.dataset("lattice", "singer");
@df singers violin(:VoicePart,:Height, side=:right, marker=(0.2, :blue, stroke(0)), label="Scala")

Got the following error:
Cannot convert CategoricalValue{String,UInt8} to series data for plotting

Stacktrace:
[1] error(::String) at ./error.jl:33
[2] _prepare_series_data(::CategoricalValue{String,UInt8}) at /home/leon/.julia/packages/RecipesPipeline/tkFmN/src/series.jl:8
[3] _series_data_vector(::CategoricalValue{String,UInt8}, ::Dict{Symbol,Any}) at /home/leon/.julia/packages/RecipesPipeline/tkFmN/src/series.jl:27
[4] (::RecipesPipeline.var"#45#48"{Dict{Symbol,Any}})(::CategoricalValue{String,UInt8}) at ./none:0
[5] iterate(::Base.Generator{CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}},RecipesPipeline.var"#45#48"{Dict{Symbol,Any}}}) at ./generator.jl:47
[6] _series_data_vector(::CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}}, ::Dict{Symbol,Any}) at /home/leon/.julia/packages/RecipesPipeline/tkFmN/src/series.jl:42
[7] macro expansion at /home/leon/.julia/packages/RecipesPipeline/tkFmN/src/series.jl:138 [inlined]
[8] apply_recipe(::Dict{Symbol,Any}, ::Type{RecipesPipeline.SliceIt}, ::CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}}, ::Array{Int32,1}, ::Nothing) at /home/leon/.julia/packages/RecipesBase/aQmWx/src/RecipesBase.jl:281
[9] _process_userrecipes!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}},Array{Int32,1}}) at /home/leon/.julia/packages/RecipesPipeline/tkFmN/src/user_recipe.jl:35
[10] recipe_pipeline!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}},Array{Int32,1}}) at /home/leon/.julia/packages/RecipesPipeline/tkFmN/src/RecipesPipeline.jl:69
[11] _plot!(::Plots.Plot{Plots.GRBackend}, ::Dict{Symbol,Any}, ::Tuple{CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}},Array{Int32,1}}) at /home/leon/.julia/packages/Plots/M1wcx/src/plot.jl:167
[12] plot(::CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}}, ::Vararg{Any,N} where N; kw::Base.Iterators.Pairs{Symbol,Any,NTuple{4,Symbol},NamedTuple{(:side, :marker, :label, :seriestype),Tuple{Symbol,Tuple{Float64,Symbol,Plots.Stroke},String,Symbol}}}) at /home/leon/.julia/packages/Plots/M1wcx/src/plot.jl:57
[13] violin(::CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}}, ::Vararg{Any,N} where N; kw::Base.Iterators.Pairs{Symbol,Any,Tuple{Symbol,Symbol,Symbol},NamedTuple{(:side, :marker, :label),Tuple{Symbol,Tuple{Float64,Symbol,Plots.Stroke},String}}}) at /home/leon/.julia/packages/RecipesBase/aQmWx/src/RecipesBase.jl:402
[14] add_label(::Array{String,1}, ::Function, ::CategoricalArray{String,1,UInt8,String,CategoricalValue{String,UInt8},Union{}}, ::Vararg{Any,N} where N; kwargs::Base.Iterators.Pairs{Symbol,Any,Tuple{Symbol,Symbol,Symbol},NamedTuple{(:side, :marker, :label),Tuple{Symbol,Tuple{Float64,Symbol,Plots.Stroke},String}}}) at /home/leon/.julia/packages/StatsPlots/6bINV/src/df.jl:153
[15] (::var"#57#58")(::DataFrame) at /home/leon/.julia/packages/Plots/M1wcx/src/components.jl:0
[16] top-level scope at In[58]:1

Hi - did you figure this out? I’m having the same problem. One can convert the categorical array to a string with string.(column) but then I lose my custom ordering. Thanks!

Sadly no. Waiting until Julia matures a bit more.

I had totally forgotten that I had asked a similar question over two years ago. See Ordering the y-axis values in a dotplot . Here is a workaround…

Assuming the :VoicePart is the categorical array, then you can do…

cticks(ctg::CategoricalArray) = (1:length(levels(ctg)), levels(ctg))
df singers violin(levelcode.(:VoicePart),:Height, xticks=cticks(:VoicePart), side=:right, marker=(0.2, :blue, stroke(0)), label="Scala")

A bit ugly, but it works. Basically, the x value is the integer code for the the level of that entry and then the xticks is a translation from that code to the string level description.

Would be nice if CategoricalArrays just worked for plotting. There’s an open issue about this at https://github.com/JuliaData/CategoricalArrays.jl/issues/256 .