
0. 问题描述
如何画出 xkcd 样式的图表,样例如下:
原问题地址:https://mathematica.stackexchange.com/questions/11350/xkcd-style-graphs
标题以“【SE】”开头的问题,来自 StackExchange 中的经典问题,由各网友翻译并整理。在此与大家共享。
您可以在【文章分类】点击【Stack Exchange】分类,阅读此类文章。
本问题由以下网友翻译整理:雾霭,瓦屋青衣
1. 精彩回答
The code below attempts to apply the XKCD style to a variety of plots and charts.
The idea is to first apply cartoon-like styles to the graphics objects (thick lines, silly font etc), and then to apply a distortion using image processing.
通过下面的代码,我们可以用MMA画出XKCD样式的各式图表。
实现的方法是通过首先改变MMA原图中的图形(例如线,字体等),然后对整个图像做变形。
The final function is xkcdConvert which is simply applied to a standard plot or chart.
The font style and size are set by xkcdStyle which can be changed to your preference.
I’ve used the dreaded Comic Sans font, as the text will get distorted along with everything else and I thought that starting with the Humor Sans font might lead to unreadable text.The function xkcdLabel is provided to allow labelling of plot lines using a little callout.
The usage is xkcdLabel[{str,{x1,y1},{xo,yo}] where str is the label (e.g. a string), {x1,y1} is the position of the callout line and {xo,yo} is the offset determining the relative position of the label.The first example demonstrates its usage.
通过使用最终的程序 xkcdConvert,我们可以很简单的画出xkcd式的基本图表。
通过改变xkcdStyle 中的参数,我们可以改变输出的字体和大小。
因为对整体图像做变形的时候同样会变形其中的字体,而使用了Comic Sans字体。
本程序中没有使用Humor Sans的原因是为了防止出现不好辨认的情况。
xkcdLabel 的功能是用来在图中方便的添加标签。
xkcdLabel[{str,{x1,y1},{xo,yo}}各参数为:str代表要添加的标注,{x1,y1} 为添加的标注线的位置,{xo,yo} 为标注的位置。
下面是几个基本的例子:
xkcdStyle = {FontFamily -> "Comic Sans MS", 16};
xkcdLabel[{str_, {x1_, y1_}, {xo_, yo_}}] := Module[{x2, y2},
x2 = x1 + xo; y2 = y1 + yo;
{Inset[
Style[str, xkcdStyle], {x2, y2}, {1.2 Sign[x1 - x2],
Sign[y1 - y2] Boole[x1 == x2]}], Thick,
BezierCurve[{{0.9 x1 + 0.1 x2, 0.9 y1 + 0.1 y2}, {x1, y2}, {x2, y2}}]}];
xkcdRules = {EdgeForm[ef:Except[None]] :> EdgeForm[Flatten@{ef, Thick, Black}],
Style[x_, st_] :> Style[x, xkcdStyle],
Pane[s_String] :> Pane[Style[s, xkcdStyle]],
{h_Hue, l_Line} :> {Thickness[0.02], White, l, Thick, h, l},
Grid[{{g_Graphics, s_String}}] :> Grid[{{g, Style[s, xkcdStyle]}}],
Rule[PlotLabel, lab_] :> Rule[PlotLabel, Style[lab, xkcdStyle]]};
xkcdShow[p_] := Show[p, AxesStyle -> Thick, LabelStyle -> xkcdStyle] /. xkcdRules
xkcdShow[Labeled[p_, rest__]] :=
Labeled[Show[p, AxesStyle -> Thick, LabelStyle -> xkcdStyle], rest] /. xkcdRules
xkcdDistort[p_] := Module[{r, ix, iy},
r = ImagePad[Rasterize@p, 10, Padding -> White];
{ix, iy} =
Table[RandomImage[{-1, 1}, ImageDimensions@r]~ImageConvolve~
GaussianMatrix[10], {2}];
ImagePad[ImageTransformation[r,
# + 15 {ImageValue[ix, #], ImageValue[iy, #]} &, DataRange -> Full], -5]];
xkcdConvert[x_] := xkcdDistort[xkcdShow[x]]
2. 一些示例:
2.1 示例1
f1[x_] := 5 + 50 (1 + Erf[x - 5]);
f2[x_] := 20 + 30 (1 - Erf[x - 5]);
xkcdConvert[Plot[{f1[x], f2[x]}, {x, 0, 10},
Epilog ->
xkcdLabel /@ {{"Label 1", {1, f1[1]}, {1, 30}}, {"Label 2", {8, f2[8]}, {0, 30}}},
Ticks -> {{{3.5, "1st Event"}, {7, "2nd Event"}}, Automatic}]]
2.2 示例2
xkcdConvert[BarChart[{10, 1}, ChartLabels -> {"XKCD", "Others"},
PlotLabel -> "Popularity of questions on MMA.SE",
Ticks -> {None, {{1, "Min"}, {10, "Max"}}}]]
2.3 示例3
xkcdConvert[BarChart[{1, 10}, ChartLegends -> {"Others", "XKCD"},
PlotLabel -> "Popularity of questions on MMA.SE",
ChartStyle -> {Red, Green}]]
2.4 示例4
xkcdConvert[PieChart[{9, 1}, ChartLabels -> {"XKCD", "Others"},
PlotLabel -> "Popularity of questions on MMA.SE"]]
2.5 示例5
xkcdConvert[
ListLinePlot[RandomInteger[10, 15], PlotMarkers -> Automatic]]
2.6 示例6
xkcdConvert[BarChart3D[{3, 2, 1}, ChartStyle -> Red, FaceGrids -> None,
Method -> {"Canvas" -> None}, ViewPoint -> {-2, -4, 1},
PlotLabel -> "This is just silly"]]
2.7 示例7
xkcdConvert[
Plot3D[Exp[-10 (x^2 + y^2)^4], {x, -1, 1}, {y, -1, 1},
MeshStyle -> Thick,
Boxed -> False, Lighting -> {{"Ambient", White}},
PlotLabel -> Framed@"This plot is not\nparticularly useful"]]
2.8 示例8
图中使用中文字符时,通常采用“迷你简卡通”字体,这是科学松鼠会和果壳网常用的做法。
比如下图:
Graphics[{BezierCurve@{{0, 0}, {0, 1}, {1, 1}},
Line[{#,
Interpolation[{{{1}, 1, 0}, {{1.25}, 0.75, 0}, {{2}, 2,
0}}][#]} & /@ Range[1, 2, 0.01]],
ReIm@Exp[I (Pi/2 - #)]/3 + {#, #}/(4 Pi) + {2, 5/3} & /@
Range[0, 4 Pi, Pi/10] // Line,
BezierCurve[
Join[{{3, 3}, {3.2, 3}}, {1, 2} # + {3, 2} & /@
RandomReal[{0, 1}, {20, 2}], {{3.8, 4}, {4, 4}}]]},
Epilog ->
xkcdLabel /@ {{"基本语法", {0.5, 1}, {0, 0.5}}, {"纯函数", {1.5,
1.5}, {-0.5, 1}}, {"模式替换", {2.5, 2.5}, {-0.5,
1}}, {"万物皆式", {3.5, 2}, {-0.5, -1}}}, Axes -> True,
PlotLabel -> "mma学习曲线",
Ticks -> {MapIndexed[{Last@#2 - 0.5, "阶段" ~~ #1} &,
ToString /@ {一, 二, 三, 四}], {}}] // xkcdConvert
【全文完】