Пользовательская функция ColorFunction / ColorData в ArrayPlot (и аналогичные функции) - PullRequest
10 голосов
/ 22 апреля 2011

Это связано с вопросом Саймона об изменении значений ColorData по умолчанию в Mathematica. Хотя все решения касались проблемы изменения ColorData в линейных графиках, я не нашел обсуждения, которое могло бы помочь изменить ColorFunction / ColorData в ContourPlot / ArrayPlot / Plot3D и т. Д.

TLDR: Есть ли способ заставить ММА использовать пользовательские цвета в ArrayPlot / ContourPlot / и т.д.


Рассмотрим следующий пример графика функции sin(x^2+y^3), которую я создал в MATLAB:

enter image description here

Теперь делаем в мма то же самое, что и:

xMax = 3; yMax = 3;
img = Transpose@
   Table[Sin[y ^3 + x^2], {x, -xMax, xMax, 0.01}, {y, -yMax, yMax, 
     0.01}];
plot = ArrayPlot[img, ColorFunction -> ColorData["Rainbow"], 
   AspectRatio -> 1, 
   FrameTicks -> {FindDivisions[{0, (img // Dimensions // First) - 1},
       4], FindDivisions[{0, (img // Dimensions // Last) - 1}, 4], 
     None, None}, 
   DataReversed -> 
    True] /. (FrameTicks -> {x_, 
      y_}) :> (FrameTicks -> {x /. {a_?NumericQ, b_Integer} :> {a, 
         2 xMax (b/((img // Dimensions // First) - 1) - 1/2)}, 
      y /. {a_?NumericQ, b_Integer} :> {a, 
         2 yMax (b/((img // Dimensions // Last) - 1) - 1/2)}})

Я получаю следующий сюжет:

enter image description here

Я предпочитаю насыщенные яркие цвета в MATLAB пастельным / тусклым цветам мамы. Как заставить mma использовать эти цвета, если у меня есть значения RGB цветовой карты из MATLAB?

Вы можете загрузить значения RGB цветовой карты по умолчанию в MATLAB и импортировать ее в mma как

cMap = Transpose@Import["path-to-colorMapJet.mat", {"HDF5", 
      "Datasets", "cMap"}];

cMap - это массив 64x3 значений от 0 до 1.

Просто, чтобы дать вам некоторое представление, вот соответствующий текст из документации MathWorks по карте цветов

Цветовая карта - это матрица размером 3 на 3 числа от 0,0 до 1,0. Каждый ряд является вектором RGB, который определяет один цвет. K-я строка цветовой карты определяет k-й цвет, где map (k, :) = [r (k) g (k) b (k)]) определяет интенсивность красного, зеленого и синего.

Здесь map=cMap и m=64.

Я пробовал тыкать в ColorDataFunction, и я вижу, что формат ColorData похож на colormap. Однако я не уверен, как заставить ArrayPlot использовать его (и, вероятно, он должен быть таким же для других функций печати).


Кроме того, поскольку мое упражнение состоит в том, чтобы просто достичь уровня комфорта в mma, аналогично тому, что я имею в MATLAB, я был бы признателен за комментарии и предложения по улучшению моего кода. В частности, я не слишком доволен своим взломом способа «исправить» FrameTicks ... наверняка должен быть более приятный / простой способ сделать это.

Ответы [ 2 ]

18 голосов
/ 17 февраля 2012

(Надеюсь, это еще не слишком поздно.)

Как оказалось, даже не нужно хранить весь набор из шестидесяти четырех RGBColor[] директив для этой цели.использования с Blend[] Подсказка, что это, безусловно, имеет место, предоставляется ListPlot[] s столбцов cMap:

{rr, gg, bb} = Transpose[Rationalize[cMap]];
GraphicsGrid[{MapThread[
   ListPlot[#1, DataRange -> {0, 1}, Frame -> True, 
     GridLines -> {{1/9, 23/63, 13/21, 55/63}, None}, 
     PlotLabel -> #2] &, {{rr, gg, bb}, {"Red", "Green", "Blue"}}]}]

LisPlot[]s of RGB components of MATLAB's jet colormap

, и мы видим,что неявно, функции, представляющие эти компоненты, являются кусочно-линейными .Поскольку Blend[] обязательно выполняет линейную интерполяцию между цветами, если мы можем найти те цвета, которые соответствуют "углам" в кусочно-линейных графиках, мы можем исключить все остальные цвета между этими углами (поскольку Blend[] выполнит интерполяцию длянам), и, следовательно, потенциально придется носить только, скажем, семь, а не шестьдесят четыре цвета.

Из прочтения приведенного выше кода вы заметите, что я уже нашел эти точки перехода для вас (подсказка: проверьте настройку для GridLines).Дополнительные указания относительно того, какими могут быть эти цвета, приведены в документации для colormap():

jet в диапазоне от синего до красного и проходят через цвета голубой, желтыйи оранжевый.

Может ли это быть?Давайте проверим:

cols = RGBColor @@@ Rationalize[cMap];
Position[cols, #][[1, 1]] & /@ {Blue, Cyan, Yellow, 
  Orange // Rationalize, Red}
{8, 24, 40, 48, 56}

Это просто дает позиции цветов в массиве cols, но мы можем изменить масштаб, чтобы соответствовать диапазону аргументов, ожидаемому от карты цветов:

(# - 1)/(Length[cols] - 1) & /@ %
{1/9, 23/63, 13/21, 47/63, 55/63}

и именно там находятся точки прерывания кусочно-линейных функций, соответствующих RGB-компонентам цветовой карты.Это пять цветов;чтобы обеспечить плавную интерполяцию, мы добавляем в этот список первый и последний цвета,

cols[[{1, Length[cols]}]]
{RGBColor[0, 0, 9/16], RGBColor[1/2, 0, 0]}

, сопоставляя исходный список cols до семи.Поскольку 7/64 составляет приблизительно 11%, это довольно большая экономия.

Таким образом, мы ищем цветовую функцию:

jet[u_?NumericQ] := Blend[
        {{0, RGBColor[0, 0, 9/16]}, {1/9, Blue}, {23/63, Cyan}, {13/21, Yellow},
         {47/63, Orange}, {55/63, Red}, {1, RGBColor[1/2, 0, 0]}}, 
                          u] /; 0 <= u <= 1

Мы делаем два сравнения для проверки jet[].Вот график градиента, сравнивающий ColorFunction s jet и Blend[cols, #]&:

GraphicsGrid[{{
   Graphics[Raster[{Range[100]/100}, ColorFunction -> (Blend[cols, #] &)], 
    AspectRatio -> .2, ImagePadding -> None, PlotLabel -> "Full", 
    PlotRangePadding -> None], 
   Graphics[Raster[{Range[100]/100}, ColorFunction -> jet], 
    AspectRatio -> .2, ImagePadding -> None, 
    PlotLabel -> "Compressed", PlotRangePadding -> None]}}]

color gradient comparison of jet and explicit 64-color Blend

и вот механическая проверка того, что 64 цвета в colsхорошо воспроизведено:

Rationalize[Table[jet[k/63], {k, 0, 63}]] === cols
True

Теперь вы можете использовать jet[] в качестве ColorFunction для любой функции построения графиков, которая его поддерживает.Наслаждайтесь!

18 голосов
/ 22 апреля 2011

Замените ваш ColorData["Rainbow"] на этот:

Function[Blend[RGBColor @@@ cMap, Slot[1]]]

и вы получите это:

enter image description here


Что касается вашего второго вопроса, вы можете сделать это следующим образом:

xMax = 3; yMax = 3;
img = Transpose@
   Table[Sin[y^3 + x^2], {x, -xMax, xMax, 0.01}, {y, -yMax, yMax, 
     0.01}];
plot = ArrayPlot[img, 
  ColorFunction -> Function[Blend[RGBColor @@@ cMap, Slot[1]]], 
  AspectRatio -> 1, FrameTicks -> Automatic, 
  DataRange -> {{-xMax, xMax}, {-yMax, yMax}}, DataReversed -> True]

enter image description here

но почему вы не используете DensityPlot?

DensityPlot[Sin[y^3 + x^2], {x, -xMax, xMax}, {y, -yMax, yMax}, 
 ColorFunction -> Function[Blend[RGBColor @@@ cMap, Slot[1]]], 
 PlotPoints -> 300]

enter image description here


EDIT
Обратите внимание, что на втором графике разметка y-диапазона обратная. Это потому, что он принимает во внимание настройку DataReversed. ArrayPlot отображает строки массивов в том же порядке, в котором они отображаются при выводе содержимого массива на экран. Таким образом, первый ряд отображается сверху, а последний - снизу. Высокие значения строки соответствуют низким значениям y и наоборот. DataReversed-> True исправляет это явление, но в этом случае оно также «исправляет» значения y. Обходной путь - заполнить массив, начиная с высоких значений y и заканчивая низшими. В этом случае вам не нужен DataReversed:

xMax = 3; yMax = 3;
img = Transpose@
   Table[Sin[y^3 + x^2], {x, -xMax, xMax, 0.01}, {y, 
     yMax, -yMax, -0.01}];
plot = ArrayPlot[img, 
  ColorFunction -> Function[Blend[RGBColor @@@ cMap, Slot[1]]], 
  AspectRatio -> 1, FrameTicks -> Automatic, 
  DataRange -> {{-xMax, xMax}, {-yMax, yMax}}]

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...