Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have an array s5 I want to plot using ListContourPlot

s5 = Import[
  "https://github.com/downloads/stackmma/Attachments/data_13545.m"];
ListContourPlot[s5, InterpolationOrder -> 6, ColorFunction -> "TemperatureMap", 
    ContourLabels -> True, ColorFunctionScaling -> True]

Mathematica graphic with labels

Note, the blue spot in the corner. Turning off ContourLabels gives

ListContourPlot[s5, InterpolationOrder -> 6, ColorFunction -> "TemperatureMap", 
  ContourLabels -> False, ColorFunctionScaling -> True] 

Mathematica graphics

The resulting images have entriely different colors. I cannot understand why adding ContourLabels should change the colors, and for other data sets it seems to not do that. I ended up using a workaround that involved making one of the pictures mostly transparent and overlaying it with a picture that had the right colors. This I think is actually the simplest workaround proposed so far:

wl = ListContourPlot[s5, InterpolationOrder -> 6, 
ColorFunction -> (Append[ColorData["TemperatureMap"][#1], 0] &), 
ContourLabels -> True, Contours -> contours];

nl = ListContourPlot[s5, InterpolationOrder -> 6, 
ColorFunction -> "TemperatureMap", Contours -> contours];
Show[nl,wl]
share|improve this question
    
@halirutan Can you repost the chat link? –  0xFE Oct 23 '12 at 23:22
    
The chat room is here chat.stackexchange.com/rooms/2234/mathematica –  rm -rf Oct 24 '12 at 3:36
1  
You may want to read my additional notes to your approach in the middle of my answer. –  halirutan Oct 24 '12 at 4:12
    
From WRI: It does appear that ListContourPlot is not behaving properly. I have forwarded an incident report to our developers with the information you provided. I included your email address so that you can be notified when a Mathematica with this corrected is released. –  0xFE Oct 25 '12 at 0:12
add comment

1 Answer

up vote 7 down vote accepted

Workaround

For a detailed discussion about this bug, see below. Here is a workaround:

ListContourPlotWithLabel[data_, opts : OptionsPattern[]] := 
 Module[{grlabl, gr},
  {grlabl, gr} = 
   ListContourPlot[data, ContourLabels -> #, 
      Evaluate[
       FilterRules[{opts}, Options[ListContourPlot]]]] & /@ {True, 
     False};
  With[{pts = 
     Dispatch@
      MapIndexed[First[#2] -> #1 &, 
       First@Cases[grlabl, {{_Real, _Real} ..}, {2}]]},
   gr /. GraphicsComplex[fst_, snd_] :> 
     GraphicsComplex[fst, Append[snd,
       Cases[grlabl, Text[__], Infinity] /. 
        Text[what_, pt_] :> Text[what, pt /. pts]]
      ]
   ]
  ]

This function creates always a plot with label. All other options can just be used as usual. Let's apply it to your data (I uploaded it to the site):

data = Import[
   "https://github.com/downloads/stackmma/Attachments/data_13545.m"];
ListContourPlotWithLabel[data, InterpolationOrder -> 6, 
 ColorFunction -> "TemperatureMap"]

Mathematica graphics

What the workaround does: Usually, the workaround should be a one-liner but due to another bug, it is not possible to call Normal on a labeled ListContourPlot. Therefore, we have to think a bit harder.

The good thing is, that both plots, with and without label have the same contour-positions (although the colors are different). What I did was to extract the labels from the labeled plot and plug it into the non-labeled, correct-color plot.

Therefore, first thing in the function above is to create a labeled and non-labeled plot of data and supply all other options to the call. Then, there is the tricky part. The labels are basically Text objects, but since the plot is created using a GraphicsComplex, the position of the Text is not a coordinate, but an ID which refers to a coordinate. This list of real coordinates is given as first parameter to GraphicsComplex and with the call

MapIndexed[First[#2] -> #1 &, 
 First@Cases[grlabl, {{_Real, _Real} ..}, {2}]]

I extract all real-tuples (which are the coordinates) and make a list like {1->{x1,y1}, 2->{x2,y2}, .... With these rules, I can replace the ID in all the Text objects with real coordinates. So what's left to do is to:

take the unlabeled graphics gr and append to the snd element of GraphicsComplex in it the Text objects where I have replaced the IDs with real coordinates

gr /. GraphicsComplex[fst_, snd_] :> 
  GraphicsComplex[fst, 
   Append[snd, 
    Cases[grlabl, Text[__], Infinity] /. 
     Text[what_, pt_] :> Text[what, pt /. pts]]]

I can imagine, that even with the explanations it is hard to follow for users which are not experienced with replacement and extraction in Mathematica-expressions. I can only give the advise, that it is worth understanding this in order to be equipped doing this alone the next time.

I suggest, to go through the explanation again while looking at the output of this:

data = Table[y, {y, 0, 1, 1/99.}, {100}];
ListContourPlot[data, ContourLabels -> True, MaxPlotPoints -> 4] /. 
  x_Real :> N[Round[x]] // InputForm

Additional note to the OPs workaround

The workaround proposed by the OP is indeed very nice. Its disadvantage of using too much memory can be suppressed. When using ContourShading -> None and ContourStyle -> None no polygons are created although (silly enough) all points are still in the GraphicsComplex

s5 = Import[
   "https://github.com/downloads/stackmma/Attachments/data_13545.m"];

wl = ListContourPlot[s5, InterpolationOrder -> 6, 
ContourShading -> None, ContourStyle -> None, 
ContourLabels -> True];

nl = ListContourPlot[s5, InterpolationOrder -> 6, 
ColorFunction -> "TemperatureMap"];

We can reduce the size to a minimum by deleting all unnecessary points, leaving only the labels:

wl2 = wl /. 
  Graphics[GraphicsComplex[data_, rest_], grest__] :> 
   With[{rules = 
      Dispatch@
       MapIndexed[Text[what_, First[#2]] :> Text[what, #1] &, data]}, 
    Graphics[
     Cases[rest, Text[__], Infinity] /. rules, grest]
    ]

Show[nl,wl2]

Comparing the sizes shows the original label-image was 70 times larger

ByteCount /@ {wl, wl2}

(* Out[72]= {201936, 2864} *)

and wl2 looks like

Mathematica graphics

Investigation in the bug

I'm sorry, but the only thing I can do is to investigate in this behavior. I'm using Linux-x86-64 and Mathematica 8.0.4 here. If someone experience important difference on other systems, feel free to edit. 

Let me reduce your problem to a very small example. We use create an array which is constant in x direction and makes a linear gradient from 0 to 1 in y direction:

data = Table[y, {y, 0, 1, 1/99.}, {100}];

Will will now use ListContourPlot with and without ContourLabels and make only very slight changes to the data. What you should know is, that ColorFunctionScaling is always turned on per default. Additionally, note that our data does not need to be rescaled because it is already in the right interval. The first simple plot shows the same with and without labels

GraphicsRow[
 ListContourPlot[data, ColorFunction -> "TemperatureMap", 
    ContourLabels -> #] & /@ {True, False}]

Mathematica graphics

If we scale our data a bit by using 0.1*data we only have values from [0,0.1]. Here the plots still look like the above one

GraphicsRow[
 ListContourPlot[.1 data, ColorFunction -> "TemperatureMap", 
    ContourLabels -> #] & /@ {True, False}]

Mathematica graphics

Now, we add a constant and we use data+1 and this is the point where the fun starts

GraphicsRow[
 ListContourPlot[data + 1, ColorFunction -> "TemperatureMap", 
    ContourLabels -> #] & /@ {True, False}]

Mathematica graphics

From this point, it only gets worse. Let's say we combine the first and second step and scale and add a constant: .1 data + 1. This results in

GraphicsRow[
 ListContourPlot[.1 data + 1, ColorFunction -> "TemperatureMap", 
    ContourLabels -> #] & /@ {True, False}]

Mathematica graphics

Please be aware, how simple it is, to rescale (which ColorFunctionScaling should do) this data to [0,1].

Extract rescaled values

Using Reap and Sow we can extract the used color-values in the plot. Let's do this for the last ugly example:

Last@Reap[
  ListContourPlot[0.1*data + 1, 
   ColorFunction -> 
    Function[f, Sow[f]; ColorData["TemperatureMap", f]], 
   ContourLabels -> True]]

(*
{{0.,0.922727,0.931818,0.940909,0.95,0.959091,0.968182,0.977273,0.986364,0.995455,1.}} 
*)

What a mess. This is nothing close to scaling the colors. One can surely make further experiments, but I think a bug-report to Wolfram is the best (I would do that for non-obvious reasons).

share|improve this answer
    
But what about the very sudden jump between 6 and 6.2 in the bottom left corner? –  0xFE Oct 23 '12 at 22:45
    
@user141603 Good point. Let me think again about it. –  halirutan Oct 23 '12 at 22:50
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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