Currently, I am trying to make my own custom legend handler by creating a proxy artist (?) patch using PatchCollections and then following http://matplotlib.org/users/legend_guide.html to make a custom handler.
However I am running into a roadblock in trying to implement this into the legend. The arguments for legend takes in patches, but not patchcollections.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.patches as mpatches
from matplotlib.path import Path
from matplotlib.collections import PatchCollection
fig = plt.figure()
ax = fig.add_subplot(111)
verts1 = [(0.,0.),(0.,1.),(1.,1.),(0.51,0.51),(0.,0.),(0.,0.),]
codes1 = [Path.MOVETO,Path.LINETO,Path.LINETO,Path.LINETO,Path.MOVETO,Path.CLOSEPOLY,]
path1 = Path(verts1,codes1)
patch1 = mpatches.PathPatch(path1,ls='dashed',ec='red',facecolor="none")
verts2 = [(0.49,0.49),(0.,0.),(1.,0.),(1.,1.),(0.5,0.5),(0.,0.),]
codes2 = [Path.MOVETO,Path.LINETO,Path.LINETO,Path.LINETO,Path.MOVETO,Path.CLOSEPOLY,]
path2 = Path(verts2,codes2)
patch2 = mpatches.PathPatch(path2,ls='solid',edgecolor='red', facecolor="none")
patch = PatchCollection([patch1,patch2],match_original=True)
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
ax.add_collection(patch)
The above is the code to visualise the handler. Basically a rectangle with the upper triangle as dashed lines and the lower as solid
Using,
plt.legend([patch],["hellocello"],loc='upper right')
Recreates the error. Is there a workaround?
From the example in this section, it looks like you need to define an object and express all coordinates in terms of the handlebox size,
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.patches as mpatches
from matplotlib.path import Path
from matplotlib.collections import PatchCollection
class AnyObject(object):
pass
class AnyObjectHandler(object):
def legend_artist(self, legend, orig_handle, fontsize, handlebox):
x0, y0 = handlebox.xdescent, handlebox.ydescent
width, height = handlebox.width, handlebox.height
hw = 0.5*width; hh = 0.5*height
verts1 = [(x0,y0),(x0,y0+height),(x0+width,y0+height),((x0+hw)*1.01,(y0+hh)*1.01),(x0,y0),(x0,y0),]
codes1 = [Path.MOVETO,Path.LINETO,Path.LINETO,Path.LINETO,Path.MOVETO,Path.CLOSEPOLY,]
path1 = Path(verts1,codes1)
patch1 = mpatches.PathPatch(path1,ls='dashed',ec='red',facecolor="none")
verts2 = [((x0+hw)*0.99,(y0+hh)*0.99),(x0,y0),(x0+width,y0),(x0+width,y0+height),(x0+hw,y0+hh),(x0,y0),]
codes2 = [Path.MOVETO,Path.LINETO,Path.LINETO,Path.LINETO,Path.MOVETO,Path.CLOSEPOLY,]
path2 = Path(verts2,codes2)
patch2 = mpatches.PathPatch(path2,ls='solid',edgecolor='red', facecolor="none")
patch = PatchCollection([patch1,patch2],match_original=True)
handlebox.add_artist(patch)
return patch
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
plt.legend([AnyObject()], ['hellocello'],
handler_map={AnyObject: AnyObjectHandler()})
plt.show()
This seems to work okay with PatchCollection, at least for me on matplotlib version 1.4.3. The result looks like,
Related
I'm sure this is probably easy and a simple fix, but I was having a lot of trouble with changing the number sizes on the colormap. Below is the code I have
from matplotlib import cm
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
cmap = cm.get_cmap('plasma')
fig = plt.figure(figsize=(25,25))
norm = Normalize(vmin=min(dz), vmax=max(dz))
colors = cmap(norm(dz))
sc = cm.ScalarMappable(cmap=cmap,norm=norm)
sc.set_array([])
plt.colorbar(sc)
I am aware on how to change them for the graph with
plt.xticks(size=20)
plt.yticks(size=20)
But just not for the colormap. If anyone can help I would appreciate it.Thank you.
You are looking for the labelsize argument of the tick_params method of the Axes associated to the colorbar. Have a look at the following example:
import matplotlib.pyplot as plt
from numpy.random import default_rng
data = default_rng(0).random((25, 100))
fig, ax = plt.subplots()
ctrf = ax.contourf(data)
cbar = fig.colorbar(ctrf)
cbar.ax.tick_params(labelsize=16)
plt.show()
I have data saved in a dataframe format (xarray, similar to Pandas), and I want it to be animated with pcolormesh.
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
graph_data = mytest.TMP_P0_L1_GLL0[i]
ax1.pcolormesh(graph_data)
FuncAnimation(plt,animate,frames=100)
which doesn't work for some reason (there is no error but when I show fig it is not animating).
the way the data is laid out is that pcolormesh(mytest.TMP_P0_L1_GLL0[0]) will output a quadmesh, pcolormesh(mytest.TMP_P0_L1_GLL0[1]) will output a slightly different quadmesh...etc
Thanks for your help!
The signature of FuncAnimation is FuncAnimation(fig, func, ...). Instead of the pyplot module you need to supply the figure to animate as first argument.
Further, you need to retain a reference to the animation class, ani = FuncAnimation. The following is a minimal example which works fine.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
class test():
TMP_P0_L1_GLL0 = [np.random.rand(5,5) for i in range(100)]
mytest = test()
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
graph_data = mytest.TMP_P0_L1_GLL0[i]
ax1.pcolormesh(graph_data)
ani = FuncAnimation(fig,animate,frames=100)
plt.show()
I am using matplotlib to get a water fall figure, but the results look very strange. Anyone have any idea what could be wrong with it?
Here I attached the figures. The second one is the same data but in an ordinary plot. In the waterfall figure, why the color is not fully filled?
Here is the code:
def water_fall_1(x,y,Z):
#x=[...]
#y=[...]
#Z=[[z1],[z2],...z[ny]]
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
from mpl_toolkits.mplot3d import Axes3D
figs=[]
for jc in range(len(y)):
figs.append(list(zip(x,Z[jc])))
x=np.array(x)
y=np.array(y)
Z=np.array(Z)
xmin=np.floor(np.min((x.astype(np.float))))
xmax=np.ceil(np.max((x.astype(np.float))))
ymin=np.min((y.astype(np.float)))
ymax=np.max((y.astype(np.float)))
zmin=(np.min((Z.astype(np.float))))
zmax=np.max((Z.astype(np.float)))
fig=plt.figure()
ax = Axes3D(fig)
poly = PolyCollection(figs, facecolors=colorConverter.to_rgba("r", alpha=0.5))
ax.add_collection3d(poly, zs=y.astype(np.float), zdir='y')
ax.set_xlim(xmin,xmax)
ax.set_ylim(ymin,ymax)
ax.set_zlim(zmin,zmax)
ax.set_xlabel('$\omega$')
ax.set_ylabel('$T$')
#ax.set_zlabel('$\\frac{1}{2}$')
plt.show()
The curve is fully filled. I.e. the surface in between the points of the curve is red.
Consider the following example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from mpl_toolkits.mplot3d import Axes3D
bottom=-0.3
x = np.linspace(0,6, num=50)
z = np.sinc(x-4)
verts = zip(x,z)
#verts=verts + [(x.max(),bottom),(x.min(),bottom)]
fig=plt.figure()
ax = Axes3D(fig)
poly = PolyCollection([verts], facecolors="r", alpha=0.5)
ax.add_collection3d(poly, zs=1, zdir='y')
ax.set_xlim(x.min(),x.max())
ax.set_ylim(0,2)
ax.set_zlim(bottom,z.max())
plt.show()
which produces the following plot, where everything between the points of the curve is filled as expected.
If we now want to have the area between the curve and some bottom line filled, we would need to add some points,
verts=verts + [(x.max(),bottom),(x.min(),bottom)]
such that the bottom line is part of the curve and can thus be filled as well.
Here is my code:
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime
import numpy as np
fig, ax = plt.subplots(1,1)
sample_dates = np.array([datetime.datetime(2000,1,1), datetime.datetime(2001,1,1)])
sample_dates = mdates.date2num(sample_dates)
plt.vlines(x=sample_dates, ymin=0, ymax=10, color = 'r')
ax.xaxis.set_major_locator(mdates.YearLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d.%m.%y'))
plt.show()
It plots two red lines at certain dates on x-axis. Now I would like to add text to every line. Text should be parallel to the line. Where do I start?
You can use Matplotlib text function to draw text on the plots. It has a lot of parameters that can be set. See documentation and examples here.
Here is an example with some text parallel to the lines:
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime
import numpy as np
from matplotlib.pyplot import text
fig, ax = plt.subplots(1,1)
sample_dates = np.array([datetime.datetime(2000,1,1), datetime.datetime(2001,1,1)])
sample_dates = mdates.date2num(sample_dates)
plt.vlines(x=sample_dates, ymin=0, ymax=10, color = 'r')
ax.xaxis.set_major_locator(mdates.YearLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d.%m.%y'))
for i, x in enumerate(sample_dates):
text(x, 5, "entry %d" % i, rotation=90, verticalalignment='center')
plt.show()
Should look like this:
I have this bit of code that plots out the points:
import matplotlib.pyplot as plot
from matplotlib import pyplot
all_data = [[1,10],[2,10],[3,10],[4,10],[5,10],[3,1],[3,2],[3,3],[3,4],[3,5]]
x = []
y = []
for i in xrange(len(all_data)):
x.append(all_data[i][0])
y.append(all_data[i][1])
plot.scatter(x,y)
pyplot.show()
but I want all the possible lines that could be made that looks something like this:
I've tried matplotlib path, but it doesn't work well for me.
This can be optimized but it works:
for point in all_data:
for point2 in all_data:
pyplot.plot([point[0], point2[0]], [point[1], point2[1]])
import matplotlib.pyplot as plt
import itertools
fig=plt.figure()
ax=fig.add_subplot(111)
all_data = [[1,10],[2,10],[3,10],[4,10],[5,10],[3,1],[3,2],[3,3],[3,4],[3,5]]
plt.plot(
*zip(*itertools.chain.from_iterable(itertools.combinations(all_data, 2))),
color = 'brown', marker = 'o')
plt.show()
One other way could be to use matplotlib patches
import matplotlib
import pylab as pl
fig, ax = pl.subplots()
import matplotlib.patches as patches
from matplotlib.path import Path
verts = [(x1,y1), (x2,y2)]
codes = [Path.MOVETO,Path.LINETO]
path = Path(verts, codes)
ax.add_patch(patches.PathPatch(path, color='green', lw=0.5))
using all combinations?
import matplotlib.pyplot as plot
from matplotlib import pyplot
all_data = [[1,10],[2,10],[3,10],[4,10],[5,10],[3,1],[3,2],[3,3],[3,4],[3,5]]
x = []
y = []
for i in combinations(all_data,2):
x.extend(i[0])
y.extend(i[1])
plot.plot(x,y)
pyplot.show()