Porting over a matplotlib cyberpunk theme for Julia with Makie
Original article: https://matplotlib.org/matplotblog/posts/matplotlib-cyberpunk-style/
using CairoMakie
# CairoMakie.activate!(type = "svg")
Theming in makie
is as simple as: https://makie.juliaplots.org/v0.17.3/documentation/theming/
fontsize_theme = Theme(fontsize=10, resolution=(300,300))
set_theme!(fontsize_theme)
f = Figure()
lines!(f, cumsum(randn(50)))
After taking a liking to matplotlib, I started to revisit Julia's Makie
package because it felt similar in how you constructed a plot. But I wanted to make the plots look better just out of the box, and the way to do that was with themes.
Let's see an example:
set_theme!()
function example_plot()
f = Figure()
ax = Axis(f[1,1])
x = [1,3,9,5,2,1,1]
y = [4,5,5,7,9,8,6]
scatterlines!(ax, x)
scatterlines!(ax, y)
f
end
example_plot()
On my MBP, the default theme with makie isn't aesthetically pleasing - the font size is way too big and the figure size is massive. Let's fix those with a basic theme:
first_theme = Theme(fontsize=12, resolution=(640,320))
set_theme!(first_theme)
example_plot()
cyberpunk_theme = Theme(
# teal/cyan, pink, yellow, matrix green, red, violet
palette = (color =["#08F7FE", "#FE53BB", "#F5D300", "#00ff41", :red, "#9467bd"],),
backgroundcolor = "#212946",
textcolor=:gray90,
resolution=(640,320),
fontsize=12,
font = "Arial",
colormap = :cool,
cycle = Cycle([:color]),
Axis = (
backgroundcolor = "#212946",
topspinevisible = false,
rightspinevisible = false,
xgridcolor = "#2A3459",
ygridcolor = "#2A3459",
bottomspinecolor = "#2A3459",
leftspinecolor = "#2A3459",
ytickcolor = "#2A3459",
xtickcolor = "#2A3459",
titlesize=16,
yautolimitmargin=(0.05, 0.1), # Leaves room for label text
),
# Note in order to apply specific settings to plot types we need to use the Struct/type
# so to theme barplots() you need to use the BarPlot type
Lines = (
linewidth=2,),
BarPlot = (
cycle=Cycle([:color]), # Interesting that I have to put it here
label_size=12,
)
)
with_theme(example_plot, cyberpunk_theme, )
Note in order to apply specific settings to plot types we need to use the Struct/type so to theme barplots() you need to use the BarPlot type. This wasn't covered in the documentation and it was weird that I had to repeat the cycle
call for BarPlot
but not Lines
, so maybe to be safe you may have to repeat yourself here and there.
Next, let's temporarily add the glow to this example plot. This is done by repeatedly overdrawing the lines and markers (with scatterlines
) but with a slight dodge effect with a very low alpha
set_theme!(cyberpunk_theme)
n_lines = 10
diff_linewidth = 1.05
alpha_value = 0.03
f = Figure()
ax = Axis(f[1,1])
colors = ["#08F7FE", "#FE53BB", "#F5D300", "#00ff41", :red, "#9467bd"]
x = [1,3,9,5,2,1,1]
y = [4,5,5,7,9,8,6]
scatterlines!(ax, x)
scatterlines!(ax, y)
for n in 1:n_lines
scatterlines!(ax, x; linewidth=2+(diff_linewidth*n), color = (colors[1], alpha_value))
scatterlines!(ax, y; linewidth=2+(diff_linewidth*n), color = (colors[2], alpha_value))
end
f
And here we have a decent start towards a better makie theme!
We also added a colormap in there, so we can handle continuous values as well:
t = range(0, stop=1, length=500) # time steps
θ = (6π) .* t # angles
x = t .* cos.(θ) # x coords of spiral
y = t .* sin.(θ) # y coords of spiral
p1 = lines(
x,
y,
color = t,
# colormap = :cool,
linewidth=8)
And here's an example with a BarPlot
where we cycle through the palette:
y = round.(randn(5) .+ 2.5, digits=1)
b = Figure()
ax = Axis(b[1,1], title="Title")
for i in 1:5
barplot!(ax, [i], [y[i]], bar_labels=[y[i]])
end
b
Though it may be better to just use the color
parameter and pull from the continuous color map.
barplot(1:3, y[1:3], bar_labels=y[1:3], color=1:3, axis = (title="Barplot with continuous colormap",))
This looks better than the discrete colors. Note in the above example, I used boxplot
instead of the mutating function boxplot!
and note the trailing comma in the axis
parameter call to make sure this creates a NamedTuple
. Nuance!
From the docs:
If you set only one attribute, be careful to do axis = (key = value,) (note the trailing comma), otherwise you're not creating a
NamedTuple
but a local variable key.