Styling AlgebraOfGraphics boxplots

I’m amazed how easy it is to make complex and good-looking figures using AlgebraOfGraphics - it is still a little opaque as to how to use custom styles in them though.

I’d like to be able to change the colors in this temperature distribution plot to be say, red and blue. Examples suggest that you can do so for many types of AlgebraOfGraphics plots by calling e.g.

Visual(Scatter; color=:red)

but the equivalent doesn’t seem to work for boxplots

2 Likes

Doesn’t something like this work?

boxplot(dataframe, :x, :y, color = :red)

You have not posted your code, so not sure without a computer what your commands are, but I remember doing it for violin.

Edit: that’s more like the StatsPlots syntax, sorry for the noise.

The relevant parts of the code (where mintemperature and maxtemperature are dataframes) are



temperature = innerjoin(mintemperature, maxtemperature, on = [:"Bureau of Meteorology station number", :Year, :Month, :Day], makeunique=true)


tstartstop = @chain temperature begin
    groupby(Symbol("Bureau of Meteorology station number"))
    combine(:Year => minimum, :Year=>maximum)
	transform!([:Year_minimum, :Year_maximum] => ((x,y) -> y.-x) => :"Year_total")
end




	axis = (width = 1000, height = 750)
	sr = renamer(70349=>"Mount Ginini. [$(tstartstop[tstartstop."Bureau of Meteorology station number".==70349, "Year_total"][1]) Years]", 
		        70351=>"Canberra Airport [$(tstartstop[tstartstop."Bureau of Meteorology station number".==70351, "Year_total"][1]) Years]")
	
	pcr = renamer("IDCJAC0010"=>"Daily Maximum", "IDCJAC0011"=>"Daily Minimum")
	
	tr2 = renamer(1=>"Jan",
				 2=>"Feb",
				 3=>"Mar",
				 4=>"Apr",
		         5=>"May",
		         6=>"Jun",
		         7=>"Jul",
		         8=>"Aug",
		         9=>"Sep",
		         10=>"Oct",
		         11=>"Nov",
		         12=>"Dec")
	
	tm = (mapping(:Month=>tr2, 
		 	    :"Minimum temperature (Degree C)"=>"Temperature (Degree C)",
		        color=:"Product code"=>pcr, dodge=:"Product code"=>pcr,
		        col=:"Bureau of Meteorology station number"=>sr)+
	      mapping(:Month=>tr2, 
		 	    :"Maximum temperature (Degree C)"=>"Temperature (Degree C)",
		        color=:"Product code_1"=>pcr, dodge=:"Product code"=>pcr,
		        col=:"Bureau of Meteorology station number"=>sr))
		
	tplt = (data(dropmissing(temperature)) * tm * visual(BoxPlot))
	
	tfig = draw(tplt; axis)

I’ve tried

visual(BoxPlot; color=[:red, :blue])

and

visual(BoxPlot; color=[[:red, :blue],[:red,:blue]])

both are ignored without throwing an error

I can’t find it right now but I think you want to change the palette where the categorical colors are defined in the first place, not pass colors directly. I think it’s something like draw(aog, palettes = (color = [:red, :green],))

1 Like

If you want to change the default colors, as Jules says, you should define your own theme and use it as the default. I couldn’t find any docs or blogs examples of how to do that. However, you can follow the way that function aog_theme is defined (see link below). Make your own my_aog_theme and use that. It will be fiddly the first time around, but afterwards you can use the theme with all your plots. (full disclosure: I haven’t used AlgebraOfGraphics yet, but it is inspired by the ggplot2 philosophy, which I use, and where I have defined my own styles: it’s well worth the effort).

https://raw.githubusercontent.com/JuliaPlots/AlgebraOfGraphics.jl/5b7f3e767dcacbecfeb424f8a633578271ed2747/src/theme.jl

I guess if I was going to actually make many of these sorts of plots it would certainly be worth it (along with packaging up things like the month-month string renamer); it is a bit of overkill if you are doing a one-off like this, especially when the default style is (in my opinion) really nice!

There’s probably an easy way to pass your own palette, as Jules suggested. You may want to look into that. Maybe package ColorSchemes works out of the box (it works great with simple Plots situations I’ve tried).

Here’s an issue I’ve made, hopefully some experts will weigh in: https://github.com/JuliaPlots/AlgebraOfGraphics.jl/issues/245

Just for the record, here’s a related discussion: Coloring boxplot groups in Makie

Finally got it to work. EDIT: Code much simplified after seeing lazarus’s answer below (I was missing the comma needed for a tuple of size 1, which led me to embark on some unnecessarily complicated workaround). To sum up, if you want to set a theme so all your plots get the same color treatment, follow the steps I outline immediately below. If you want to change the color for a single plot, use the palettes (with an s at the end of palettes) option inside draw, as shown by lazarusA in his answer further down.

using AlgebraOfGraphics, CairoMakie
using Colors  # for the palette
set_aog_theme!()
update_theme!(
    Theme(
        palette = (color = ["#1f78b4", "#ff7f00", "#029e73"],) # DON'T FORGET THE COMMA HERE!
    )
)

df = (x=rand(["a", "b", "c"], 100), y=rand(100))
plt = data(df) * mapping(:x, :y, color = :x) * visual(BoxPlot)
draw(plt)

1 Like

I do follow @jules suggestion here.

aesHist = data(penguins) * mapping(:bill_length_mm  => "bill length mm",
        color = :species, stack = :species) * AlgebraOfGraphics.histogram(;bins = 20)

    estilo = (color=["#FC7808", "#8C00EC", "#107A78"],
                marker=[:circle, :utriangle, :rect])
    # the actual plot with AoG and Makie
    fig = Figure(; resolution = (700, 700))
    axH = draw!(fig[1,1], aesHist, palettes = estilo)
2 Likes

this also works for me:

using AlgebraOfGraphics, CairoMakie
using Colors
colors = ["#FC7808", "#8C00EC", "#107A78"]
style = (color= colors, )
df = (x=rand(["a", "b", "c"], 100), y=rand(100))
plt = data(df) * mapping(:x, :y, color = :x) * visual(BoxPlot)
draw(plt, palettes = style)
3 Likes

Wow, great job lazarusA!

That comma was essential, I was going crazy without it.

That comma, if I understand, is there because it is a tuple of size 1.

Yep. As an alternative I like to write e.g. style = (; color=colors) instead of a dangling comma. I find the leading ; less easy to forget. It also has more general use, for example in the following:

a = [1,2,3]
b = ["xx", "xy", "yy"]
df = DataFrame(; x, y) # ; required so x,y are treated as keyword arguments

You could actually use this feature in your case with

using AlgebraOfGraphics, CairoMakie
color = ["#FC7808", "#8C00EC", "#107A78"]
df = (x=rand(["a", "b", "c"], 100), y=rand(100))
plt = data(df) * mapping(:x, :y, color=:x) * visual(BoxPlot)
draw(plt, palettes=(; color))
2 Likes

I agree the semi-colon is easier to see! :grinning:

Thanks everyone for the discussion!

4 Likes