Why doesn't the Inset item show in Prolog in a plot?
I apologise for the length of this question. My current Mathematica programming project involves replicating the very specific business rules my employing institution has for publication-quality plots of time series. One of these rules is that multipanel graphs have panel titles and subtitles centered near the top of the plot area. This worked fine using Prolog
and Inset
until I redid that bit of the function to allow explicit Prolog
elements to be included as well. Then only the item passed in the Prolog
option shows, not the panel titles and subtitles. If there is no explicit Prolog
option, the panel titles and subtitles show up fine.
To explicate a bit further, imagine the function body is all in a big Module
, including the local variable pl=OptionValue[Prolog]
and mp=OptionValue[MultiPanel]
.
A bit further down is this definition (ppl
, title
and subtitle
were also defined as local variables, and Rfont
and framecol
are constants defined elsewhere in the package, namely to be "Arial"
and "Black"
):
ppl=If[mp===False,pl,If[Length[pl]>0,Join[{
If[ToString[subtitle] == "None", Inset[
DisplayForm[GridBox[{{Style[title, 20, FontFamily -> Rfont, framecol]}}]],
Scaled[{0.5,0.96}],{Center,Top} ],
Inset[DisplayForm[
GridBox[{{Style[title, 20, FontFamily -> Rfont, framecol]},
{Style[subtitle, 16, FontFamily -> Rfont, framecol]}},
RowSpacings -> 0]],Scaled[{0.5,0.98}],{Center,Top}] ]},pl],
{If[ToString[subtitle] == "No开发者_开发百科ne",
Inset[ DisplayForm[
GridBox[{{Style[title, 20, FontFamily -> Rfont, framecol]}}]],
Scaled[{0.5,0.96}],{Center,Top} ],
Inset[DisplayForm[
GridBox[{{Style[title, 20, FontFamily -> Rfont, framecol]},
{Style[subtitle, 16, FontFamily -> Rfont, framecol]}},
RowSpacings -> 0]],Scaled[{0.5,0.98}],{Center,Top}]] }] ]
All fine as far as it goes. The Inset
is used if the option MultiPanel
(and thus mp
) is not False
and there is no Prolog
explicitly set. But if a prolog is set, e.g., Prolog -> {Text["test", Scaled[{0.6
, 0.5}]]}
, then the Inset
doesn't show, only the Text
element.
It isn't a problem with the way I am joining them together. Capturing and printing the value of ppl
gives:
{Inset[{{Style["This is a test", LineColor -> GrayLevel[0],
FrontFaceColor -> GrayLevel[0], BackFaceColor -> GrayLevel[0],
GraphicsColor -> GrayLevel[0], FontFamily -> "Arial", FontSize -> 20,
FontColor -> GrayLevel[0]]},
{Style["Year-ended percentage change", LineColor -> GrayLevel[0],
FrontFaceColor -> GrayLevel[0], BackFaceColor -> GrayLevel[0],
GraphicsColor -> GrayLevel[0], FontFamily -> "Arial", FontSize -> 16,
FontColor -> GrayLevel[0]]}},
Scaled[{0.5, 0.98}], {Center, Top}], Text["test", Scaled[{0.6, 0.5}]]}
(And yes, those are a bunch of undocumented options which I shall ask about in another question.)
Does anyone know if there is anything preventing Prolog
(or Epilog
for that matter) combining Inset
elements and other things in the one set of graphics options?
As you have not given a working fragment of code, I'm not sure what's going wrong in it.
How does my simple example not replicate what you're trying?
plot = Plot[x^2, {x, -5, 5}, Prolog -> Inset[Style[Text[":) = \[HappySmiley]"], Large]]]
pl = Flatten@{Prolog /. AbsoluteOptions[plot, Prolog]}
join = Show[{Plot[x^2 + 1, {x, -5, 5}, PlotStyle -> Red],
Plot[x^2, {x, -5, 5}, PlotStyle -> Blue]},
Prolog -> Join[{Inset[Graphics@Circle[]]}, If[Length[pl] > 0, pl, {}]]]
I feel a bit stupid now. I worked out the issue. Let me see if I can explain clearly enough.
Suppose you have a custom function (say, XYZPlot
) that is built on a built-in one (say, DateListPlot
). Suppose you want to pass some options to DateListPlot
, as well as handling some options that are specific to XYZPlot
. Then you probably want to pass any options the user includes explicitly before you pass the default options that apply to your custom function. This is a toy example: normally you'd set default PlotRange
as an option to your custom function with SetOptions
etc.
defaultplotrange = {1,5};
XYZPlot[args___,opts:OptionsPattern[{XYZPlot,DateListPlot}]]:=
DateListPlot[args,Sequence @@ FilterRules[{opts}, Options[DateListPlot]],
PlotRange->defaultplotrange]
So far so good. But if you want to catch the value of an option and modify it even if the user provides an explicit value for it when they call the function, for example to add [ahem] panel titles if some other option is set to True
, then you can't put that option after the FilterRules
bit. It has to come before. Otherwise the value of Prolog
that the user gave will be used, not the one with the bit added. So the right way is to do something like this.
defaultplotrange = {1,5};
XYZPlot[args___,opts:OptionsPattern[{XYZPlot,DateListPlot}]]:=
With[{pl=OptionValue[Prolog],mp=OptionValue[MultiPanel]},
DateListPlot[args,
Prolog -> If[mp===False,pl,Join[pl,{Inset[(* something else *)]}]],
Sequence @@ FilterRules[{opts}, Options[DateListPlot]],
PlotRange->defaultplotrange]]
Sorry to bother you all.
精彩评论