我正在尝试创建一些函数,以避免我为不同类型的绘图重复绘图选项。当我尝试创建机制来自动处理Frameticks&时,我遇到了一些麻烦。给定在给定图中考虑的数据的绘图范围。
Module[{chartData},
chartData = RandomInteger[20, 20];
BarChart[chartData,
Frame -> {{True, True}, {True, True}},
ImageSize -> 300,
ChartStyle -> Black,
FrameLabel -> {{"yName", None}, {None, "xName"}},
ChartElementFunction -> "FadingRectangle",
LabelStyle -> Directive[Black, Bold, 18],
PlotRange -> {Automatic, 1.3*Max@chartData},
FrameTicks -> {{{Round@Min@chartData, Round@(Max@chartData/2),
Round@Max@chartData}, None},
{{0, Round@(Length@chartData/2), Length@chartData}, None}}
]]
现在我试图简化我的生活:
chartOptions[yName_, xName_] := {Frame -> {{True, True}, {True, True}},
ImageSize -> 300,
ChartStyle -> Blue,
FrameLabel -> {{yName, None}, {None, xName}},
ChartElementFunction -> "FadingRectangle",
LabelStyle -> Directive[Black, Bold, 18],
FrameTicks -> {{{Round@Min@chartData, Round@(Max@chartData/2),
Round@Max@chartData}, None},
{{0,Round@(Length@chartData/2),
Length@chartData}, None}},
PlotRange -> {Automatic, 1.3*Max@chartData}}
这样,希望我的实际图表代码是这样的:
Module[{chartData},
chartData = RandomInteger[20, 20];
BarChart[chartData,
chartOptions["yName", "xName"]]]
但这不起作用:
我们的想法是,图表选项功能将根据使用它的实际绘图的图表数据进行调整。
我现在只想使用我真正理解的东西,所以我希望这个问题不需要你的大部分技巧:-)!
答案 0 :(得分:14)
不是问题的直接答案(@WReach已经回答过),但我认为@500触及了一个重要的话题。我们可能经常想要创建类似于包含某些自定义选项设置的配置。在全球范围内改变选择是IMO,这通常不是一个坏主意(这不会减损@Verbeia的答案。当然有一些情况下全局选项重置是合适的。我的建议应被视为互补)。在这里,我将重现一个非常轻量级的选项配置管理器的实现,以创建持久的选项配置,我在回答similar question on Mathgroup时写的,以及相关的讨论。
让我从使用开始 - 可以在我的帖子底部找到选项配置管理器的实现。我们将从带有选项的测试函数开始:
In[54]:=
ClearAll[bar];
Options[bar] = {barA -> 1, barB -> 2};
bar[x__, OptionsPattern[]] :=
Module[{},
{"barA: " -> OptionValue[barA], "barB: " -> OptionValue[barB]}];
首先,我们只是在没有任何明确传递的选项的情况下调用它。它显示当前使用的选项的值 - 在这种情况下,通过选项(OptionValue
全局设置的那些选项可以处理它们):
In[57]:= bar[1, 2]
Out[57]= {"barA: " -> 1, "barB: " -> 2}
我们现在调用我们的经理API中的一个函数(参见下面的实现):
setOptionConfiguration[bar,"first", {barA -> 11, barB -> 22, fooA -> 1}];
这定义了名为bar
的函数"first"
的选项配置。要使用此选项配置,我们使用另一个函数:withOptionConfiguration
,如下所示:
In[58]:= withOptionConfiguration[bar[1, 2], "first"]
Out[58]= {"barA: " -> 11, "barB: " -> 22}
这看起来好像我们确实在全球范围内更改了bar
的选项,但实际上我们没有。现在,在显式传递的选项存在的情况下使用我们的选项配置:
In[59]:= withOptionConfiguration[bar[1,2,barA->"overriding_barA"],"first"]
Out[59]= {barA: ->overriding_barA,barB: ->22}
在此设置中,选项配置会覆盖Options[bar]
,但显式传递给bar
的选项会覆盖两者。也可以通过从我们的API调用另一个函数来检查给定函数的选项配置:
In[60]:= getOptionConfiguration[bar,"first"]
Out[60]= {barA->11,barB->22}
使用这个结构,人们可以做一些很酷的事情,比如创建这样的快捷方式:
In[61]:=
first=Function[code,withOptionConfiguration[code,"first"],HoldFirst];
In[62]:= first@bar[1,2,barA->"overriding_barA"]
Out[62]= {barA: ->overriding_barA,barB: ->22}
通过这种方式,人们可以创建任意数量的选项配置,任何阅读此代码的人都可以清楚地知道发生了什么。
ClearAll[setOptionConfiguration, getOptionConfiguration, withOptionConfiguration];
SetAttributes[withOptionConfiguration, HoldFirst];
Module[{optionConfiguration},
optionConfiguration[_][_] = {};
setOptionConfiguration[f_, tag_, {opts___?OptionQ}] :=
optionConfiguration[f][tag] = FilterRules[{opts}, Options[f]];
getOptionConfiguration[f_, tag_] := optionConfiguration[f][tag];
withOptionConfiguration[f_[args___], tag_] :=
f[args, Sequence @@ optionConfiguration[f][tag]];
];
有几次,我发现这种类型的结构很有用。它们的主要优点是虽然选项配置是持久的,但它们通过在本地传递选项来工作,因此选项不会全局重置。全局选项重置是一项危险的业务,特别是对于常见(例如内置)功能,以及将功能交付给其他人时。此外,上述实施方案非常轻巧,可以轻松扩展或修改以满足个人需求。
答案 1 :(得分:6)
问题在于chartOptions
变量chartData
是一个引用全局定义的自由变量。在BarChart
表达式中,chartData
变量已本地化为包含模块,因此chartOptions
不可见。将chartOptions
更改为接受chartData
作为参数:
chartOptions[chartData_, yName_, xName] := ...
然后相应地调整BarChart
表达式:
Module[{chartData},chartData=RandomInteger[20,20];
BarChart[chartData,chartOptions[chartData, "yName","xName"]]]
答案 2 :(得分:5)
创建这样的函数是处理依赖于要绘制的数据的选项的正确方法。但是,可以使用BarChart
为Mathematica会话中SetOptions
的所有用途设置其中一些选项。对于您的示例,您可以选择定义:
SetOptions[BarChart, Frame -> {{True, True}, {True, True}},
ImageSize -> 300,
ChartStyle -> Black,
ChartElementFunction -> "FadingRectangle",
LabelStyle -> Directive[Black, Bold, 18]]
并且只保留取决于chartOptions
函数中数据的选项。
编辑 - 告诫我没有附近Mathematica的工作副本这样做 - 错别字可能仍然存在
如果你不想全局设置选项,正如@Leonid指出的那样,可能会导致其他不需要的效果,你可以定义一个自定义函数:
myBarChart[data_List,yName_,xName_,
opts:OptionsPattern[{myBarChart,BarChart,RectangleChart,Graphics}]]:=
BarChart[data,opts,FrameLabel -> {{yName, None}, {None, xName}},
FrameTicks -> {{{Round@Min@data, Round@(Max@data/2),
Round@Max@data}, None}, PlotRange -> {Automatic, 1.3*Max@data}}
]
然后定义该功能的选项:
Options[myBarChart] = {Frame -> True, ImageSize -> 300,
ChartStyle -> Black,
ChartElementFunction -> "FadingRectangle",
LabelStyle -> Directive[Black, Bold, 18]};
SetOptions[BarChart, Frame -> True, ImageSize -> 300,
ChartStyle -> Black,
ChartElementFunction -> "FadingRectangle",
LabelStyle -> Directive[Black, Bold, 18]]
我还应该指出,您可以通过将其设置为PlotRange
并根据需要设置PlotRangePadding选项来避免自定义All
选项。可能是PlotRangePadding->{{Automatic, Automatic},{Scaled[0.23],0}}
。 Scaled
将填充作为绘图尺寸的一部分。由于您希望空白为整个数据范围的0.3,这可能是0.3 / 1.3 = 0.23,但您可能想要进行实验。