Drawing Lines Between Two Plots in Matplotlib

Drawing lines between two plots in Matplotlib

The solution from the other answers are suboptimal in many cases (as they would only work if no changes are made to the plot after calculating the points).

A better solution would use the specially designed ConnectionPatch:

import matplotlib.pyplot as plt
from matplotlib.patches import ConnectionPatch
import numpy as np

fig = plt.figure(figsize=(10,5))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

x,y = np.random.rand(100),np.random.rand(100)

ax1.plot(x,y,'ko')
ax2.plot(x,y,'ko')

i = 10
xy = (x[i],y[i])
con = ConnectionPatch(xyA=xy, xyB=xy, coordsA="data", coordsB="data",
axesA=ax2, axesB=ax1, color="red")
ax2.add_artist(con)

ax1.plot(x[i],y[i],'ro',markersize=10)
ax2.plot(x[i],y[i],'ro',markersize=10)

plt.show()

Sample Image

Plot a line between two subplots while handling the zoom with Matplotlib

As the comment in the linked question (Drawing lines between two plots in Matplotlib) suggests, you should use a ConnectionPatch to connect the plots. The good thing about this ConnectionPatch is not only that it is easy to realize, but also it will move and zoom together with the data.

Here is an example of how to use it.

import matplotlib.pyplot as plt
from matplotlib.patches import ConnectionPatch
import numpy as np

fig, (ax1, ax2) = plt.subplots(1,2, sharex=True, sharey=True)

x,y = np.arange(23), np.random.randint(0,10, size=23)
x=np.sort(x)
i = 10
ax1.plot(x,y, marker="s", linestyle="-.", c="r")
ax2.plot(x,y, marker="o", linestyle="", c="b")

con = ConnectionPatch(xyA=(x[i],y[i]), xyB=(x[i],y[i]),
coordsA="data", coordsB="data",
axesA=ax2, axesB=ax1, arrowstyle="-")

ax2.add_artist(con)

plt.show()

Draw a separator or lines between subplots

I find a solution but not a perfect one, but works for me.

Apply below code to each object of subplot.

Where [-1, 1.5] are values suppose to cover all areas of X axis in figure. not all the same.

axes.plot([-1, 1.5], [0, 0], color='black', lw=1, transform=axes.transAxes, clip_on=False)
axes.plot([-1, 1.5], [1, 1], color='black', lw=1, transform=axes.transAxes, clip_on=False)

I tried another way which I think is the most perfect way. As the code show below.

    trans = blended_transform_factory(self.figure.transFigure, axes.transAxes)
line = Line2D([0, 1], [0, 0], color='w', transform=trans)
self.figure.lines.append(line)

In above code the line would begin at the start of every figure edge, and it will change when the figure size changed.

How to draw lines between mouseclicks on a matplotlib plot?

The API says:
**line_kwargs (kwargs) – Line2D objects (from ax.plot) are used to generate the markers. line_kwargs will be passed through to all of the ax.plot calls.

So, let's set the linestyle:

klicker = clicker(ax, ["event"], markers=["x"], **{"linestyle": "--"})

Sample output:

Sample Image

Other Line2D keywords can be found here.

How to draw a line between a data point and an axis in matplotlib?

In my opinion, this is simple enough (4 lines):

fig, ax = plt.subplots()
x = np.arange(10)
y = np.arange(10)
ax.plot(x, y)
# starting from here
ymin, ymax = ax.get_ylim()
for i in range(len(x)):
ax.vlines(x[i], ymin, y[i])
ax.set_ylim(ymin, ymax)

Output:

Sample Image

How to plot a new line between the markers on two separate plot lines using matplotlib?

If I understood your request correctly, this should do the trick.

from matplotlib import pyplot as plt
from matplotlib.collections import LineCollection

plt.figure(figsize=(8,7))
f, ax = plt.subplots(1, 1)
ax.plot(points_vs_xpoints["xpts"],points_vs_xpoints.index, label="Projected", linestyle = 'None', marker="o")
ax.plot(points_vs_xpoints["pts"], points_vs_xpoints.index, label="Actual", linestyle = 'None', marker="o", markeredgecolor="r", markerfacecolor='None')

lines = LineCollection([[[el[0], points_vs_xpoints.index[i]], [el[1], points_vs_xpoints.index[i]]] for i, el in enumerate(zip(points_vs_xpoints["xpts"],points_vs_xpoints["pts"]))], label='Connection', linestyle='dotted')
ax.add_collection(lines)

ax.set_xticks(np.arange(0, 100, 10))
plt.tick_params(rotation=90)
ax.legend()
ax.grid(color='grey', linewidth=0.2)
f.tight_layout()
plt.show()

See the resulting graph here

Edit

I wrongly assumed your index was a numeric one. With a string index, you can try something like this

from matplotlib import pyplot as plt
from matplotlib.collections import LineCollection

plt.figure(figsize=(8,7))
f, ax = plt.subplots(1, 1)
ax.plot(points_vs_xpoints["xpts"],points_vs_xpoints.index, label="Projected", linestyle = 'None', marker="o")
ax.plot(points_vs_xpoints["pts"], points_vs_xpoints.index, label="Actual", linestyle = 'None', marker="o", markeredgecolor="r", markerfacecolor='None')

# Let's go with a simple index
lines = LineCollection([[[el[0], i], [el[1], i]] for i, el in enumerate(zip(points_vs_xpoints["xpts"],points_vs_xpoints["pts"]))], label='Connection', linestyle='dotted')
ax.add_collection(lines)

# Change for labels rotation
ax.set_xticklabels(np.arange(0, 100, 10), rotation=90)
ax.legend()
ax.grid(color='grey', linewidth=0.2)
f.tight_layout()
plt.show()

See the resulting graph here

Plotting lines connecting points

I think you're going to need separate lines for each segment:

import numpy as np
import matplotlib.pyplot as plt

x, y = np.random.random(size=(2,10))

for i in range(0, len(x), 2):
plt.plot(x[i:i+2], y[i:i+2], 'ro-')

plt.show()

(The numpy import is just to set up some random 2x10 sample data)

Sample Image

Plotting a line over several graphs

You can pull this off by turning clipping off for the relevant lines. There's probably a cleaner way to do this -- you might be able to draw lines on the main frame directly -- but the following worked for me:

from matplotlib import pyplot as plt
from numpy import arange, sin, cos

xx = arange(100)
cut = (xx > 0) & (xx % 17 == 0)
y1 = sin(xx)
y2 = (xx**2) % 2.0+cos(xx+0.5)

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.plot(xx, y1, c="blue",zorder=1)
ax1.scatter(xx[cut], y1[cut], c="red",zorder=2)
ax2 = fig.add_subplot(212)
ax2.plot(xx, y2, c="green",zorder=1)
ax2.scatter(xx[cut], y2[cut], c="red",zorder=2)

for x in xx[cut]:
ax1.axvline(x=x,ymin=-1.2,ymax=1,c="red",linewidth=2,zorder=0, clip_on=False)
ax2.axvline(x=x,ymin=0,ymax=1.2,c="red",linewidth=2, zorder=0,clip_on=False)

plt.draw()
fig.savefig('pic.png')

With a bit more work you could modify the line drawing to handle the general case of multiple subplot windows, but I'm profoundly lazy. :^)

example of cross-subplot vertical lines



Related Topics



Leave a reply



Submit