Issue
Say I have a bunch of triangles, I know how to draw them using matplotlib.pyplot.tripcolor
, I want to know how to fill the individual triangles with completely random RGB colors from the entire RGB color space (all 16777216 colors) unrelated to x, y whatsoever, how to get this done?
I have this: source
import matplotlib.pyplot as plt
import numpy as np
from scipy.spatial import Delaunay
from random import random, randbytes
plt.style.use('_mpl-gallery-nogrid')
pts = np.zeros((360,2))
pts[:,0] = np.random.randint(0,1920,360)
pts[:,1] = np.random.randint(0,1080,360)
tri = Delaunay(pts)
plt.xlim(0, 1920)
plt.ylim(0, 1080)
centers = np.sum(pts[tri.simplices], axis=1, dtype='int')/3.0
colors = np.array([ (x-960)**2 + (y-540)**2 for x,y in centers])
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
l = centers.shape[0]
colors = np.random.random(size=l)
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
They are working, but the color variations of the two examples are too small.
The first generates something like this:
The colors are not random at all.
The second generates this:
There is little variation of colors in the second image.
I have tried a number of methods, all of them failed:
colors = np.random.random((l, 3))
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
colors = [tuple(randbytes(3)) for i in range(l)]
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
colors = [tuple(randbytes(4)) for i in range(l)]
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
colors = [tuple([random() for i in range(3)]) for j in range(l)]
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
colors = [tuple([random() for i in range(4)]) for j in range(l)]
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
colors = [randbytes(3).hex() for j in range(l)]
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
colors = [randbytes(4).hex() for j in range(l)]
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
colors = ['#'+randbytes(3).hex() for j in range(l)]
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
colors = ['#'+randbytes(4).hex() for j in range(l)]
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
The first seven raise ValueError: Collections can only map rank 1 arrays
.
The last two raise TypeError: Image data of dtype <U6 cannot be converted to float
.
How to properly do this? Exactly what should be put into facecolors
? The official documentation is extremely vague about what it should be.
For completeness' sake, my intention is to:
from PIL import Image
fig = plt.figure(frameon=False, figsize=(19.2,10.8), dpi=100)
ax = fig.add_subplot(111)
ax.set_axis_off()
...
fig.canvas.draw()
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
plt.axis('scaled')
plt.box(False)
Image.frombytes('RGB', fig.canvas.get_width_height(), fig.canvas.tostring_rgb())
I was able to get this:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Polygon
from PIL import Image
from scipy.spatial import Delaunay
from random import random, randbytes
plt.style.use('_mpl-gallery-nogrid')
points = np.zeros((360,2))
points[:,0] = np.random.randint(0,1920,360)
points[:,1] = np.random.randint(0,1080,360)
triangles = points[Delaunay(points).simplices]
fig = plt.figure(frameon=False, figsize=(19.2,10.8), dpi=100)
ax = fig.add_subplot(111)
ax.set_axis_off()
for triangle in triangles:
ax.add_patch(Polygon(triangle, edgecolor='#c0c0c0', facecolor='#'+randbytes(3).hex(), fill=True))
plt.xlim(0, 1920)
plt.ylim(0, 1080)
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
plt.axis('scaled')
plt.box(False)
fig.canvas.draw()
Image.frombytes('RGB', fig.canvas.get_width_height(), fig.canvas.tostring_rgb()).show()
But my code is obviously much less efficient than tripcolor
.
Solution
It's probably easiest to avoid using tripcolor
alltogether, unless you need some of it's specific functionality? You can create your own PolyCollection
from the Delauny triangulation, which is a lot more flexible regarding formatting.
from matplotlib.collections import PolyCollection
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay
from copy import copy
n_points = 360
pts = np.random.randint(0, 1920, (n_points, 2)).astype(np.float32)
tri = Delaunay(pts)
vertices = np.stack((
tri.points[tri.simplices, 0], # x
tri.points[tri.simplices, 1], # y
), axis=-1)
collection = PolyCollection(vertices, edgecolor="k")
collection.set_facecolor(np.random.rand(len(vertices), 3))
fig, ax = plt.subplots(figsize=(8,8), facecolor="w")
ax.add_collection(copy(collection))
ax.autoscale_view()
Answered By - Rutger Kassies
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.