I promised to give you some hints and I want to concentrate on some specific points in your implementation.
Calling style of your custom function.
When I looked at your function and how you call it I instantly thought that those are many parameters you have to remember. On every call of your function, you have to input 15 values where some of them maybe don't change.
My Question is here: Your function is basically a plot, why don't you keep the simple call style of it and ensure that it does something useful even if you don't supply all settings. The real work of your own implementation is the creation of the grid. So what you basically want is
- A function where you are able to set the grid-density and how many lines are highlighted.
- A function which takes certain inital values for
Options to e.g. ImageSize, BaseStyle,.. where (and here comes the point) you want to be able to easily change them without adjusting the code.
- A function which works like
Plot meaning you can set any Options you like.
Let me give you an outline for such a function
Options[PlotSpecial] = {
GridStep -> Automatic,
GridHighlight -> 5,
ImageSize -> 400, Epilog -> Text[0, {0, 0}, {1, 1}],
BaseStyle -> {FontSize -> 18, FontFamily -> "Times"},
AspectRatio -> Automatic,
GridLines -> Automatic};
SetAttributes[PlotSpecial, {HoldAll}];
PlotSpecial[f_, range : {x_, xmin_, xmax_}, opts : OptionsPattern[{PlotSpecial, Plot}]] :=
Module[{(*...*)},
(*...*)
Plot[f, {x, xmin, xmax}, GridLines -> grid,
Evaluate@FilterRules[Flatten@{opts, Options[PlotSpecial]}, Options[Plot]]]
]
As you can see I switched from a giving parameters every time to a set option when needed style. The Options of your PlotSpecial contain of (1) some new options and (2) some options which are concrete settings for Plot. In the function definition you can see how you tell that PlotSpecial that it takes options from both functions. Since the options are optional you have the same calling style as Plot itself and since you give the symbol x you circumvent the issue the issue of a global symbol inside a package.
Since it sometimes happens, that x has a value (set with for instance x=2) we have to prevent the evaluation when you call e.g. PlotSpecial[f,{x,0,10}]. If we wouldn't hold the evaluation back, x and f would, before anything happens, be evaluated into numbers and the plot would not work. Therefore, we prevent evaluation, by giving PlotSpecial the attribute HoldAll.
The last lines show in principle what we call. We use Plot, set our calculated GridLines and supply at the end all other options which Plot can handle. These options are (1) the ones which are fixed in the options-list of PlotSpecial and (2) the ones which may be set by the user in the function call.
Calcuation of GridLines
This is in my opinion a minor issue, because calculating something step by step can sometimes be better decrypted by a possible reader of your code. On the other hand you are doing almost the same thing twice for xgrid and ygrid which is a waste of useful time. Maybe you are a bit overwhelmed by all this, but I give my best to explain everything in detail.
Let's first find a function which takes a list in the form of the result of Range[min, max, scale] and returns a correct grid definition like you want, so for instance
{{1, GrayLevel[0.5]}, {2, GrayLevel[0.5]}, {3, GrayLevel[0.5]}, {4,
GrayLevel[0.5]}, {6, GrayLevel[0.5]}, {7, GrayLevel[0.5]}, {8,
GrayLevel[0.5]}, {9, GrayLevel[0.5]}, {0, GrayLevel[0]}, {5,
GrayLevel[0]}, {10, GrayLevel[0]}}
We first want to divide the list given by Range[min,max,scale] into numbers which are divisible by 5 and those which are not. There are many ways, but let's stick with Select which you chose. You don't need to call Select twice because the other list ist just the Complement of the other. Assume vals are the values of the grid then you all those which are divisible by some integer and then you calculate the complement to this:
{#, Complement[vals, #]} &@Select[vals, Mod[#, 5] === 0 &]
To bring now the colors in, let me create a function from the above line and add one little Transpose and call it with Range[0,10,1], so we see the output
Function[{vals},Transpose[{{#,Complement[vals,#]}&@
Select[vals,Mod[#,5]===0&],{Black,Gray}}]][Range[0,10,1]]
(* {{{0,5,10},GrayLevel[0]},{{1,2,3,4,6,7,8,9},GrayLevel[0.5]}} *)
Now we want the color in the last part of each sublist get anyhow in between the numbers. Funny enough, Riffle does exactly this
Riffle[{0,5,10},GrayLevel[0],{2,-1,2}]
(* {0,GrayLevel[0],5,GrayLevel[0],10,GrayLevel[0]} *)
So what we want to do is to Apply this special Riffle (with the last argument which states where to put the colors) to both sublists. This can be achieve with the @@@ operator which applies the function the the sublists. Combining this with what we have already gives
Function[{vals},Riffle[##,{2,-1,2}]&@@@Transpose[{{#,Complement[vals,#]}&@
Select[vals,Mod[#,5]===0&],{Black,Gray}}]][Range[0,10,1]]
(*
{{0,GrayLevel[0],5,GrayLevel[0],10,GrayLevel[0]},
{1,GrayLevel[0.5],2,GrayLevel[0.5],3,GrayLevel[0.5],4,GrayLevel[0.5],
6,GrayLevel[0.5],7,GrayLevel[0.5],8,GrayLevel[0.5],9,GrayLevel[0.5]}}
*)
This looks already quite close to the output we want and indeed the only thing which is left, is to Flatten this list completely and to collect every two elements again with Partition[...,2].
The funny thing is, that this function can be applied on any range specification, may it be the x-direction or the y-direction. Therefore the first 12 lines of your function can be reduced to something like
grid = Function[{vals},Partition[Flatten[Riffle[##,{2,-1,2}]&@@@
Transpose[{{#,Complement[vals,#]}&@Select[vals,Mod[#,5]===0&],
{Black,Gray}}]],2]] /@ vals
where vals at the end is {xvals, yvals} which are created with Range like you did.
Calculating ticks
As you can see I did not introduce a special ticks options. This is because we will just use the option Ticks for our purpose, meaning if it is set to Automatic we will draw ticks on all the black lines. Nevertheless, by giving an explicit setting of Ticks to the function call, you can always adjust this.
This part of the code is going to be very small
ticks = If[OptionValue[Ticks] === Automatic,
Select[#, crit] & /@ vals,
OptionValue[Ticks]
];
One thing is new: crit. Since we use the Mod[#,optGH]===0& function in the grid calculation and here, we just introduce a variable crit for it. Note, that you may not want to use 5 everytime for the positions of the black lines. Therefore, our function has the new GridHighlight option which is set to 5 per default but can take any value and black grid-lines and ticks can appear even at multiples of 2 or whatever.
The rest of the values
You might ask now: "Where is the rest of the information which I gave in my 15 parameters, because you only used 2 options?". Here's the deal. xmin, xmax, ymin, ymax is only the PlotRange. This can be set by just setting PlotRange or it can be extracted from a plot if you don't want to set it manually. So we do a trick here: We make a plot as first step in our function which is only used to extract an absolute value of the PlotRange.
origopts = AbsoluteOptions[Plot[f, range, Evaluate@FilterRules[{opts},
Options[Plot]]],PlotRange];
Next parameters are {xscale,scale} which are extracted from the GridStep option. xtickmin, ... are parameters I did not use. I just asume you want ticks everywhere where black lines are.
From the plot-range in origopts and the scale-parameters we can calculate vals by
{xscale, yscale} = OptionValue[GridStep];
vals = Range @@@ Append @@@ Transpose[{Round[PlotRange /. origopts], {xscale, yscale}}];
Final code and examples
Final changes I made are, that the grid is only calculated when the option GridLines is set to Automatic (which is the default).
Options[PlotSpecial] = {
GridStep -> {1, 1},
GridHighlight -> 5,
ImageSize -> 400, Epilog -> Text[0, {0, 0}, {1, 1}],
BaseStyle -> {FontSize -> 18, FontFamily -> "Times"},
AspectRatio -> Automatic,
GridLines -> Automatic};
SetAttributes[PlotSpecial, {HoldAll}];
PlotSpecial[f_, range:{x_, xmin_, xmax_}, opts:OptionsPattern[{PlotSpecial, Plot}]] :=
Module[{origopts, xscale, yscale, grid, optGH, vals, crit, ticks},
origopts = AbsoluteOptions[
Plot[f, range, Evaluate@FilterRules[{opts}, Options[Plot]]], PlotRange];
{xscale, yscale} = OptionValue[GridStep];
optGH = OptionValue[GridHighlight];
vals = Range @@@ Append @@@ Transpose[{Round[PlotRange /. origopts], {xscale, yscale}}];
crit = Mod[#, optGH] === 0 &;
ticks = If[OptionValue[Ticks] === Automatic,
Select[#, crit] & /@ vals,
OptionValue[Ticks]
];
grid = If[OptionValue[GridLines] === Automatic,
Function[{vals}, Partition[Flatten[Riffle[##, {2, -1, 2}] & @@@
Transpose[{{#, Complement[vals, #]} &@Select[vals,crit],
{Black, GrayLevel[0.9]}}]],2]] /@ vals,
OptionValue[GridLines]];
Plot[f, {x, xmin, xmax}, GridLines -> grid, Ticks -> ticks,
Evaluate@FilterRules[Flatten@{opts, Options[PlotSpecial]}, Options[Plot]]]
]
Now you can call your function without any additional options and get
f[x_] := 6 Sin[.1 x^2];
g[x_] := 3 Sin[.2 x] + 4 Cos[.3 x]
PlotSpecial[{f[x], g[x], f[x] - g[x], g[x] - f[x]}, {x, -10, 10}]

Or you want to change the grid
PlotSpecial[{f[x], g[x], f[x] - g[x], g[x] - f[x]}, {x, -6, 6}, GridHighlight -> 3]

Or you adjust several options. Note, that I set PlotRange manually and still the grid works, although it completely relies on it
PlotSpecial[{f[x], g[x], f[x] - g[x], g[x] - f[x]}, {x, -10, 10},
PlotRange -> {Automatic, {0, 10}}, GridHighlight -> 4,
GridStep -> {1/2, 1/2}, PlotStyle -> Thick]

Or you overwrite your BaseStyle. Even exact rationals are possible for the grid
PlotSpecial[{f[x], g[x], f[x] - g[x], g[x] - f[x]}, {x, -10,
10}, GridHighlight -> 7/3, GridStep -> {2/3, 2/3},
PlotStyle -> Directive[ColorData[6, 1]],
BaseStyle -> {FontSize -> 22, ColorData[6, 2],
FontFamily -> "Euler"}]

And here comes the last example: since grid and ticks are only calculated when their setting is Automatic, you can set both manually bypassing your whole approach.
PlotSpecial[{f[x], g[x], f[x] - g[x], g[x] - f[x]}, {x, -2 Pi,
2 Pi}, PlotStyle -> Directive[Thick, ColorData[6, 1]], Ticks -> None,
BaseStyle -> {FontSize -> 22, ColorData[6, 2], FontFamily -> "Euler"},
GridLines -> {{-2 Pi, -Pi, 0, Pi, 2 Pi}, Automatic}]

I hope this gives you some ideas. Please, don't think that this is the way to go. There are always many ways and you should find your own way.
Additionally, I tested the function inside a package and it seems to work fine. Don't forget to give the your custom options a usage message to export them too.
GridLinesoption? – J. M.♦ Oct 24 '12 at 13:14xin your call tospecialAis in theGlobalcontext, whereas thexin thePlotcommand is in the package context. You could try includingxas one of the arguments tospecialA– Simon Woods Oct 24 '12 at 14:26specialA. – m_goldberg Oct 24 '12 at 14:44