13
$\begingroup$

I am preparing a figure for an article, and I would like very much to be able to fill a curve, but not under it, but to the vertical axis, i.e. to the left. Due to the meaning of the data I present, I cannot exchange the axes.

Here is a minimal example:

Plot[ArcCot[x], {x, 0, 1}, PlotRange -> {{0, 1.1}, {0.5, 2}}, AxesLabel -> {x, y}]

Can anyone think of a way of filling the curve to they axis? I find no mention of this kind of filling in the standard documentation.

$\endgroup$
3
  • $\begingroup$ Duplicate of this? $\endgroup$ Commented Oct 4, 2013 at 11:17
  • $\begingroup$ Sorry everyone: that was a typing error. I surely meant "filling to the vertical axis, i.e. to the left". But thanks to it I have got even better understanding of the question than originally intended! $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:34
  • $\begingroup$ Related: Filling Fill incomplete in ListLinePlot $\endgroup$
    – Mr.Wizard
    Commented Jan 10, 2014 at 9:56

7 Answers 7

6
$\begingroup$

Adding a line at the minimum value and shading as normal:-

min = MinValue[ArcCot[x], 0 <= x <= 1, x];
Plot[{ArcCot[x], min}, {x, 0, 1}, PlotRange -> {{0, 1.1}, {0.5, 2}}, 
 AxesLabel -> {x, y}, Filling -> {1 -> {2}}, PlotStyle -> {Automatic, None}]

enter image description here

$\endgroup$
2
  • $\begingroup$ @mike-honeychurch. That's filling to the vertical axis indeed, thanks, that was what I was seeking. And in this aspect it's the same answer as that of Mike Honeychurch. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:41
  • $\begingroup$ Choosing yours as the first simple answer to what I sought. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:56
12
$\begingroup$

This is my second answer, which is a rather different (and simpler) idea than my first one, namely, add a polygon that shades from a Line in the plot to a vertical axis at x = x0.

fillVertical[plot_, x0_: 0.] := plot /. Line[p_] :>
   {{Opacity[0.2], Polygon[p ~Join~ {{N @ x0, p[[-1, 2]]}, {N @ x0, p[[1, 2]]}}]}, 
    Line[p]}

The shading automatically takes the color (and other directives) from the plot styles. If the graph of a single function consists of several lines, then several polygons will be drawn and they might overlap. If the endpoints of the graph are not the extrema, then an edge of the polygon will cut through the graph.*

Example

fillVertical[
 Plot[{ArcCot[x], 0.4 Sin[10 x] + x/2, 2 - x^2/3}, {x, 0.5, 2}, 
  PlotRange -> {{0, 2.1}, {0., 2}}, AxesLabel -> {x, y}]]

Mathematica graphics

**Note:* I thought about using MaxValue and MinValue, but it seemed unclear to me what the desired shading would be if the extrema do not occur at endpoints. I imagine that shading to a vertical axis would be sought only when the function is invertible (i.e., when $x$ is a function of $y$). So, for example, not the case of the sine graph shown above. It turns out fillVertical works for invertible Piecewise functions. The one below would be difficult with the standard filling options of Plot. (Observe that the extrema do occur at endpoints of Lines of the graph).

fillVertical[
 Plot[Piecewise[{{x, 0 <= x <= 1}, {3 - x, 1 < x}}], {x, 0.5, 2}, 
  PlotRange -> {{0, 2.1}, {0., 2}}, AxesLabel -> {x, y}]]

Mathematica graphics

$\endgroup$
4
  • $\begingroup$ Thank you, Michael. It is a nice solution indeed, what you proposed. And the curves you get are really pretty. I suppose that I would chose this one if I needed to fill several curves on the same plot. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 11, 2013 at 11:19
  • 1
    $\begingroup$ To my mind, what you wish to obtain if the extrema do not occur at the endpoints, depends on what the nature of the curve you plot. In my case, the filling to the vertical axis represents the region in which a specific physical assumption is valid. So, if I had a sine curve like you show above, I would desire filling also through the white space under the curve between the minima. Although in my special case, such curves are not possible. Still, as a theoretical question, it is an interesting one. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 11, 2013 at 11:25
  • $\begingroup$ @Szczypawka Thanks. You can use Max and Min on the coordinates in the Lines to get the bounding box of the curve and locations of the extrema. Theoretically, one could get all sorts of shading by modifying this method. It seems for your application that filling to the minimum is simplest. $\endgroup$
    – Michael E2
    Commented Oct 11, 2013 at 12:55
  • $\begingroup$ Great solution. +1 $\endgroup$
    – Mr.Wizard
    Commented Jan 10, 2014 at 9:58
7
$\begingroup$

Some of these answers seem overcomplicated.

min = MinValue[ArcCot[x], 0 <= x <= 1, x];
Plot[{ArcCot[x]}, {x, 0, 1}, PlotRange -> {{0, 1.1}, {0.5, 2}}, 
 AxesLabel -> {x, y}, Filling -> {1 -> min}]

enter image description here

Edit

Frankly it is unclear to me what is wanted here. My comment is more directed toward the other answers than toward the actual question. But regarding the comment from @rm here is an example of filling to the right (if that is in fact what is required):

max = MaxValue[ArcCot[x], 0 <= x <= 1, x];
Plot[{ArcCot[x]}, {x, 0, 1}, PlotRange -> {{0, 1.1}, {0.5, 2}}, 
 AxesLabel -> {x, y}, Filling -> {1 -> max}]

enter image description here

Happy to delete all this if none of it is what is being sought.

$\endgroup$
3
  • $\begingroup$ @rm-rf, MichaelE2, Mike. Thank you, your answer is simple and elegant. I am sorry, I surely meant "left", but was just tired and wrote "right". Have already corrected. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:37
  • $\begingroup$ So your comment is well directed towards the question I asked. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:38
  • $\begingroup$ See also the answer of Chris Degnen. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:44
6
$\begingroup$

A somewhat roundabout way (switch x,y; fill; switch x,y again):

With[{plot = Plot[ArcCot[x], {x, 0, 1}, PlotRange -> {{0, 1.1}, {0.5, 2}}, 
    AxesLabel -> {x, y}]},
 With[{pts = Cases[plot,
                   Line[p_] :> (p /. {x_Real, y_Real} :> {y, x}), 
                   Infinity]},
  Show[
   ListLinePlot[pts, Filling -> Axis] /. {x_Real, y_Real} :> {y, x}, 
   FilterRules[Options[plot], Options[Graphics]]]
  ]]

Mathematica graphics

One advantage to this roundabout way is filling to the axis x = 0 when the Plot domain does not include it. Here we change the plot domain to {x, 0.5, 2}:

With[{plot = Plot[ArcCot[x], {x, 0.5, 2},
                  PlotRange -> {{0, 2.1}, {0., 2}}, AxesLabel -> {x, y}]},
 With[{pts = Cases[plot,
                   Line[p_] :> (p /. {x_Real, y_Real} :> {y, x}),
                   Infinity]},
  Show[
   ListLinePlot[pts, Filling -> Axis, AxesOrigin -> {0, 0},
     FilterRules[Options[plot], Cases[Options[ListLinePlot], Except[PlotRange -> _]]],
     Options[plot, PlotRange] /. {rx_List, ry_List} :> {rx, ry}] /.
       {x_Real, y_Real} :> {y, x},
   Options[plot, PlotRange]]
  ]]

Mathematica graphics

If placing the y axis to the right is desired, then the AxesOrigin can be used with ListLinePlot (when the coordinates are switched). Something like this:

Clear[x, y];
With[{plot = Plot[ArcCot[x], {x, 0.5, 2},
    PlotRange -> {{0.4, 2.1}, {0., 2}}, AxesLabel -> {x, y}]},
 With[{pts = Cases[plot,
                   Line[p_] :> (p /. {x_Real, y_Real} :> {y, x}),
                   Infinity]},
  Show[ListLinePlot[pts, Filling -> Axis, Frame -> True, AxesOrigin -> {0, 2.1},
     FilterRules[Options[plot], Cases[Options[ListLinePlot], Except[PlotRange -> _]]],
     Options[plot, 
       PlotRange] /. {rx_List, ry_List} :> {rx, ry}] /. {x_Real, y_Real} :> {y, x},
   Options[plot, PlotRange]]
  ]]

Mathematica graphics

$\endgroup$
2
  • $\begingroup$ That's filling to the vertical axis that I desired, thank you! And it's an intersting solution. Although a bit complicated, I should admit. Taking into account the other answers, I suppose it is possible to fill to x=0, when the figure does not include it if you fill not only to the min value, but between a max a and a min... $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:47
  • $\begingroup$ Having thought about it, I should add, that may indeed be an advantage. Suppose filling to x=0 if it is not included may be impossible with ordianary methods. So, thanks again. ) $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:55
3
$\begingroup$

If you mean to fill everything to the right of the curve (you wrote "to the right", did not you?), try this:

    RegionPlot[y > ArcCot[x], {x, 0, 1.1}, {y, 0.5, 2}, 
 AxesLabel -> {x, y}]

enter image description here

In response to your doubts: all this in your hands. This is without extra axes:

  RegionPlot[y > ArcCot[x], {x, 0, 1.1}, {y, 0.5, 2}, AxesLabel -> {x, y}, FrameTicks -> {Automatic, Automatic, None, None}] 

enter image description here

This is without off-set:

RegionPlot\[y > ArcCot\[x\], {x, 0, 1.1}, {y, 0.5, 2}, 
 AxesLabel -> {x, y}, PlotRangePadding -> 0\]][3]

enter image description here This is with a blue boundary, rather than gray one:

RegionPlot[y > ArcCot[x], {x, 0, 1.0}, {y, 0.5, 2}, AxesLabel -> {x, y}, PlotRangePadding -> 0, FrameTicks -> {Automatic, Automatic, None, None}, Frame -> {True, True, False, False}, BoundaryStyle -> {Blue, Thickness[0.005]}, PlotRange -> {{-0.1, 1.1}, {-0.1, 2.1}}]

enter image description here

and this is, if you like to have in blue only the line ActCot[x]:

    Show[{
  RegionPlot[y > ArcCot[x], {x, 0, 1.0}, {y, 0.5, 2}, 
   AxesLabel -> {x, y}, PlotRangePadding -> 0, 
   FrameTicks -> {Automatic, Automatic, None, None}, 
   Frame -> {True, True, False, False}, 
   PlotRange -> {{-0.1, 1.1}, {-0.1, 2.1}}],
  Plot[ ArcCot[x], {x, 0, 1.0}, PlotStyle -> {Blue, Thickness[0.005]}]
  }]

enter image description here

Have fun!

$\endgroup$
5
  • $\begingroup$ Thanks, but using region plot, the way how the plot looks (I mean the axes at all 4 sides) also changes. And I suppose the solution with filling to minimum is easier. Still, your is also an interesting one. Thanks. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:49
  • $\begingroup$ @Szczypawka That's in your hands: RegionPlot[y > ArcCot[x], {x, 0, 1.1}, {y, 0.5, 2}, AxesLabel -> {x, y}, FrameTicks -> {Automatic, Automatic, None, None}] $\endgroup$ Commented Oct 8, 2013 at 11:18
  • $\begingroup$ Right. That works. Although, I think, it would be nicer if I could fill to the axis itself: you see, now one has a small interval left (which is quite expected if one uses RegionPlot, surely). $\endgroup$
    – Dr_Zaszuś
    Commented Oct 11, 2013 at 11:29
  • $\begingroup$ @Szczypawka That's also in your hands. Try this: RegionPlot[y > ArcCot[x], {x, 0, 1.1}, {y, 0.5, 2}, AxesLabel -> {x, y}, PlotRangePadding -> 0]. Have fun. $\endgroup$ Commented Oct 14, 2013 at 7:09
  • $\begingroup$ Right. Still, you know, even if I put all the comments in one string: RegionPlot[y > ArcCot[x], {x, 0, 1.0}, {y, 0.5, 2}, AxesLabel -> {x, y}, PlotRangePadding -> 0, FrameTicks -> {Automatic, Automatic, None, None}, Frame -> {True, True, False, False}, PlotRange -> {{-0.1, 1.1}, {-0.1, 2.1}}] the plot looses the curve. If you evaluate the string, you will obtain a region with a grey boundary, which is not exactly what I would like to have. I mean like that the initial curve is hidden, which is no surprise if one uses RegionPlot. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 14, 2013 at 10:33
2
$\begingroup$

Using the function that I've previously defined here, we can do this:

Clear[x, y];

p = Plot[ArcCot[x], {x, 0, 1}, PlotRange -> {{0, 1.1}, {0.5, 2}}, AxesLabel -> {x, y}];

shadeBoundedArea[p, ArcCot[1] < y < ArcCot[x]]

filled

$\endgroup$
4
  • $\begingroup$ Thank you for the answer. Nice function! But I find that filling to a minimum value is just easier in this case. $\endgroup$
    – Dr_Zaszuś
    Commented Oct 7, 2013 at 8:50
  • $\begingroup$ Still there seems to be a strange artefact of filling near x=1... $\endgroup$
    – Dr_Zaszuś
    Commented Oct 11, 2013 at 11:26
  • $\begingroup$ @Szczypawka Yeah, I haven't had time to check that out. The function mostly works very nicely, though. (In the background this executes RegionPlot just as in Alexei's solution.) For your scenario other answers are better anyway. $\endgroup$
    – C. E.
    Commented Oct 11, 2013 at 11:31
  • 1
    $\begingroup$ You can fix that artefact by adding PlotPoints -> 100 to RegionPlot in shadeBoundedArea. $\endgroup$ Commented Oct 15, 2013 at 10:28
2
$\begingroup$

I know this thread is long time inactive, but Michael E2's excellent fillVertical function above helped me out a lot. I did need a more "density"-like fill, so I'm sharing my variant of it (using my novice-level Mathematica programming skills) which splits the Line into monotonic segments:

fillVertical2[plot_, x0_: 0.] := plot /. Line[p_] :>
  Function[{mp},{{Opacity[0.2],
      Polygon[mp ~Join~ {{N@x0, mp[[-1, 2]]}, {N@x0, mp[[1, 2]]}}]}, Line[mp]}] /@ 
  SequenceCases[p, lp_ /; Less @@ lp[[All, 2]] || Greater @@ lp[[All, 2]]];

This gives a plot like

fillVertical2[Plot[Sin[x] + 0.3 x, {x, 0, 10}, PlotStyle -> Red]]

overlayed fillVertical

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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