Ideas
Follow


Shade between curves

Image Analyst on 6 Nov 2024 at 16:18
Latest activity Edit by Adam Danz on 7 Nov 2024 at 18:43

It would be nice to have a function to shade between two curves. This is a common question asked on Answers and there are some File Exchange entries on it but it's such a common thing to want to do I think there should be a built in function for it. I'm thinking of something like
plotsWithShading(x1, y1, 'r-', x2, y2, 'b-', 'ShadingColor', [.7, .5, .3], 'Opacity', 0.5);
So we can specify the coordinates of the two curves, and the shading color to be used, and its opacity, and it would shade the region between the two curves where the x ranges overlap. Other options should also be accepted, like line with, line style, markers or not, etc. Perhaps all those options could be put into a structure as fields, like
plotsWithShading(x1, y1, options1, x2, y2, options2, 'ShadingColor', [.7, .5, .3], 'Opacity', 0.5);
the shading options could also (optionally) be a structure. I know it can be done with a series of other functions like patch or fill, but it's kind of tricky and not obvious as we can see from the number of questions about how to do it.
Does anyone else think this would be a convenient function to add?
Adam Danz
Adam Danz on 6 Nov 2024 at 20:41 (Edited on 6 Nov 2024 at 20:52)
What would be the expected behavior in these cases below?
figure()
tiledlayout()
nexttile()
th = 0:.01:2*pi;
x = cos(th);
y = sin(th);
plot(x,y,'-b')
hold on
plot([-.2 2], [-2 .2], '-r')
axis padded square
title("Example 1")
nexttile()
plot(th,y,'-k')
hold on
plot(th+7, y+.5, '-b')
title("Example 2")
nexttile()
x = linspace(-5, 5, 100);
y1 = 0.5*x.^2;
plot(x,y1,'-m')
hold on
refline(-1.5,10)
axis padded
title("Example 3")
nexttile()
th = .8:.1:1.8*pi;
x = cos(th);
y = sin(th);
plot(x,y,'-b')
hold on
plot([-2 2], [0 0], 'k-')
title("Example 4")
axis equal
goc3
goc3 on 6 Nov 2024 at 22:24
Your examples provide quite a few combinations. Of course, typical one-to-one functions are easier to assess. But, many users are likely to also apply this to functions that are not one-to-one, such as the circle shown in Example 1.
I have provided six use cases below for Example 3. The default case (x-coordinates and vertical slices) is indicated by the top row. The top-left image shows shading from the pink curve (the 1st input) up to the orange line (2nd input) in vertical slices. Note that the shading only appears within the frame where the orange line is above the pink parabola. In the top-middle image, the shading appears on the right side, only where the orange line (1st input) is below the pink parabola (2nd input). The last image of the top row shows how the shading could be restricted by user input.
The bottom row illustrates the non-default case, shading between y-coordinates, as specified by direction = horizontal (slices). These cases are similar to those in the top row, showing how input order matters along with an additional input being used to restrict the range.
Regarding functions that are not one-to-one, additional inputs could help clarify the situation by defining the search method for points along each curve. For example, the option lowerCurveSearchMethod could have choices of "first", "last", "min", and "max". For each slice, and presuming the default case (vertical slices), each option would find all y-coordinates corresponding to the bounding x-coordinates for the slice and assign the first, last, minimum, or maximum y-coordinates for each slice. There would also be an upperCurveSearchMethod with the same choices.
Adam Danz
Adam Danz on 7 Nov 2024 at 15:03
Thanks for taking the time to explain those options.
The charting team added a fill-between function on the File Exchange about a year ago. https://www.mathworks.com/matlabcentral/fileexchange/133622
Your feedback will be noted in case any plans develop in this area.
Image Analyst
Image Analyst on 7 Nov 2024 at 16:19
Unfortunately it says it requires the Mapping Toolbox, so most people won't be able to use it.
Adam Danz
Adam Danz on 7 Nov 2024 at 18:43 (Edited on 7 Nov 2024 at 18:43)
It requires mapping TB for full functionality but there's a condition in the code that uses a second path if mapping TB isn't installed. The dependency is due to the use of polyxpoly.
goc3
goc3 on 6 Nov 2024 at 20:24
Additional thoughts:
I would recommend that shadeBetweenCurves operate on the entire curves by default. Otherwise, the user should be able to specify the lower and/or upper limits for shading.
The first input should be for the lower curve and the second input for the upper curve. I would expect that inputting the upper and then lower would yield no shading, similar to how 3:1 yields an empty vector.
It would be a good idea to also allow shading in either direction. This would be vertical by default (between x values) but also allowable for horizontal (between y values). Then, this function, or a new one designed similar to this one, could be extended to 3D plots by creating surfaces between curves or volumes between surfaces.
goc3
goc3 on 6 Nov 2024 at 17:32
I agree that a built-in function to shade between lines would be very helpful. I also agree that the syntax could be tricky. Perhaps it could operate on handles of already-plotted curves. For example:
h1 = plot(x1, y1, 'r-');
h2 = plot(x2, y2, 'b-');
shadeBetweenCurves(h1, h2, opts);
That way, the plot options for each of the curves would not clutter the function signature for shading between them. And, the opts struct (or name-value pairs) could accommodate the typical patch properties.

Tags

No tags entered yet.