10

Is there a proper way to draw a border to outline a matplotlib plot?

The best I've found so far is this answer[1] and a matplotlib tutorial[2] that use matplotlib.patheffects to draw a slightly thicker stroke for the outline.

My issue though is that it breaks semitransparent plots, if you set alpha < 1.0 you will see the full stroke behind the main one while I'd like a true border. Is there a way to draw a real outline?

import numpy as np import matplotlib.pyplot as plt import matplotlib.patheffects as mpe outline=mpe.withStroke(linewidth=8, foreground='black') x = np.linspace(0, 2*np.pi, 1000) plt.plot(x, np.sin(x), lw=5, color='red', path_effects=[outline], label="stroke no alpha") plt.plot(x, np.sin(x-np.pi/3.), lw=5, alpha=0.5, color='red', path_effects=[outline], label="stroke with alpha") plt.plot(x, np.sin(x-2*np.pi/3.), lw=5, alpha=0.5, color='red', label="no stroke with alpha") plt.legend() plt.show() 

enter image description here

8
  • The main issue is with the "stroke with alpha" and "no stroke with alpha" having different colors? Or is seeing the lines underneath also relevant? Commented May 18, 2018 at 23:28
  • @xg.plt.py I'd like the line with the black border to behave like a normal matplotlib line, so if you set alpha you should definitely see what's behind Commented May 19, 2018 at 1:49
  • Doesn't this already happen in your example? Commented May 19, 2018 at 1:53
  • @xg.plt.py nope, in my example if I set alpha I see the border is not a border but a full black thicker line. I'd like a real border Commented May 19, 2018 at 2:07
  • 1
    "Stroke" is not really a stroke; it's a copy of the path which is a little thicker. Hence I doubt one can achieve the desired with the available patheffects. One may create a new effect though. Possibly relevant here: In matplotlib, how can I plot a multi-colored line, like a rainbow. Commented May 21, 2018 at 21:40

1 Answer 1

6

There is one way of drawing a true border using alpha, in the sense that the thicker black line won't be seen beneath the red line. The trick is to plot a white line covering the unwanted part of the black line, in order to leave only the border.

Thus, the "stroke with alpha" would instead be like:

pe1 = [mpe.Stroke(linewidth=8, foreground='black'), mpe.Stroke(foreground='white',alpha=1), mpe.Normal()] plt.plot(x, np.sin(x-np.pi/3.), color='red', label="stroke with alpha", lw=5, alpha=0.5, path_effects=pe1) 

Which yields the following plot:

stroke

As it can be seen, this solves the color difference problem between having a border and not having one, but prevents seeing the lines below.

Depending on the application, the alpha parameter of the white layer could be set to a semitransparent value too, in order to achieve a trade-off between masking the black line to plot the border and allowing to see other lines that may be below. For instance, the following path_effect:

pe1 = [mpe.Stroke(linewidth=8, foreground='black'), mpe.Stroke(foreground='white',alpha=0.6), mpe.Normal()] 

yields:

strokes alpha

which is half way between the pinkish color resulting from combining red and alpha 0.5, and seeing completely the black line beneath; while still allowing to see the other lines previously plotted.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi, thanks for the answer, but I'm not after the pink color, I'd like to see what's behind just like alpha usually does. The only way for this to work would be to draw a real outline, but I don't know how... maybe some kind of clipping
the point, beside being a useful thing on its own, is that I need to use this in a lot more crowded plot where the amount of blending between overlapping lines is informative and this way it can be misleading

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.