I'm trying to plot a colored 2D Hilbert curve using matplotlib. After getting the x
and y
coordinates, a plain ax.plot(x,y)
gives the correct curve, but if I want to color-code the curve using the technique introduced in this post, it gives me an empty canvas (so not shown).
Strangely, the random path as shown in the original answer works.
My code below:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.collections as mcoll
import matplotlib.path as mpath
def xy2d(n,x,y):
d=0
s=n/2
while s>0:
rx=(x&s)>0
ry=(y&s)>0
d+=s*s*((3*rx)^ry)
s,x,y,rx,ry=rot(s,x,y,rx,ry)
s/=2
return d
def d2xy(n,d):
t=d
x=y=0
s=1
while s<n:
rx=1&(t/2)
ry=1&(t^rx)
s,x,y,rx,ry=rot(s,x,y,rx,ry)
x+=s*rx
y+=s*ry
t/=4
s*=2
return x,y
def rot(n,x,y,rx,ry):
if ry==0:
if rx==1:
x=n-1-x
y=n-1-y
x,y=y,x
return n,x,y,rx,ry
#--------------These are copied from SO--------------
def colorline(
x, y, z=None, ax=None, cmap=plt.get_cmap('copper'), norm=plt.Normalize(0.0, 1.0),
linewidth=3, alpha=1.0):
"""
http://nbviewer.ipython.org/github/dpsanders/matplotlib-examples/blob/master/colorline.ipynb
http://matplotlib.org/examples/pylab_examples/multicolored_line.html
Plot a colored line with coordinates x and y
Optionally specify colors in the array z
Optionally specify a colormap, a norm function and a line width
"""
# Default colors equally spaced on [0,1]:
if z is None:
z = np.linspace(0.0, 1.0, len(x))
# Special case if a single number:
if not hasattr(z, "__iter__"): # to check for numerical input -- this is a hack
z = np.array([z])
z = np.asarray(z)
segments = make_segments(x, y)
lc = mcoll.LineCollection(segments, array=z, cmap=cmap, norm=norm,
linewidth=linewidth, alpha=alpha)
if ax is None:
ax = plt.gca()
ax.add_collection(lc)
return lc
def make_segments(x, y):
"""
Create list of line segments from x and y coordinates, in the correct format
for LineCollection: an array of the form numlines x (points per line) x 2 (x
and y) array
"""
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
return segments
#--------------These are copied from SO--------------
if __name__=='__main__':
xs=[]
ys=[]
N=16
for i in range(N**2-1):
x,y=d2xy(N,i)
xs.append(x)
ys.append(y)
#-------------------Plot------------------------
figure=plt.figure(figsize=(12,10),dpi=100)
cmap=plt.cm.jet
ax=figure.add_subplot(111)
path = mpath.Path(np.column_stack([xs, ys]))
#verts = path.interpolated(steps=1).vertices
verts=path.vertices
x, y = verts[:, 0], verts[:, 1]
z = np.linspace(0, 1, len(xs))
colorline(x, y, z, ax=ax, cmap=cmap, linewidth=1)
#ax.plot(x,y) # this works, but with blue line
plt.show(block=False)
Am I missing something obvious?
My setup:
The code is working, however both the axis limits are (0,1)
, therefore you're too zoomed in to see the plot. It seems that add_collection
doesn't auto scale the axes.
The solution is to simply scale the axes yourself:
ax.set_ylim(0,15)
ax.set_xlim(0,15)
# or use plt.xlim() if not using object oriented API