2
$\begingroup$

I'm trying to rewrite a ListDensityPlot expression to systematiccaly add an option:

SetAttributes[myShow, HoldAll]
myShow[plots__] := With[{
   mplots = Hold[{plots}] /. {
      ListDensityPlot[args__] :> 
       ListDensityPlot[args, ColorFunction -> "Rainbow"]
      }
   }, Show[
   Sequence[ReleaseHold[mplots]]
   ]
  ]

myShow[
 ListDensityPlot[({#1, #2, #1*#2}) & @@@ Tuples[Range[-2, 2], 2]]
 ]

It looks like it works since the plot is using the ColorFunction specified in my replacement rule. However, alongside the graphic, I also have the error message:

ListDensityPlot::arrayerr -- args__ must be a valid array.

enter image description here

Could you explain what is causing this error message and how to fix that?

$\endgroup$
4
  • 2
    $\begingroup$ Replace ListDensityPlot[args__] :> ... with HoldPattern[ListDensityPlot[args__]] :> ...? (ListDensityPlot does not have the Hold attribute. So we need to prevent ListDensityPlot[args__] from being evaluated. $\endgroup$
    – kglr
    Dec 21 '19 at 2:55
  • $\begingroup$ Thanks, @kglr. I spend more than one-hour trying different things before asking the question. And I found HoldPattern just after having posted here! I took the liberty to self answer my question below. I tried to explain what was happening to the best of my Mathematica skills. Don't hesitate to correct me if necessary. $\endgroup$ Dec 21 '19 at 3:02
  • $\begingroup$ Interesting @kglr. I will try that immediately. Do you know if there is any rationale explaining why different plot functions have different Hold* attributes? $\endgroup$ Dec 21 '19 at 13:46
  • 1
    $\begingroup$ Sylvain, I misspoke re the real reason for the need to wrap the rhs with HoldPattern (as you explain in your answer it is the fact that RuleDelayed does not have the HoldAll attribute). $\endgroup$
    – kglr
    Dec 21 '19 at 22:56
4
$\begingroup$

HoldPattern is the solution.

For some reason, I thought both sides of a delayed expression remained unevaluated. However:

Attributes[RuleDelayed]
{HoldRest,Protected,SequenceHold}

As you can see, RuleDelayed has the attribute HoldRest and not HoldAll. So, I was wrong: the left-hand side of a delayed rule is evaluated.

So, in my case, Mathematica tried to evaluate ListDensityPlot[args__] -- which produced an error and returned the expression unevaluated. Then, this unevaluated expression was used as the left-hand side for the replacement rule. Making it work "as expected".

To prevent evaluation of the left-hand side, we must use HoldPattern:

 mplots = Hold[{plots}] /. {
      HoldPattern[ListDensityPlot[args__]] :> 
       ListDensityPlot[args, ColorFunction -> "Rainbow"]
      }
   }
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.