1
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ 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? $\endgroup$ – Jason B. May 3 '16 at 7:45
  • $\begingroup$ 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.. ? $\endgroup$ – Pierre L. May 3 '16 at 23:43
1
$\begingroup$

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

$\endgroup$
  • $\begingroup$ This works great ! Thank you $\endgroup$ – Pierre L. May 4 '16 at 15:58

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.