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
|
# 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
|
# 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
|
# contourf - filled contours
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user