установка фиксированных значений цветовой шкалы - PullRequest
2 голосов
/ 10 февраля 2020

Я строю некоторые данные узловых точек, анимированные с шагом по времени, следующим образом:

fig, ax = plt.subplots()
fig.tight_layout()
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)

def animate(i):
    ax.cla()
    plt.cla()
    ax.set_aspect('equal', 'box')
    c = ax.tricontourf(triang, z[:, i], 10, cmap='plasma')
    c.set_clim(np.min(z), np.max(z))
    plt.colorbar(c, cax=cax)

anim = FuncAnimation(fig, animate, interval=100, frames=nt)

Где z - это nnodes x number_of_timesteps матрица узловых значений. Но, как вы можете видеть на картинке ниже, диапазон и значения цветовой панели не являются фиксированными. Я имею в виду, что значения, присвоенные определенному цвету, кажутся фиксированными, но цветовая легенда меняется со временем. Я подумал, что c.set_clim(np.min(z), np.max(z)) должен это исправить, так как он принимает минимальные и максимальные узловые значения из всего набора данных на каждом временном шаге, но, видимо, он не исправляет цветовую полосу. Есть ли способ решить это?

enter image description here enter image description here enter image description here

Ответы [ 2 ]

1 голос
/ 10 февраля 2020

Каждый раз вы получаете новую цветную полосу, потому что вы не указываете свои уровни контура. Попробуйте:

c = ax.tricontourf(triang, z[:, i], 10, cmap='plasma', vmin=-1, vmax=1, levels=np.arange(-1, 1.02, 0.1))

0 голосов
/ 10 февраля 2020

@ SKPS, здесь мы go. В приведенном ниже скрипте я использую поддельную функцию координат, просто чтобы дать вам некоторые значения, так как оригинал основан на процедуре FEM, и поэтому он довольно массивный. С помощью предоставленной ссылки вы можете скачать файл me sh, используемый в скрипте. В приведенном ниже коде я пробовал это двумя способами: FuncAnimation, который используется в animate_plot() и ArtistAnimation, который находится в animate_plot2(). Вы можете переключаться между ними, редактируя последнюю строку кода. Видите, проблемы с FuncAnimation уже описаны. При использовании ArtistAnimation цветовая полоса выглядит как stati c, но на самом деле это цветовая полоса самого последнего временного шага. Чтобы продемонстрировать это, я изменил построенную функцию в animate_plot2(), поэтому, если вы запустите ее, вы поймете, что я имею в виду. Также в этом случае вы видите, что заголовок графика больше не обновляется - он всегда показывает одно значение. Я попытался исправить это, добавив строки ax.cla() и plt.cla(), как и в предыдущем случае, но это еще больше испортило.

С уважением.

Я sh: https://www.dropbox.com/s/x4njq0t93636wfv/new_cave.msh?dl=0

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.tri as mtri
import meshio

from matplotlib.animation import FuncAnimation
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.offsetbox import (AnchoredOffsetbox, DrawingArea, HPacker,
                                  TextArea)


def load_mesh(mesh_filename):
    m = meshio.read(mesh_filename)
    p = m.points.transpose()
    p = np.delete(p, 2, axis=0)
    t = m.cells["triangle"]
    return p, t


def animate_plot(nt, p, t):
    x = p[0, :]
    y = p[1, :]
    triang = mtri.Triangulation(x, y, t)
    nnodes = len(p[0])
    z = np.zeros((nnodes, nt))
    for j in range(nt):
        z[:, j] = j ** 2 * (np.sin(x * 10) + np.sin(y * 10))

    fig, ax = plt.subplots()
    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="5%", pad=0.05)

    def animate(i):
        ax.cla()
        plt.cla()
        ax.set_aspect('equal', 'box')
        ax.set(xlim=(min(x), max(x)), ylim=(min(y), max(y)))
        c = ax.tricontourf(triang, z[:, i], 10, cmap='plasma', vmin=-1, vmax=1)
        c.set_clim(np.min(z), np.max(z))
        ax.triplot(triang, color='white', lw=0.1)
        ax.set_title('test, ' + 'np.min(z)=' + str(np.min(z)) + ', np.max(z)=' + str(np.max(z)) + '.')
        cbar = plt.colorbar(c, cax=cax, format='%.0e')
        ax.set_xlabel('x [m]')
        ax.set_ylabel('y [m]')

    anim = FuncAnimation(
        fig, animate, interval=600, frames=nt)
    anim.save('test.gif', writer='imagemagick')


def animate_plot2(nt, p, t):
    x = p[0, :]
    y = p[1, :]
    triang = mtri.Triangulation(x, y, t)
    nnodes = len(p[0])
    z = np.zeros((nnodes, nt))
    for j in range(nt):
        z[:, j] = 100 * (np.sin(x * 10) + np.sin(y * 10)) - j ** 2 * (np.sin(x * 10) + np.sin(y * 10))

    img = []
    fig, ax = plt.subplots()
    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="5%", pad=0.05)

    for i in range(nt):
        # ax.cla()
        # plt.cla()
        ax.set_aspect('equal', 'box')
        ax.set(xlim=(min(x), max(x)), ylim=(min(y), max(y)))
        fig.tight_layout()
        ax.set_title('time step = ' + str(i))
        c = ax.tricontourf(triang, z[:, i], 10, cmap='plasma')
        c.set_clim(np.min(z), np.max(z))
        ax.triplot(triang, color='white', lw=0.1)
        plt.colorbar(c, cax=cax)
        img.append(c.collections)

    name = 'test.gif'
    anim_img = animation.ArtistAnimation(fig, img, interval=300, blit=True)
    anim_img.save(name, writer='imagemagick', bitrate=300)


mesh_filename = 'new_cave.msh'
p, t = load_mesh(mesh_filename)

nt = 10
animate_plot2(nt, p, t)
...