Skip to main content

Plotting contours plot for f(x,y,z)=c


I have the following question: I have a file that has structure:


x1 y1 z1 f1
x2 y2 z2 f2
...
xn yn zn fn


I can easily visualize it with Mathematica using ListContourPlot3D. But could you please tell me how I can plot contour plot for this surface? I mean with these data I have a set of surfaces corresponding to different isovalues (f) and I want to plot intersection between all these surfaces and some certain plane. I tried to Google but didn't get any results. Any help and suggestions are really appreciated. Thanks in advance!



Answer



Ok, lets give this a try. @Mr.Wizard already showed you, how you can use Interpolate to make a function from your discrete data and since you didn't provide some test-data, I just assume we are speaking of an isosurface of a function $f(x,y,z)=c$ which is defined in some box in $\mathbb{R}^3$.


For testing we use $$f(x,y,z) = x^3+y^2-z^2\;\;\mathrm{and}\;\; -2\leq x,y,z \leq 2$$ which accidently happens to be the first example of ContourPlot3D.


The idea behind the following is pretty easy: As you may know from school, there is a simple representation of a plane in 3d which uses a point vector $p_0$ and two direction vectors $v_1$ and $v_2$. Every point on this plane can be reached through the $(s,t)$ parametrization


$$p(s,t)=p_0+s\cdot v_1+t\cdot v_2$$


Please note that $p_0, p, v_1, v_2$ are vectors in 3d and $s,t$ are scalars. The other form which we will use only for illustration is called the normal form of a plane. It is give by


$$n\cdot (p-p_0)=0$$


where $n$ is the vector normal to the plane, which can easily be calculated with the cross-product by $v_1\times v_2$. Lets start by looking at our example. To draw the plane inside ContourPlot3D we use the normal form which is plane2:


f[{x_, y_, z_}] := x^3 + y^2 - z^2;

v1 = {1, 1, 0};
v2 = {0, 0, 1};
p0 = {0, 0, 0};
plane1 = p0 + s*v1 + t*v2;
plane2 = Cross[v1, v2].({x, y, z} - p0);
gr3d = ContourPlot3D[{f[{x, y, z}], plane2}, {x, -2, 2}, {y, -2, 2}, {z, -2, 2},
Contours -> {0},
ContourStyle -> {ColorData[22, 3], Directive[Opacity[0.5], ColorData[22, 4]]}]

Mathematica graphics



What we do now is, that we try to find the contour value (which is 0 here) of $f(x,y,z)$ for all points, that lie on our plane. This is like doing a normal ContourPlot because our plane is 2d (although placed in 3d space). Therefore, we use the 2d to 3d mapping of plane1


gr2d = ContourPlot[f[plane1], {s, -2, 2}, {t, -2, 2}, Contours -> {0}, 
ContourShading -> None, ContourStyle -> {ColorData[22, 1], Thick}]

Mathematica graphics


Look at the intersection. It is exactly the loop we would have expected from the 3d illustration. Now you could object something like "ew.. but I really like a curve in 3d..". Again, the mapping from this 2d curve to 3d is given in the plane equation. You can simply extract the Line[..] directives from the above plot and transfer it back to 3d:


Show[{gr3d, 
Graphics3D[{Red, Cases[Normal[gr2d], Line[__], Infinity] /.
Line[pts_] :> Tube[p0 + #1*v1 + #2*v2 & @@@ pts, .05]}]
}]


I extract the Lines with Cases and then use the exact same definition of plane1 as pure function to transform the pts.


Mathematica graphics


When I'm not completely wasted at 5:41 in the morning, than this approach should work for your interpolated data too.


Apply method on test-data


I uploaded your test-data to our Git-repository and therefore, the code below should work without downloading anything. The approach is the same as above but some small things have changed, since we work on interpolated data now. I'll explain only the differences.


First we import the data and since we have a long list of {x,y,z,f} values, we transform them to {{x,y,z},f} as required by the Interpolation function. I'm not using the interpolation-function directly. I wrap a kind of protection around it which tests whether a given {x,y,z} is numeric and lies inside the interpolation box. Otherwise I just return 0.


data = {Most[#], Last[#]} & /@ 
Import["https://raw.github.com/stackmma/Attachments/master/data_9304_187.m"];
ip = Interpolation[data];

fip[{x_?NumericQ, y_?NumericQ, z_?NumericQ}] :=
If[Apply[And, #2[[1]] < #1 < #2[[2]] & @@@
Transpose[{{x, y, z}, First[ip]}]],
ip[x, y, z], 0.0]

The code below is almost the same. I only adapted the plane that it goes through your interpolation box. Furthermore, if you inspect your data you see that the value run from 0 to 1.2. Therefore I'm plotting the 0.5 contour by subtracting 0.5 from the function value and using Contours -> {0}. Remember that when I would simply plot the 0.5 contour, it would draw me a different plane, since we use one combined ContourPlot3D call.


Furthermore, notice that I normalized the direction vectors of the plane. This makes it easier to adjust the 2d plot of the contour. The rest should be the same.


v1 = Normalize[{30, 30, 0}];
v2 = Normalize[{0, 0, 21}];
p0 = {26, 26, 17};

plane1 = p0 + s*v1 + t*v2;
plane2 = Cross[v1, v2].({x, y, z} - p0);
gr3d = ContourPlot3D[{fip[{x, y, z}] - 0.5, plane2}, {x, 27, 30}, {y,
27, 30}, {z, 17.3, 21}, Contours -> {0},
ContourStyle -> {Directive[Opacity[.5], ColorData[22, 3]],
Directive[Opacity[.8], ColorData[22, 5]]}]

gr2d = ContourPlot[fip[plane1] - 0.5, {s, 2, 5}, {t, 1, 4},
Contours -> {0}, ContourShading -> None,
ContourStyle -> {ColorData[22, 1], Thick}];

Show[{gr3d,
Graphics3D[{Red,
Cases[Normal[gr2d], Line[__], Infinity] /.
Line[pts_] :> Tube[p0 + #1*v1 + #2*v2 & @@@ pts, .05]}]}]

Mathematica graphics


As you can see, your sphere has a whole inside.


Mathematica graphics


Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...