matplotlib.pyplot.tripcolor 如何用随机 RGB 颜色填充三角形?
matplotlib.pyplot.tripcolor how to fill triangles with random RGB colors?
假设我有一堆三角形,我知道如何使用 matplotlib.pyplot.tripcolor
绘制它们,我想知道如何使用整个 RGB 颜色中完全随机的 RGB 颜色填充单个三角形 space(所有 16777216 种颜色)与 x、y 无关,如何完成?
我有这个:
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()
他们工作正常,但两个示例的颜色变化太小。
第一个生成如下内容:
颜色一点都不随机。
第二个生成这个:
第二张图片颜色变化不大。
我尝试了很多方法,都失败了:
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()
前七次加注ValueError: Collections can only map rank 1 arrays
.
最后两个加注TypeError: Image data of dtype <U6 cannot be converted to float
.
如何正确地做到这一点? facecolors
到底应该放什么?官方文档对它应该是什么非常模糊。
为了完整起见,我的意图是:
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())
我得到了这个:
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()
但是我的代码明显比tripcolor
效率低很多。
解决此问题的一种方法是创建一个生成随机颜色的颜色图,独立于您分配给 facecolors
或 C
的值。例如:
import matplotlib.pyplot as plt
from matplotlib.colors import Colormap
import numpy as np
from scipy.spatial import Delaunay
class RandomColors(Colormap):
def __init__(self):
pass
def __call__(self, X, alpha=None, bytes=False):
# randomly generate an RGBA [N x 4] matrix of colors
# where N is the number of elements of X
# X is what we assigne to `facecolors` or `C`
X = np.atleast_1d(X)
col = np.random.random((X.shape[0], 4))
# set alpha=1
col[:, -1] = 1
return col
plt.figure()
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
# Don't really care about what's in this array: our custom colormap
# is going to ignore it!
colors = np.ones(centers.shape[0])
# instantiate the colormap
cmap = RandomColors()
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, cmap=cmap, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
避免一起使用 tripcolor
可能是最简单的方法,除非您需要它的某些特定功能?您可以根据 Delauny 三角剖分创建自己的 PolyCollection
,这在格式方面更加灵活。
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()
假设我有一堆三角形,我知道如何使用 matplotlib.pyplot.tripcolor
绘制它们,我想知道如何使用整个 RGB 颜色中完全随机的 RGB 颜色填充单个三角形 space(所有 16777216 种颜色)与 x、y 无关,如何完成?
我有这个: 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()
他们工作正常,但两个示例的颜色变化太小。
第一个生成如下内容:
颜色一点都不随机。
第二个生成这个:
第二张图片颜色变化不大。
我尝试了很多方法,都失败了:
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()
前七次加注ValueError: Collections can only map rank 1 arrays
.
最后两个加注TypeError: Image data of dtype <U6 cannot be converted to float
.
如何正确地做到这一点? facecolors
到底应该放什么?官方文档对它应该是什么非常模糊。
为了完整起见,我的意图是:
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())
我得到了这个:
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()
但是我的代码明显比tripcolor
效率低很多。
解决此问题的一种方法是创建一个生成随机颜色的颜色图,独立于您分配给 facecolors
或 C
的值。例如:
import matplotlib.pyplot as plt
from matplotlib.colors import Colormap
import numpy as np
from scipy.spatial import Delaunay
class RandomColors(Colormap):
def __init__(self):
pass
def __call__(self, X, alpha=None, bytes=False):
# randomly generate an RGBA [N x 4] matrix of colors
# where N is the number of elements of X
# X is what we assigne to `facecolors` or `C`
X = np.atleast_1d(X)
col = np.random.random((X.shape[0], 4))
# set alpha=1
col[:, -1] = 1
return col
plt.figure()
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
# Don't really care about what's in this array: our custom colormap
# is going to ignore it!
colors = np.ones(centers.shape[0])
# instantiate the colormap
cmap = RandomColors()
plt.tripcolor(pts[:,0], pts[:,1], tri.simplices.copy(), facecolors=colors, cmap=cmap, edgecolors='k')
plt.gca().set_aspect('equal')
plt.show()
避免一起使用 tripcolor
可能是最简单的方法,除非您需要它的某些特定功能?您可以根据 Delauny 三角剖分创建自己的 PolyCollection
,这在格式方面更加灵活。
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()