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

Function 创建函数以灵活定义Mathematica中的图表选项列表,function,wolfram-mathematica,plot,Function,Wolfram Mathematica,Plot,我正在尝试创建一些函数,以避免对不同类型的绘图重复绘图选项。当我尝试创建自动处理帧标记和绘图范围的机制时,遇到了一些问题,因为给定的绘图中考虑了数据 Module[{chartData}, chartData = RandomInteger[20, 20]; BarChart[chartData, Frame -> {{True, True}, {True, True}}, ImageSize -> 3

我正在尝试创建一些函数,以避免对不同类型的绘图重复绘图选项。当我尝试创建自动处理帧标记和绘图范围的机制时,遇到了一些问题,因为给定的绘图中考虑了数据

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"]]]
但这不起作用:

这样做的目的是,根据使用的实际绘图的图表数据,调整chartOptions功能


我现在只尝试使用我真正理解的东西,所以我希望这样的问题不需要你太多的复杂技能:-)

问题在于,在
chartOptions
中,变量
chartData
是引用全局定义的自由变量。在
BarChart
表达式中,
chartData
变量被定位到包含的模块,因此
chartOptions
不可见。更改
chartOptions
以接受
chartData
作为参数:

chartOptions[chartData_, yName_, xName] := ...
然后相应地调整
条形图
表达式:

Module[{chartData},chartData=RandomInteger[20,20];
  BarChart[chartData,chartOptions[chartData, "yName","xName"]]]

创建这样的函数是处理依赖于要打印的数据的选项的正确方法。但其中一些选项可以使用
SetOptions
在Mathematica会话中为所有使用
BarChart
设置。对于您的示例,您可以选择定义:

 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]]
然后定义该函数的选项:

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
选项设置为
All
并根据需要设置该选项来避免该选项。可能
PlotRangePadding->{{Automatic,Automatic},{Scaled[0.23],0}}
<代码>缩放将填充作为绘图尺寸的一部分。由于您希望空白为整个数据范围的0.3,这可能是0.3/1.3=0.23,但您可能希望进行实验。

这不是对问题的直接回答(该问题已由@rorach回答),但我认为@500触及了一个重要主题。我们可能经常想要创建一个配置,其中包含若干选项的特定自定义选项设置。在我看来,在全球范围内更改期权通常是个不错的主意(这并不是要减损@Verbeia的答案。当然,在某些情况下,全球期权重置是适当的。我的建议应该被视为补充)。在这里,我将重现一个非常轻量级的选项配置管理器的实现,以创建持久的选项配置,这是我在回答a时写的,以及相关的讨论


用法 让我从用法开始——option configuration manager的实现可以在我文章的底部找到。我们将从一个带有选项的测试函数开始:

In[54]:= 
ClearAll[bar];
Options[bar] = {barA -> 1, barB -> 2};
bar[x__, OptionsPattern[]] :=
  Module[{},
    {"barA:  " -> OptionValue[barA], "barB:  " -> OptionValue[barB]}];
首先,我们只调用它,没有任何显式传递的选项。它显示当前使用的选项的值—在本例中,是通过选项全局设置的选项(
OptionValue
处理这些选项):

现在,我们从manager API调用其中一个函数(请参见下面的实现):

这定义了名为“first”下功能条的选项配置。为了使用此选项配置,我们使用另一个函数:
with optionConfiguration
,如下所示:

In[58]:= withOptionConfiguration[bar[1, 2], "first"]
Out[58]= {"barA:  " -> 11, "barB:  " -> 22}
这看起来好像我们确实在全球范围内更改了
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}
通过这种方式,您可以创建任意数量的选项配置,阅读此代码的任何人都很清楚,这是怎么回事


实施
评论
有几次,我发现这种结构很有用。它们的主要优点是,虽然选项配置是持久的,但它们通过在本地传递选项来工作,因此选项不会全局重置。全局选项重置是一项危险的业务,尤其是对于常见(如内置)功能,以及当您向其他人交付功能时。此外,上述实现非常轻量级,可以轻松地进行扩展或修改以满足用户的需要。

Define:不起作用。运行此选项时会给您什么?我可以建议使用
PlotRangePadding->0
选项以确保栏一直到框架?啊!这就是问题所在!非常感谢。由于各种作用域构造经常让我感到困惑,将
模块
更改为
帮助会吗?@rcollyer它应该会有帮助,是的。@rcollyer使用
确实有效,因为它会临时更改符号的全局定义。然而,我通常会建议人们尽可能地坚持使用参数和局部变量,以避免微妙的范围界定问题——比如这个问题所确定的问题。在
图表选项
的情况下,读者并不清楚函数是否依赖于全局定义。这种缺乏透明度的做法经常会(而且确实)导致麻烦。我同意消除对全球风险值的依赖
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]];
];