I created a sequence of points that I would like to convert into a Patch.
The goal is then to draw the patch on the left side of the y-label (see in Red in the figure), or draw it in any other part of the figure.
Although it can be accomplished with Gridspec, I would like to do it with a Patch.
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
npoints = 100
td = np.linspace(np.pi*3/4, np.pi*5/4, npoints)
xd = np.cos(td)
yd = np.sin(td)
plt.plot(xd,yd)
EDIT1:
I am now able to make a Patch (just need to move it outside the axis):
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.path as mpath
import matplotlib.patches as mpatches
npoints = 100
td = np.linspace(np.pi*3/4, np.pi*5/4, npoints)
xd = np.cos(td)
yd = np.sin(td)
fig, ax = plt.subplots()
ax.axis([-2, 0, -1, 1])
verts=np.c_[xd,yd]
codes = np.ones(len(xd))*2 # Path.LINETO for all points except the first
codes[0] = 1 #Path.MOVETO only for the first point
path1 = mpath.Path(verts, codes)
patch = mpatches.PathPatch(path1, facecolor='none')
ax.add_patch(patch)
The result:
Now, I only need to move it outside the axis, maybe using a translation or scale.
I'm sure the key to do it is somewhere in this Matplotlib Transforms tutorial, more specifically, I am pretty sure the solution is using fig.transFigure.
EDIT 2: Almost there!
In order to use Figure coordinates (that are between [0,1]) I normalized the points that define the path. And instead of using ax.add_patch()
that adds a patch to the axis, I use fig.add_artist()
that adds the patch to the figure, over the axis.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.path as mpath
import matplotlib.patches as mpatches
#Normalized Data
def normalize(x):
return (x - min(x)) / (max(x) - min(x))
#plt.figure()
npoints = 100
td = np.linspace(np.pi*3/4, np.pi*5/4, npoints)
xd = np.cos(td)
yd = np.sin(td)
#plt.plot(xd,yd)
xd = normalize(xd)
yd = normalize(yd)
fig, ax = plt.subplots()
ax.axis([-2, 2, -1, 1])
verts=np.c_[xd,yd]
codes = np.ones(len(xd))*2 # Path.LINETO for all points except the first
codes[0] = 1 #Path.MOVETO only for the first point
path1 = mpath.Path(verts, codes)
patch1 = mpatches.PathPatch(path1, facecolor='none')
ax.add_patch(patch1)
patch2 = mpatches.PathPatch(path1, fc='none', ec='red', transform=fig.transFigure)
fig.add_artist(patch2)
Doing this, I just need to scale and translate the patch, maybe using Affine2D.
EDIT 3: Done!
Finally I was able to do it! I used Try and Error in the scale()
and translate()
parameters as I did not get what coordinate system they were using. However, it would be great to get the exact y center (0.5 in Figure coordinates).
Here is the complete code:
import numpy as np
import matplotlib.path as mpath
import matplotlib.patches as mpatches
#Normalized Data
def normalize(x):
return (x - min(x)) / (max(x) - min(x))
npoints = 100
td = np.linspace(np.pi*3/4, np.pi*5/4, npoints)
xd = np.cos(td)
yd = np.sin(td)
xd = normalize(xd)
yd = normalize(yd)
fig, ax = plt.subplots()
ax.axis([-2, 2, -1, 1])
verts=np.c_[xd,yd]
codes = np.ones(len(xd))*2 # Path.LINETO for all points except the first
codes[0] = 1 #Path.MOVETO only for the first point
path1 = mpath.Path(verts, codes)
patch1 = mpatches.PathPatch(path1, fc='none', ec='green')
ax.add_patch(patch1) #draw inside axis
patch2 = mpatches.PathPatch(path1, fc='none', ec='C0', transform=fig.transFigure)
fig.add_artist(patch2) #this works! Draw on figure
import matplotlib.transforms as mtransforms
tt = fig.transFigure + mtransforms.Affine2D().scale(0.02, 0.8).translate(10,45)
patch3 = mpatches.PathPatch(path1, fc='none', ec='red', transform=tt)
fig.add_artist(patch3)
And the resulting figure: