从Mathematica中的ContourPlot中提取轮廓 [英] Extract contours from ContourPlot in Mathematica

查看:460
本文介绍了从Mathematica中的ContourPlot中提取轮廓的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含两个变量的函数f(x,y),我需要知道它与零交叉的曲线的位置。 ContourPlot非常有效地做到了这一点(也就是说:它使用了巧妙的多网格方法,不仅是蛮力的细粒度扫描),还给了我一个图。我想要一组值{x,y}(具有某些指定的分辨率)或某些插值函数,这些函数可以让我访问这些轮廓的位置。



曾经想过从ContourPlot的FullForm中提取此内容,但这似乎有点hack。还有更好的方法吗?

解决方案

如果最终从 ContourPlot ,这是一种简单的方法:

 点=案例[
Normal @ ContourPlot [Sin [x] Sin [y] == 1/2,{x,-3,3},{y,-3,3}],
Line [pts_]-> pts,
Infinity
]

加入@@点(*,如果您不希望分离的分量分开*)

编辑



似乎是 ContourPlot 不能产生非常精确的轮廓。它们当然是用于绘图的,并且已经足够好了,但是这些点并不恰好位于轮廓上:

 在[78]:=参加[加入@@点/。 {x_,y_}-> Sin [x] Sin [y]-1/2,10] 

Out [78] = {0.000163608,0.0000781187,0.000522698,0.000516078,
0.000282781,0.000659909,0.000626086,0.0000917416,0.000470424 ,
0.0000545409}

我们可以尝试提出自己的方法来跟踪轮廓,但是以一般方式进行操作很麻烦。这是一个对具有平滑轮廓的平滑变化函数起作用的概念:


  1. 从某点开始( pt0 ),然后沿着 f 的梯度找到与轮廓的交点。


  2. 现在轮廓上有一个点。沿着轮廓的切线移动固定的步长(分辨率),然后从步骤1开始重复。


这是一个基本实现,仅适用于可以象征性区分的功能:

  rot90 [{x_,y_}]:= {y,-x} 

step [f_,pt:{x_,y_},pt0:{x0_,y0_},resolution_]:=
Module [
{grad,grad0,t,outlinePoint},
grad = D [f,{pt}];
grad0 =研究生/。线程[pt-> pt0];
outlinePoint =
grad0 t + pt0 /。 First @ FindRoot [f /。线程[pt-> grad0 t + pt0],{t,0}];
Sow [contourPoint];
Grad = Grad /。线程[pt-> ContourPoint];
outlinePoint + rot90 [grad]分辨率
]

结果= Reap [
NestList [step [Sin [x] Sin [y]-1/2,{ x,y},#,.5]& ;, {1,1},20]
];

ListPlot [{result [[1]],result [[-1,1]]},PlotStyle-> {Red,Black},已加入
->是的,AspectRatio->自动,PlotMarkers->自动]



红色点是起点,黑色点是轮廓的痕迹。 / p>

编辑2



也许使用类似技术是一种更简便,更好的解决方案以使我们从 ContourPlot 中获得的点更加精确。从初始点开始,然后沿渐变移动,直到与轮廓相交。只需将函数定义为 f [x_?NumericQ,y_?NumericQ]:= ... (在这种情况下)。

  f [x_,y_]:= Sin [x] Sin [y]-1/2 

fine [f_,pt0:{x_, y_}]:=
Module [{grad,t},
grad = N [{Derivative [1,0] [f] [x,y],Derivative [0,1] [f] [x,y]}];
pt0 + grad * t /。 FindRoot [f @@(pt0 + grad * t),{t,0}]
]

积分=加入@@案例[
Normal @ ContourPlot [f [x ,y] == 0,{x,-3,3},{y,-3,3}],
Line [pts_]-> pts,
Infinity
]

fine [f,#]& / @点


I have a function f(x,y) of two variables, of which I need to know the location of the curves at which it crosses zero. ContourPlot does that very efficiently (that is: it uses clever multi-grid methods, not just a brute force fine-grained scan) but just gives me a plot. I would like to have a set of values {x,y} (with some specified resolution) or perhaps some interpolating function which allows me to get access to the location of these contours.

Have thought of extracting this from the FullForm of ContourPlot but this seems to be a bit of a hack. Any better way to do this?

解决方案

If you end up extracting points from ContourPlot, this is one easy way to do it:

points = Cases[
  Normal@ContourPlot[Sin[x] Sin[y] == 1/2, {x, -3, 3}, {y, -3, 3}],
  Line[pts_] -> pts,
  Infinity
]

Join @@ points (* if you don't want disjoint components to be separate *)

EDIT

It appears that ContourPlot does not produce very precise contours. They're of course meant for plotting and are good enough for that, but the points don't lie precisely on the contours:

In[78]:= Take[Join @@ points /. {x_, y_} -> Sin[x] Sin[y] - 1/2, 10]

Out[78]= {0.000163608, 0.0000781187, 0.000522698, 0.000516078, 
0.000282781, 0.000659909, 0.000626086, 0.0000917416, 0.000470424, 
0.0000545409}

We can try to come up with our own method to trace the contour, but it's a lot of trouble to do it in a general way. Here's a concept that works for smoothly varying functions that have smooth contours:

  1. Start from some point (pt0), and find the intersection with the contour along the gradient of f.

  2. Now we have a point on the contour. Move along the tangent of the contour by a fixed step (resolution), then repeat from step 1.

Here's a basic implementation that only works with functions that can be differentiated symbolically:

rot90[{x_, y_}] := {y, -x}

step[f_, pt : {x_, y_}, pt0 : {x0_, y0_}, resolution_] :=
 Module[
  {grad, grad0, t, contourPoint},
  grad = D[f, {pt}];
  grad0 = grad /. Thread[pt -> pt0];
  contourPoint = 
    grad0 t + pt0 /. First@FindRoot[f /. Thread[pt -> grad0 t + pt0], {t, 0}];
  Sow[contourPoint];
  grad = grad /. Thread[pt -> contourPoint];
  contourPoint + rot90[grad] resolution
 ]

result = Reap[
   NestList[step[Sin[x] Sin[y] - 1/2, {x, y}, #, .5] &, {1, 1}, 20]
];

ListPlot[{result[[1]], result[[-1, 1]]}, PlotStyle -> {Red, Black}, 
 Joined -> True, AspectRatio -> Automatic, PlotMarkers -> Automatic]

The red points are the "starting points", while the black points are the trace of the contour.

EDIT 2

Perhaps it's an easier and better solution to use a similar technique to make the points that we get from ContourPlot more precise. Start from the initial point, then move along the gradient until we intersect the contour.

Note that this implementation will also work with functions that can't be differentiated symbolically. Just define the function as f[x_?NumericQ, y_?NumericQ] := ... if this is the case.

f[x_, y_] := Sin[x] Sin[y] - 1/2

refine[f_, pt0 : {x_, y_}] := 
  Module[{grad, t}, 
    grad = N[{Derivative[1, 0][f][x, y], Derivative[0, 1][f][x, y]}]; 
    pt0 + grad*t /. FindRoot[f @@ (pt0 + grad*t), {t, 0}]
  ]

points = Join @@ Cases[
   Normal@ContourPlot[f[x, y] == 0, {x, -3, 3}, {y, -3, 3}],
   Line[pts_] -> pts,
   Infinity
   ]

refine[f, #] & /@ points

这篇关于从Mathematica中的ContourPlot中提取轮廓的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆