У меня есть двумерная треугольная сетка с n вершинами, которая хранится в переменной tri (объект matplotlib.tri.Triangulation); Я могу достаточно легко построить сетку с помощью функции tripcolor от matplotlib, и все работает отлично. Тем не менее, у меня также есть (r, g, b) тройки для каждой вершины (vcolors), и эти значения не попадают в одно измерение, поэтому их нелегко преобразовать в карту цветов (например, представьте, что если вы наложили треугольную сетку на большую фотографию парка, то присвойте каждой вершине цвет пикселя под ней).

Я думал, что смогу сделать что-то вроде этого:

matplotlib.pyplot.tripcolor(tri, vcolors)

ValueError: Коллекции могут отображать только массивы ранга 1

Есть ли удобный способ конвертировать vcolors -подобную (n x 3) матрицу во что-то, что можно использовать в tripcolor? Есть ли альтернатива tripcolor, которая принимает цвета вершин?

Одна вещь, которую я попробовал, состоит в том, чтобы сделать мою собственную цветовую карту:

z = numpy.asarray(range(len(vcolors)), dtype=np.float) / (len(vcolors) - 1)
cmap = matplotlib.colors.Colormap(vcolors, N=len(vcolors))
matplotlib.pyplot.tripcolor(tri, z, cmap=cmap)
matplotlib.pyplot.show()

Это, однако, ничего не сделало - никакая фигура не появляется и не возникает ошибка; функция возвращает дескриптор фигуры, но ничего не отображается (я использую записную книжку IPython). Обратите внимание, что если я назову следующее, сюжет выглядит просто отлично:

tripcolor(tri, np.zeros(len(vcolors)))
matplotlib.pyplot.show()

Я использую Python 2.7.

2
nben 11 Янв 2017 в 19:51

3 ответа

Лучший ответ

После рутирования в matplotlib коде tripcolor и Colormap я пришел к следующему решению, которое, кажется, работает только до тех пор, пока используется затенение «Гуро» (в противном случае это делает очень плохую работу по определению цвета лица, см. ниже).

Хитрость заключается в том, чтобы создать цветовую карту, которая при заданных n равномерно расположенных числах между 0 и 1 (включительно) воспроизводит исходный массив цветов:

def colors_to_cmap(colors):
    '''
    colors_to_cmap(nx3_or_nx4_rgba_array) yields a matplotlib colormap object that, when
    that will reproduce the colors in the given array when passed a list of n evenly
    spaced numbers between 0 and 1 (inclusive), where n is the length of the argument.

    Example:
      cmap = colors_to_cmap(colors)
      zs = np.asarray(range(len(colors)), dtype=np.float) / (len(colors)-1)
      # cmap(zs) should reproduce colors; cmap[zs[i]] == colors[i]
    '''
    colors = np.asarray(colors)
    if colors.shape[1] == 3:
        colors = np.hstack((colors, np.ones((len(colors),1))))
    steps = (0.5 + np.asarray(range(len(colors)-1), dtype=np.float))/(len(colors) - 1)
    return matplotlib.colors.LinearSegmentedColormap(
        'auto_cmap',
        {clrname: ([(0, col[0], col[0])] + 
                   [(step, c0, c1) for (step,c0,c1) in zip(steps, col[:-1], col[1:])] + 
                   [(1, col[-1], col[-1])])
         for (clridx,clrname) in enumerate(['red', 'green', 'blue', 'alpha'])
         for col in [colors[:,clridx]]},
        N=len(colors))

Опять же, обратите внимание, что 'gouraud' затенение требуется для того, чтобы это работало. Чтобы продемонстрировать, почему это не помогает, следующие блоки кода показывают мой конкретный вариант использования. (Я рисую часть плоского кортикального листа с частично прозрачным наложением данных). В этом коде имеется 40 886 вершин (в the_map.coordinates) и 81 126 треугольников (в the_map.indexed_faces); массив colors имеет форму (40886, 3).

Следующий код прекрасно работает с затенением 'gouraud':

tri = matplotlib.tri.Triangulation(the_map.coordinates[0],
                                   the_map.coordinates[1],
                                   triangles=the_map.indexed_faces.T)
cmap = rgbs_to_cmap(colors)
zs = np.asarray(range(the_map.vertex_count), dtype=np.float) / (the_map.vertex_count - 1)
plt.figure(figsize=(16,16))
plt.tripcolor(tri, zs, cmap=cmap, shading='gouraud')

График с использованием затенения Гуро

Но без затенения «gouraud», цвета лица, возможно, назначаются в соответствии со средним значением их вершин (не подтвердили это), что явно неверно:

plt.figure(figsize=(16,16))
plt.tripcolor(tri, zs, cmap=cmap)

введите описание изображения здесь

1
nben 25 Янв 2017 в 16:20

В то время как для функции tripcolor использование карты цветов является обязательным, классы PolyCollection и TriMesh (из matplotlib.collection), которые она вызывает внутри, могут также работать с массивами цветов RGB. , Я использовал следующий код, основанный на источнике tripcolor, для рисования треугольной сетки с заданными цветами граней RGB:

tri = Triangulation(...)
colors = nx3 RGB array
maskedTris = tri.get_masked_triangles()
verts = np.stack((tri.x[maskedTris], tri.y[maskedTris]), axis=-1)
collection = PolyCollection(verts)
collection.set_facecolor(colors)
plt.gca().add_collection(collection)
plt.gca().autoscale_view()

Чтобы установить цвета для каждой вершины (затенение по Гуро), используйте вместо этого TriMeshset_facecolor).

0
P Hege 16 Окт 2019 в 08:47

Гораздо проще создать карту цветов с помощью from_list :

z = numpy.arange(n)
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
    'mymap', rgb, N=len(rgb)
    )
0
Nico Schlömer 18 Янв 2018 в 15:39