Search code examples
pythonexportwolfram-mathematicaequivalent

Understanding Mathematica contour lines extraction


My Professor sent me a Mathematica Notebook, where he plots a 2d contour and then extracts the contour as lines (i.e. a list of lists of coordinate-tuples). The specific code segment looks like this:

xdiv = 0.05
zt = 1.
lis = Table[SomeFunction[x, y, zt], {y, -xmax, xmax, xdiv}, {x, -xmax, xmax, xdiv}];
plot = ListContourPlot[lis, PlotLegends -> Automatic, Contours -> {0}, ContourShading -> None];
lines = Cases[Normal@plot, Line[pts_, ___] :> xdiv*pts, Infinity];

I do not fully understand how exactly the code does what it does and an I'm seeking help for an explanation. I want to write a similar code in python and understand how. Also I want to know if I can extract the lines without using the ContourPlot function. I am not particularly interested in plotting the contours, I only need a list of its lines.

Edit: Rephrased the question. Also: matplotlib - extracting data from contour lines seems to explain how to achieve my goal in python. However, I don't really understand how it does what it does and judge if there is a better way, in terms of performance, to achieve it (I am dealing with very large lists, so this contour extraction seems like quite the bottleneck). I was looking for something more of an explanation to understand what exactly happens. The provided answer does really well at explaining the Mathematica code. I will read more into the matplotlib methods.


Solution

  • Here is some explanation of what is happening, with an example function:

    SomeFunction[x_, y_, zt_] := Sin[3 x + y^2]
    xmax = 4;
    
    xdiv = 0.05;
    zt = 1.;
    lis = Table[SomeFunction[x, y, zt], {y, -xmax, xmax, xdiv}, {x, -xmax, xmax, xdiv}];
    plot = ListContourPlot[lis, PlotLegends -> Automatic, Contours -> {0},
      ContourShading -> None];
    normalplot = Normal@plot
    

    enter image description here

    cases = Cases[normalplot, Line[pts_, ___], Infinity];
    Length[cases]
    First[cases]
    
    17
    Line[{{16.2216, 1.}, {17., 1.29614}, ... , {16.7818, 160.782}, {16.2216, 161.}}]
    

    The Cases statement extracts each line from the normalized plot. (Normal simplifies the graphics form to one amenable to Cases.) There are 17 separate lines of the form Line[List[{x, y}, {x, y}, ...]].

    For each line List[{x, y}, {x, y}, ...] is represented by pts, so

    lines = Cases[normalplot, Line[pts_, ___] :> xdiv*pts, Infinity]
    

    multiplies each list of pts by xdiv.

    0.05 * {{16.2216, 1.}, {17., 1.29614}, ... , {16.7818, 160.782}, {16.2216, 161.}}
    = {{0.81108, 0.05}, {0.85, 0.0648069}, ... {0.839088, 8.03909}, {0.81108, 8.05}}
    

    The lines can be plotted.

    ListLinePlot[lines, AspectRatio -> 1]
    

    enter image description here