创建函数以在Mathematica中灵活定义图表选项列表

时间:2011-08-25 14:57:10

标签: function wolfram-mathematica plot

我正在尝试创建一些函数,以避免我为不同类型的绘图重复绘图选项。当我尝试创建机制来自动处理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}}
          ]]

enter image description here

现在我试图简化我的生活:

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"]]]

但这不起作用:

enter image description here

我们的想法是,图表选项功能将根据使用它的实际绘图的图表数据进行调整。

我现在只想使用我真正理解的东西,所以我希望这个问题不需要你的大部分技巧:-)!

3 个答案:

答案 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,但您可能想要进行实验。