0
$\begingroup$

Here comes a sample data set

data = {{1.03971, 0.00617284, 12.11, 0.227037, 1}, 
        {1.0231, 0.0216931, 27.23, 1.40703, 1}, 
        {1.02864, -0.0294533, 1450, 0.0821789, 1}, 
        {1.01636, -0.0149912, 16.89, 1.02227, 1}, 
        {0.938865, -0.00899471, 68.94, 0.0000322202, 1}, 
        {0.955953, 0.0199295, 1.89, 0.00448189, 9}, 
        {1.03321, 0.0329806, 84.23, 0.094761, 1}, 
        {1.02406, 0.0393298, 13.21, 0.099565, 1}, 
        {0.9728, -0.00194004, 1000, 0.000845306, 0}, 
        {1.00649, -0.00582011, 62.1, 0.0286736, 1}};

The first two columns correspond to the coordinates $(x,y)$, while the other three are some indicators. Now we want to plot those $(x,y)$ coordinates for which the fifth column is equal to 1, while the color of each point should be according to the value of the third column.

First we define a custom color function

valrange = {0, 100};
data[[All, 3]] = Rescale[data[[All, 3]] // N, valrange];
colfunc[x_, cf_] := 
 If[x[[5]] == -2 || x[[5]] == -1 || x[[5]] == 0 || x[[5]] == 2 || 
 x[[5]] == 9 || x[[5]] == 99, White, ColorData[cf][1 - x[[3]]]];

Then the graphics of the points

S0 = Graphics[{PointSize[0.01], Point[#[[1 ;; 2]], VertexColors -> colfunc[#, "Rainbow"]] & /@ 
 data}];

and a custom colorbar

Clear[colorbar]
colorbar[{min_, max_}, colorFunction_: Automatic, divs_: 150] := 
DensityPlot[y, {x, 0, 0.1}, {y, min, max}, AspectRatio -> 10, 
PlotRangePadding -> 0, PlotPoints -> {2, divs}, MaxRecursion -> 0, 
Frame -> True, FrameLabel -> {{None, Row[{Subscript["t", "esc"]}]}, {None, None}}, 
LabelStyle -> Directive[FontFamily -> "Helvetica", 20], 
FrameTicks -> {{None, All}, {None, None}}, 
FrameTicksStyle -> Directive[FontFamily -> "Helvetica", 20, Plain], 
ColorFunction -> colorFunction]

Finally we merge together the graphics with the colorbar

With[{opts = {ImageSize -> {Automatic, 400}}, cf = "Rainbow"}, 
Row[{Show[{S0}, Axes -> False, Frame -> True, 
FrameLabel -> {"x", "y"}, RotateLabel -> False, 
LabelStyle -> Directive[FontFamily -> "Helvetica", 20], 
AspectRatio -> 3/4, ImagePadding -> {{90, 10}, {60, 40}}, opts], 
Show[colorbar[valrange, ColorData[cf][1 - #] &], 
ImagePadding -> {{10, 80}, {60, 40}}, opts]}]]

which produces the following

enter image description here

The range of the colorbar is between 0 and 100, according to valrange. However in the real data set there are some few initial conditions which have $(x,y)$ coordinates with fifth column equal to 1, while the value of the third column is higher than 100 (see e.g., the third element of data list).

My question: Is there an elegant way to set automatically the higher label of the color bar "> 100", instead of simply "100"?

Many thanks in advance!

EDIT

If I set FrameTicks -> {{None, {0, 20, 40, 60, 80, "> 100"}}, {None, None}}, it does not work.

$\endgroup$
  • $\begingroup$ You're misusing the syntax of FrameTicks. When you provide it with a simple list, you need to give it numeric values of where the ticks will appear, it obviously can't interpret ">100" properly. In this case you need to provide it with a list of the form {{value, label}, {value, label}, ...}. For a "nice" range like {0, 100} it's quite easy to handle this, but what if you feed it a range like {5, 98}? $\endgroup$ – LLlAMnYP Mar 6 '17 at 10:38
1
$\begingroup$

This is hopefully sufficiently general to handle most cases.

First roll a little helper function:

ticksHelper[min_, max_] :=
  Module[
    {
      out = 
        Charting`ScaledTicks[{Identity, Identity}][min, max]
            // #[[;; , {1, 2}]] &
          // Cases[#, {_, _?NumberQ}] &
    },
    If[
      First@Last@out < max,
      AppendTo[out, {max, "> " <> ToString@max}],
      out[[-1, -1]] = "> " <> ToString@max
    ];
    out
  ]

Then modify the definition of your colorbar to include the helper:

colorbar[{min_, max_}, colorFunction_: Automatic, divs_: 150] := 
DensityPlot[y, {x, 0, 0.1}, {y, min, max}, AspectRatio -> 10, 
PlotRangePadding -> 0, PlotPoints -> {2, divs}, MaxRecursion -> 0, 
Frame -> True, FrameLabel -> {{None, Row[{Subscript["t", "esc"]}]}, {None, None}}, 
LabelStyle -> Directive[FontFamily -> "Helvetica", 20], 
FrameTicks -> {{None, ticksHelper[min, max]}, {None, None}}, 
FrameTicksStyle -> Directive[FontFamily -> "Helvetica", 20, Plain], 
ColorFunction -> colorFunction]

It might be slightly problematic for a range like {0., 101.} though (you'll get a label at 100 and then a > 101 label at 101 and they'll overlap). It should be quite easy to fix, the exact manner depending on your needs.

$\endgroup$
  • $\begingroup$ Nice! It works fine because always I use range with round limits. $\endgroup$ – Vaggelis_Z Mar 6 '17 at 11:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.