Skip to content

Commit 3e715b5

Browse files
committed
Add title, subtitle and footnotes option
1 parent 623bd2a commit 3e715b5

8 files changed

+251
-1
lines changed

docs/src/layers/draw.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,33 @@ If you want to add a title to a merged group, you can add it with the `group =>
332332
```@example legendorder2
333333
draw(spec1 + spec2_custom_scale; legend = (; order = [[:Color, :color2] => "Title"]))
334334
```
335+
336+
## Figure options
337+
338+
AlgebraOfGraphics can add a title, subtitle and footnotes to a figure automatically.
339+
Settings for these must be passed to the `figure` keyword.
340+
Check the [`draw`](@ref) function for a complete list.
341+
342+
```@example
343+
using AlgebraOfGraphics
344+
using CairoMakie
345+
346+
spec = pregrouped(
347+
fill(1:5, 6),
348+
fill(11:15, 6),
349+
[reshape(sin.(1:25), 5, 5) .+ i for i in 1:6],
350+
layout = 1:6 => nonnumeric) * visual(Heatmap)
351+
352+
draw(
353+
spec;
354+
figure = (;
355+
title = "Numbers in square configuration",
356+
subtitle = "Arbitrary data exhibits sinusoidal properties",
357+
footnotes = [
358+
rich(superscript("1"), "First footnote"),
359+
rich(superscript("2"), "Second ", rich("footnote", color = :red)),
360+
],
361+
),
362+
axis = (; width = 100, height = 100)
363+
)
364+
```

src/draw.jl

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@ arguments of either `legend` or `colorbar`.
4646
4747
For finer control, use [`draw!`](@ref),
4848
[`legend!`](@ref), and [`colorbar!`](@ref) independently.
49+
50+
## Figure options
51+
52+
AlgebraOfGraphics accepts the following special keywords under the `figure` keyword,
53+
the remaining attributes are forwarded to Makie's `Figure` constructor.
54+
The `title`, `subtitle` and `footnotes` arguments accept objects of any kind that Makie's
55+
`Label` or `text` function can handle, such as `rich` text.
56+
57+
- `title`
58+
- `subtitle`
59+
- `titlesize::Union{Nothing,Float64}`
60+
- `subtitlesize::Union{Nothing,Float64}`
61+
- `titlealign::Union{Nothing,Symbol}`
62+
- `titlecolor`
63+
- `subtitlecolor`
64+
- `titlefont`
65+
- `subtitlefont`
66+
- `titlelineheight`
67+
- `subtitlelineheight`
68+
- `footnotes::Union{Nothing,Vector{Any}}`
69+
- `footnotesize::Union{Nothing,Float64}`
70+
- `footnotefont`
71+
- `footnotecolor`
72+
- `footnotealign`
73+
- `footnotelineheight`
4974
"""
5075
function draw(d::AbstractDrawable, scales::Scales = scales();
5176
axis=NamedTuple(), figure=NamedTuple(),
@@ -62,10 +87,78 @@ end
6287

6388
_remove_show_kw(pairs) = filter(((key, value),) -> key !== :show, pairs)
6489

90+
struct FigureSettings
91+
title
92+
subtitle
93+
titlesize::Union{Nothing,Float64}
94+
subtitlesize::Union{Nothing,Float64}
95+
titlealign::Union{Nothing,Symbol}
96+
titlecolor
97+
subtitlecolor
98+
titlefont
99+
subtitlefont
100+
titlelineheight
101+
subtitlelineheight
102+
footnotes::Union{Nothing,Vector{Any}}
103+
footnotesize::Union{Nothing,Float64}
104+
footnotefont
105+
footnotecolor
106+
footnotealign
107+
footnotelineheight
108+
end
109+
110+
function figure_settings(;
111+
title = nothing,
112+
subtitle = nothing,
113+
titlefont = nothing,
114+
subtitlefont = nothing,
115+
titlecolor = nothing,
116+
subtitlecolor = nothing,
117+
titlesize = nothing,
118+
subtitlesize = nothing,
119+
titlealign = nothing,
120+
titlelineheight = nothing,
121+
subtitlelineheight = nothing,
122+
footnotes = nothing,
123+
footnotesize = nothing,
124+
footnotefont = nothing,
125+
footnotecolor = nothing,
126+
footnotealign = nothing,
127+
footnotelineheight = nothing,
128+
kwargs...,
129+
)
130+
131+
f = FigureSettings(
132+
title,
133+
subtitle,
134+
titlesize,
135+
subtitlesize,
136+
titlealign,
137+
titlecolor,
138+
subtitlecolor,
139+
titlefont,
140+
subtitlefont,
141+
titlelineheight,
142+
subtitlelineheight,
143+
footnotes,
144+
footnotesize,
145+
footnotefont,
146+
footnotecolor,
147+
footnotealign,
148+
footnotelineheight,
149+
)
150+
151+
return f, kwargs
152+
end
153+
65154
function _draw(d::AbstractDrawable, scales::Scales;
66155
axis, figure, facet, legend, colorbar)
67156

68-
return update(Figure(; pairs(figure)...)) do f
157+
fs, remaining_figure_kw = figure_settings(; pairs(figure)...)
158+
159+
_filter_nothings(; kwargs...) = (key => value for (key, value) in kwargs if value !== nothing)
160+
161+
return update(Figure(; pairs(remaining_figure_kw)...)) do f
69162
grid = plot!(f, d, scales; axis)
70163
fg = FigureGrid(f, grid)
71164
facet!(fg; facet)
@@ -75,6 +168,25 @@ function _draw(d::AbstractDrawable, scales::Scales;
75168
if get(legend, :show, true)
76169
legend!(fg; _remove_show_kw(pairs(legend))...)
77170
end
171+
172+
base_fontsize = Makie.theme(fg.figure.scene)[:fontsize][]
173+
174+
if fs.subtitle !== nothing
175+
Label(fg.figure[begin-1, :], fs.subtitle; tellwidth = false, halign = :left, _filter_nothings(; font = fs.subtitlefont, color = fs.subtitlecolor, fontsize = fs.subtitlesize, halign = fs.titlealign, lineheight = fs.subtitlelineheight)...)
176+
end
177+
if fs.title !== nothing
178+
Label(fg.figure[begin-1, :], fs.title; tellwidth = false, fontsize = base_fontsize * 1.15, font = :bold, halign = :left, _filter_nothings(; font = fs.titlefont, color = fs.titlecolor, fontsize = fs.titlesize, halign = fs.titlealign, lineheight = fs.titlelineheight)...)
179+
end
180+
if fs.subtitle !== nothing
181+
fg.figure.layout.addedrowgaps[1] = Fixed(0)
182+
end
183+
if fs.footnotes !== nothing
184+
fgl = GridLayout(fg.figure[end+1, :]; halign = :left, _filter_nothings(; halign = fs.footnotealign)...)
185+
for (i, note) in enumerate(fs.footnotes)
186+
Label(fgl[i, 1], note; tellwidth = false, halign = :left, fontsize = base_fontsize / 1.15, _filter_nothings(; halign = fs.footnotealign, font = fs.footnotefont, color = fs.footnotecolor, fontsize = fs.footnotesize, lineheight = fs.footnotelineheight)...)
187+
end
188+
fgl.addedrowgaps .= Ref(Fixed(0))
189+
end
78190
resize_to_layout!(fg)
79191
return fg
80192
end

test/reference_tests.jl

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,4 +793,112 @@ reftest("categorical color from continuous") do
793793
legend!(f[i, 2], fg, nbanks = 2)
794794
end
795795
f
796+
end
797+
798+
reftest("title subtitle footnotes") do
799+
spec = pregrouped(
800+
fill(1:5, 6),
801+
fill(11:15, 6),
802+
[reshape(sin.(1:25), 5, 5) .+ i for i in 1:6],
803+
layout = 1:6 => nonnumeric) * visual(Heatmap)
804+
805+
draw(
806+
spec;
807+
figure = (;
808+
title = "Numbers in square configuration",
809+
subtitle = "Arbitrary data exhibits sinusoidal properties",
810+
footnotes = [
811+
rich(superscript("1"), "First footnote"),
812+
rich(superscript("2"), "Second ", rich("footnote", color = :red)),
813+
],
814+
),
815+
axis = (; width = 100, height = 100)
816+
)
817+
end
818+
819+
reftest("title subtitle footnotes single unconstrained facet") do
820+
spec = data((; x = 1:10, y = 11:20)) * mapping(:x, :y) * visual(Scatter)
821+
draw(
822+
spec;
823+
figure = (;
824+
title = "Some title",
825+
subtitle = "Some subtitle",
826+
footnotes = [
827+
rich(superscript("1"), "First footnote"),
828+
rich(superscript("2"), "Second ", rich("footnote", color = :red)),
829+
],
830+
),
831+
)
832+
end
833+
834+
reftest("title") do
835+
spec = pregrouped(
836+
fill(1:5, 6),
837+
fill(11:15, 6),
838+
[reshape(sin.(1:25), 5, 5) .+ i for i in 1:6],
839+
layout = 1:6 => nonnumeric) * visual(Heatmap)
840+
841+
draw(
842+
spec;
843+
figure = (;
844+
title = "Numbers in square configuration",
845+
),
846+
axis = (; width = 100, height = 100)
847+
)
848+
end
849+
850+
reftest("title subtitle footnotes settings") do
851+
spec = pregrouped(
852+
fill(1:5, 6),
853+
fill(11:15, 6),
854+
[reshape(sin.(1:25), 5, 5) .+ i for i in 1:6],
855+
layout = 1:6 => nonnumeric) * visual(Heatmap)
856+
857+
draw(
858+
spec;
859+
figure = (;
860+
title = "Numbers in square configuration",
861+
titlefont = :italic,
862+
titlesize = 20,
863+
titlecolor = :orange,
864+
subtitle = "Arbitrary data exhibits sinusoidal properties",
865+
subtitlefont = :bold_italic,
866+
subtitlesize = 10,
867+
subtitlecolor = :brown,
868+
titlealign = :right,
869+
footnotes = [
870+
rich(superscript("1"), "First footnote"),
871+
rich(superscript("2"), "Second ", rich("footnote", color = :red)),
872+
],
873+
footnotefont = :bold,
874+
footnotecolor = :blue,
875+
footnotesize = 20,
876+
footnotealign = :right,
877+
),
878+
axis = (; width = 100, height = 100)
879+
)
880+
881+
end
882+
883+
reftest("title subtitle footnotes fontsize inherit") do
884+
spec = pregrouped(
885+
fill(1:5, 6),
886+
fill(11:15, 6),
887+
[reshape(sin.(1:25), 5, 5) .+ i for i in 1:6],
888+
layout = 1:6 => nonnumeric) * visual(Heatmap)
889+
890+
draw(
891+
spec;
892+
figure = (;
893+
fontsize = 20,
894+
title = "Numbers in square configuration",
895+
subtitle = "Arbitrary data exhibits sinusoidal properties",
896+
footnotes = [
897+
rich(superscript("1"), "First footnote"),
898+
rich(superscript("2"), "Second ", rich("footnote", color = :red)),
899+
],
900+
),
901+
axis = (; width = 100, height = 100)
902+
)
903+
796904
end

test/reference_tests/title ref.png

13.9 KB
Loading
28.4 KB
Loading
20.6 KB
Loading
24 KB
Loading
13.7 KB
Loading

0 commit comments

Comments
 (0)