【问题标题】:Increasing the speed of (or an alternative to) RegionPlot提高 RegionPlot 的速度(或替代方案)
【发布时间】:2011-12-07 03:00:55
【问题描述】:

我想在Manipulate 结构中包含一些区域图,但是渲染速度几乎令人望而却步。代码是

ClearAll[regions, rplot]
r:regions[n_Integer, o_Integer] := r = Apply[And, 
    Subsets[Table[(#1 - Cos[t])^2 + (#2 - Sin[t])^2 <= 1, {t, 2 Pi/n, 
       2 Pi, 2 Pi/n}], {o}], {1}] &
r:rplot[n_Integer, o_Integer] := r = Show[{RegionPlot[
     Evaluate[regions[n, o][x, y]], {x, -2, 2}, {y, -2, 2},
     PlotRange -> {{-2, 2}, {-2, 2}}, PlotRangePadding -> .1, 
     Frame -> False, PlotPoints -> 100], 
    Graphics[Table[Circle[{Cos[t], Sin[t]}, 1], {t, 2 Pi/n, 2 Pi, 2 Pi/n}]]}]

这会产生类似的图形

GraphicsGrid[{{rplot[3, 2], rplot[5, 3]}, {rplot[7, 2], rplot[4, 1]}}]

在我的电脑上计算和渲染上述内容大约需要 40 秒。 谁能建议一种更快地获得类似质量图形的方法?


注意 1:我已经记住了图形对象,因此在我的演示中不需要每次都重新计算它 - 但即使是第一次也太慢了。
注 2:我对光栅化图像很满意,因此也许可以选择泛洪填充类型的解决方案...
注意 3:我需要像 Manipulate[ rplot[n, o], {n, 2, 10, 1, Appearance -> "Labeled"}, {{o, 1}, Range[1, (n + 1)/2], ControlType -> RadioButtonBar}] 这样的东西才能使用。

【问题讨论】:

  • 形状总是圆形吗?
  • 是的-所以我只想替换rplot,除了它的速度之外,它与上面的没有区别。但是,如果您有更通用的解决方案,也欢迎!
  • 西蒙,我刚做完运动,脑子里一片混乱。您想为 n 或更多圆圈重叠的区域着色,每个离散区域的颜色不同。这是正确的吗?
  • @Mr.Wizard:是的。或者,更准确地为 n 圆圈重叠的区域着色。如果填充不是完全不透明的,那么重叠超过n 的地方会更暗。
  • (还是多云)如果你不给 more 多于n 圆圈重叠的区域着色,那么这些区域不会是 白色而不是更暗?

标签: wolfram-mathematica plot


【解决方案1】:

你可以这样做

rplot[n_Integer, o_Integer] :=  Module[{centres, masks, opacity = .3, 
   colours, region, img, createmask},
  centres = Table[Through[{Re, Im}[Exp[I t]]], {t, 2 Pi/n, 2 Pi, 2 Pi/n}];
  createmask[centres_] := Fold[ImageMultiply, #[[1]], Rest[#]] &@ 
     (ColorNegate[ Image[Graphics[Disk[#, 1], PlotRange -> {{-2, 2}, {-2, 2}}, 
          PlotRangePadding -> .1], ColorSpace -> "Grayscale"]] & /@ centres);
  masks = createmask /@ Subsets[centres, {o}];
  colours = PadRight[#, Length[masks], #] & @ (List @@@ ColorData[1, "ColorList"]);
  region[img_, col_] := 
   SetAlphaChannel[ColorCombine[ImageMultiply[img, #] & /@ col, "RGB"], 
    ImageMultiply[img, opacity]];
  img = Fold[ImageCompose, #[[1]], Rest[#]] &@(MapThread[region, {masks, colours}]);
  Overlay[{img, Graphics[Circle[#, 1] & /@ centres, PlotRangePadding -> .1, 
     PlotRange -> {{-2, 2}, {-2, 2}}]}]
 ]

然后GraphicsGrid[{{rplot[3, 2], rplot[5, 3]}, {rplot[7, 2], rplot[4, 1]}}] 产生类似的东西

编辑

将之前的编辑移至单独的答案。

【讨论】:

  • 这看起来不错,但在版本 7 中不起作用。如果没有 SetAlphaChannelOverlay,这可能吗?
  • @Mr.Wizard:应该可以用ImageCompose 替换Overlay,但SetAlphaChannel 在我为正确区域着色和正确混合的方法中非常重要。不过,我会试着想一个替代方案。
  • @Mr.Wizard:效果很好!它比RegionPlot 代码快约10 倍,比ParametricPlot 解决方案慢约5 倍。 Heike:现在我有时间解析代码,这是一个不错的方法。谢谢!
  • @Simon 现在你在分发寄生虫? :o) (我把它学成复选标记。)
  • Heike,我想看看使用 FilledCurve 的解决方案,尽管它在 v7 中不起作用。
【解决方案2】:

我之前发布了这个作为我其他答案的补充。它的灵感来自 Simon 的分析方法,并进行了一些修改以加快速度

intersect[n_, o_] :=
  With[{a = Pi/2 - (o-1) Pi/n},
   If[o-1 >= n/2, Return[{}]]; (* intersection is {} *)
   Polygon[
    Join[Table[{Sin[a] + Sin[phi], (-Cos[a] + Cos[phi])}, {phi, -a, a-2 a/10, 2 a/10}], 
     Table[{Sin[a] + Sin[phi], (Cos[a] - Cos[phi])}, {phi, a, -a+2 a/10, -2 a/10}]]]]

rplot2[n_, o_] := With[{pl = intersect[n, o], opac = .3, col = ColorData[1]},
  Graphics[{{Opacity[opac], 
     Table[{col[k], Rotate[pl, Mod[o - 1, 2] Pi/n + 2 Pi k/n, {0, 0}]}, {k, n}]},
    {Black, Circle[Through[{Re, Im}[Exp[I #]]]] & /@ (Range[n] 2 Pi/n)}}]
 ]

首先,对于no 的给定值,i-th 和i+o-1-th 圆之间的相交区域与第一个和o-th 个圆,除了旋转角度2 Pi (i-1)/n,因此只需计算一次区域并使用Rotate 旋转区域。

另外,我没有使用 ParametricPlot 来绘制交叉区域,而是使用 Polygon,所以我只需要计算边界上的一些点,这样可以节省时间。

GraphicsGrid[{{rplot2[3, 2], rplot2[5, 2]}, {rplot2[7, 3], rplot2[4, 1]}}] 的结果看起来像

我得到的时间是

rplot2[10, 3]; // Timing

(* ==> {0.0016, Null} *)

与西蒙的解决方案相比

rplot[10, 3]; // Timing

(* ==> {0.16519, Null} *)

【讨论】:

    【解决方案3】:

    先生。向导让我意识到,虽然我有一个可以在RegionPlot 中使用的区域的分析表格,但如果我获得了边界的参数化表格,那么我可以使用ParametricPlot。所以,让我们这样做吧!

    第 ith (i=0,...,n-1) 圆在复平面上通过
    Exp[I t] + Exp[2 i Pi I / n]t[0, 2 Pi] 中参数化。

    我们可以求解找到ith(i+o-1)th 圆的交集,其中o 是重叠的数量,如问题的原始代码。这给出了点

    point[n_, o_, i_] := {Cos[(2 i Pi)/n] + Cos[(2 Pi (i + o - 1))/n], 
                          Sin[(2 i Pi)/n] + Sin[(2 Pi (i + o - 1))/n]}
    

    现在我们可以对从原点到point[n,o,i] 的弧线进行参数化,并将它们反映在从原点到point[n,o,i] 的直线上。使用参数s 在两者之间进行插值得到参数化区域

    area[n_, o_, i_, t_, s_] := With[{a = 2 Sin[((2 + n - 2 o) (1 - t) )/(2 n) Pi], 
       b = (2 - 4 i + 2 t + n t - 2 o (1 + t))/(2 n) Pi, 
       c = ((2 + n - 2 o) (1 - t) - 4 i)/(2 n) Pi}, 
       {a (s Cos[b] + (1 - s) Sin[c]) , -a (s Sin[b] - (1 - s) Cos[c])}]
    

    然后我们可以定义

    rplot[n_Integer, o_Integer] := ParametricPlot[Evaluate[
      Table[area[n, o, i, t, s], {i, 0, n - 1}]], {t, 0, 1}, {s, 0, 1},
      Mesh -> False, MaxRecursion -> 1, Frame -> False, Axes -> False, 
      PlotRange -> 2.1 {{-1, 1}, {-1, 1}},
      Epilog -> {Table[Circle[{Cos[t], Sin[t]}, 1], {t, 0, 2 Pi (n-1)/n, 2 Pi/n}],
        Red, Point[Table[point[n, o, i], {i, 1, n}]]}]
    

    GraphicsGrid[{{rplot[3, 2], rplot[5, 3]}, {rplot[7, 2], rplot[4, 1]}}] 产生

    【讨论】:

    • @Mr.Wizard:我只需要正确的提示(谢谢)和晚餐休息!
    【解决方案4】:

    分析法

    如果圆总是如图所示排列成一个偶数环,则圆-圆交点应该有解析解。我会从环上每个圆圈之间的度数开始。

    如果时间允许,我将探索这种方法。

    光栅法

    1. 在正确位置对一系列磁盘进行二进制光栅化

    2. 将唯一的 2 次幂值分配给每个栅格以代替 1

    3. 添加数组

    4. 根据总计数组中每个点的值计算唯一的重叠集

    5. 将正确的颜色映射到结果数组并生成输出


    光栅方法的第一次粗略通过,仅作为概念证明。您可以看到每个区域都有一个独特的阴影,这只是该点栅格的总和。

    raster = 
      1 - First@Binarize@Rasterize@Graphics[#, PlotRange -> {{-2, 2}, {-2, 2}}] &;
    
    disks =
      Table[raster @ Disk[{Cos[t], Sin[t]}, 1], {t, 2 Pi/#, 2 Pi, 2 Pi/#}] &;
    
    n = 5;
    
    array = disks[n] * 2^Range[0, n - 1] //Total;
    
    ArrayPlot[array]
    


    第二稿,添加颜色。它仍然相当笨重。

    n = 7; o = 2;
    
    sets = Table[
       NestList[RotateLeft, PadLeft[Table[1, {o + i}], n], n - 1],
       {i, 0, n - o}
       ];
    
    colors = NestList[
       Mean /@ Partition[#, 2, 1, 1] &,
       List @@@ Take[ColorData[4, "ColorList"], n],
       n - o
       ];
    
    rules = Append[Rule @@@ Flatten[{sets, colors}, {{2, 3}}], _ -> {1, 1, 1}];
    
    Replace[Transpose[disks[n], {3, 2, 1}], rules, {2}] // Image
    

    【讨论】:

    • 我在处理光栅化图像方面没有经验,这就是我发布问题的原因。
    • 至于解析方法,我的RegionPlot表达式不就是这样吗?我想我/你也可以创建参数化曲线并将其发送到ParametricPlot 或生成Polgons。这可能有效 - 只需要计算交点,然后在这些点的标准圆参数化之间切换。
    • @Simon,我将在一分钟内添加一个非常基本的光栅方法示例。据我所知,RegionPlot 只是映射出一个函数空间。它实际上并没有解决相交方程。
    猜你喜欢
    • 2020-06-30
    • 1970-01-01
    • 2019-11-15
    • 2020-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-24
    • 1970-01-01
    相关资源
    最近更新 更多