7
$\begingroup$

Consider a dataset such as the one you can find here. Using ListContourPlot on this dataset we get something like the following:

dat = Import["https://pastebin.com/raw/2V32Zs29", "Package"];
ListContourPlot[dat, ColorFunction -> "TemperatureMap", PlotLegends -> True]

contour plot

What I want is to have this same image, but as a primitive that can be embedded in a Graphics3D, so that I can for example stack a number of such images on top of each other.

Is there any easy way to do that?

$\endgroup$
9
$\begingroup$

Consider modifying your data by adding a dummy $z$ value, used as a sort of index to each dataset, then using ListSliceContourPlot3D:

Flatten[{{#1, #2, -3, #3}& @@@ data, {#1, #2, 3, 2 #3}& @@@ data}, 1];

ListSliceContourPlot3D[
   %, 
   {"ZStackedPlanes", {-3, 3}},  
   PlotRange -> {Automatic, Automatic, {-6, 6}}
]

Mathematica graphics

Here I am arbitrarily positioning your original data on the $z=-3$ plane; then creating a new dataset by simply multiplying your original $z$ values by an arbitrary constant, just to have something else to plot.

$\endgroup$
6
$\begingroup$

Here is another possibility if you really want to use Graphics3D with 2D contour plots. I think MarcoB's answer is probably the best, but it might depend on exactly what you're doing with your data.

I define dat to be the data you linked to on PasteBin.

plot = ListContourPlot[dat, AspectRatio -> 1/2, 
  ColorFunction -> "TemperatureMap", PlotRangePadding -> 0]

Contour plot of OP's data.

Show[
 Graphics3D[{
   Texture[plot],
   Polygon[{{0, 0, 0}, {2, 0, 0}, {2, 1, 0}, {0, 1, 0}}, 
    VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}],
   Texture[plot],
   Polygon[{{0, 0, 0.5}, {2, 0, 0.5}, {2, 1, 0.5}, {0, 1, 0.5}}, 
    VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}],
   Texture[plot],
   Polygon[{{0, 0, 1}, {2, 0, 1}, {2, 1, 1}, {0, 1, 1}}, 
    VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]
  }],
 Lighting -> {"Ambient", White}
]

Using the Texture option in Graphics3D, I can add the plot as the texture of a 2D polygon in 3D space. I believe it will stretch the texture to fit the polygon as long as you specify the VertexTextureCoordinates to be the 4 corners.

Contour plots in 3D space.

Of course you can make the white border transparent if you prefer, and other tweaks like changing the aspect ratio, etc.

$\endgroup$
  • 2
    $\begingroup$ You can do something like ListContourPlot[dat, ColorFunction -> "TemperatureMap", Frame -> False, PlotRangePadding -> None] to get an image that is suitable for making textures. $\endgroup$ – J. M. is away Mar 3 at 2:50
  • 1
    $\begingroup$ @J.M.iscomputer-less That's a good point. I had thought about that, but I wasn't sure if they wanted the frame and tick labels or not. $\endgroup$ – MassDefect Mar 3 at 8:25
1
$\begingroup$

The other answer probably provide more handy solutions in general, but just for the sake of completeness let me show here a method to directly extract the components of the GraphicsComplex object produced by ListContourPlot in a way amenable to reuse.

Defining a couple of helper functions we can readily extract, for example, the contour lines that have been produced:

dat = Import["https://pastebin.com/raw/2V32Zs29", "Package"];
fig = ListContourPlot[dat, ColorFunction -> "TemperatureMap", 
  PlotLegends -> True, Contours -> Append[Range[0, 1, 0.05], 0.99]];

getGraphicsComplexPoints[graphicsObject_] := Cases[
    graphicsObject,
    GraphicsComplex[{pts___}, ___] :> pts, All
  ];
extractLines[obj_] := Cases[obj, Line[___], All];
threedifyPoints[points_, zCoordinate_] := {##, zCoordinate} & @@@ points;

basePoints = getGraphicsComplexPoints@fig;
lines = extractLines@fig;

Graphics3D@Table[
    {
        ColorData["Rainbow"][(2 k - 1)/3], 
        GraphicsComplex[threedifyPoints[basePoints, k], lines]
    },
    {k, {1, 2, 3, 4} 0.5}
  ]

enter image description here

In a similar fashion, we can extract the GraphicsGroup that make up the various coloured regions bounded by the contour lines:

extractGraphicsGroupSpecs[graphicsObject_] := Cases[
    graphicsObject,
    {___, GraphicsGroup[___], ___},
    All
];
Graphics@GraphicsComplex[basePoints, extractGraphicsGroupSpecs@fig]

enter image description here

Once we have this, we can essentially manipulate and restructure the data as we like. For example, we can have some fun by making up an "exploded" view of the contour plot:

With[{groups = extractGraphicsGroupSpecs@fig}, Graphics3D[{
   Table[
    GraphicsComplex[threedifyPoints[basePoints, k/20], groups[[k]]],
    {k, Length@groups}
    ]
   }, Boxed -> False]]

enter image description here

$\endgroup$

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.