The data

I have the following three datasets: data1 data2 data3

{d1, d2, d3} = 
  Import["3Ddata" <> ToString[#] <> ".txt", "CSV"] & /@ Range[3];
ListPointPlot3D[{d1, d2, d3}, 
 PlotLegends -> {"data1", "data2", "data3"}, 
 PlotTheme -> "Scientific", 
 PlotStyle -> {ColorData[97], AbsolutePointSize[4]}, 
 ScalingFunctions -> {"Log", "Linear", "Linear"}]

enter image description here

The issue

The problem I have is that the data are not easy to read and unfortunately ListDensityPlot and ListContourPlot are too jagged and messy when overlapping data.

I am not sure what is the best way to present the data. My first thought is to reduce in 2D akin to a contour plot but with smooth edges-something like the following:

enter image description here

Current attempts

Creating 2D contours:

Unfortunately this leaves the system with very jagged results, and it loses information about the z-axis.

  ListContourPlot[#1, Contours -> {0.2, 0.5, 0.7}, (*vaguely Quartile values*)
    ScalingFunctions -> {"Log", "Linear"}, ContourShading -> None, 
    InterpolationOrder -> Automatic, 
    ContourStyle -> Directive@{#2, AbsoluteThickness[2]}] &, {{d1, d2,
     d3}, (ColorData[97][#] & /@ Range[3])}]]

enter image description here

Creating 2D ListPlots

I start by filtering out some of the smaller values to give a more robust shape and then reduce to 2D. I then use Style to map each individual point based on its 3rd value (as suggested here):

dat2 = Select[d1, #[[3]] >= 0.2 &];
dat2[[All, 3]] = Rescale[dat2[[All, 3]]];
 Style[#[[;; 2]], ColorData["TemperatureMap"][#[[3]]]] & /@ dat2, 
 AspectRatio -> 1, Frame -> True, PlotRange -> {Full, {0, 1000}},
 ScalingFunctions -> {"Log", "Linear"}]

enter image description here

As you can see, this works a bit better, but when you then want to combine d1,d2,d3, it will be rather difficult to do.

One could in principle plot 3 separate panels, but it becomes much harder to do when you have more than 3 datasets, and I am unsure how to best normalise the ColorFunction so that they all share a unified color scheme across all datasets d1,d2,d3:

Grid@{{"d1", "d2", "d3"}, 
    Style[#[[;; 2]], ColorData["TemperatureMap"][#[[3]]]] & /@ data, 
    AspectRatio -> 1, Frame -> True, 
    PlotRange -> {{0, 4000}, {0, 1000}},
    ScalingFunctions -> {"Log", "Linear"}], {data, {d1, d2, d3}}]}

enter image description here

Any advice or help would be greatly appreciated!

Thank you all!

  • $\begingroup$ Any time you plot 3D data on a 2D plane, you are merely seeing a projection with the attendant loss of information. If you search 2D 3D on this site you will see plenty of questions that have addressed similar queries. Once you choose the plot layout, you can frame ColorFunction related questions more concretely. $\endgroup$
    – Syed
    Commented Apr 26 at 2:00
  • $\begingroup$ Hi Syed, the question I am asking is for precisely what you are asking me to do: how to best create the layout. I'm not (yet!) asking for 'ColorFunction' advice :) $\endgroup$
    – alex
    Commented Apr 26 at 7:57
  • $\begingroup$ Would help if you post the data, maybe just one set at least. $\endgroup$
    – josh
    Commented Apr 26 at 11:39
  • $\begingroup$ Hi Josh, I have already put them in the top line. There should be three pastebin links. Let me know if they do not work for you. $\endgroup$
    – alex
    Commented Apr 26 at 12:14

1 Answer 1


Using BubbleChart might be an option:

polygon = Polygon[{{1, 0}, {-1/2, Sqrt[3]/2}, {-1/2, -1/2*Sqrt[3]}}];
markers = {
 Graphics[polygon, ImageSize -> 30]
 , Graphics[GeometricTransformation[polygon, RotationTransform[180°]], ImageSize -> 30]
 , Graphics[GeometricTransformation[polygon, RotationTransform[90°]], ImageSize -> 30]

  {d1, d2, d3}
 , BubbleSizes -> {.005, .02}
 , ChartElements -> markers 
 , ChartBaseStyle -> Directive[EdgeForm[], Opacity[.3]]
 , ChartStyle -> {Red, Green, Blue}
 , ScalingFunctions -> {"Log", "Linear"}
 , PlotRange -> All
 , ChartLegends -> {"d1", "d2", "d3"}
 , ImageSize -> Large

enter image description here

Plotting each dataset separately;

rangeMinMax = Append[0] /@ 
 Ceiling@ArrayReduce[{1, Max@#} &, Join[d1, d2, d3][[All, ;; 2]], 1];

    Join[rangeMinMax, #1]
  , BubbleSizes -> {.005, .02}
  , ChartElements -> {#2}
  , ChartBaseStyle -> Directive[EdgeForm[], Opacity[.3]]
  , ChartStyle -> {#3}
  , ScalingFunctions -> {"Log", "Linear"}
  , PlotRange -> MapThread[Ceiling[#@#2] &, {{Log, Identity}, Most /@ rangeMinMax}]
  , ChartLegends -> {#4}
  , ImageSize -> Medium
 ] & @@ d, {d, Thread[{{d1, d2, d3}, markers, {Red, Green, Blue}, {"d1", "d2", "d3"}}]}]

enter image description here

Adding ListContourPlot as a reference:

     {Join[rangeMinMax, #1]}
     , ScalingFunctions -> {"Log", "Linear"}
     , InterpolationOrder -> 1
     , Contours -> 6
     , ContourShading -> Rest@Table[Blend[{#2, White}, i], {i, 1, 0, -.1}]
     , ContourStyle -> None
     , PlotRange -> Most /@ rangeMinMax
     , ImageSize -> Medium
     , PlotLegends -> Placed[Automatic, Below]
     ] & @@ d, {d, Thread[{ {d1, d2, d3}, {Red, Green, Blue}}]}]

enter image description here

  • $\begingroup$ Hi vindobona! It was one of the first things I tried [with terrible results], but you have a much more masterful usage of the Opacity and marker size. My only concern is that you completely lose information of what is on the z-axis, by contrast to what one would get from a ContourPlot. I will most likely wrestle a bit more with it but if I can't do any better I will most likely follow your suggestion. $\endgroup$
    – alex
    Commented Apr 28 at 9:51
  • $\begingroup$ Hi @alex! Thank you for your feedback. I understand your challenge and I am eager to see other suggestions as well. $\endgroup$
    – vindobona
    Commented Apr 28 at 11:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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