New recipe: lens (#2372)
* create recipe, add box and line * add subplot * improve linking * add ghost subplot * draw line only if inset is in subplot * sp_bbox -> inset_bbox * better linking * add lens! shorthand * apply keywords only to inset * check bbox type * add lens example * fix typo and stray * * move legend out of the plot * move lens example down
This commit is contained in:
parent
25c53f0e52
commit
55ea8b4a70
@ -853,6 +853,28 @@ const _examples = PlotExample[
|
||||
),
|
||||
],
|
||||
),
|
||||
PlotExample(
|
||||
"Lens",
|
||||
"A lens lets you easily magnify a region of a plot. x and y coordinates refer to the to be magnified region and the via the `inset` keyword the subplot index and the bounding box (in relative coordinates) of the inset plot with the magnified plot can be specified. Additional attributes count for the inset plot.",
|
||||
[
|
||||
quote
|
||||
begin
|
||||
plot(
|
||||
[(0, 0), (0, 0.9), (1, 0.9), (2, 1), (3, 0.9), (80, 0)],
|
||||
legend = :outertopright,
|
||||
)
|
||||
plot!([(0, 0), (0, 0.9), (2, 0.9), (3, 1), (4, 0.9), (80, 0)])
|
||||
plot!([(0, 0), (0, 0.9), (3, 0.9), (4, 1), (5, 0.9), (80, 0)])
|
||||
plot!([(0, 0), (0, 0.9), (4, 0.9), (5, 1), (6, 0.9), (80, 0)])
|
||||
lens!(
|
||||
[1, 6],
|
||||
[0.9, 1.1],
|
||||
inset = (1, bbox(0.5, 0.0, 0.4, 0.4)),
|
||||
)
|
||||
end
|
||||
end,
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
# Some constants for PlotDocs and PlotReferenceImages
|
||||
|
||||
@ -899,6 +899,91 @@ end
|
||||
# note: don't add dependencies because this really isn't a drop-in replacement
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# lens! - magnify a region of a plot
|
||||
lens!(args...;kwargs...) = plot!(args...; seriestype=:lens, kwargs...)
|
||||
export lens!
|
||||
@recipe function f(::Type{Val{:lens}}, plt::AbstractPlot)
|
||||
sp_index, inset_bbox = plotattributes[:inset_subplots]
|
||||
if !(width(inset_bbox) isa Measures.Length{:w,<:Real})
|
||||
throw(ArgumentError("Inset bounding box needs to in relative coordinates."))
|
||||
end
|
||||
sp = plt.subplots[sp_index]
|
||||
xl1, xl2 = xlims(plt.subplots[sp_index])
|
||||
bbx1 = xl1 + left(inset_bbox).value * (xl2 - xl1)
|
||||
bbx2 = bbx1 + width(inset_bbox).value * (xl2 - xl1)
|
||||
yl1, yl2 = ylims(plt.subplots[sp_index])
|
||||
bby1 = yl1 + (1 - bottom(inset_bbox).value) * (yl2 - yl1)
|
||||
bby2 = bby1 + height(inset_bbox).value * (yl2 - yl1)
|
||||
bbx = bbx1 + width(inset_bbox).value * (xl2 - xl1) / 2
|
||||
bby = bby1 + height(inset_bbox).value * (yl2 - yl1) / 2
|
||||
lens_index = last(plt.subplots)[:subplot_index] + 1
|
||||
x1, x2 = plotattributes[:x]
|
||||
y1, y2 = plotattributes[:y]
|
||||
seriestype := :path
|
||||
label := ""
|
||||
linecolor := :lightgray
|
||||
bbx_mag = (x1 + x2) / 2
|
||||
bby_mag = (y1 + y2) / 2
|
||||
xi_lens, yi_lens = intersection_point(bbx_mag, bby_mag, bbx, bby, abs(bby2 - bby1), abs(bbx2 - bbx1))
|
||||
xi_mag, yi_mag = intersection_point(bbx, bby, bbx_mag, bby_mag, abs(y2 - y1), abs(x2 - x1))
|
||||
# add lines
|
||||
if xl1 < xi_lens < xl2 &&
|
||||
yl1 < yi_lens < yl2
|
||||
@series begin
|
||||
subplot := sp_index
|
||||
x := [xi_mag, xi_lens]
|
||||
y := [yi_mag, yi_lens]
|
||||
()
|
||||
end
|
||||
end
|
||||
# add magnification shape
|
||||
@series begin
|
||||
subplot := sp_index
|
||||
x := [x1, x1, x2, x2, x1]
|
||||
y := [y1, y2, y2, y1, y1]
|
||||
()
|
||||
end
|
||||
# add subplot
|
||||
for series in sp.series_list
|
||||
@series begin
|
||||
plotattributes = merge(plotattributes, copy(series.plotattributes))
|
||||
subplot := lens_index
|
||||
label := ""
|
||||
xlims := (x1, x2)
|
||||
ylims := (y1, y2)
|
||||
()
|
||||
end
|
||||
end
|
||||
backup = copy(plotattributes)
|
||||
empty!(plotattributes)
|
||||
seriestype := :path
|
||||
series_plotindex := backup[:series_plotindex]
|
||||
end
|
||||
|
||||
function intersection_point(xA, yA, xB, yB, h, w)
|
||||
s = (yA - yB) / (xA - xB)
|
||||
hh = h / 2
|
||||
hw = w / 2
|
||||
# left or right?
|
||||
if -hh <= s * hw <= hh
|
||||
if xA > xB
|
||||
# right
|
||||
return xB + hw, yB + s * hw
|
||||
else # left
|
||||
return xB - hw, yB - s * hw
|
||||
end
|
||||
# top or bot?
|
||||
elseif -hw <= hh/s <= hw
|
||||
if yA > yB
|
||||
# top
|
||||
return xB + hh/s, yB + hh
|
||||
else
|
||||
# bottom
|
||||
return xB - hh/s, yB - hh
|
||||
end
|
||||
end
|
||||
end
|
||||
# ---------------------------------------------------------------------------
|
||||
# contourf - filled contours
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user