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.

Ian Gilman
  • 107
  • 2
  • 6
  • [Literally googled, "How to remove lines from plot matplotlib:"](https://stackoverflow.com/questions/4981815/how-to-remove-lines-in-a-matplotlib-plot?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa) – ChootsMagoots Mar 21 '18 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. –  Mar 21 '18 at 21:36
  • 1
    @ChootsMagoots, I do not want the _entire_ line removed, only the small sections that overlap with the points themselves. – Ian Gilman Mar 21 '18 at 21:38
  • 1
    @moenad, I'm going to be overlaying a number of these so I want to keep the transparency relatively high. – Ian Gilman Mar 21 '18 at 21:38
  • @ChootsMagoots can you demonstrate how this can be used to solve my problem? – Ian Gilman Mar 21 '18 at 21:49
  • The point is this, your question is very nitpicky, and the capabilities of matplotlib are limited. I highly doubt that what you want is possible, but I'm not sure why anyone would ever really need to do it – ChootsMagoots Mar 21 '18 at 21:55

2 Answers2

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

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 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 – Bonlenfum Mar 22 '18 at 11:18
  • Thank you, this is just what I was looking for. – Ian Gilman Mar 22 '18 at 14:37
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...

Nathan
  • 3,558
  • 1
  • 18
  • 38
  • 1
    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. – ImportanceOfBeingErnest Mar 22 '18 at 10:42