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

Update for Makie v0.20 #45

Merged
merged 6 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading