5
$\begingroup$

I have a list density plot from a list ls={{x1,y1,z1},{x2,y2,z2}}.... How can I extract the line density with a fix y, such that I could get a ListPlot {{xi,zi},{xj,zj}}.... Please start from list ls or the graph p1, avoid using the functions, they are only used to generate the list.

The graph in ListDensityPlot is smooth, so I would require the ListPlot also be smooth. However, the list ls may not be very dense. Below is the code creating the list and ListDensityPlot:

(*Creating a list ls*)
f[x_] := Sqrt[1 - x];
stepSize = 100/1000;
ls0 = Table[{x, f[x]}, {x, 0, 1, stepSize}];
ls1 = Flatten[
   Table[{#[[1]], y, Exp[y - #[[2]]] - 1}, {y, #[[2]], 1.5, 
       stepSize}] & /@ ls0, 1];
ls2 = Flatten[
   Table[{#[[1]], y, 0}, {y, 0, #[[2]], stepSize}] & /@ ls0, 1];
ls = Join[ls1, ls2];
(*Draw the ListDensity of ls*)

p1 = ListDensityPlot[ls, PlotLegends -> Automatic];
p2 = Plot[{0.83, 1.14}, {x, 0, 1}, 
   PlotStyle -> {{Dashed, Red}, {Dashed, Green}}];
Show[p1, p2]
ListPointPlot3D[ls]

enter image description here

For example, how to extract the red and green dashed line smoothly?

enter image description here

It can be seen that the points may not be dense.

$\endgroup$
9
  • $\begingroup$ f[x] is undefined. $\endgroup$
    – bbgodfrey
    Dec 30, 2015 at 13:46
  • $\begingroup$ @bbgodfrey Sorry, added $\endgroup$ Dec 30, 2015 at 13:47
  • $\begingroup$ @buzhidao - In your previous question you specified that you did not want an interpolation function to be used, but in this case I don't see how to avoid it since 0.83 and 1.14 are not points that are explicitly included in the y values of ls $\endgroup$
    – Jason B.
    Dec 30, 2015 at 13:57
  • $\begingroup$ @JasonB This is a different question, use it as you wish... I choose this two value on purpose. However, it would be best if the extracted data reflect the color in the listdensityplot. $\endgroup$ Dec 30, 2015 at 14:01
  • $\begingroup$ @buzhidao So, is an interpolation function from the List that goes into the DensityPlot acceptable, or do you wish the extracted data to be from the DensityPlot itself? $\endgroup$
    – bbgodfrey
    Dec 30, 2015 at 14:13

3 Answers 3

4
$\begingroup$

An alternative, which is my go-to method of extracting these kinds of things. First construct a 3D-plot of the data using Mesh lines that sit at y-values of 0.83 and 1.14:

p3 = ListPlot3D[ls
  , PlotRange -> All
  , InterpolationOrder -> 1
  , MeshFunctions -> (#2 &), Mesh -> {{0.83, 1.14}}
  , BoundaryStyle -> None, Boxed -> False, Axes -> False]

enter image description here

Then extract the lines from the graph:

lns = Cases[Normal@p3, Line[a_] :> a, Infinity];
ListLinePlot /@ Apply[{#1, #3} &, lns, {2}]

enter image description here

To see the points, consider:

Plot[Interpolation[{#1, #3} & @@@ #, InterpolationOrder -> 0][t], {t, 0, 1}] & /@ lns

enter image description here

$\endgroup$
5
  • $\begingroup$ This method is great! Two questions: How to change the two mesh lines into the color and style as shown in my plot? $\endgroup$ Dec 31, 2015 at 2:31
  • $\begingroup$ ListLinePlot[{#1, #3} & @@@ #] & /@ lns.This code snippet is insane, it seems a pure function in another pure function. I don't quite understand it, though I know what it does. It seems that lns and # & /@ lns are same but {#1, #3} & @@@ lns and {#1, #3} & @@@ # & /@ lns are very different... Can you explain how this code works in some detail? $\endgroup$ Dec 31, 2015 at 2:35
  • $\begingroup$ @buzhidao. lns is a list containing the two lists of points corresponding to the two plots. Everything preceding the /@ lns is just a pure function which operates on each of these lists of points (thus making two ListLinePlots). {#1, #3} & @@@ # is then really just {#1, #3} & @@@ <list of points in 3D>. It could also be written as {#[[1]], #[[3]]} & /@ # or, more straightforwardly, Table[pt[[{1,3}]], {pt, #}]. $\endgroup$
    – march
    Dec 31, 2015 at 5:28
  • $\begingroup$ Wrapping Show[...] around the 'ListLinePlot[{#1, #3} & @@@ #] & /@ lns' does what I'm looking for, but doesn't differentiate each line by color. How can I do that (and add a legend)? $\endgroup$
    – user12734
    Dec 7, 2020 at 19:25
  • 1
    $\begingroup$ @user12734. ListLinePlot[Apply[{#1, #3} &, lns, {2}], PlotLegends -> Automatic] $\endgroup$
    – march
    Dec 7, 2020 at 19:29
7
$\begingroup$

Extracting data directly from ListDensityPlot

make a grayscale plot:

p1 = ListDensityPlot[ls, PlotLegends -> Automatic, 
  ColorFunction -> GrayLevel]

enter image description here

extract the polynomials from the graphics , then the ones that cross the desired line:

polys = Cases[Normal@p1, Polygon[v_List, VertexColors -> c_List], 
   Infinity];
Graphics[{
  EdgeForm[{Thick, Blue}], 
   Select[ polys, 
    Max[#[[1, All, 2]]] > 1.14 && Min[#[[1, All, 2]]] < 1.14 & ],
  Red, Line[{{0, 1.14}, {1, 1.14}}]} ]

enter image description here

then extract the edges that cross..

tedges[poly_, y_] :=
 MapThread[{ {poly[[1, #1]], poly[[2, 2, #1]]}  , {poly[[1, #2]], 
     poly[[2, 2, #2]]} } & ,
  ({#, RotateLeft[#]} &@Range[Length@poly[[1]]])]
crossedges[polys_, y_] := 
  Select[  Flatten[
    tedges[#, y] & /@ (Select[ polys, 
       Max[#[[1, All, 2]]] > y && Min[#[[1, All, 2]]] < y & ]), 
    1] , ((Max[#[[All, 1, 2]] ] >= y && 
           Min[#[[All, 1, 2]] ] <= y) &)];

linear interpolate edge color along each edge:

intedge[edge_, y_] := 
 Module[{ ci = (y - edge[[2, 1, 2]])/(edge[[1, 1, 2]] - 
       edge[[2, 1, 2]])},
  {edge[[1, 1, 1]] ci + edge[[2, 1, 1]] (1 - ci)  , 
   edge[[1, 2]] ci + edge[[2, 2]] (1 - ci)}]
ListPlot[Union[intedge[#, 1.14] & /@ crossedges[polys, 1.14]]]

enter image description here

note the scale here is the grayscale.. go back and use ColorFunctionScaling->False for the plot..

enter image description here

and...after all that we see we have precisely the same result as JasonB's Interpolation..

enter image description here

$\endgroup$
7
$\begingroup$

So your interpolation function will suffer a bit since the data is on a non-rectangular grid. This is the case also for the density plot, you can see that the interpolation on the 2D plot isn't great.

intfunc = Interpolation[DeleteDuplicates@ls]

enter image description here

You can see that the result isn't perfectly smooth,

Plot[{intfunc[x, .83], intfunc[x, 1.14]}, {x, 0, 1}, 
 PlotStyle -> {Red, Green}]

enter image description here

But you can also see that it matches your data points as well

ListPointPlot3D[{ls, {#, .83, intfunc[#, .83]} & /@ 
   Range[0, 1, .1], {#, 1.14, intfunc[#, 1.14]} & /@ Range[0, 1, .1]},
  PlotStyle -> {{PointSize[.01], Blue}, {PointSize[.01], 
    Red}, {PointSize[.01], Green}}]

enter image description here

$\endgroup$
0

Your Answer

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

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