简体   繁体   English

matplotlib.pyplot.tripcolor 如何用随机 RGB 颜色填充三角形?

[英]matplotlib.pyplot.tripcolor how to fill triangles with random RGB colors?

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?假设我有一堆三角形,我知道如何使用matplotlib.pyplot.tripcolor绘制它们,我想知道如何用与 x 无关的整个 RGB 颜色空间(所有 16777216 种颜色)中完全随机的 RGB 颜色填充各个三角形,无论如何,如何完成这项工作?

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 .前七个引发ValueError: Collections can only map rank 1 arrays

The last two raise TypeError: Image data of dtype <U6 cannot be converted to float .最后两个引发TypeError: Image data of dtype <U6 cannot be converted to float

How to properly do this?如何正确地做到这一点? Exactly what should be put into facecolors ?究竟应该在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 .但是我的代码显然比tripcolor效率低得多。

One way to work around it is to create a colormap that generates random colors, independently of the values you have assigned to facecolors or C .解决此问题的一种方法是创建一个生成随机颜色的颜色图,与您分配给facecolorsC的值无关。 For example:例如:

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()

在此处输入图像描述

It's probably easiest to avoid using tripcolor alltogether, unless you need some of it's specific functionality?除非您需要它的某些特定功能,否则可能最容易避免一起使用tripcolor You can create your own PolyCollection from the Delauny triangulation, which is a lot more flexible regarding formatting.您可以从 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()

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM