fill function sometimes working and sometimes not working, why?

I am using R2024a on a linux system.
I thought that the fill() command will fill-in a closed polygon with a given colour whether the points are in anti-clockwise order or in clockwise order. In the test script attached I have created a cubic x^3+c*x+d which has 3 real roots r(1)<r(2)<r(3) and I wish to fill-in the region above the axis with one colour and the region below the axis in another colour. I have 3 attempts in what is given in the attachment with just the second attempt working. If I change to c=-2.4 and dfac=0.11 then all 3 cases work. For most choices of the parameters all 3 cases give the same graphics.
There are no warnings or messages when fill() does not do anything.
Is there something that needs to be done to ensure that fill() always works? I guess that I can always give both orders of the points but this will mostly seem to be unnecessary.

 采纳的回答

I generally use patch rather than fill because I understand patch and I have more control over what it does.
I'm not certain what question you're actually asking, however after experimenting a bit, reversing the arguments of the second fill call (putting the 0 first in all of them) works as I assume you want it to in evary plot with both sets of 'c' and 'dfac'. The reason that approach solves this is not obvious to me. It has something to do with how fill implements patch, however I didn't look through the fill code to search for it.
% ----- test_of_fill -----
% first create a cubic as f()
c=-2.4;
dfac=0.11;
% c=-2.4;
% dfac=0.11;
gamma=sqrt(abs(c)/3);
beta=2*gamma^3;
d=dfac*beta;
f =@(x) x.^3+c*x+d;
% get the roots in ascending order as r()
r=sort(roots([1, 0, c, d]))
r = 3×1
-1.5810 0.0657 1.5153
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
c=-5.8;
dfac=0.38;
% c=-2.4;
% dfac=0.11;
gamma=sqrt(abs(c)/3);
beta=2*gamma^3;
d=dfac*beta;
f =@(x) x.^3+c*x+d;
% get the roots in ascending order as r()
r=sort(roots([1, 0, c, d]))
r = 3×1
-2.5682 0.3603 2.2079
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% set the number of points and the colours
m=200;
lcol=[0, 0, 1];
rcol=[1, 0, 0];
% first attempt to fillin parts above and below the x-axis
% anti-clockwise for the polygons in both cases
figure(10)
clf
hold on
xf1=linspace(r(2), r(1), m);
yf1=f(xf1);
xf1_yf1 = [xf1; yf1]
xf1_yf1 = 2×200
0.3603 0.3456 0.3309 0.3162 0.3014 0.2867 0.2720 0.2573 0.2426 0.2279 0.2132 0.1984 0.1837 0.1690 0.1543 0.1396 0.1249 0.1101 0.0954 0.0807 0.0660 0.0513 0.0366 0.0218 0.0071 -0.0076 -0.0223 -0.0370 -0.0517 -0.0665 -0.0000 0.0799 0.1602 0.2409 0.3220 0.4036 0.4855 0.5677 0.6503 0.7332 0.8164 0.8999 0.9837 1.0676 1.1518 1.2362 1.3208 1.4056 1.4904 1.5755 1.6606 1.7458 1.8310 1.9163 2.0017 2.0870 2.1724 2.2577 2.3430 2.4282
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
directions = mean(diff(xf1_yf1,[],2),2)
directions = 2×1
-0.0147 0.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
fill([xf1, r(2)], [0 yf1], lcol)
xf2=linspace(r(2), r(3), m);
yf2=f(xf2);
xf2_yf2 = [xf2; yf2]
xf2_yf2 = 2×200
0.3603 0.3696 0.3789 0.3882 0.3974 0.4067 0.4160 0.4253 0.4346 0.4439 0.4532 0.4624 0.4717 0.4810 0.4903 0.4996 0.5089 0.5181 0.5274 0.5367 0.5460 0.5553 0.5646 0.5738 0.5831 0.5924 0.6017 0.6110 0.6203 0.6296 -0.0000 -0.0501 -0.1001 -0.1498 -0.1994 -0.2487 -0.2979 -0.3468 -0.3955 -0.4440 -0.4922 -0.5402 -0.5880 -0.6355 -0.6828 -0.7298 -0.7766 -0.8231 -0.8693 -0.9153 -0.9610 -1.0064 -1.0515 -1.0963 -1.1408 -1.1851 -1.2290 -1.2726 -1.3159 -1.3589
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
directions = mean(diff(xf2_yf2,[],2),2)
directions = 2×1
0.0093 0.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
fill([xf2, r(2)], [0 yf2], rcol)
hold off
% second attempt to fillin parts above and below the x-axis
% clockwise for the left part and anti-clockwise for the right part
figure(20)
clf
hold on
xf1r=linspace(r(1), r(2), m);
yf1r=f(xf1r);
xf1r_yf1r = [xf1r; yf1r]
xf1r_yf1r = 2×200
-2.5682 -2.5535 -2.5387 -2.5240 -2.5093 -2.4946 -2.4799 -2.4652 -2.4504 -2.4357 -2.4210 -2.4063 -2.3916 -2.3769 -2.3621 -2.3474 -2.3327 -2.3180 -2.3033 -2.2886 -2.2739 -2.2591 -2.2444 -2.2297 -2.2150 -2.2003 -2.1856 -2.1708 -2.1561 -2.1414 0.0000 0.2042 0.4050 0.6025 0.7968 0.9878 1.1756 1.3601 1.5415 1.7196 1.8946 2.0664 2.2352 2.4008 2.5633 2.7227 2.8791 3.0325 3.1829 3.3302 3.4746 3.6161 3.7546 3.8901 4.0228 4.1526 4.2796 4.4037 4.5250 4.6435
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
directions = mean(diff(xf1r_yf1r,[],2),2)
directions = 2×1
0.0147 -0.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
fill([xf1r, r(1)], [yf1r, 0], lcol)
xf2=linspace(r(2), r(3), m);
yf2=f(xf2);
xf2_yf2 = [xf2; yf2]
xf2_yf2 = 2×200
0.3603 0.3696 0.3789 0.3882 0.3974 0.4067 0.4160 0.4253 0.4346 0.4439 0.4532 0.4624 0.4717 0.4810 0.4903 0.4996 0.5089 0.5181 0.5274 0.5367 0.5460 0.5553 0.5646 0.5738 0.5831 0.5924 0.6017 0.6110 0.6203 0.6296 -0.0000 -0.0501 -0.1001 -0.1498 -0.1994 -0.2487 -0.2979 -0.3468 -0.3955 -0.4440 -0.4922 -0.5402 -0.5880 -0.6355 -0.6828 -0.7298 -0.7766 -0.8231 -0.8693 -0.9153 -0.9610 -1.0064 -1.0515 -1.0963 -1.1408 -1.1851 -1.2290 -1.2726 -1.3159 -1.3589
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
directions = mean(diff(xf2_yf2,[],2),2)
directions = 2×1
0.0093 0.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% fill([xf2, r(2)], [yf2, 0], rcol)
fill([xf2, r(2)], [0 yf2], rcol)
hold off
% third attempt to fillin parts above and below the x-axis
% clockwise for the polygons in both cases
figure(30)
clf
hold on
% xf1r=linspace(r(1), r(2), m);
% yf1r=f(xf1r);
fill([xf1r, r(1)], [yf1r, 0], lcol)
xf2r=linspace(r(3), r(2), m);
yf2r=f(xf2r);
xf2r_yf2r = [xf2r; yf2r]
xf2r_yf2r = 2×200
2.2079 2.1986 2.1893 2.1800 2.1707 2.1614 2.1522 2.1429 2.1336 2.1243 2.1150 2.1057 2.0965 2.0872 2.0779 2.0686 2.0593 2.0500 2.0407 2.0315 2.0222 2.0129 2.0036 1.9943 1.9850 1.9758 1.9665 1.9572 1.9479 1.9386 0.0000 -0.0814 -0.1616 -0.2407 -0.3186 -0.3954 -0.4712 -0.5458 -0.6193 -0.6916 -0.7629 -0.8331 -0.9023 -0.9703 -1.0372 -1.1031 -1.1679 -1.2316 -1.2943 -1.3559 -1.4165 -1.4760 -1.5345 -1.5920 -1.6484 -1.7038 -1.7581 -1.8115 -1.8638 -1.9151
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
directions = mean(diff(xf2r_yf2r,[],2),2)
directions = 2×1
-0.0093 -0.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% fill([xf2r, r(3)], [yf2r, 0], rcol)
fill([xf2r, r(3)], [0 yf2r], rcol)
hold off
% ---------------------- END ----------------------
.

10 个评论

Thank you your quick attempt with showing ways it could be done.
As context I had about 100 different cases of the paramters c and dfac
(and also of the colours to use) as a part of exercise where
every person had a slightly different task to do.
As I put in the post I could always get a fill of the
two regions but I could not explain why certain ways were not
working in a small number of cases. Without knowing exactly how
the function fill works I can conjecture an explanation and offer
a simpler solution to get something that always works.
I think that the original issue was connected with the difference
between the start point and the end point of the closed polygon
in the attempt to give the same start and end point. If you just
let fill() close the polygon then it always works. If you specify
exactly the same point for the start and end then it always works.
In what I originally tried r(2) is only a very close approximation
to a root of the cubic and f(r(2)) is not exactly 0. Thus the end
point was not exactly the same as the start point. As most values
of c and d worked I can just conjecture that it depends on how close
these are as to whether it considers that we have a closed polygon.
It is a little surprising that when fill() does not believe that it
has a polygon that it can handle that it shows nothing without any warning.
% in all cases for xf1 and yf1
xf1=linspace(r(2), r(1), m);
yf1=f(xf1);
% ---------------------------------------
% this works
fill(xf1, yf1, lcol)
% ---------------------------------------
% this also works
fill([xf1, r(2)], [yf1, yf1(1)], lcol)
% ---------------------------------------
% the original version which did not work for every c and d
fill([xf1, r(2)], [yf1, 0], lcol)
My pleasure!
An option that would likely always qork would be to use patch --
% ----- test_of_fill -----
% first create a cubic as f()
c=-2.4;
dfac=0.11;
% c=-2.4;
% dfac=0.11;
gamma=sqrt(abs(c)/3);
beta=2*gamma^3;
d=dfac*beta;
f =@(x) x.^3+c*x+d;
% get the roots in ascending order as r()
r=sort(roots([1, 0, c, d]))
r = 3×1
-1.5810 0.0657 1.5153
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% set the number of points and the colours
m=200;
lcol=[0, 0, 1];
rcol=[1, 0, 0];
xv = linspace(r(1), r(end));
yv = f(xv);
Lv1 = xv <= r(2); % Logical Vector
Lv2 = xv >= r(2); % Logical Vector
figure
hold on
patch([xv(Lv1) flip(xv(Lv1))], [zeros(1,nnz(Lv1)) flip(yv(Lv1))], rcol)
patch([xv(Lv2) flip(xv(Lv2))], [zeros(1,nnz(Lv2)) flip(yv(Lv2))], lcol)
hold off
title(sprintf('f(x) = x^3+%.1f*x+%.2f',c,dfac))
c=-5.8;
dfac=0.38;
% c=-2.4;
% dfac=0.11;
gamma=sqrt(abs(c)/3);
beta=2*gamma^3;
d=dfac*beta;
f =@(x) x.^3+c*x+d;
% get the roots in ascending order as r()
r=sort(roots([1, 0, c, d]))
r = 3×1
-2.5682 0.3603 2.2079
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% set the number of points and the colours
m=200;
lcol=[0, 0, 1];
rcol=[1, 0, 0];
xv = linspace(r(1), r(end), m);
yv = f(xv);
Lv1 = xv <= r(2); % Logical Vector
Lv2 = xv >= r(2); % Logical Vector
figure
hold on
patch([xv(Lv1) flip(xv(Lv1))], [zeros(1,nnz(Lv1)) flip(yv(Lv1))], rcol)
patch([xv(Lv2) flip(xv(Lv2))], [zeros(1,nnz(Lv2)) flip(yv(Lv2))], lcol)
hold off
title(sprintf('f(x) = x^3+%.1f*x+%.2f',c,dfac))
% ---------------------- END ----------------------
If this is all you want to do, copying those patch calls would probably work. You could even enclose them in a function, and then pass 'c' and 'dfac' to it as arguments.
.
Thanks for your contribution. Your version will always work.
As a minor point about the title of the plot,
title(sprintf('f(x) = x^3+%.1f*x+%.2f',c,dfac))
should be replaced by
title(sprintf('f(x) = x^3+%.1f*x+%.2f', c, d))
dfac was always a number in the range (0, 1) which helped
to get a constant term d such that the f(x) had 3 real roots.
I started with g(x)=x^3+cx=x(x^2+c) and determined the range of possible
values of d such that f(x)=g(x)+d has 3 real roots.
I am not sure that this is of interest but the issue I had in
a small number of cases of fill() not doing anything is from testing with
release R24a. I get the same outcome with the R25a online version.
With an older computer which still has release R20a this does not happen.
The Matlab implementation of fill would seem to have changed since that time.
There was a change in fill in R2021a, however I doubt the noted change affected the aspects you're interested in here.
The title change is easy enough, and creating a function to plot them is straightforward --
% ----- test_of_fill -----
% first create a cubic as f()
c=-2.4;
dfac=0.11;
% c=-2.4;
% dfac=0.11;
gamma=sqrt(abs(c)/3);
beta=2*gamma^3;
d=dfac*beta;
f =@(x) x.^3+c*x+d;
% get the roots in ascending order as r()
r=sort(roots([1, 0, c, d]))
r = 3×1
-1.5810 0.0657 1.5153
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% set the number of points and the colours
m=200;
lcol=[0, 0, 1];
rcol=[1, 0, 0];
xv = linspace(r(1), r(end));
yv = f(xv);
Lv1 = xv <= r(2); % Logical Vector
Lv2 = xv >= r(2); % Logical Vector
figure
hold on
patch([xv(Lv1) flip(xv(Lv1))], [zeros(1,nnz(Lv1)) flip(yv(Lv1))], rcol)
patch([xv(Lv2) flip(xv(Lv2))], [zeros(1,nnz(Lv2)) flip(yv(Lv2))], lcol)
hold off
title(sprintf('$f(x) = x^3 %+.1f x %+.2f$',c,d), Interpreter='LaTeX')
c=-5.8;
dfac=0.38;
% c=-2.4;
% dfac=0.11;
gamma=sqrt(abs(c)/3);
beta=2*gamma^3;
d=dfac*beta;
f =@(x) x.^3+c*x+d;
% get the roots in ascending order as r()
r=sort(roots([1, 0, c, d]))
r = 3×1
-2.5682 0.3603 2.2079
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% set the number of points and the colours
m=200;
lcol=[0, 0, 1];
rcol=[1, 0, 0];
xv = linspace(r(1), r(end), m);
yv = f(xv);
Lv1 = xv <= r(2); % Logical Vector
Lv2 = xv >= r(2); % Logical Vector
figure
hold on
patch([xv(Lv1) flip(xv(Lv1))], [zeros(1,nnz(Lv1)) flip(yv(Lv1))], rcol)
patch([xv(Lv2) flip(xv(Lv2))], [zeros(1,nnz(Lv2)) flip(yv(Lv2))], lcol)
hold off
title(sprintf('$f(x) = x^3 %+.1f x %+.2f$',c,d), Interpreter='LaTeX')
c = -4.2; % Test The 'patchroots' Function
dfac = 0.42;
figure
fig=gcf;
patchroots(fig,c,dfac)
function patchroots(fig,c,dfac)
m=200;
lcol=[0, 0, 1];
rcol=[1, 0, 0];
gamma=sqrt(abs(c)/3);
beta=2*gamma^3;
d=dfac*beta;
f =@(x) x.^3+c*x+d;
r=sort(roots([1, 0, c, d]));
xv = linspace(r(1), r(end), m);
yv = f(xv);
Lv1 = xv <= r(2); % Logical Vector
Lv2 = xv >= r(2); % Logical Vector
hold on
patch([xv(Lv1) flip(xv(Lv1))], [zeros(1,nnz(Lv1)) flip(yv(Lv1))], rcol)
patch([xv(Lv2) flip(xv(Lv2))], [zeros(1,nnz(Lv2)) flip(yv(Lv2))], lcol)
hold off
title(sprintf('$f(x) = x^3 %+.1f x %+.2f$',c,d), Interpreter='LaTeX')
end
% ---------------------- END ----------------------
The 'patchroots' function is a simple implementation of the existing code. The first argument is a figure handle, so you can call it with respect to any figure handle you want and it will plot in it.
It currently doesn't return anything, and just plots. You can code it to return any results you want.
.
I am inclined to think that there is a bug in the latest implementation of fill.
When I run what I attach with R2024a one version does no fill and another version with an end point y value which is 1e-16 different does the fill. Should that be what happens? In R2020a both figures look the same.
I believe you're on to something, although I'm not quite sure what that is.
I suggest that you Contact Support and report this as a bug. Include the URL of this thread in your note to MathWorks so you don't have to repeat everything here.
In the meantime, use patch.
Extending that idea slightly --
% ----- exper_with_fill -----
% first create a cubic as f()
c=-5.8;
dfac=0.38;
gamma=sqrt(abs(c)/3);
beta=2*gamma^3;
d=dfac*beta;
f =@(x) x.^3+c*x+d;
% get the roots in ascending order as r()
r=sort(roots([1, 0, c, d]));
% set the number of points and the colours
m=201;
lcol=[0, 0, 1];
rcol=[1, 0, 0];
% create almost all the points
x1=linspace(r(2), r(1), m);
y1=f(x1);
x2=linspace(r(2), r(3), m);
y2=f(x2);
% experiment with forcing a close of the polygon
for k = 3:6 % <- EXTENDED
% for k=4:5
figure(10*k)
clf
hold on
fill([x1, r(2)], [y1, -k*1e-16], lcol)
fill([x2, r(2)], [y2, 0], rcol)
hold off
title("k = "+k) % <- ADDED
end
% ---------------------- END ----------------------
.
A bug report has been submitted.
Below is a copy of what I put.
fill function with version R2024a
Case Number: 08004848
Status: Open
Last Updated: 11 Aug 2025
Case Details
How frequently do you encounter this issue?
Every time I follow the reproduction steps
Description:
Dear Contact Support,
I raised a question on the community pages and the URL of this as give below.
https://uk.mathworks.com/matlabcentral/answers/2179273-fill-function-sometimes-working-and-sometimes-not-working-why?s_tid=mlc_ans_email_ques
The question is about how the graphics function fill now behaves. I know how to use the fill function and to get the graphics that I wish and the question relates to why it now behaves in a certain way.
For a mathematical description let z_i=(x_i, y_i), i=1, ..., n denote points which nearly describe a closed polygon with z_n very close to z_1. The problem is that when z_n is not exactly z_1 it sometimes does not show anything. Running the attached file illustrates what happens when z_n and z_1 are close enough and when they are not. (As a comparison, when it is run in release R2020a what is generated is visually the same in all cases.) I can only guess that when the turning angle is 180 degrees at any vertex in the closed polygon used internally by fill it cannot deduce the interior region and gives up without any warning. I can understand why it may wish not to do anything as the interior region may not be properly determined but I would have expected a warning. Is this a bug in how fill is currently implemented.
Thank you,
Michael
Noted!
Please post the response MathWorks sends.
Below is the response that I have been sent today from mathworks.
"I have investigated about the issue, and this seems like a bug from MATLAB R2022a and the development team is aware of it.''
The original posting was due to not knowing something why something that I was doing several year ago no longer worked in all cases of the parameters. What has been learned is to take care with the use of the fill function if you attempt to close the polygon to fill. It is important to ensure that the last point given is exactly the same as the first point given. If it is different but extremely close then in some cases fill will not do anything and there will not be any warnings.
Thank you for posting the reply. Your best option iw likely to use patch instead, at least until that bug is fixed. In 2D, patch is relatively strtaightforward to work with. The advantage is that it interprets the last point from the available arguments, and completes the region to be filled on its own.

请先登录,再进行评论。

更多回答(1 个)

Seems trivial to me. (Ok, easy. Triviality is in the eye of the beholder.) I don't give a hoot about how many real roots it has, or their locations.
fcd = @(x,c,d) x.^3 + c*x + d;
f = @(x) fcd(x,-2.4,0.11);
fplot(f,'k-',[-2,2])
grid on
x = [-2,linspace(-2,2,1000),2];
ypos = max(f(x),0);
ypos([1,end]) = 0;
yneg = min(f(x),0);
yneg([1,end]) = 0;
hold on
fill(x,ypos,'g')
fill(x,yneg,'r')
I never looked at your code, but from what you said, I'll conjecture you were trying too hard, worrying about things like root locations, etc. Sometimes you need to just step back and gain a better focus on the problem.

3 个评论

Thank you your quick attempt with showing ways it could be done.
I give more information in the comment to the earlier answer and
the full task did specifically involve roots of a cubic.
I believe that the issue with fill is concerned with whether or not
fill determines that a closed polygon is being supplied.
It was my attempt to close the polygon which is my conjecture of
why fill was doing nothing in a small number of cases.
What can I say? I showed how to solve your problem, without even needing to worry about the roots. It works nicely, in a very few lines of code. But if this was a homework assignment, well, it is your issue to deal with. You never did tell us the parameters of the assignment, and why you wanted to solve it that way. Honestly, solving for the roots is a poor approach, in the sense that it forces you to do much more work. But an assignment typically dictates how you should solve it. You will get better help if you are forthcoming with what is needed.
Thank you again for your contribution and I apologies that my specification may have been too brief. I tried to follow the guidelines in submitting a question which indicated that it should be kept brief.
For a bit more context, it was small part of an assignment that I set for about 100 students several years ago. Every student had a slightly different version of each task and there was about 6 weeks to complete the assignment. Each student was sent a pdf which was 20 pages long which had their version of all the tasks. There was no generic version of the assignment. To get marks students had to do things in the manner asked. Students could work together on similar things but they needed their submission to be for their version of what they are asked to do. This helped cut down on any investigations of collusion that might otherwise arise if everyone is given the same task. As well as generating 100 individual assignments I generated solutions to every different case and this helped when I marked. On revisiting what was done a few years ago I was surprised that an aspect of the ``graphics task'' was not working now in the same way as it did a few years ago. This is what prompted me to submit the question and I could not see why in some cases the fill-in part was not working. I could always get a way to do the task but has taken a while to determine why certain ways might not work. The investigation now has revealed something which might not always work as I wanted.
Just for information, there were other parts of the assignment connected with the graphics task which did not need fill. The most difficult part was in implementing an algorithm that I gave them to attempt to determine and show the largest circle that you can put in the filled region with the larger area.
I still have an old computer with release R20a. On that computer the fill function works as it did a few years ago. All the fill instructions did what I wanted. With release R24a and also the online version R25a I get a small number of cases where the programs from few year ago no longer work as they did before. It seems that the implementation of the fill function has changed since the assignment was set several years ago.
Thank you for the comment ``Sometimes you need to just step back and gain a better focus on the problem.''
The aspect of that which has helped here is to take care with how you attempt to close a polygon before using the fill function. The default way fill closes a polygon may be the best thing to rely on.

请先登录,再进行评论。

类别

帮助中心File Exchange 中查找有关 Graphics Object Programming 的更多信息

产品

版本

R2024a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by