How to change `annotate!` background color?

I’m trying to use Plots and annotate function to plot a numerical value onto the line.

plotly()
plot(sin)
annotate!(0, sin(0), text("0"))

It works not bad.

Furthermore, I want to put a text on the line with removing a part of a line on which to put a text.
I used a white square Unicode to fill a part of the line, and plot a text on it.

plotly()
plot(sin)
annotate!(0, sin(0), text("■", :white, 30))
annotate!(0, sin(0), text("0"))

Is there any more sophisticated way?
i.e. Control a background color of a text.

Late reply but I could not find an answer so I put together a short hack.

function annotatewithbox!(
		fig::Plots.Plot,
		text::Plots.PlotText,
		x::Real, y::Real, Δx::Real, Δy::Real = Δx;
		kwargs...)
	
	box = Plots.Shape(:rect)
	
	Plots.scale!(box, Δx, Δy)
	Plots.translate!(box, x, y)

	Plots.plot!(fig, box, c = :white, linestroke = :black, label = false; kwargs...)
	Plots.annotate!(fig, x, y, text)
	
	fig
end

There is definitely a better way to do it but it does the trick,

fig = plot(xlim = (-10, 10), ylims = (-10, 10))
annotatewithbox!(fig, text("hello how are you?!"), 2, 2, 4, 1)

3 Likes

FWIW, the workaround from @takuizum could be further improved by using a FULL BLOCK Unicode character instead of the BLACK SQUARE:

using Plots; gr()
fntcm = "Computer Modern"
fntsz = 12
default(fontfamily= fntcm)
str = "Hello Julia!"
n = length(str)
str0 = "█"^(n÷2+1)   # FULL BLOCK Unicode character
plot(sin, legend = false)
annotate!(0, sin(0), text(str0,:white, fntcm,fntsz+2))
annotate!(0, sin(0), text(str, fntcm,fntsz))

One case where this hack breaks down is in the case where the string is multi-line.
In which case, n = length(str) gives a spuriously large value and even worse, the “background” will not cover the whole text area.

See:

@takuizum of @rafael.guerra did you file an issue in the Plots.jl repo? I think it makes sense to do.

I did not fill an issue.

Note that if we use a monospaced font such as “Courier”, then the character masking will be much easier to perform. See your example reproduced below, quick and dirty.

CODE: multi-line mask with monospaced font
using Plots; gr()

fntcm = "Courier"
fntsz = 8
default(fontfamily= fntcm)
str = "Hello Julia!\nThis is a second line\nand a third one!!!\nThis will result in a ton of whitespace"
n = length.(eachline(IOBuffer(str)))
str0 = join(hcat("█".^n), "\n")   # FULL BLOCK Unicode character
plot(sin, legend = false)
annotate!(0, sin(0), text(str0,:white, fntcm, fntsz))
annotate!(0, sin(0), text(str, fntcm, fntsz))
1 Like