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()
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:
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:
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)
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. :^)
Related Topics
How to Turn Off Info Logging in Spark
How to Merge 200 CSV Files in Python
Generate a Random Derangement of a List
How to Declare an Array in Python
Matplotlib: Overlay Plots with Different Scales
Display Fullscreen Mode on Tkinter
Creating a Bat File for Python Script
Search in Lists of Lists by Given Index
How to Get "Python -M Venv" to Directly Install Latest Pip Version
How to Add a Custom Ca Root Certificate to the Ca Store Used by Pip in Windows
Pyspark: Split Multiple Array Columns into Rows
Conditionally Fill Column Values Based on Another Columns Value in Pandas
Bin Elements Per Row - Vectorized 2D Bincount for Numpy
Defining Private Module Functions in Python
Assignment Inside Lambda Expression in Python