6.5 Colors and Colormaps

Choosing an appropriate set of colors or colorbar for your plot is an essential part when presenting results. Using Colors.jl is supported in Makie.jl so that you can use named colors or pass RGB or RGBA values. Additionally, colormaps from ColorSchemes.jl and PerceptualColourMaps.jl can also be used. It is worth knowing that you can reverse a colormap by doing Reverse(:colormap_name) and obtain a transparent color or colormap with color=(:red,0.5) and colormap=(:viridis, 0.5).

Different use cases will be shown next. Then we will define a custom theme with new colors and a colorbar palette.

By default Makie.jl has a predefined set of colors in order to cycle through them automatically, as shown in the previous figures, where no specific color was set. Overwriting these defaults is done by calling the keyword color in the plotting function and specifying a new color via a Symbol or String. See this in action in the following example:

  1. function set_colors_and_cycle()
  2. # Epicycloid lines
  3. x(r, k, θ) = r * (k .+ 1.0) .* cos.(θ) .- r * cos.((k .+ 1.0) .* θ)
  4. y(r, k, θ) = r * (k .+ 1.0) .* sin.(θ) .- r * sin.((k .+ 1.0) .* θ)
  5. θ = LinRange(0, 6.2π, 1000)
  6. axis = (; xlabel=L"x(\theta)", ylabel=L"y(\theta)",
  7. title="Epicycloid", aspect=DataAspect())
  8. figure = (; resolution=(600, 400), font="CMU Serif")
  9. fig, ax, _ = lines(x(1, 1, θ), y(1, 1, θ); color="firebrick1", # string
  10. label=L"1.0", axis=axis, figure=figure)
  11. lines!(ax, x(4, 2, θ), y(4, 2, θ); color=:royalblue1, #symbol
  12. label=L"2.0")
  13. for k = 2.5:0.5:5.5
  14. lines!(ax, x(2k, k, θ), y(2k, k, θ); label=latexstring("$(k)")) #cycle
  15. end
  16. Legend(fig[1, 2], ax, latexstring("k, r = 2k"), merge=true)
  17. colsize!(fig.layout, 1, Aspect(1, 1.0))
  18. fig
  19. end
  20. JDS.set_colors_and_cycle()

Figure 21: Set colors and cycle.

Figure 21: Set colors and cycle.

Where, in the first two lines we have used the keyword color to specify our color. The rest is using the default cycle set of colors. Later, we will learn how to do a custom cycle.

Regarding colormaps, we are already familiar with the keyword colormap for heatmaps and scatters. Here, we show that a colormap can also be specified via a Symbol or a String, similar to colors. Or, even a vector of RGB colors. Let’s do our first example by calling colormaps as a Symbol, String and cgrad for categorical values. See ?cgrad for more information.

  1. figure = (; resolution=(600, 400), font="CMU Serif")
  2. axis = (; xlabel=L"x", ylabel=L"y", aspect=DataAspect())
  3. fig, ax, pltobj = heatmap(rand(20, 20); colorrange=(0, 1),
  4. colormap=Reverse(:viridis), axis=axis, figure=figure)
  5. Colorbar(fig[1, 2], pltobj, label = "Reverse sequential colormap")
  6. colsize!(fig.layout, 1, Aspect(1, 1.0))
  7. fig

Figure 22: Reverse sequential colormap and colorrange.

Figure 22: Reverse sequential colormap and colorrange.

When setting a colorrange usually the values outside this range are colored with the first and last color from the colormap. However, sometimes is better to specify the color you want at both ends. We do that with highclip and lowclip:

  1. using ColorSchemes
  1. figure = (; resolution=(600, 400), font="CMU Serif")
  2. axis = (; xlabel=L"x", ylabel=L"y", aspect=DataAspect())
  3. fig, ax, pltobj = heatmap(randn(20, 20); colorrange=(-2, 2),
  4. colormap="diverging_rainbow_bgymr_45_85_c67_n256",
  5. highclip=:black, lowclip=:white, axis=axis, figure=figure)
  6. Colorbar(fig[1, 2], pltobj, label = "Diverging colormap")
  7. colsize!(fig.layout, 1, Aspect(1, 1.0))
  8. fig

Figure 23: Diverging Colormap with low and high clip.

Figure 23: Diverging Colormap with low and high clip.

But we mentioned that also RGB vectors are valid options. For our next example you could pass the custom colormap perse or use cgrad to force a categorical Colorbar.

  1. using Colors, ColorSchemes
  1. figure = (; resolution=(600, 400), font="CMU Serif")
  2. axis = (; xlabel=L"x", ylabel=L"y", aspect=DataAspect())
  3. #cmap = ColorScheme(range(colorant"red", colorant"green", length=3))
  4. # this is another way to obtain a colormap, not used here, but try it.
  5. mycmap = ColorScheme([RGB{Float64}(i, 1.5i, 2i) for i in [0.0, 0.25, 0.35, 0.5]])
  6. fig, ax, pltobj = heatmap(rand(-1:1, 20, 20);
  7. colormap=cgrad(mycmap, 3, categorical=true, rev=true), # cgrad and Symbol, mycmap
  8. axis=axis, figure=figure)
  9. cbar = Colorbar(fig[1, 2], pltobj, label="Categories")
  10. cbar.ticks = ([-0.66, 0, 0.66], ["negative", "neutral", "positive"])
  11. colsize!(fig.layout, 1, Aspect(1, 1.0))
  12. fig

Figure 24: Categorical Colormap.

Figure 24: Categorical Colormap.

Lastly, the ticks in the colorbar for the categorial case are not centered by default in each color. This is fixed by passing custom ticks, as in cbar.ticks = (positions, ticks).

The last situation is when passing a multiple colors to colormap. You will get an interpolated colormap between these two colors. Also, hexadecimal coded colors are accepted. So, on top of our heatmap let’s put one semi-transparent point using this.

  1. figure = (; resolution=(600, 400), font="CMU Serif")
  2. axis = (; xlabel=L"x", ylabel=L"y", aspect=DataAspect())
  3. fig, ax, pltobj = heatmap(rand(20, 20); colorrange=(0, 1),
  4. colormap=["red", "black"], axis=axis, figure=figure)
  5. scatter!(ax, [11], [11], color=("#C0C0C0", 0.5), markersize=150)
  6. Colorbar(fig[1, 2], pltobj, label="2 colors")
  7. colsize!(fig.layout, 1, Aspect(1, 1.0))
  8. fig

Figure 25: Colormap from two colors.

Figure 25: Colormap from two colors.

6.5.1 Custom cycle

Here, we could define a global Theme with a new cycle for colors, however that is not the recommend way to do it. It’s better to define a new theme and use as shown before. Let’s define a new one with a cycle for :color, :linestyle, :marker and a new colormap default. And add these new attributes to our previous publication_theme.

  1. function new_cycle_theme()
  2. # https://nanx.me/ggsci/reference/pal_locuszoom.html
  3. my_colors = ["#D43F3AFF", "#EEA236FF", "#5CB85CFF", "#46B8DAFF",
  4. "#357EBDFF", "#9632B8FF", "#B8B8B8FF"]
  5. cycle = Cycle([:color, :linestyle, :marker], covary=true) # alltogether
  6. my_markers = [:circle, :rect, :utriangle, :dtriangle, :diamond,
  7. :pentagon, :cross, :xcross]
  8. my_linestyle = [nothing, :dash, :dot, :dashdot, :dashdotdot]
  9. Theme(
  10. fontsize=16, font="CMU Serif",
  11. colormap=:linear_bmy_10_95_c78_n256,
  12. palette=(color=my_colors, marker=my_markers, linestyle=my_linestyle),
  13. Lines=(cycle=cycle,), Scatter=(cycle=cycle,),
  14. Axis=(xlabelsize=20, xgridstyle=:dash, ygridstyle=:dash,
  15. xtickalign=1, ytickalign=1, yticksize=10, xticksize=10,
  16. xlabelpadding=-5, xlabel="x", ylabel="y"),
  17. Legend=(framecolor=(:black, 0.5), bgcolor=(:white, 0.5)),
  18. Colorbar=(ticksize=16, tickalign=1, spinewidth=0.5),
  19. )
  20. end

And apply it to a plotting function like the following:

  1. function scatters_and_lines()
  2. x = collect(0:10)
  3. xh = LinRange(4, 6, 25)
  4. yh = LinRange(70, 95, 25)
  5. h = randn(25, 25)
  6. fig = Figure(resolution=(600, 400), font="CMU Serif")
  7. ax = Axis(fig[1, 1], xlabel=L"x", ylabel=L"f(x,a)")
  8. for i in x
  9. lines!(ax, x, i .* x; label=latexstring("$(i) x"))
  10. scatter!(ax, x, i .* x; markersize=13, strokewidth=0.25,
  11. label=latexstring("$(i) x"))
  12. end
  13. hm = heatmap!(xh, yh, h)
  14. axislegend(L"f(x)"; merge=true, position=:lt, nbanks=2, labelsize=14)
  15. Colorbar(fig[1, 2], hm, label="new default colormap")
  16. limits!(ax, -0.5, 10.5, -5, 105)
  17. colgap!(fig.layout, 5)
  18. fig
  19. end
  1. with_theme(scatters_and_lines, new_cycle_theme())

Figure 26: Custom theme with new cycle and colormap.

Figure 26: Custom theme with new cycle and colormap.

At this point you should be able to have complete control over your colors, line styles, markers and colormaps for your plots. Next, we will dive into how to manage and control layouts.

6.5 Colors and Colormaps - 图7 Support this project
CC BY-NC-SA 4.0 Jose Storopoli, Rik Huijzer, Lazaro Alonso