Визначення середньої точки кольорової карти в matplotlib


87

Я хочу встановити середню точку кольорової карти, тобто мої дані переходять від -5 до 10, я хочу, щоб нуль був середнім. Я думаю, що спосіб це зробити - підкласифікація нормалізації та використання норми, але я не знайшов жодного прикладу, і мені не зрозуміло, що саме я повинен реалізувати.


це називається "розбіжною" або "біполярною" кольоровою картою, де центральна точка карти є важливою, а дані переходять вище і нижче цієї точки. sandia.gov/~kmorel/documents/ColorMaps
ендоліти

3
Усі відповіді в цій темі здаються досить складними. Просте у використанні рішення показано в цій чудовій відповіді , яка тим часом також потрапила до документації matplotlib, розділ Спеціальна нормалізація: Два лінійних діапазони .
ImportanceOfBeingErnest

Відповіді:


15

Зверніть увагу, що у matplotlib версії 3.1 був доданий клас DivergingNorm . Я думаю, що це охоплює ваш варіант використання. Його можна використовувати так:

from matplotlib import colors
colors.DivergingNorm(vmin=-4000., vcenter=0., vmax=10000)

У matplotlib 3.2 клас перейменовано на TwoSlopesNorm


Це виглядає цікаво, але, схоже, це потрібно використовувати для перетворення даних перед побудовою графіку. Легенда кольорової панелі стосуватиметься трансформованих даних, а не вихідних.
бли

3
@bli це не так. normробить нормалізацію для вашого образу. normsйти рука об руку з кольоровими картами.
Paul H

1
Прикро це застаріло станом на 3.2, не маючи документації щодо того, як його замінити: matplotlib.org/3.2.0/api/_as_gen/…
daknowles

1
Так, документи незрозумілі. Я думаю, що його було перейменовано на TwoSlopeNorm: matplotlib.org/3.2.0/api/_as_gen/…
macKaiver

91

Я знаю, що це пізно до гри, але я щойно пройшов цей процес і придумав рішення, яке, можливо, менш надійне, ніж підкласифікація, нормалізує, але набагато простіше. Я думав, що було б непогано поділитися цим тут для нащадків.

Функція

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import AxesGrid

def shiftedColorMap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'):
    '''
    Function to offset the "center" of a colormap. Useful for
    data with a negative min and positive max and you want the
    middle of the colormap's dynamic range to be at zero.

    Input
    -----
      cmap : The matplotlib colormap to be altered
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower offset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to 
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax / (vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highest point in the colormap's range.
          Defaults to 1.0 (no upper offset). Should be between
          `midpoint` and 1.0.
    '''
    cdict = {
        'red': [],
        'green': [],
        'blue': [],
        'alpha': []
    }

    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)

    # shifted index to match the data
    shift_index = np.hstack([
        np.linspace(0.0, midpoint, 128, endpoint=False), 
        np.linspace(midpoint, 1.0, 129, endpoint=True)
    ])

    for ri, si in zip(reg_index, shift_index):
        r, g, b, a = cmap(ri)

        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))

    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)

    return newcmap

Приклад

biased_data = np.random.random_integers(low=-15, high=5, size=(37,37))

orig_cmap = matplotlib.cm.coolwarm
shifted_cmap = shiftedColorMap(orig_cmap, midpoint=0.75, name='shifted')
shrunk_cmap = shiftedColorMap(orig_cmap, start=0.15, midpoint=0.75, stop=0.85, name='shrunk')

fig = plt.figure(figsize=(6,6))
grid = AxesGrid(fig, 111, nrows_ncols=(2, 2), axes_pad=0.5,
                label_mode="1", share_all=True,
                cbar_location="right", cbar_mode="each",
                cbar_size="7%", cbar_pad="2%")

# normal cmap
im0 = grid[0].imshow(biased_data, interpolation="none", cmap=orig_cmap)
grid.cbar_axes[0].colorbar(im0)
grid[0].set_title('Default behavior (hard to see bias)', fontsize=8)

im1 = grid[1].imshow(biased_data, interpolation="none", cmap=orig_cmap, vmax=15, vmin=-15)
grid.cbar_axes[1].colorbar(im1)
grid[1].set_title('Centered zero manually,\nbut lost upper end of dynamic range', fontsize=8)

im2 = grid[2].imshow(biased_data, interpolation="none", cmap=shifted_cmap)
grid.cbar_axes[2].colorbar(im2)
grid[2].set_title('Recentered cmap with function', fontsize=8)

im3 = grid[3].imshow(biased_data, interpolation="none", cmap=shrunk_cmap)
grid.cbar_axes[3].colorbar(im3)
grid[3].set_title('Recentered cmap with function\nand shrunk range', fontsize=8)

for ax in grid:
    ax.set_yticks([])
    ax.set_xticks([])

Результати прикладу:

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


Велике спасибі за ваш чудовий внесок! Однак код не був здатний як кадрування і зрушуючи ту ж колірну карту і ваші інструкції були трохи неточні і вводять в оману. Зараз я це виправив і дозволив вам відредагувати ваш пост. Крім того, я включив його в одну зі своїх особистих бібліотек і додав вас як автора. Я сподіваюсь ти не заперечуєш.
TheChymera

Карта кольорів @TheChymera у нижньому правому куті була обрізана та переглянута. Не соромтеся використовувати це як вам зручно.
Paul H

Так, це так, на жаль, це виглядає приблизно правильно як випадковість. Якщо startі stopне є 0 і 1 відповідно, після того, як ви це зробите reg_index = np.linspace(start, stop, 257), ви більше не можете вважати, що значення 129 є середньою точкою вихідного cmap, тому вся масштабування не має сенсу при кожному обрізанні. Крім того, startмає бути від 0 до 0,5 і stopвід 0,5 до 1, а не від 0 до 1, як ви вказуєте.
TheChymera

@TheChymera Я спробував вашу версію і про неї двічі думав. 1) мені здається, що всі створені вами індекси мають довжину 257, а в matplotlib за замовчуванням 256, я припускаю? 2) припустимо, що мої дані варіюються від -1 до 1000, у них переважають позитиви, і тому більше рівнів / шарів має йти до позитивної гілки. Але ваша функція дає 128 рівнів як негативам, так і позитивам, тому було б більш «справедливо» розділити рівні нерівномірно, я думаю.
Джейсон

Це відмінне рішення, але воно не вдається, якщо значення midpointданих дорівнює 0 або 1. Див. Мою відповідь нижче для простого вирішення цієї проблеми.
DaveTheScientist

22

Ось рішення підкласу Normalize. Щоб використовувати його

norm = MidPointNorm(midpoint=3)
imshow(X, norm=norm)

Ось клас:

import numpy as np
from numpy import ma
from matplotlib import cbook
from matplotlib.colors import Normalize

class MidPointNorm(Normalize):    
    def __init__(self, midpoint=0, vmin=None, vmax=None, clip=False):
        Normalize.__init__(self,vmin, vmax, clip)
        self.midpoint = midpoint

    def __call__(self, value, clip=None):
        if clip is None:
            clip = self.clip

        result, is_scalar = self.process_value(value)

        self.autoscale_None(result)
        vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint

        if not (vmin < midpoint < vmax):
            raise ValueError("midpoint must be between maxvalue and minvalue.")       
        elif vmin == vmax:
            result.fill(0) # Or should it be all masked? Or 0.5?
        elif vmin > vmax:
            raise ValueError("maxvalue must be bigger than minvalue")
        else:
            vmin = float(vmin)
            vmax = float(vmax)
            if clip:
                mask = ma.getmask(result)
                result = ma.array(np.clip(result.filled(vmax), vmin, vmax),
                                  mask=mask)

            # ma division is very slow; we can take a shortcut
            resdat = result.data

            #First scale to -1 to 1 range, than to from 0 to 1.
            resdat -= midpoint            
            resdat[resdat>0] /= abs(vmax - midpoint)            
            resdat[resdat<0] /= abs(vmin - midpoint)

            resdat /= 2.
            resdat += 0.5
            result = ma.array(resdat, mask=result.mask, copy=False)                

        if is_scalar:
            result = result[0]            
        return result

    def inverse(self, value):
        if not self.scaled():
            raise ValueError("Not invertible until scaled")
        vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint

        if cbook.iterable(value):
            val = ma.asarray(value)
            val = 2 * (val-0.5)  
            val[val>0]  *= abs(vmax - midpoint)
            val[val<0] *= abs(vmin - midpoint)
            val += midpoint
            return val
        else:
            val = 2 * (value - 0.5)
            if val < 0: 
                return  val*abs(vmin-midpoint) + midpoint
            else:
                return  val*abs(vmax-midpoint) + midpoint

Чи можна використовувати цей клас на додаток до масштабування журналу або сим-журналу без необхідності створювати більше підкласів? У моєму поточному випадку вже використовується "norm = SymLogNorm (linthresh = 1)"
AnnanFay

Прекрасно, це саме те, що я шукав. Може, вам слід додати малюнок, щоб продемонструвати різницю? Тут середня точка відцентрована в смузі, на відміну від інших нормалізаторів середньої точки, де середню точку можна перетягнути до кінцівок.
щедрий

18

Це найпростіше просто використовувати vminі vmaxаргументи imshow(за умови , що ви працюєте з даними зображення) , а не на підкласи matplotlib.colors.Normalize.

Напр

import numpy as np
import matplotlib.pyplot as plt

data = np.random.random((10,10))
# Make the data range from about -5 to 10
data = 10 / 0.75 * (data - 0.25)

plt.imshow(data, vmin=-10, vmax=10)
plt.colorbar()

plt.show()

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


1
Чи можливо оновити приклад до гауссової кривої, щоб ми могли краще бачити градацію кольору?
Дат Чу

3
Мені не подобається це рішення, оскільки воно не використовує повний динамічний діапазон доступних кольорів. Крім того, я хотів би на прикладі нормалізації побудувати симлоговий вид нормалізації.
tillsten

2
@tillsten - Тоді я розгублений ... Ви не можете використовувати повний динамічний діапазон кольорової панелі, якщо хочете 0 в середині, так? Тоді ви хочете нелінійну шкалу? Одна шкала для значень вище 0, одна шкала для значень нижче? У такому випадку, так, вам потрібно буде підклас Normalize. Я лише трохи додам приклад (припускаючи, що хтось інший мене не бив ...).
Джо Кінгтон,

@Joe: Ви маєте рацію, це не лінійно (точніше, дві лінійні частини). Використовуючи vmin / vmax, колоранж для значень менше -5 не використовується (що має сенс у деяких програмах, але не в моєму.)
tillsten

2
для загальних даних у Z:vmax=abs(Z).max(), vmin=-abs(Z).max()
ендоліт

12

Тут я створюю підклас, за Normalizeяким слід мінімальний приклад.

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt


class MidpointNormalize(mpl.colors.Normalize):
    def __init__(self, vmin, vmax, midpoint=0, clip=False):
        self.midpoint = midpoint
        mpl.colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        normalized_min = max(0, 1 / 2 * (1 - abs((self.midpoint - self.vmin) / (self.midpoint - self.vmax))))
        normalized_max = min(1, 1 / 2 * (1 + abs((self.vmax - self.midpoint) / (self.midpoint - self.vmin))))
        normalized_mid = 0.5
        x, y = [self.vmin, self.midpoint, self.vmax], [normalized_min, normalized_mid, normalized_max]
        return np.ma.masked_array(np.interp(value, x, y))


vals = np.array([[-5., 0], [5, 10]]) 
vmin = vals.min()
vmax = vals.max()

norm = MidpointNormalize(vmin=vmin, vmax=vmax, midpoint=0)
cmap = 'RdBu_r' 

plt.imshow(vals, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

Результат: рис-1

Той самий приклад із лише позитивними даними vals = np.array([[1., 3], [6, 10]])

рис-2

Властивості:

  • Серединна точка отримує середній колір.
  • Верхній та нижній діапазони масштабуються за допомогою одного і того ж лінійного перетворення.
  • На кольоровій панелі відображаються лише кольори, що відображаються на малюнку.
  • Здається, працює нормально, навіть якщо vminбільше ніж midpoint(хоча не протестували всі випадки краю).

Це рішення натхнене класом з такою ж назвою з цієї сторінки


3
Найкраща відповідь завдяки простоті. Інші відповіді найкращі, лише якщо ви вже є експертом Matplotlib, який намагається стати супер-експертом. Більшість тих, хто шукає відповіді на matplotlib, просто намагаються щось зробити, щоб повернутися додому до свого собаки та / або сім'ї, і для них ця відповідь найкраща.
sapo_cosmico

Це рішення здається справді найкращим, але не працює! Я щойно провів тест-скрипт, і результат зовсім інший (включаючи лише сині квадрати, а жодного червоного). @icemtel, ти можеш перевірити? (поруч із проблемою з відступом def __call__)
Філіпе

Добре, я знайшов проблему (і): цифри при обчисленні normalized_minі normalized_maxприймаються як цілі числа. Просто поставте їх як 0.0. Крім того, щоб отримати правильний результат вашої фігури, я повинен був використовувати vals = sp.array([[-5.0, 0.0], [5.0, 10.0]]) . Дякую за відповідь, у будь-якому разі!
Філіпе

Привіт @Filipe, я не можу відтворити вашу проблему на моїй машині (Python 3.7, matplotlib 2.2.3, і я думаю, що це має бути і в нових версіях). Яка у вас версія? У будь-якому випадку, я зробив невелику редакцію, створивши масив типу float, і виправив проблему з відступами. Дякуємо, що
icemtel

Хм .. Я щойно спробував з python3, і він також працює. Але я використовую python2.7. Дякуємо за виправлення та відповідь. Це дуже просто у використанні! :)
Філіпе

5

Не впевнений, чи все ще шукаєте відповідь. Для мене намагаються підкласNormalize була невдалою. Тому я зосередився на створенні вручну нового набору даних, галочок та позначок, щоб отримати той ефект, на який, на вашу думку, ви прагнете.

Я знайшов scaleмодуль у matplotlib, який має клас, який використовується для перетворення графіків рядків за правилами 'syslog', тому я використовую його для перетворення даних. Потім я масштабую дані так, щоб вони переходили від 0 до 1 (щоNormalize зазвичай робиться), але позитивні числа масштабую інакше, ніж від’ємні. Це тому, що ваші vmax і vmin можуть бути не однаковими, тому .5 -> 1 може охоплювати більший позитивний діапазон, ніж .5 -> 0, негативний діапазон. Мені було простіше створити процедуру обчислення значень галочки та мітки.

Нижче наведено код і приклад рисунка.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mpl as mpl
import matplotlib.scale as scale

NDATA = 50
VMAX=10
VMIN=-5
LINTHRESH=1e-4

def makeTickLables(vmin,vmax,linthresh):
    """
    make two lists, one for the tick positions, and one for the labels
    at those positions. The number and placement of positive labels is 
    different from the negative labels.
    """
    nvpos = int(np.log10(vmax))-int(np.log10(linthresh))
    nvneg = int(np.log10(np.abs(vmin)))-int(np.log10(linthresh))+1
    ticks = []
    labels = []
    lavmin = (np.log10(np.abs(vmin)))
    lvmax = (np.log10(np.abs(vmax)))
    llinthres = int(np.log10(linthresh))
    # f(x) = mx+b
    # f(llinthres) = .5
    # f(lavmin) = 0
    m = .5/float(llinthres-lavmin)
    b = (.5-llinthres*m-lavmin*m)/2
    for itick in range(nvneg):
        labels.append(-1*float(pow(10,itick+llinthres)))
        ticks.append((b+(itick+llinthres)*m))
    # add vmin tick
    labels.append(vmin)
    ticks.append(b+(lavmin)*m)

    # f(x) = mx+b
    # f(llinthres) = .5
    # f(lvmax) = 1
    m = .5/float(lvmax-llinthres)
    b = m*(lvmax-2*llinthres) 
    for itick in range(1,nvpos):
        labels.append(float(pow(10,itick+llinthres)))
        ticks.append((b+(itick+llinthres)*m))
    # add vmax tick
    labels.append(vmax)
    ticks.append(b+(lvmax)*m)

    return ticks,labels


data = (VMAX-VMIN)*np.random.random((NDATA,NDATA))+VMIN

# define a scaler object that can transform to 'symlog'
scaler = scale.SymmetricalLogScale.SymmetricalLogTransform(10,LINTHRESH)
datas = scaler.transform(data)

# scale datas so that 0 is at .5
# so two seperate scales, one for positive and one for negative
data2 = np.where(np.greater(data,0),
                 .75+.25*datas/np.log10(VMAX),
                 .25+.25*(datas)/np.log10(np.abs(VMIN))
                 )

ticks,labels=makeTickLables(VMIN,VMAX,LINTHRESH)

cmap = mpl.cm.jet
fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(data2,cmap=cmap,vmin=0,vmax=1)
cbar = plt.colorbar(im,ticks=ticks)
cbar.ax.set_yticklabels(labels)

fig.savefig('twoscales.png')

vmax = 10, vmin = -5 та linthresh = 1e-4

Не соромтеся налаштовувати "константи" (наприклад VMAX) у верхній частині сценарію, щоб підтвердити, що він добре себе поводить.


Дякую за вашу пропозицію, як видно нижче, я мав успіх у підкласифікації. Але ваш код все ще дуже корисний для виправлення міток.
tillsten

4

Я використовував чудову відповідь Пола Х, але зіткнувся з проблемою, оскільки деякі мої дані коливались від негативних до позитивних, тоді як інші набори варіювали від 0 до позитивних або від негативних до 0; в будь-якому випадку я хотів, щоб 0 був пофарбований як білий (середина використовуваної мапи кольорів). З наявною реалізацією, якщо ваше midpointзначення дорівнює 1 або 0, оригінальні зіставлення не перезаписувались. Ви можете бачити це на наступному малюнку: графіки перед редагуванням 3-й стовпець виглядає правильно, але темно-синя область у 2-му стовпці та темно-червона область в решті стовпцях мають бути білими (їх значення даних фактично 0). Використання мого виправлення дає мені: графіки після редагування Моя функція по суті така ж, як і у Пола Х, з моїми редагуваннями на початку forциклу:

def shiftedColorMap(cmap, min_val, max_val, name):
    '''Function to offset the "center" of a colormap. Useful for data with a negative min and positive max and you want the middle of the colormap's dynamic range to be at zero. Adapted from /programming/7404116/defining-the-midpoint-of-a-colormap-in-matplotlib

    Input
    -----
      cmap : The matplotlib colormap to be altered.
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower ofset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax/(vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highets point in the colormap's range.
          Defaults to 1.0 (no upper ofset). Should be between
          `midpoint` and 1.0.'''
    epsilon = 0.001
    start, stop = 0.0, 1.0
    min_val, max_val = min(0.0, min_val), max(0.0, max_val) # Edit #2
    midpoint = 1.0 - max_val/(max_val + abs(min_val))
    cdict = {'red': [], 'green': [], 'blue': [], 'alpha': []}
    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)
    # shifted index to match the data
    shift_index = np.hstack([np.linspace(0.0, midpoint, 128, endpoint=False), np.linspace(midpoint, 1.0, 129, endpoint=True)])
    for ri, si in zip(reg_index, shift_index):
        if abs(si - midpoint) < epsilon:
            r, g, b, a = cmap(0.5) # 0.5 = original midpoint.
        else:
            r, g, b, a = cmap(ri)
        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))
    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)
    return newcmap

РЕДАКТУВАТИ: Я знову зіткнувся з подібною проблемою, коли деякі мої дані коливались від невеликого позитивного значення до більшого позитивного значення, де дуже низькі значення були пофарбовані червоним, а не білим кольором. Я виправив це, додавши рядок Edit #2у коді вище.


Це виглядає приємно, але, схоже, аргументи змінилися з відповіді Пола Х (та коментарів) ... Чи можете ви додати приклад дзвінка до своєї відповіді?
Філіпе

1

Якщо ви не проти визначити співвідношення між vmin, vmax і нулем, це досить проста лінійна карта від синього до білого до червоного, яка встановлює білий відповідно до співвідношення z:

def colormap(z):
    """custom colourmap for map plots"""

    cdict1 = {'red': ((0.0, 0.0, 0.0),
                      (z,   1.0, 1.0),
                      (1.0, 1.0, 1.0)),
              'green': ((0.0, 0.0, 0.0),
                        (z,   1.0, 1.0),
                        (1.0, 0.0, 0.0)),
              'blue': ((0.0, 1.0, 1.0),
                       (z,   1.0, 1.0),
                       (1.0, 0.0, 0.0))
              }

    return LinearSegmentedColormap('BlueRed1', cdict1)

Формат cdict досить простий: рядки - це точки у створеному градієнті: перший запис - це значення x (відношення вздовж градієнта від 0 до 1), другий - кінцеве значення для попереднього сегмента, і третє - початкове значення для наступного сегмента - якщо ви хочете плавні градієнти, останні два завжди однакові. Докладніше див. У документації .


1
Існує також можливість вказати всередині LinearSegmentedColormap.from_list()кортежів (val,color)і передати їх як список colorаргументу цього методу where val0=0<val1<...<valN==1.
maurizio

0

У мене була подібна проблема, але я хотів, щоб найвищим значенням було повне червоне і відсікали низькі значення синього, роблячи так, що це виглядає по суті так, ніби кольорова панель відрубана. Це працювало для мене (включає додаткову прозорість):

def shift_zero_bwr_colormap(z: float, transparent: bool = True):
    """shifted bwr colormap"""
    if (z < 0) or (z > 1):
        raise ValueError('z must be between 0 and 1')

    cdict1 = {'red': ((0.0, max(-2*z+1, 0), max(-2*z+1, 0)),
                      (z,   1.0, 1.0),
                      (1.0, 1.0, 1.0)),

              'green': ((0.0, max(-2*z+1, 0), max(-2*z+1, 0)),
                        (z,   1.0, 1.0),
                        (1.0, max(2*z-1,0),  max(2*z-1,0))),

              'blue': ((0.0, 1.0, 1.0),
                       (z,   1.0, 1.0),
                       (1.0, max(2*z-1,0), max(2*z-1,0))),
              }
    if transparent:
        cdict1['alpha'] = ((0.0, 1-max(-2*z+1, 0), 1-max(-2*z+1, 0)),
                           (z,   0.0, 0.0),
                           (1.0, 1-max(2*z-1,0),  1-max(2*z-1,0)))

    return LinearSegmentedColormap('shifted_rwb', cdict1)

cmap =  shift_zero_bwr_colormap(.3)

x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2*np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y) * 5 + 5
plt.plot([0, 10*np.pi], [0, 20*np.pi], color='c', lw=20, zorder=-3)
plt.imshow(Z, interpolation='nearest', origin='lower', cmap=cmap)
plt.colorbar()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.