3
$\begingroup$

I have already been looking for a solution to my problem but maybe I was focusing on the wrong topics. What I want to do is to overlay two plots (in this case a ListPlot and a ListLinePlot) while limiting the x plot range to the data range of the ListPlot without range padding. Right now my approach to do so is this:

plot1 = ListLinePlot[{{0, 1}, {1, 0.5}, {3, 2}}, Frame -> True];
plot2 = ListPlot[{{0, 1}, {1, 1}, {2, 1}}, PlotStyle -> Directive[Red, PointSize[0.05]]];
Show[plot1, plot2, PlotRange -> {{0, 2}, {0, 2}}, PlotRangePadding -> None] 

output

What I do not like is that the symbols of the ListPlot are clipped at the plot edges. Using the PlotRangeClipping->False option achieves the desired result for the symbols but since I am using Show to overlay the plots the option gets extended to the ListLinePlot, making the line not being clipped either (but I want it to be clipped).

So my question is: Is there a simple way to combine the plots and selectively define the clipping? Additionally: Would it be possible to disable the clipping only at the right and top part of the plot but not at the left and bottom part (so that the symbols do not cross the x- & y- axis)?

$\endgroup$
1

2 Answers 2

4
$\begingroup$

You can achieve this by making your ListLinePlot to be a Prolog for ListPlot like in the following:

opts = Sequence[PlotRange -> {{0, 2}, {0, 2}}, ImageSize -> 350, 
   PlotRangePadding -> None, ImagePadding -> 20, Axes -> False];

Show[plot2, Frame -> True, PlotRangeClipping -> False, opts, 
 Prolog -> Inset[Show[plot1, Frame -> False, opts]]]

output

With this solution you must explicitly specify ImageSize and ImagePadding (in this thread you can find ways to automatize this). Another disadvantage of this method is that it doesn't allow interactive resizing of the enclosing graphics by mouse (the inset won't be resized and hence its coordinate system won't be aligned with the coordinate system of the enclosing graphics anymore).

However we can manage to get the same result without explicit ImageSize and ImagePadding specifications if we specify Inset's size in the intrinsic coordinate system of the enclosing graphics:

plotRange = {{0, 2}, {0, 2}};
opts = Sequence[PlotRange -> plotRange, PlotRangePadding -> None, Axes -> False];

Show[plot2, Frame -> True, PlotRangeClipping -> False, opts, 
 Prolog -> Inset[Show[plot1, Frame -> False, opts], {0, 0}, {0, 0}, 
   Abs[Subtract @@@ plotRange]]]

output

The same can be achieved even simpler with Scaled size specification:

opts = Sequence[PlotRange -> {{0, 2}, {0, 2}}, PlotRangePadding -> None, Axes -> False];

Show[plot2, Frame -> True, PlotRangeClipping -> False, opts, 
 Prolog -> Inset[Show[plot1, Frame -> False, opts], {0, 0}, {0, 0}, Scaled[1]]]

output

Note that the last two methods assume that the inset has zero ImagePadding (in our case it has due to the Frame -> False, Axes -> False options).

Note also that the issue with limited precision of clipping mask is applicable here (no good workaround at the moment):

Another possible approach is to use the SciDraw` package which (AFAIK) offers some functionality for explicit control over clipping, but I have no experience with it yet.

$\endgroup$
1
  • $\begingroup$ Thank you very much! I was not aware of the Prolog and Inset commands. This is very helpful! $\endgroup$
    – user48392
    Commented May 8, 2017 at 18:16
3
$\begingroup$

Using the options Mesh and MeshShading with PlotRangeClipping -> False:

ListPlot[{{{0, 1}, {1, 0.5}, {3, 2}}, {{0, 1}, {1, 1}, {2, 1}}}, 
 Joined -> {True, False}, PlotRange -> {{0, 2}, {0, 2}}, Frame -> True, 
 PlotStyle -> {Directive[Thick, Blue], Directive[Red, PointSize[0.05]]}, 
 Mesh -> {{0, 2}}, MeshStyle -> Opacity[0], MeshShading -> {White, Automatic},
 PlotRangeClipping -> False, ImagePadding -> 20, ImageSize -> 400]

enter image description here

If you have to use Show you can use

Show[ListLinePlot[{{0, 1}, {1, 0.5}, {3, 2}}, 
   PlotStyle -> Directive[Thick, Blue], Mesh -> {{0, 2}}, 
   MeshStyle -> Opacity[0], MeshShading -> {White, Automatic}], 
 ListPlot[{{0, 1}, {1, 1}, {2, 1}}, 
   PlotStyle -> Directive[Red, PointSize[0.05]]], 
 PlotRange -> {{0, 2}, {0, 2}}, Frame -> True, 
 PlotRangeClipping -> False, PlotRangePadding -> None, 
 ImagePadding -> 20, ImageSize -> 400]

to get the same picture.

$\endgroup$
2
  • 1
    $\begingroup$ Very unexpected solution (+1). Can you explain why Mesh -> {{0, 2}} forces clipping for the joined curve? $\endgroup$ Commented Oct 1, 2017 at 15:47
  • 2
    $\begingroup$ @Alexey, MeshShading -> {White, Automatic} makes White the portion of the line before 0 and after 2. $\endgroup$
    – kglr
    Commented Oct 1, 2017 at 15:53

Your Answer

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