Пользовательские ColorFunction/ColorData в ArrayPlot (и аналогичные функции)
Это связано с вопросом Саймона об изменении ColorData по умолчанию в Mathematica. Несмотря на то, что все решения касались проблемы изменения ColorData
на линейных графиках, я не нашел обсуждения, которое могло бы помочь изменить ColorFunction
/ColorData
в ContourPlot
/ArrayPlot
/Plot3D
и т.д.
TL;DR: есть ли способ заставить mma использовать пользовательские цвета в ArrayPlot/ContourPlot/etc.
Рассмотрим следующий пример графика функции
sin(x^2+y^3)
которую я создал в MATLAB:
![enter image description here]()
Теперь делаю то же самое в ММА как:
xMax = 3; yMax = 3;
img = [email protected]
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 = [email protected]["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
использовать его (и, вероятно, он должен быть таким же для других функций ArrayPlot
).
Кроме того, поскольку мое упражнение здесь состоит в том, чтобы просто достичь уровня комфорта в mma, подобно тому, что я имею в MATLAB, я был бы признателен за комментарии и предложения по улучшению моего кода. В частности, я не слишком доволен своим взломом способа "исправить" FrameTicks
... конечно, должен быть более хороший/более простой способ сделать это.
Ответы
Ответ 1
Замените ColorData["Rainbow"]
на это:
Function[Blend[RGBColor @@@ cMap, Slot[1]]]
и вы получите следующее:
![enter image description here]()
Что касается вашего второго вопроса, вы можете сделать это следующим образом:
xMax = 3; yMax = 3;
img = [email protected]
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]()
ИЗМЕНИТЬ
Обратите внимание, что на втором графике маркировка y-диапазона меняется на обратную. Это связано с тем, что он учитывает параметр DataReversed. ArrayPlot отображает строки массивов в том же порядке, в каком они появляются, когда содержимое массива печатается на экране. Итак, первая строка построена сверху, а последняя строка - внизу. Высокие значения строк соответствуют низким значениям y и наоборот. DataReversed- > True исправляет это явление, но в этом случае он также "исправляет" значения y. Обходной путь состоит в том, чтобы заполнить массив, начиная с высоких значений y, вплоть до нижних. В этом случае вам не требуется DataReversed:
xMax = 3; yMax = 3;
img = [email protected]
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]()
Ответ 2
(Я надеюсь, что это не слишком поздно добавление.)
Как оказалось, даже не нужно содержать весь набор из шестидесяти четырех директив RGBColor[]
для использования с ключом Blend[]
A, который, безусловно, имеет место, это ListPlot[]
столбцов 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
, но мы можем перемасштабировать объекты, соответствующие диапазону аргументов, ожидаемому от colormap:
(# - 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
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
для любой функции построения, которая ее поддерживает. Наслаждайтесь!