1

I would like to customize the function DensityPlot and use it in a package as a function called MyDensityPlot:

The functions looks like that in a package MyPackage.m :

BeginPackage["MyPackage`"];
MyDensityPlot::usage=""
Begin["Private`"]
    Options[MyDensityPlot]:=Options[DensityPlot];
        MyDensityPlot[fn_,range_,options:OptionsPattern[]] := 
          Module[{ii, p1, externalSymbol, localx,localy}, 
           externalSymbol = With[{currentContextQ=Context@#===$Context&},DeleteDuplicates@Cases[{fn},_Symbol?currentContextQ,Infinity]];
           ii = Unevaluated[fn] /. externalSymbol[[1]] :> localx/.externalSymbol[[2]]:>localy;
           p1 = DensityPlot[ii, {localx,localy} \[Element] Disk[{0,0},range],options]
        ]//Quiet;
End[];

I used the answer of the following question: Pass function or formula as function parameter in order to pass the function fn as an argument.

Then, from this answer: Extracting variables from an expression, I extract, in the package context, the variable names of the function fn and replace them by local variables localx localy for the plot.

It's working but I think it's not a good code, in particular if the function fn as just one variable, externalSymbol[[2]] wouldn't exist :

MyDensityPlot[x, 1]
Part::partw: Part 2 of {x} does not exist. >>

But the graphic will be displayed anyway. I'm then using a //Quiet; at the end of the function... but it's really circumvent the problem. So if you have any suggestions to improve this function definition.

Thank you for your help.

sekisushai
  • 335
  • 1
  • 9
  • What is the desired outcome when the function given has a number of variables not equal to 2? I feel like the results from all of these {MyDensityPlot[Sin[a^2 - b], 5, PlotPoints -> 50], MyDensityPlot[Sin[f], 5], MyDensityPlot[3, 5], MyDensityPlot[a + b + c, 5]} make sense. Would you rather the function not make a plot at all if the list of variables is not equal to 2? – Jason B. May 03 '16 at 07:45
  • If the function is one variable or two, the function makes sens, but if it's three or more variable like your example MyDensityPlot[a+b+c,5], the plot fails, as in DensityPlot built-in function. So yep, the behaviour should be as in DensityPlot. However DensityPlot doesn't generate an error when there is only one variable, and MyDensityPlot does, thus my question about more efficient code maybe.. ? – sekisushai May 03 '16 at 23:43

1 Answers1

1

This seems to meet your requirements,

MyDensityPlot::argerr = "Number of undefined variables > 3";
Options[MyDensityPlot] := Options[DensityPlot];
MyDensityPlot[fn_, range_, options : OptionsPattern[]] := 
  Module[{p1, externalSymbol, localx, localy, reg},
   externalSymbol = 
    With[{currentContextQ = Context@# === $Context &},
     DeleteDuplicates@
      Cases[{fn}, _Symbol?currentContextQ, Infinity]];
   If[Length@externalSymbol > 2,
    Message[MyDensityPlot::argerr];
    $Failed,
    reg = 
     PadRight[externalSymbol, 2, {localx, localy}] \[Element] 
      Disk[{0, 0}, range];
    p1 = DensityPlot[fn, Evaluate@reg, options]
    ]
   ];

Here are examples using 0, 1, 2, and 3 variables, the last of which generates a user-defined error message,

{MyDensityPlot[Sin[a^2 - b], 5, PlotPoints -> 50, FrameStyle -> Red],
 MyDensityPlot[Sin[f], 5],
 MyDensityPlot[3, 5],
 MyDensityPlot[a + b + c, 5]}

MyDensityPlot::argerr: Number of undefined variables > 3

Mathematica graphics

Jason B.
  • 68,381
  • 3
  • 139
  • 286