2
$\begingroup$

I know that there are plenty of posts on this, but I just cannot find the right one that solves my issue. The issue is that I have two datasets that I plot them using ListLinePlot. I would like to fill the area enclosed by them with different colors (use Green when A is on B and use Yellow when B is on A). But this simple issue turns out to be challenging. No matter how I play around with the command Filling the color that it uses for the areas is always the same (see the photo). I know that one way is to find the intersection point and then regenrate the data but I don't want to mess with that. I believe there should be an easy workaround for this.

enter image description here

And secondly, how to calculate the two areas separately?

Here is the code:

test1 = {{0.01, 21.96}, {0.19, 22.06}, {0.36, 22.06}, {0.54, 
    22.06}, {0.71, 22.06}, {0.89, 22.06}, {1.06, 22.05}, {1.24, 
    22.05}, {1.41, 22.06}, {1.59, 22.05}, {1.76, 22.05}, {1.94, 
    22.05}, {2.11, 22.05}, {2.29, 22.05}, {2.46, 22.06}, {2.64, 
    22.04}, {2.81, 22.03}, {2.99, 21.96}, {3.16, 21.79}, {3.34, 
    20.56}, {3.51, 16.5}, {3.69, 11.71}, {3.86, 7.62}, {4.04, 
    4.52}, {4.21, 3.19}, {4.39, 2.99}, {4.56, 2.95}, {4.74, 
    2.95}, {4.91, 2.95}, {5.09, 2.95}, {5.26, 2.96}, {5.44, 
    2.96}, {5.61, 2.96}, {5.79, 2.96}, {5.96, 2.96}, {6.14, 2.96}};

test2 = {{0.02, 22.16}, {0.08, 22.14}, {0.16, 22.07}, {0.22, 
    22.07}, {0.29, 22.07}, {0.36, 22.07}, {0.44, 22.06}, {0.5, 
    22.06}, {0.58, 22.06}, {0.64, 22.06}, {0.72, 22.06}, {0.78, 
    22.06}, {0.86, 22.06}, {0.92, 22.06}, {1., 22.06}, {1.06, 
    22.06}, {1.14, 22.06}, {1.2, 22.06}, {1.27, 22.06}, {1.34, 
    22.06}, {1.41, 22.06}, {1.48, 22.06}, {1.56, 22.06}, {1.62, 
    22.06}, {1.69, 22.06}, {1.76, 22.06}, {1.84, 22.06}, {1.9, 22.06},
    {1.97, 22.06}, {2.04, 22.06}, {2.11, 22.06}, {2.18, 22.06}, {2.25,
     22.06}, {2.32, 22.06}, {2.4, 22.06}, {2.46, 22.06}, {2.54, 
    22.06}, {2.6, 22.06}, {2.68, 22.06}, {2.74, 22.05}, {2.82, 
    22.05}, {2.88, 22.04}, {2.96, 22.02}, {3.02, 22.}, {3.09, 
    21.97}, {3.16, 21.92}, {3.24, 21.83}, {3.3, 21.73}, {3.38, 
    21.59}, {3.44, 21.34}, {3.52, 20.82}, {3.58, 17.72}, {3.66, 
    12.82}, {3.72, 9.42}, {3.8, 6.91}, {3.86, 5.12}, {3.94, 
    4.05}, {4., 3.51}, {4.08, 3.25}, {4.14, 3.13}, {4.22, 
    3.06}, {4.28, 3.02}, {4.36, 3.}, {4.42, 2.99}, {4.5, 2.99}, {4.57,
     2.99}, {4.63, 2.99}, {4.7, 2.99}, {4.78, 2.99}, {4.84, 
    2.99}, {4.92, 2.99}, {4.98, 2.99}, {5.05, 2.99}, {5.12, 
    2.99}, {5.2, 2.99}, {5.26, 2.99}, {5.34, 2.99}, {5.4, 
    2.99}, {5.48, 2.99}, {5.54, 2.99}, {5.62, 2.99}, {5.68, 
    2.99}, {5.76, 2.99}, {5.82, 2.99}, {5.9, 2.99}, {5.96, 
    2.99}, {6.04, 2.99}, {6.1, 2.99}, {6.18, 2.99}, {6.24, 2.99}};

ListLinePlot[{test1, test2}, Filling -> {1 -> {{2}, {Yellow, Green}}}]

Thanks

enter image description here

$\endgroup$
2
  • $\begingroup$ The Filling commands seem to work for me , I think I put them in exactly as you have them? Sorry that I don't really know how to identify what is causing the Filling behavior here $\endgroup$
    – ydd
    Commented Jul 6 at 16:58
  • $\begingroup$ @ydd please see the edited post. $\endgroup$
    – KratosMath
    Commented Jul 6 at 17:27

3 Answers 3

3
$\begingroup$

It looks like the points need to be at the same x-values.

I first create linear interpolations and select the x-values that are in the domain for both interpolations:

int1 = Interpolation[test1, InterpolationOrder -> 1];
int2 = Interpolation[test2, InterpolationOrder -> 1];

xPoints = Union[test1[[All, 1]], test2[[All, 1]]];

(*select points that are in the range of both interpolations*)
domains = Interval[#["Domain"][[1]]] & /@ {int1, int2};
range = IntervalIntersection @@ domains;
xPoints = Select[xPoints, IntervalMemberQ[range, #] &];

Then evaluate the interpolations at these points:

p1 = {#, int1[#]} & /@ xPoints;
p2 = {#, int2[#]} & /@ xPoints;
ListLinePlot[{p1, p2}, Filling -> {1 -> {{2}, {Yellow, Green}}}]

interpolations at xPoints

Then using Clip I define two functions that are nonzero only when int2 > int1 or int1 > int2, respectively. I plot the absolute value of these clipped functions to show this behavior:

(*define diff to be the difference between the interpolations*)
diff[x_] = int1[x] - int2[x];
(*when int2>int1,diff is negative*)
yellowReg[x_] := Clip[diff[x], {-Infinity, 0}]
(*when int1>int2,diff is positive*)
greenReg[x_] := Clip[diff[x], {0, Infinity}];

Plot[{Abs@yellowReg[x], Abs@greenReg[x]}, {x, xPoints[[1]], 
  xPoints[[-1]]}, Filling -> Axis, PlotStyle -> {Yellow, Green}, 
 FillingStyle -> Opacity[1], PlotRange -> All]

difference between the two interpolated functions evaluated at 'xPoints' in the yellow and green regions. 0 everywhere else

And now we can find the magnitude of the two areas:

(*calculate magnitude of yellow and green regions*)
yellowArea = 
 NIntegrate[yellowReg[x], {x, xPoints[[1]], xPoints[[-1]]}] // Abs

greenArea = 
 NIntegrate[greenReg[x], {x, xPoints[[1]], xPoints[[-1]]}] // Abs

(*1.12331*)

(*0.814679*)

Note that the yellow region also includes the small region on the left where int2 > int1. If you don't want to include that, you can change the lower integration bound xPoints[[1]] to something larger that still includes the big yellow region.

$\endgroup$
1
  • $\begingroup$ I like your answer. It provides more information than I expected. $\endgroup$
    – KratosMath
    Commented Jul 7 at 9:13
7
$\begingroup$
  • The two lines crossing each other many times,not exact only one intersection points. We can see this by
polys = PolygonDecomposition[Polygon[Join[Reverse@test1, test2]]];
n = Length[polys]
colors = {Yellow, Blue, Green, Brown, Red, Blue, Cyan};
mapping = Association[Thread[colors -> polys]]
Graphics[Thread[{colors, polys}], AspectRatio -> 1]

enter image description here

  • So you want the area of the red and the green polygon.
{Area[mapping@Red], Area[mapping@Green]}

{1.03459, 0.814679}

Edit

  • If we only want to distinguish the two regions,we can also set the InterpolationOrder >=2.
ListLinePlot[{test1, test2}, Filling -> {1 -> {{2}, {Yellow, Green}}},
  InterpolationOrder -> 2]

enter image description here

$\endgroup$
0
0
$\begingroup$

As you did not give any data at first, I made some arbitrary data:

dat1 = Table[{x, -ArcTan[10 x]}, {x, -21, 21}] // N;
dat2 = Table[{x, -ArcTan[2 x]}, {x, -20, 20}] // N;
dat2 = Join[{dat1[[1]]}, dat2, {dat1[[-1]]}]

Now we can plot these data. Here is the format of the option: "Filling" that will do what you want:

ListLinePlot[{dat1, dat2},  Filling -> {1 -> {{2}, {Blue, Red}}}]

Plot with filling

To get the areas of the 2 pieces between the curves,you first define an interpolating function through the points and then you integrate:

f1 = Interpolation[dat1];
f2 = Interpolation[dat2];
NIntegrate[f1[x] - f2[x], {x, -21, 0}]

1.42858

-NIntegrate[f1[x] - f2[x], {x, 0, 21}]

1.42858
$\endgroup$
2
  • $\begingroup$ Thank you for the answer. I have already had this Filling option in my command, but it didn't work out. $\endgroup$
    – KratosMath
    Commented Jul 6 at 18:42
  • 1
    $\begingroup$ I think the reason it did not work out is, that the x arguments are not the same. If this is true, you could use the interpolated functions in a "Plot" command instead of using the "ListLinePlot" $\endgroup$ Commented Jul 6 at 19:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.