1

I have the following matplotlib snippet:

fig, ax = plt.subplots(figsize=(6,6))
values = np.random.normal(loc=0, scale=1, size=10)
ax.plot(range(10), values, 'r^', markersize=15, alpha=0.4);

which produces

enter image description here

as planned.

I'd like to make the line invisible where it overlaps with the points so that the points look more joined by the line rather than lying on top of the line. It is possible to do this by either making the line invisible where they overlap or to create a new line object that simply links the points rather than traces them?

To be explicit, I do not want the entire line removed, just the sections that overlap with the points.

6
  • Literally googled, "How to remove lines from plot matplotlib:" Commented Mar 21, 2018 at 21:33
  • Your best bet is to just increase the alpha to something like 1, that way you won't see the lines below the points. I'm not sure if I understand you correctly though. Commented Mar 21, 2018 at 21:36
  • 1
    @ChootsMagoots, I do not want the entire line removed, only the small sections that overlap with the points themselves. Commented Mar 21, 2018 at 21:38
  • 1
    @moenad, I'm going to be overlaying a number of these so I want to keep the transparency relatively high. Commented Mar 21, 2018 at 21:38
  • @ChootsMagoots can you demonstrate how this can be used to solve my problem? Commented Mar 21, 2018 at 21:49

2 Answers 2

2

It is in general hard to let the lines stop at the edges of the markers. The reason is that lines are defined in data coordinates, while the markers are defined in points.

A workaround would be to hide the lines where the markers are. We may think of a three layer system. The lowest layer (zorder=1) contains the lines, just as they are. The layer above contains markers of the same shape and size as those which are to be shown. Yet they would be colored in the same color as the background (usually white). The topmost layer contains the markers as desired.

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(42)

fig, ax = plt.subplots(figsize=(6,5))

def plot_hidden_lines(x,y, ax = None, ms=15, color="r", 
                      marker="^", alpha=0.4,**kwargs):
    if not ax: ax=plt.gca()
    ax.scatter(x,y, c=color, s=ms**2, marker=marker, alpha=alpha, zorder=3)
    ax.scatter(x,y, c="w", s=ms**2, marker=marker, alpha=1, zorder=2)
    ax.plot(x,y, color=color, zorder=1,alpha=alpha,**kwargs)


values1 = np.random.normal(loc=0, scale=1, size=10)
values2 = np.random.normal(loc=0, scale=1, size=10)
x = np.arange(len(values1))

plot_hidden_lines(x,values1)
plot_hidden_lines(x,values2, color="indigo", ms=20, marker="s")

plt.show()

enter image description here

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

2 Comments

If the 2nd call to ax.scatter used a slightly larger marker (e.g. (ms+5)**2), it would cover a bit of the line nearby to the marker, giving a dot/dash appearance as I think the OP is asking. It doesn't zoom well because of the data / points issue you identify, but for final production it could be tweaked
Thank you, this is just what I was looking for.
0

I think the best way to go about it is to overlay the triangles over the lines:

import matplotlib.pyplot as plt
import numpy as np

values = np.random.normal(loc=0, scale=1, size=10)
plt.plot( range(10), values, marker='^', markerfacecolor='red', markersize=15, color='red', linewidth=2)
plt.show()

The program outputs: output of program

If you really want the see through aspect, I suggest you somehow calculate where the lines overlap with the markers and only draw the lines inbetween:

import numpy as np
import matplotlib.pyplot as plt
values = np.random.normal(loc= 0, scale=1, size=10)
for i in range(9):
     start_coordinate, end_coordinate = some_function(values[i], values[i+1])
     plt.plot([i, i+1], [start_coordinate, end_coordinate], *whatever_other_arguments)
plt.scatter(range(10), values, *whatever_other_arguments)
plt.show()

The hard part here is of course calculating these coordinates (if you want to zoom in this won't work), but honestly, given the difficulty of this question, I think you won't find anything much better...

1 Comment

I think that would be possible, just a huge amount of work. You would need to find out the marker edges in terms of data coordinates, i.e. scale the marker path by the inverse of the transData transform. Taking the shape of the marker into account is even harder, but one may start by assuming a circle.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.