在ask.sagemath的this question启发,在Plot
,ContourPlot
等产生的曲线末尾添加箭头的最佳方式是什么? ...?这些是高中看到的情节类型,表明曲线在页面末尾继续。
经过一番搜索后,我无法找到内置方式或最新的软件包来执行此操作。 (有ArrowExtended,但它已经很老了。
ask.sagemath问题中给出的解决方案依赖于函数及其端点的知识以及(可能)获取衍生物的能力。它翻译成Mathematica是
f[x_] := Cos[12 x^2]; xmin = -1; xmax = 1; small = .01;
Plot[f[x],{x,xmin,xmax}, PlotLabel -> y==f[x], AxesLabel->{x,y},
Epilog->{Blue,
Arrow[{{xmin,f[xmin]},{xmin-small,f[xmin-small]}}],
Arrow[{{xmax,f[xmax]},{xmax+small,f[xmax+small]}}]
}]
另一种方法是简单地将Line[]
生成的Plot[]
对象替换为Arrow[]
。例如
Plot[{x^2, Sin[10 x], UnitStep[x]}, {x, -1, 1},
PlotStyle -> {Red, Green, {Thick, Blue}},
(*AxesStyle -> Arrowheads[.03],*) PlotRange -> All] /.
Line[x__] :> Sequence[Arrowheads[{-.04, .04}], Arrow[x]]
但是这有一个问题,即线条中的任何不连续都会产生你不想要它们的箭头(这通常可以通过选项Exclusions -> None
来修复)。更重要的是,CountourPlot
s这种方法毫无希望。例如,尝试
ContourPlot[x^2 + y^3 == 1, {x, -2, 2}, {y, -2, 1}] /.
Line[x__] :> Sequence[Arrowheads[{-.04, .04}], Arrow[x]]
(上述情况中的问题可由规则修正,例如{a___, l1_Line, l2_Line, b___} :> {a, Line[Join[l2[[1]], l1[[1]]]], b}
或使用适当的单头箭头。)。
正如您所看到的,上述(快速黑客)都不是特别强大或灵活。有谁知道这种做法?
答案 0 :(得分:4)
以下似乎可行,首先对片段进行排序:
f[x_] := {E^-x^2, Sin[10 x], Sign[x], Tan[x], UnitBox[x],
IntegerPart[x], Gamma[x],
Piecewise[{{x^2, x < 0}, {x, x > 0}}], {x, x^2}};
arrowPlot[f_] :=
Plot[{#}, {x, -2, 2}, Axes -> False, Frame -> True, PlotRangePadding -> .2] /.
{Hue[qq__], a___, x___Line} :> {Hue[qq], a, SortBy[{x}, #[[1, 1, 1]] &]} /.
{a___,{Line[x___], d___, Line[z__]}} :>
List[Arrowheads[{-.06, 0}], a, Arrow[x], {d},
Arrowheads[{0, .06}], Arrow[z]] /.
{a___,{Line[x__]}}:> List[Arrowheads[{-.06, 0.06}], a, Arrow[x]] & /@ f[x];
arrowPlot[f]
答案 1 :(得分:2)
受Alexey的评论和belisarius的回答的启发,这是我的尝试。
makeArrowPlot[g_Graphics, ah_: 0.06, dx_: 1*^-6, dy_: 1*^-6] :=
Module[{pr = PlotRange /. Options[g, PlotRange], gg, lhs, rhs},
gg = g /. GraphicsComplex -> (Normal[GraphicsComplex[##]] &);
lhs := Or@@Flatten[{Thread[Abs[#[[1, 1, 1]] - pr[[1]]] < dx],
Thread[Abs[#[[1, 1, 2]] - pr[[2]]] < dy]}]&;
rhs := Or@@Flatten[{Thread[Abs[#[[1, -1, 1]] - pr[[1]]] < dx],
Thread[Abs[#[[1, -1, 2]] - pr[[2]]] < dy]}]&;
gg = gg /. x_Line?(lhs[#]&&rhs[#]&) :> {Arrowheads[{-ah, ah}], Arrow@@x};
gg = gg /. x_Line?lhs :> {Arrowheads[{-ah, 0}], Arrow@@x};
gg = gg /. x_Line?rhs :> {Arrowheads[{0, ah}], Arrow@@x};
gg
]
我们可以在某些功能上测试这个
Plot[{x^2, IntegerPart[x], Tan[x]}, {x, -3, 3}, PlotStyle -> Thick]//makeArrowPlot
在一些等高线图上
ContourPlot[{x^2 + y^2 == 1, x^2 + y^2 == 6, x^3 + y^3 == {1, -1}},
{x, -2, 2}, {y, -2, 2}] // makeArrowPlot
失败的地方是地块边缘有水平或垂直线;
Plot[IntegerPart[x],{x,-2.5,2.5}]//makeArrowPlot[#,.03]&
可以通过PlotRange->{-2.1,2.1}
或Exclusions->None
等选项修复此问题。
最后,添加一个选项会很好,这样每个“曲线”只能在其边界上显示箭头。这将给出像Belisarius的回答中的情节(它也可以避免上面提到的问题)。但这是一个品味问题。
答案 2 :(得分:2)
以下构造的优点是不会弄乱Graphics结构的内部结构,并且比ask.sagemath中建议的更通用,因为它更好地管理PlotRange和infinities。
f[x_] = Gamma[x]
{plot, evals} =
Reap[Plot[f[x], {x, -2, 2}, Axes -> False, Frame -> True,
PlotRangePadding -> .2, EvaluationMonitor :> Sow[{x, f[x]}]]];
{{minX, maxX}, {minY, maxY}} = Options[plot, PlotRange] /. {_ -> y_} -> y;
ev = Select[evals[[1]], minX <= #[[1]] <= maxX && minY <= #[[2]] <= maxY &];
seq = SortBy[ev, #[[1]] &];
arr = {Arrow[{seq[[2]], seq[[1]]}], Arrow[{seq[[-2]], seq[[-1]]}]};
Show[plot, Graphics[{Red, arr}]]
修改
作为一项功能:
arrowPlot[f_, interval_] := Module[{plot, evals, within, seq, arr},
within[p_, r_] :=
r[[1, 1]] <= p[[1]] <= r[[1, 2]] &&
r[[2, 1]] <= p[[2]] <= r[[2, 2]];
{plot, evals} = Reap[
Plot[f[x], Evaluate@{x, interval /. List -> Sequence},
Axes -> False,
Frame -> True,
PlotRangePadding -> .2,
EvaluationMonitor :> Sow[{x, f[x]}]]];
seq = SortBy[Select[evals[[1]],
within[#,
Options[plot, PlotRange] /. {_ -> y_} -> y] &], #[[1]] &];
arr = {Arrow[{seq[[2]], seq[[1]]}], Arrow[{seq[[-2]], seq[[-1]]}]};
Show[plot, Graphics[{Red, arr}]]
];
arrowPlot[Gamma, {-3, 4}]
仍然在想ListPlot&amp;人