MatrixPlotで歪んだBarLegendティック

Sep 04 2020

ここの多くのスレッド(this、this、...)に示されているように、Ticksはの有効なオプションですBarLegend。しかし、この単純なものではうまく機能しないようですMatrixPlot。いくつかの目盛りが欠落しているだけで、0.5は明らかに適切な場所(色)にありません。カスタムティックを使用したデフォルトのプロットが必要であることに注意してください。ここで何が欠けているのですか、または回避策はありますか?

data = Table[Sin[x] Cos[y], {x, 0, 2 Pi, 0.01}, {y, 0, 2 Pi, 0.01}];
MatrixPlot[data, 
 PlotLegends -> BarLegend[Automatic, "Ticks" -> {-0.5, 0, 0.5}], 
 LabelStyle -> Large]

更新:

非対称データ範囲のより一般的なケース

data = Table[Sin[x] Cos[y] + 0.05 x y, {x, 0, 2 Pi, 0.01}, {y, 0, 2 Pi, 0.01}]; 
MatrixPlot[data, PlotLegends -> BarLegend[Automatic, "Ticks" -> {-0.2, 0.5, 1.1}], 
LabelStyle -> Large]

回答

9 kglr Sep 04 2020 at 07:04

更新:この関数Graphics`ArrayPlotDump`Private`HybridRankingAndNaturalScaleは、不思議な「各行列要素の相対値とランク付けの混合に基づくスケーリング」を実行します。を使用して区分的再スケーリング関数(reScale)を作成しmpReScale、それを使用して次のオプション値を指定します"Ticks"。

ClearAll[reScale,  cfMinMax]
reScale[{min_, max_}, {cfmin_, cfmax_}]  := 
  If[# < 0, Rescale[#, {min, 0}, {cfmin, 1/2}], Rescale[#, {0, max}, {1/2, cfmax}]] &;

cfMinMax = MinMax @ Graphics`ArrayPlotDump`Private`HybridRankingAndNaturalScale[
   Union @ SparseArray[#]["NonzeroValues"], 0., {0, 1}, .5] &;

例:

data = {{1, 2, 1}, {2, 0, 1}, {0, -5, -1}};
ticks = {-4, -2, 3/2, 2};

cfminmax = cfMinMax[data];
minmax = MinMax @ data;
 
Row[{MatrixPlot[data, ImageSize -> 400, 
   PlotLegends -> BarLegend[Automatic], LabelStyle -> 16, 
   PlotLabel -> "default"], 
  MatrixPlot[data, ImageSize -> 400, 
   PlotLegends -> BarLegend[Automatic, 
     "Ticks" -> (Transpose[{reScale[minmax, cfminmax] /@ #, #}] & @ ticks)], 
   LabelStyle -> 16, 
   PlotLabel -> Row[{"Ticks : ", ticks}]]}, Spacer[10]]

余談ですが、別の文書化されていないオプションを使用してティックラベルを指定できます

BarLegend[Automatic, "TickLabels" -> ticks, 
    "Ticks" -> (reScale[minmax, cfminmax] /@ ticks)]

上記の2番目のプロットの画像を取得します。

変更dataしticksて

data = Table[Sin[x] Cos[y], {x, 0, 2 Pi, 0.01}, {y, 0, 2 Pi, 0.01}];
ticks = {-0.5, 0, 0.5};

取得するため

OPの2番目の例を使用する:

data = Table[Sin[x] Cos[y] + 0.05 x y, {x, 0, 2 Pi, 0.01}, {y, 0, 2 Pi, 0.01}];
ticks = {-0.2, 0.5, 1.1};

我々が得る

と

data = 1. + Table[Sin[x] Cos[y] + 0.05 x y, {x, 0, 2 Pi, 0.01}, {y, 0, 2 Pi,  0.01}] ;
ticks = {0.1, 0.5, 1.1, 2};

我々が得る

元の答え:

これはMatrixPlot、MatrixPlot >> Details and Optionsで説明されているように、スケーリングが行われる特別な方法に関連しているようです。

OPの場合、最も簡単な修正はティック仕様をTranspose[{Rescale[#, {-1, 1}, {0, 1}], #} &@{-0.5, 0, 0.5}]次のように変更することです。

MatrixPlot[data, 
 PlotLegends -> 
  BarLegend[Automatic, 
   "Ticks" -> Transpose[{Rescale[#, {-1, 1}, {0, 1}], #} & @ {-0.5, 0, 0.5}]], 
 LabelStyle -> Large]

別の(より一般的な)回避策として、再スケーリングされた引数とオプションを指定したデフォルトのカラー関数を使用しますColorFunctionScaling -> False。

defaultCF = "DefaultColorFunction" /.
    (Method /. Charting`ResolvePlotTheme[Automatic, MatrixPlot])
 Blend[System`PlotThemeDump`$ThemeDefaultMatrix, #1] &
MatrixPlot[data, 
 ColorFunction -> (defaultCF[Rescale[#, {-1, 1}]] &), 
 ColorFunctionScaling -> False, 
 PlotLegends -> BarLegend[Automatic, "Ticks" -> {-0.5, 0, 0.5}], 
 LabelStyle -> Large]

または、BarLegend:で色関数を指定します。

MatrixPlot[data, 
 PlotLegends -> BarLegend[{defaultCF[Rescale[#, {-1, 1}]] &, {-1, 1}}, 
   ColorFunctionScaling -> False, "Ticks" -> {-0.5, 0, 0.5}], 
 LabelStyle -> Large]

3 xzczd Sep 07 2020 at 08:38

kglrはすでに問題を解決しています。ここでは、いくつかの追加の分析と別の可能な回避策を示します。

まず第一に、これはバグではないと思います。デフォルトでは、次のMatrixPlot適切な設定方法を知っているからTicksですBarLegend。

plot = MatrixPlot[data, ImageSize -> 400, PlotLegends -> Automatic]

見るとplot、我々はそれを見つけます:

plot[[2, 1]] // InputForm
(*
BarLegend[{Blend[System`PlotThemeDump`$ThemeDefaultMatrix, #1] & , 
  {0.2889327547713697, 1.}}, LabelStyle -> {}, 
 LegendLayout -> "Column", LegendMarkerSize -> 400, 
 Ticks -> {{0.39446607623278385, -0.5}, {0.5, 0.}, {0.3100389372190109, 
  -0.9}, {0.626985112913238, 0.5}, {0.753970225826476, 1.}, 
  {0.880955338739714, 1.5}, {0.9825434290703043, 1.9000000000000001}}, 
 "PinningPoint" -> 0.5, "SmoothRange" -> False, 
 Charting`TickSide -> Right, ColorFunctionScaling -> False]
 *)

ご覧のとおり、の目盛りはBarLegend文書化されていないTicksオプションによって設定されています。目盛りをプロットします。

autotick = Cases[plot[[2, 1]], (Ticks -> a_) :> a][[1]] // Sort

ListLinePlot[autotick]

で分割された区分的線であることに気付くのは難しくありません{0.5, 0.}。これはLinearModelFit次の方法でさらに確認できます。

LinearModelFit[autotick[[#]], {1, x}, x]["RSquared"] & /@ {;; 3, 3 ;;}
(* {1., 1.} *)

したがって、を認識していなくてGraphics`ArrayPlotDump`Private`HybridRankingAndNaturalScaleも、次の方法でティックを再スケーリングできます。

ticks = {-0.2, 0.5, 1.1}

Clear[rescale]
rescale[tick_List, rest__] := rescale[#, rest] & /@ tick
rescale[tick_?Positive, mysteryminmax_, {min_, max_}] := 
 Rescale[tick, {0, max}, {1/2, mysteryminmax[[2]]}]
rescale[tick_, mysteryminmax_, {min_, max_}] := 
 Rescale[tick, {min, 0}, {mysteryminmax[[1]], 1/2}]

plot /. (Ticks -> _) :> (Ticks -> {rescale[ticks, 
       Sequence @@ (autotick[[{1, -1}]]\[Transpose])], ticks}\[Transpose])