使用PlotMarkers的ListPlot绘图速度缓慢

8
我正在做这个:

ClearAll[matrix];
matrix[p_,q_,nu_:0]:=Module[{sigma},
 sigma=p/q;
 N@SparseArray[
  {{m_,m_}\[Rule]2Cos[2\[Pi]*m*p/q+nu],{i_,j_}/;
   Abs[i-j]\[Equal]1\[Rule]1},{q,q}]]

ClearAll[attachsigma]
attachsigma[sigma_,lst_]:={sigma,#}&/@lst

然后执行

fracs = Table[p/q, {q, 2, 30}, {p, 2, q}] // Flatten // DeleteDuplicates;
pq = {Numerator@#, Denominator@#} & /@ fracs;
(ens = Eigenvalues[#] & /@ 
Normal /@ (matrix[#[[1]], #[[2]]] & /@ pq);) // Timing
pts = Flatten[#, 1] &@MapThread[attachsigma, {fracs, ens}];

最后,我按照以下方式绘制点(这里是问题的真正关键):
plot = ListPlot[pts,
 PlotMarkers \[Rule] Graphics[{PointSize[Tiny], Point[{0, 0}]}]]

霍夫斯塔德

在我的电脑上,计算所有点大约需要2.6秒,但绘图需要大约25秒。如果我像这样绘制它:

ListPlot[pts]

Hofstadter

如果不使用 PlotMarkers,绘图几乎是瞬间完成的(只有5256个点)。因此,PlotMarkers 会严重拖慢绘图速度。

请问, a)为什么会这样?我有些模糊地理解了一下,类比于如果给 Sort 提供自定义排序函数时会发生的情况。 b)更重要的是,如何避免这种减速?我正在尝试创建具有更多点的图形,所以它们非常缓慢;此外,我正在创建很多这样的图形(实际上是电影)。

一种解决方法是不绘制所有点,但随着参数的变化,找出应该包含哪些点和不包含哪些点变得不容易(如果我只需要这一个框架,则这当然可以工作)。因此,我希望在不删除点的情况下加快绘图速度。

编辑:在 Sjoerd 的提示下回答:

ListPlot[pts] /. Point[List[x___]] \[RuleDelayed] {PointSize[Tiny], Point[List[x]]}

瞬间生成正确的东西。这只是通过手动将Graphics结构中的Points替换为较小的点。

现在可以将fracs = Table[p/q, {q, 2, 30}, {p, 2, q}] // Flatten // DeleteDuplicates中表格的上限增加到80左右,以获得更多的点(这个东西是Hofstadter蝴蝶,是一个分形):

enter image description here

3个回答

9

PlotMarkers是用于包含相对较少点的数据图的。它非常适用于您使用标记来识别各种条件的情况下。每个单独的标记都是一个Inset,如下所示:

Inset[Graphics[List[Hue[0.67`,0.6,0.6`],PointSize[Tiny],Point[List[0, 0]]]],10512].

你可以想象这需要花费一些时间和内存。
我还发现了一个似乎是bug的问题。使用PlotMarkers的图形被结构化为GraphicsComplex[pointlist,graphicsinstructions]。这个点列表似乎包含了绘图中的点两次!
In[69]:= pts // Length

Out[69]= 5256

In[66]:= plot[[1, 1]] // Length

Out[66]= 10512

In[64]:= Union[plot[[1, 1]]] == Union[pts]

Out[64]= True

In[68]:= Tally[plot[[1, 1]]][[All, 2]] // Mean (*the average number each point occurs*)

Out[68]= 2

谢谢。你说得对,FullForm 显示这确实是它们的表示方式。不过你有什么加速的建议吗?例如,如果我能选择正确的 smth,那么 ListPlot[pts] /. Point[List[x___]] :> smth 可以起作用,但是 mma 中的图形不是我的强项... - acl
@acl 看到了你的编辑。问题迅速得到解决。你看到我的最后一次编辑了吗? - Sjoerd C. de Vries
是的,我刚刚在尝试实验,看起来你是正确的。有趣。 - acl
现在它的速度与ListPlot一般是一样快的。太好了。 - acl

6

个人而言,我更喜欢使用Graphics而非ListPlot,特别是当数据点数量较大时。

Graphics[{Hue[{2/3, 1, 1, .5}], AbsolutePointSize[1.5], Point@pts}, 
 PlotRange -> {{0, 1}, {-4, 4}}, Axes -> False, 
 AspectRatio -> 1/GoldenRatio]

例如,提供以下内容:
例如:输入图像描述
Length@pts

102969


这个程序与没有PlotMarkersListPlot花费相同的时间,这是有道理的! - acl

3

我认为你在问题中添加的解决方案可以简化:

ListPlot[pts] /. x_Point :> {PointSize[Tiny], x}

我投票支持之前的两个答案,但我同意TomD对于直接使用Graphics的看法。


你说得对,一次性完成确实少打几个键。也许使用Graphics确实更好:我本来希望通过使用ListPlot来减少工作量(但最终显然没有这样做...)。 - acl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接