Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rich text #2321

Merged
merged 47 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
d45299c
add first implementation of rich text via tree of nodes
jkrumbiegel Oct 8, 2022
31e9c94
Merge branch 'master' into jk/rich-text
jkrumbiegel Oct 9, 2022
f3694b1
add lineheight, alignment, justification
jkrumbiegel Oct 9, 2022
68a6325
rename RTFNode to RT
jkrumbiegel Oct 11, 2022
5af625b
add :span as default, feed in color
jkrumbiegel Oct 11, 2022
55cac85
use span, superscript, subscript
jkrumbiegel Oct 11, 2022
2d87ebd
allow stacking super and subscript
jkrumbiegel Oct 11, 2022
566c266
add fontset type
jkrumbiegel Oct 11, 2022
ab0b0c6
add fontset and first docs entry
jkrumbiegel Oct 11, 2022
38cb03f
move inner constructor out
jkrumbiegel Oct 11, 2022
ba82c78
remove Makie. qualifier
jkrumbiegel Oct 11, 2022
26dc806
Merge branch 'master' into jk/rich-text
jkrumbiegel Oct 23, 2022
b8bb3d4
switch to Attributes for `fonts`
jkrumbiegel Oct 23, 2022
554b562
improve error message
jkrumbiegel Oct 23, 2022
5b93ca5
remove all font field typings for Blocks
jkrumbiegel Oct 23, 2022
ec78baa
change to RichText / rich
jkrumbiegel Oct 23, 2022
8af97a3
improve docs
jkrumbiegel Oct 24, 2022
1c96794
add fonts section
jkrumbiegel Oct 24, 2022
18f45c6
fix glmakie precompile
jkrumbiegel Oct 24, 2022
40a3e42
fix block
jkrumbiegel Oct 24, 2022
78eb825
show outputs
jkrumbiegel Oct 24, 2022
cfa6b30
replace explicit font mentions
jkrumbiegel Oct 24, 2022
6e24f0b
change default font to :regular
jkrumbiegel Oct 24, 2022
198a6ad
Merge branch 'master' into jk/rich-text
jkrumbiegel Oct 24, 2022
582ca03
use rich text for logtick superscripts
jkrumbiegel Oct 24, 2022
65fa6bd
use minus glyph instead of hyphen for ticks
jkrumbiegel Oct 25, 2022
da1e49d
change to dejavu because times doesn't exist
jkrumbiegel Oct 25, 2022
e14a80e
fix vertical center align
jkrumbiegel Oct 25, 2022
a36939d
smaller fontsize
jkrumbiegel Oct 25, 2022
bbbe8cd
remove minus replacement again
jkrumbiegel Oct 28, 2022
7daa2bd
add show method for RichText
jkrumbiegel Oct 28, 2022
112117b
use String instead
jkrumbiegel Oct 28, 2022
14f6fd2
add ability to set fontsize
jkrumbiegel Oct 28, 2022
a92ea49
add xshift and yshift
jkrumbiegel Oct 28, 2022
ab4ea3b
use offset instead
jkrumbiegel Oct 28, 2022
9d82278
add offset example
jkrumbiegel Oct 28, 2022
4339e3e
add test, fix rotation, add section about sub/superscripts
jkrumbiegel Oct 28, 2022
3c9a1cf
fix test syntax
jkrumbiegel Oct 28, 2022
701765e
fix example block syntax
jkrumbiegel Oct 28, 2022
9447087
cleanup type names and "Makie."
ffreyer Nov 2, 2022
f93d157
capitalize string to make fontsize changes more obvious
ffreyer Nov 2, 2022
7636732
Merge branch 'master' into jk/rich-text
SimonDanisch Nov 11, 2022
9c1d079
Merge branch 'master' into jk/rich-text
jkrumbiegel Nov 23, 2022
3f82104
remove super-subscript stacking (for now)
jkrumbiegel Nov 23, 2022
60ccd21
Merge branch 'master' into jk/rich-text
jkrumbiegel Nov 23, 2022
b6c035f
add resolution to test image
jkrumbiegel Nov 23, 2022
ff7b065
Merge branch 'jk/release-v0.19' into jk/rich-text
jkrumbiegel Nov 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion MakieCore/src/basic_plots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ Plots one or multiple texts passed via the `text` keyword.

- `text` specifies one piece of text or a vector of texts to show, where the number has to match the number of positions given. Makie supports `String` which is used for all normal text and `LaTeXString` which layouts mathematical expressions using `MathTeXEngine.jl`.
- `align::Tuple{Union{Symbol, Real}, Union{Symbol, Real}} = (:left, :bottom)` sets the alignment of the string w.r.t. `position`. Uses `:left, :center, :right, :top, :bottom, :baseline` or fractions.
- `font::Union{String, Vector{String}} = "TeX Gyre Heros Makie"` sets the font for the string or each character.
- `font::Union{String, Vector{String}} = :regular` sets the font for the string or each character.
- `justification::Union{Real, Symbol} = automatic` sets the alignment of text w.r.t its bounding box. Can be `:left, :center, :right` or a fraction. Will default to the horizontal alignment in `align`.
- `rotation::Union{Real, Quaternion}` rotates text around the given position.
- `fontsize::Union{Real, Vec2f}` sets the size of each character.
Expand Down Expand Up @@ -517,6 +517,7 @@ Plots one or multiple texts passed via the `text` keyword.
default_theme(scene)...,
color = theme(scene, :textcolor),
font = theme(scene, :font),
fonts = theme(scene, :fonts),
strokecolor = (:black, 0.0),
strokewidth = 0,
align = (:left, :bottom),
Expand Down
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
RelocatableFolders = "05181044-ff0b-4ac5-8273-598c1e38db00"
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"
Showoff = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
SignedDistanceFields = "73760f76-fbc4-59ce-8f25-708e95d2df96"
SnoopPrecompile = "66db9d55-30c0-4569-8b51-7e840670fc0c"
Expand Down Expand Up @@ -77,8 +78,8 @@ KernelDensity = "0.5, 0.6"
LaTeXStrings = "1.2"
MakieCore = "=0.5.2"
Match = "1.1"
MiniQhull = "0.4"
MathTeXEngine = "0.5"
MiniQhull = "0.4"
Observables = "0.5.3"
OffsetArrays = "1"
Packing = "0.4"
Expand Down
15 changes: 15 additions & 0 deletions ReferenceTests/src/tests/examples2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -761,3 +761,18 @@ end
ax.yticks = ([3, 6, 9], [L"x" , L"y" , L"z"])
f
end

@reference_test "Rich text" begin
f = Figure(fontsize = 30, resolution = (800, 600))
ax = Axis(f[1, 1],
limits = (1, 100, 0.001, 1),
xscale = log10,
yscale = log2,
title = rich("A ", rich("title", color = :red, font = :bold_italic)),
xlabel = rich("X", subscript("label", fontsize = 25)),
ylabel = rich("Y", superscript("label")),
)
Label(f[1, 2], rich("Hi", rich("Hi", offset = (0.2, 0.2), color = :blue)), tellheight = false)
Label(f[1, 3], rich("X", superscript("super"), subscript("sub")), tellheight = false)
f
end
60 changes: 60 additions & 0 deletions docs/documentation/fonts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Fonts

Makie uses the `FreeType.jl` package for font support, therefore, most fonts that this package can load should be supported by Makie as well.
Fonts can be selected in multiple different ways:

## String

If you pass a `String` as a font, this can either be resolved as a file name for a font file, or as the (partial) name of the font itself (font family plus style).
Font name matching is case insensitive and accepts partial matches.

```julia
font_by_path = "/some/path/to/a/font_file.ttf"
font_by_name = "TeX Gyre Heros Makie"
```

If you want to find out what exact font your string was resolved as, you can execute `Makie.to_font(the_string)`:

```julia:fonts1
using Makie
Makie.to_font("Blackchancery")
```
\show{fonts1}

## Symbol

A `Symbol` will be resolved by looking it up in the `text`'s `fonts` attribute.
The default theme has the following fonts set:

```julia:fonts2
using Makie
Makie.current_default_theme()[:fonts]
```
\show{fonts2}

Therefore, you can pick a font from this set by setting, for example, `font = :bold_italic`.
The advantage of this is that you can set your fonts not by hardcoding specific ones at every place where you use `text`, but by setting the fonts at the top level.

You can modify or add keys in the font set using `set_theme!`, `with_theme`, `update_theme!`, or by passing them to the `Figure` constructor.
Here's an example:

\begin{examplefigure}{svg = true}
```julia
using CairoMakie
CairoMakie.activate!() # hide
Makie.inline!(true) # hide

f = Figure(fontsize = 24, fonts = (; regular = "Dejavu", weird = "Blackchancery"))
Axis(f[1, 1], title = "A title", xlabel = "An x label", xlabelfont = :weird)

f
```
\end{examplefigure}

## Emoji and color fonts

Currently, Makie does not have the ability to draw emoji or other color fonts.
This is due to the implementation of text drawing in GLMakie and WGLMakie, which relies on signed distance fields that can only be used to render monochrome glyphs, but not arbitrary bitmaps.
If you want to use emoji as scatter markers, consider using images (you will need to find suitable images separately, you cannot easily extract emoji from fonts with Makie).


4 changes: 2 additions & 2 deletions docs/examples/blocks/axis.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ Axis(
f[2, 1],
title = "Third Title",
titlecolor = :gray50,
titlefont = "TeX Gyre Heros Bold Italic Makie",
titlefont = :bold_italic,
titlealign = :right,
titlesize = 25,
)
Expand All @@ -200,7 +200,7 @@ Axis(
titlealign = :left,
subtitlegap = 2,
titlegap = 5,
subtitlefont = "TeX Gyre Heros Italic Makie",
subtitlefont = :italic,
subtitlelineheight = 0.9,
titlelineheight = 0.9,
)
Expand Down
73 changes: 73 additions & 0 deletions docs/examples/plotting_functions/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,76 @@ Legend(f[1, 2], ax)
f
```
\end{examplefigure}

## Rich text

With rich text, you can conveniently plot text whose parts have different colors or fonts, and you can position sections as subscripts and superscripts.
You can create such rich text objects using the functions `rich`, `superscript` and `subscript`, all of which create `RichText` objects.

Each of these functions takes a variable number of arguments, each of which can be a `String` or `RichText`.
Each can also take keyword arguments such as `color` or `font`, to set these attributes for the given part.
The top-level settings for font, color, etc. are taken from the `text` attributes as usual.

\begin{examplefigure}{svg = true}
```julia
using CairoMakie
CairoMakie.activate!() # hide
Makie.inline!(true) # hide

f = Figure(fontsize = 30)
Label(
f[1, 1],
rich(
"H", subscript("2"), "O is the formula for ",
rich("water", color = :cornflowerblue, font = :italic)
)
)

str = "A BEAUTIFUL RAINBOW"
rainbow = cgrad(:rainbow, length(str), categorical = true)
fontsizes = 30 .+ 10 .* sin.(range(0, 3pi, length = length(str)))

rainbow_chars = map(enumerate(str)) do (i, c)
rich("$c", color = rainbow[i], fontsize = fontsizes[i])
end

Label(f[2, 1], rich(rainbow_chars...), font = :bold)

f
```
\end{examplefigure}

### Tweaking offsets

Sometimes, when using regular and italic fonts next to each other, the gaps between glyphs are too narrow or too wide.
You can use the `offset` value for rich text to shift glyphs by an amount proportional to the fontsize.


\begin{examplefigure}{svg = true}
```julia
using CairoMakie
CairoMakie.activate!() # hide
Makie.inline!(true) # hide

f = Figure(fontsize = 30)
Label(
f[1, 1],
rich(
"ITALIC",
superscript("Regular without x offset", font = :regular),
font = :italic
)
)

Label(
f[2, 1],
rich(
"ITALIC",
superscript("Regular with x offset", font = :regular, offset = (0.15, 0)),
font = :italic
)
)

f
```
\end{examplefigure}
12 changes: 6 additions & 6 deletions docs/tutorials/layout-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ colgap!(ga, 10)
rowgap!(ga, 10)

Label(ga[1, 1:2, Top()], "Stimulus ratings", valign = :bottom,
font = "TeX Gyre Heros Bold",
font = :bold,
padding = (0, 0, 5, 0))

xs = LinRange(0.5, 6, 50)
Expand Down Expand Up @@ -111,7 +111,7 @@ axs[3, 1].xlabel = "Day 1"
axs[3, 2].xlabel = "Day 2"

Label(gd[1, :, Top()], "EEG traces", valign = :bottom,
font = "TeX Gyre Heros Bold",
font = :bold,
padding = (0, 0, 5, 0))

rowgap!(gd, 10)
Expand All @@ -133,7 +133,7 @@ colsize!(gd, 2, Auto(n_day_2))
for (label, layout) in zip(["A", "B", "C", "D"], [ga, gb, gc, gd])
Label(layout[1, 1, TopLeft()], label,
fontsize = 26,
font = "TeX Gyre Heros Bold",
font = :bold,
padding = (0, 5, 5, 0),
halign = :right)
end
Expand Down Expand Up @@ -283,7 +283,7 @@ We can make a title by placing a label across the top two elements.
\begin{examplefigure}{px_per_unit = 1.5}
```julia
Label(ga[1, 1:2, Top()], "Stimulus ratings", valign = :bottom,
font = "TeX Gyre Heros Bold",
font = :bold,
padding = (0, 0, 5, 0))

f
Expand Down Expand Up @@ -413,7 +413,7 @@ We can make a little title for the six axes by placing a `Label` in the top prot
\begin{examplefigure}{px_per_unit = 1.5}
```julia
Label(gd[1, :, Top()], "EEG traces", valign = :bottom,
font = "TeX Gyre Heros Bold",
font = :bold,
padding = (0, 0, 5, 0))

f
Expand Down Expand Up @@ -485,7 +485,7 @@ That will leave all other alignments intact, because we're not creating any new
for (label, layout) in zip(["A", "B", "C", "D"], [ga, gb, gc, gd])
Label(layout[1, 1, TopLeft()], label,
fontsize = 26,
font = "TeX Gyre Heros Bold",
font = :bold,
padding = (0, 5, 5, 0),
halign = :right)
end
Expand Down
15 changes: 8 additions & 7 deletions src/Makie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import FileIO
import SparseArrays
import TriplotBase
import MiniQhull
import Setfield

using IntervalSets: IntervalSets, (..), OpenInterval, ClosedInterval, AbstractInterval, Interval, endpoints
using FixedPointNumbers: N0f8
Expand Down Expand Up @@ -88,6 +89,9 @@ const RGBAf = RGBA{Float32}
const RGBf = RGB{Float32}
const NativeFont = FreeTypeAbstraction.FTFont

const ASSETS_DIR = RelocatableFolders.@path joinpath(@__DIR__, "..", "assets")
assetpath(files...) = normpath(joinpath(ASSETS_DIR, files...))

include("documentation/docstringextension.jl")
include("utilities/quaternions.jl")
include("bezier.jl")
Expand All @@ -101,16 +105,16 @@ include("utilities/utilities.jl") # need Makie.AbstractPattern
# Basic scene/plot/recipe interfaces + types
include("scenes.jl")

include("interfaces.jl")
include("conversions.jl")
include("units.jl")
include("shorthands.jl")
include("theming.jl")
include("themes/theme_ggplot2.jl")
include("themes/theme_black.jl")
include("themes/theme_minimal.jl")
include("themes/theme_light.jl")
include("themes/theme_dark.jl")
include("interfaces.jl")
include("units.jl")
include("conversions.jl")
include("shorthands.jl")

# camera types + functions
include("camera/projection_math.jl")
Expand Down Expand Up @@ -273,9 +277,6 @@ export cgrad, available_gradients, showgradients

export Pattern

const ASSETS_DIR = RelocatableFolders.@path joinpath(@__DIR__, "..", "assets")
assetpath(files...) = normpath(joinpath(ASSETS_DIR, files...))

export assetpath
# default icon for Makie
function icon()
Expand Down
8 changes: 4 additions & 4 deletions src/basic_recipes/axis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ $(ATTRIBUTES)
scale = Vec3f(1),
padding = 0.1,
inspectable = false,

fonts = theme(scene, :fonts),
names = Attributes(
axisnames = ("x", "y", "z"),
textcolor = (:black, :black, :black),
Expand Down Expand Up @@ -222,7 +222,7 @@ to3tuple(x::Tuple{Any, Any}) = (x[1], x[2], x[2])
to3tuple(x::Tuple{Any, Any, Any}) = x
to3tuple(x) = ntuple(i-> x, Val(3))

function draw_axis3d(textbuffer, linebuffer, scale, limits, ranges_labels, args...)
function draw_axis3d(textbuffer, linebuffer, scale, limits, ranges_labels, fonts, args...)
# make sure we extend all args to 3D
ranges, ticklabels = ranges_labels
args3d = to3tuple.(args)
Expand Down Expand Up @@ -284,7 +284,7 @@ function draw_axis3d(textbuffer, linebuffer, scale, limits, ranges_labels, args.
end
end
if !isempty(axisnames[i])
font = to_font(tfont[i])
font = to_font(fonts, tfont[i])
tick_widths = maximum(ticklabels[i]) do label
widths(text_bb(label, font, tfontsize[i]))[1]
end / scale[j]
Expand Down Expand Up @@ -337,7 +337,7 @@ function plot!(scene::SceneLike, ::Type{<: Axis3D}, attributes::Attributes, args
map_once(
draw_axis3d,
Observable(textbuffer), Observable(linebuffer), scale(scene),
axis[1], axis.ticks.ranges_labels, args...
axis[1], axis.ticks.ranges_labels, Observable(axis.fonts), args...
)
push!(scene, axis)
return axis
Expand Down
6 changes: 5 additions & 1 deletion src/basic_recipes/buffers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ function append!(tb::Annotations, text_positions::Vector{Tuple{String, Point{N,
isempty(tb[key][]) && error("please provide default for $key")
return last(tb[key][])
end
val_vec = same_length_array(text_positions, val, Key{key}())
val_vec = if key === :font
same_length_array(text_positions, to_font(tb.fonts, val))
else
same_length_array(text_positions, val, Key{key}())
end
append!(tb[key][], val_vec)
end
return
Expand Down
Loading