Skip to content

Commit

Permalink
Update for Makie v0.20 (#45)
Browse files Browse the repository at this point in the history
* Update for new Makie

* Add more docstrings and comments

* Rename `text_override.jl` to `text_utils.jl`

* fix

* Fix init and tests.

* Fix tests
  • Loading branch information
asinghvi17 authored Feb 16, 2024
1 parent 8e97853 commit 48449fe
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 60 deletions.
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "MakieTeX"
uuid = "6d554a22-29e7-47bd-aee5-0c5f06619414"
authors = ["Anshul Singhvi"]
version = "0.3.1"
version = "0.3.2"

[deps]
Cairo = "159f3aea-2a34-519c-b102-8c37f9878175"
Expand All @@ -18,11 +18,11 @@ tectonic_jll = "d7dd28d6-a5e6-559c-9131-7eb760cdacc5"

[compat]
Cairo = "1.0.5"
CairoMakie = "0.10"
CairoMakie = "0.11"
Colors = "0.9, 0.10, 0.11, 0.12"
DocStringExtensions = "0.8, 0.9"
LaTeXStrings = "1"
Makie = "0.18, 0.19"
Makie = "0.20"
Poppler_jll = "21.9"
julia = "1"

Expand Down
50 changes: 33 additions & 17 deletions src/MakieTeX.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const TEXT_RENDER_DENSITY = Ref(5)
include("types.jl")
include("rendering.jl")
include("recipe.jl")
include("text_override.jl")
include("text_utils.jl")
include("layoutable.jl")

export TeXDocument, CachedTeX
Expand All @@ -51,6 +51,8 @@ end

"Checks whether the default latex engine is correct"
function __init__()

# First, determine latex engine support
latexmk = Sys.which("latexmk")
if isnothing(latexmk)
@warn """
Expand All @@ -61,25 +63,39 @@ function __init__()
Defaulting to the bundled `tectonic` renderer for now.
"""
CURRENT_TEX_ENGINE[] = `tectonic`
return
else
t1 = try_tex_engine(CURRENT_TEX_ENGINE[]) # by default `lualatex`

if !isnothing(t1)

@warn("""
The specified TeX engine $(CURRENT_TEX_ENGINE[]) is not available.
Trying pdflatex:
"""
)

CURRENT_TEX_ENGINE[] = `pdflatex`
else
return
end

t2 = try_tex_engine(CURRENT_TEX_ENGINE[])
if !isnothing(t2)

@warn "Could not find a TeX engine; defaulting to bundled `tectonic`"
CURRENT_TEX_ENGINE[] = `tectonic`
else
return
end

end

t1 = try_tex_engine(CURRENT_TEX_ENGINE[])
isnothing(t1) && return

@warn("""
The specified TeX engine $(CURRENT_TEX_ENGINE[]) is not available.
Trying pdflatex:
"""
)

CURRENT_TEX_ENGINE[] = `pdflatex`

t2 = try_tex_engine(CURRENT_TEX_ENGINE[])
isnothing(t1) && return


# TODO: Once the correct tex engine is found, load the rendering extensions
# (currently CairoMakie, but we may do WGLMakie in the future since it can display SVG)


@warn "Could not find a TeX engine; defaulting to bundled `tectonic`"
CURRENT_TEX_ENGINE[] = `tectonic`
return
end

Expand Down
18 changes: 9 additions & 9 deletions src/layoutable.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Makie.MakieLayout: inherit
import Makie: inherit

# This code has basically been adapted from the Label code in the main repo.

Makie.MakieLayout.@Block LTeX begin
Makie.@Block LTeX begin
@attributes begin
"The LaTeX code to be compiled and drawn. Can be a String, a TeXDocument or a CachedTeX."
tex = "\\LaTeX"
Expand Down Expand Up @@ -35,7 +35,7 @@ end

LTeX(x, tex; kwargs...) = LTeX(x; tex = tex, kwargs...)

function Makie.MakieLayout.initialize_block!(l::LTeX)
function Makie.initialize_block!(l::LTeX)

topscene = l.blockscene
layoutobservables = l.layoutobservables
Expand All @@ -55,24 +55,24 @@ function Makie.MakieLayout.initialize_block!(l::LTeX)
textbb = Ref(BBox(0, 1, 0, 1))

onany(l.tex, l.scale, l.rotation, l.padding) do tex, scale, rotation, padding
textbb[] = Makie.rotatedrect(Makie.MakieLayout.Rect2f(0,0,(t[1][][1].dims .* scale)...), rotation)
autowidth = Makie.MakieLayout.width(textbb[]) + padding[1] + padding[2]
autoheight = Makie.MakieLayout.height(textbb[]) + padding[3] + padding[4]
textbb[] = Makie.rotatedrect(Makie.Rect2f(0,0,(t[1][][1].dims .* scale)...), rotation)
autowidth = Makie.width(textbb[]) + padding[1] + padding[2]
autoheight = Makie.height(textbb[]) + padding[3] + padding[4]
layoutobservables.autosize[] = (autowidth, autoheight)
end

onany(layoutobservables.computedbbox, l.padding) do bbox, padding

tw = Makie.MakieLayout.width(textbb[])
th = Makie.MakieLayout.height(textbb[])
tw = Makie.width(textbb[])
th = Makie.height(textbb[])

box = bbox.origin[1]
boy = bbox.origin[2]

tx = box + padding[1] + 0.5 * tw
ty = boy + padding[3] + 0.5 * th

textpos[] = Makie.MakieLayout.Point3f[(tx, ty, 0)]
textpos[] = Makie.Point3f[(tx, ty, 0)]
end


Expand Down
78 changes: 63 additions & 15 deletions src/recipe.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@
# scale::Real
# render_density::Real
# rotations::Vector{Real}
"""
teximg(tex; position, ...)
teximg!(ax_or_scene, tex; position, ...)
This recipe plots rendered `TeX` to your Figure or Scene.
There are three types of input you can provide:
- Any `String`, which is rendered to LaTeX cognizant of the figure's overall theme,
- A [`TeXDocument`](@ref) object, which is rendered to LaTeX directly, and can be customized by the user,
- A [`CachedTeX`](@ref) object, which is a pre-rendered LaTeX document.
`tex` may be a single one of these objects, or an array of them.
## Attributes
$(Makie.ATTRIBUTES)
"""
@recipe(TeXImg, tex) do scene
merge(
default_theme(scene),
Expand All @@ -17,6 +33,34 @@
)
end

# First, handle the case of one or more abstract strings passed in!
# These are themable.

# Makie.used_attributes(::Type{<: TeXImg}, string_s::Union{<: AbstractString, AbstractVector{<: AbstractString}}) = (:font, :fontsize, :justification, :color, :word_wrap_width, :lineheight)
# Makie.convert_arguments(::Type{<: TeXImg}, string::AbstractString) = Makie.convert_arguments(TeXImg, [string])

# function Makie.convert_arguments(
# ::Type{<: TeXImg},
# strings::AbstractVector{<: AbstractString};
# font = Makie.texfont(),
# fontsize = 14,
# justification = Makie.automatic,
# color = :black,
# word_wrap_width = -1,
# lineheight = 1.0,
# )

# # This function will convert the strings to CachedTeX, so that it can track changes in attributes.
# # It will have to handle the case where the parameters given are for all strings in an array, or per string,
# # using Makie's `broadcast_foreach` function.

# # First, we need to convert the strings to CachedTeX.
# # This is done by using the `CachedTeX` constructor, which will render the LaTeX and store it in a CachedTeX object.
# # This is then stored in an array, which is then returned.


# end

function Makie.boundingbox(x::T) where T <: TeXImg
Makie.boundingbox(
x[1][] isa CachedTeX ? [x[1][]] : x[1][],
Expand Down Expand Up @@ -63,7 +107,7 @@ function Makie.plot!(plot::T) where T <: TeXImg
# We always want to draw this at a 1:1 ratio, so increasing scale or
# changing dpi should rerender
plottable_images = lift(plot[1], plot.render_density, plot.scale) do cachedtex, render_density, scale
to_array(firstpage2img((cachedtex); render_density = render_density * scale))
to_array(firstpage2img.((cachedtex); render_density = render_density * scale))
end

scatter_images = Observable(plottable_images[])
Expand All @@ -77,7 +121,7 @@ function Makie.plot!(plot::T) where T <: TeXImg
onany(plottable_images, plot.position, plot.rotations, plot.align, plot.scale) do images, pos, rotations, align, scale
if length(images) != length(pos)
# skip this update and let the next one propagate
@debug "Length of images ($(length(images))) != length of positions ($(length(pos))). Skipping this update."
@debug "TexImg: Length of images ($(length(images))) != length of positions ($(length(pos))). Skipping this update."
return
end

Expand All @@ -94,7 +138,7 @@ function Makie.plot!(plot::T) where T <: TeXImg
notify(scatter_rotations)
end

plot.position[] = plot.position[]
notify(plot.position) # trigger the first update

scatter!(
plot,
Expand All @@ -112,7 +156,6 @@ end
# CairoMakie direct drawing method
function draw_tex(scene::Scene, screen::CairoMakie.Screen, cachedtex::CachedTeX, position::VecTypes, scale::VecTypes, rotation::Real, align::Tuple{Symbol, Symbol})
# establish some initial values
x0, y0 = 0.0, 0.0
w, h = cachedtex.dims
ctx = screen.context
# First we center the position with respect to the center of the image,
Expand All @@ -124,21 +167,22 @@ function draw_tex(scene::Scene, screen::CairoMakie.Screen, cachedtex::CachedTeX,
# Then, we find the appropriate "marker offset" w.r.t. alignment.
# This is separate because of Cairo's reversed y-axis.
halign, valign = align
pos = Point2f(0)
pos = if halign == :left
pos .- (-scale[1] / 2, 0)
offset_pos = Point2f(0)
# First, we handle the horizontal alignment
offset_pos = if halign == :left
offset_pos .- (-scale[1] / 2, 0)
elseif halign == :center
pos .- (0, 0)
offset_pos .- (0, 0)
elseif halign == :right
pos .- (scale[1] / 2, 0)
offset_pos .- (scale[1] / 2, 0)
end

pos = if valign == :top
pos .+ (0, scale[2]/2)
# and then the vertical alignment.
offset_pos = if valign == :top
offset_pos .+ (0, scale[2]/2)
elseif valign == :center
pos .+ (0, 0)
offset_pos .+ (0, 0)
elseif valign == :bottom
pos .- (0, scale[2]/2)
offset_pos .- (0, scale[2]/2)
end

# Calculate, with respect to the rotation, where the rotated center of the image
Expand All @@ -161,7 +205,7 @@ function draw_tex(scene::Scene, screen::CairoMakie.Screen, cachedtex::CachedTeX,
#compensate for that with previously calculated values
Cairo.translate(ctx, cx, cy)
# apply "marker offset" to implement/simulate alignment
Cairo.translate(ctx, pos[1], pos[2])
Cairo.translate(ctx, offset_pos[1], offset_pos[2])
# scale the marker appropriately
Cairo.scale(
ctx,
Expand Down Expand Up @@ -198,6 +242,10 @@ function draw_tex(scene::Scene, screen::CairoMakie.Screen, cachedtex::CachedTeX,
Cairo.restore(ctx)
end

# Override `is_cairomakie_atomic_plot` to allow `TeXImg` to remain a unit,
# instead of auto-decomposing into its component scatter plot.
CairoMakie.is_cairomakie_atomic_plot(plot::TeXImg) = true

function CairoMakie.draw_plot(scene::Scene, screen::CairoMakie.Screen, img::T) where T <: MakieTeX.TeXImg

broadcast_foreach(img[1][], img.position[], img.scale[], CairoMakie.remove_billboard(img.rotations[]), img.align[]) do cachedtex, position, scale, rotation, align
Expand Down
Loading

2 comments on commit 48449fe

@asinghvi17
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/101036

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.3.2 -m "<description of version>" 48449feb4b865071772ebadc11bda37b9a352174
git push origin v0.3.2

Please sign in to comment.