Mathematica: how to apply more than one rule at once - wolfram-mathematica

I have a list of points where each point is a list of its 3 coordinates: x,y and z.
But some of those points in their coordinates x and y are "bad" and I'd like to clean them. Is it possibile to write a single rule to do that? I've tried with:
cleanAdjustedPoints[adjustedPoints_List] := adjustedPoints /. {x_, y_, z_} /; x < 0 -> {0, y, z}; /; y > constB -> {x, constB, z};
and I've seen that only the first rule is applied to the points with bad x, while the ones with bad y do not change. Mathematica does not give a sintax error so I thought that it was right.
Any suggestions? thanks.

You just need to put the rules in a list. Also, note use of RuleDelayed (:>) which localises the variables x, y & z ensuring they don't pick up values from elsewhere in your program.
cleanAdjustedPoints[adjustedPoints_List] :=
adjustedPoints /. {{x_, y_, z_} /; x < 0 :> {0, y, z},
{x_, y_, z_} /; y > constB :> {x, constB, z}};
constB = 5;
cleanAdjustedPoints[{{-1, 2, 3}, {4, 5, 6}, {7, 8, 9}}]
{{0, 2, 3}, {4, 5, 6}, {7, 5, 9}}

Related

"Tag Part in (...) is Protected"

I am currently writing a module that's supposed to take some data points of 2-dimensional function (a 3 x N matrix) and draw contour plot of approximation based on those points (functions and variables for fitting are provided by user).
The "header" looks like this:
project4[dataPoints_, functionList_, fittingVarsList_, plotArgs___] :=
Module[{fitFunc, functionContourPlot, dataPointsXY, pointsPlot,
xList, yList},
Example of usage:
project4[data, {1, x, y, x y, x^2, y^2}, {x, y}]
(where data = {{x1,y1,f1}...})
After checking if the arguments are valid I do:
fitFunc = Fit[dataPoints, functionList, fittingVarsList];
To obtain the approximation.
Then I want to obtain plot of it by doing:
functionContourPlot = ContourPlot[fitFunc, {fittingVarsList[[1]], xMin, xMax},{fittingVarsList[[2]],yMin, yMax};
Which leads to an errors:
ContourPlot::write: Tag Part in {x,y}[[1]] is Protected. Show::gcomb:
"Could not combine the graphics objects in
Show[ContourPlot[fitFunc$2187,{{x,y}[[1]],xMin,xMax},{{x,y}[[2]],yMin,yMax}],"
What am I doing wrong?
The problem is ContourPlot having attribute HoldAll, which prevents Part evaluating.
Attributes#ContourPlot
You can fix it like this.
data = {{6, 4, 7.92}, {6, 5, 9.31}, {6, 6, 9.74},
{7, 4, 11.24}, {7, 5, 12.09}, {7, 6, 12.62},
{8, 4, 14.31}, {8, 5, 14.58}, {8, 6, 16.16}};
fittingVarsList = {x, y};
{xMin, xMax} = Through[{Min, Max}#data[[All, 1]]];
{yMin, yMax} = Through[{Min, Max}#data[[All, 2]]];
fitFunc = Fit[data, {1, x, y}, {x, y}]
This reproduces the problem :-
functionContourPlot = ContourPlot[fitFunc,
{fittingVarsList[[1]], xMin, xMax},
{fittingVarsList[[2]], yMin, yMax}];
The problem can be fixed by using With to create local variables :-
functionContourPlot =
With[{a = fittingVarsList[[1]], b = fittingVarsList[[2]]},
ContourPlot[fitFunc, {a, xMin, xMax}, {b, yMin, yMax}]]
If you remove HoldAll from the attributes of ContourPlot the first version works ...
Unprotect#ContourPlot;
ClearAttributes[ContourPlot, HoldAll]
... but that would be reckless programming.

Evaluating functions at several points

I want to evaluate f[x,y]=-4 x + x^2 - 4 y - y^2 at points (1,-2); (2,-3); (3,-2); (2,-1).
I tried using Outer but for some reason it does not give me actual values. Help.
Remember that Mathematica has a specific way of defining functions. In your case it would be f[x_,y_]:=-4 x + x^2 - 4 y - y^2. Then you could simply use f[1,-2] etc.
Perhaps consider using a 'pure' function. For example:
-4 #1 + #1^2 - 4*#2 - #2^2 & ### {{1, -2}, {2, -3}, {3, -2}, {2, -1}}
gives
{1, -1, 1, -1}
Here are some variations on the theme:
Clear[f]
f[{x_, y_}] := -4 x + x^2 - 4 y - y^2
points = {{1, -2}, {2, -3}, {3, -2}, {2, -1}};
Map[f, points]
{1, -1, 1, -1}
f[x_, y_] := -4 x + x^2 - 4 y - y^2
f[1, -2]
1
f = Function[{x, y}, -4 x + x^2 - 4 y - y^2];
f[1, -2]
1
You can use functions like Apply and Map to evaluate a function in a list of points, for example
f[x_, y_] := -4 x + x^2 - 4 y - y^2
pts = {{1, -2}, {2, -3}, {3, -2}, {2, -1}};
Apply[f, pts, {1}]
(* out: {1, -1, 1, -1} *)
or using ### as a short hand for Apply[ ...., {1}]
f ### pts

Working with implicit functions in Mathematica

Can I plot and deal with implicit functions in Mathematica?
for example :-
x^3 + y^3 = 6xy
Can I plot a function like this?
ContourPlot[x^3 + y^3 == 6*x*y, {x, -2.7, 5.7}, {y, -7.5, 5}]
Two comments:
Note the double equals sign and the multiplication symbols.
You can find this exact input via the WolframAlpha interface. This interface is more forgiving and accepts your input almost exactly - although, I did need to specify that I wanted some type of plot.
Yes, using ContourPlot.
And it's even possible to plot the text x^3 + y^3 = 6xy along its own curve, by replacing the Line primitive with several Text primitives:
ContourPlot[x^3 + y^3 == 6 x y, {x, -4, 4}, {y, -4, 4},
Background -> Black, PlotPoints -> 7, MaxRecursion -> 1, ImageSize -> 500] /.
{
Line[s_] :>
Map[
Text[Style["x^3+y^3 = 6xy", 16, Hue[RandomReal[]]], #, {0, 0}, {1, 1}] &,
s]
}
Or you can animate the equation along the curve, like so:
res = Table[ Normal[
ContourPlot[x^3 + y^3 == 6 x y, {x, -4, 4}, {y, -4, 4},
Background -> Black,
ImageSize -> 600]] /.
{Line[s_] :> {Line[s],
Text[Style["x^3+y^3 = 6xy", 16, Red], s[[k]], {0, 0},
s[[k + 1]] - s[[k]]]}},
{k, 1, 448, 3}];
ListAnimate[res]
I'm guessing this is what you need:
http://reference.wolfram.com/mathematica/Compatibility/tutorial/Graphics/ImplicitPlot.html
ContourPlot[x^3 + y^3 == 6 x*y, {x, -10, 10}, {y, -10, 10}]

Using PatternSequence with Cases in Mathematica to find peaks

Given pairs of coordinates
data = {{1, 0}, {2, 0}, {3, 1}, {4, 2}, {5, 1},
{6, 2}, {7, 3}, {8, 4}, {9, 3}, {10, 2}}
I'd like to extract peaks and valleys, thus:
{{4, 2}, {5, 1}, {8, 4}}
My current solution is this clumsiness:
Cases[
Partition[data, 3, 1],
{{ta_, a_}, {tb_, b_}, {tc_, c_}} /; Or[a < b > c, a > b < c] :> {tb, b}
]
which you can see starts out by tripling the size of the data set using Partition. I think it's possible to use Cases and PatternSequence to extract this information, but this attempt doesn't work:
Cases[
data,
({___, PatternSequence[{_, a_}, {t_, b_}, {_, c_}], ___}
/; Or[a < b > c, a > b < c]) :> {t, b}
]
That yields {}.
I don't think anything is wrong with the pattern because it works with ReplaceAll:
data /. ({___, PatternSequence[{_, a_}, {t_, b_}, {_, c_}], ___}
/; Or[a < b > c, a > b < c]) :> {t, b}
That gives the correct first peak, {4, 2}. What's going on here?
One of the reasons why your failed attempt doesn't work is that Cases by default looks for matches on level 1 of your expression. Since your looking for matches on level 0 you would need to do something like
Cases[
data,
{___, {_, a_}, {t_, b_}, {_, c_}, ___} /; Or[a < b > c, a > b < c] :> {t, b},
{0}
]
However, this only returns {4,2} as a solution so it's still not what you're looking for.
To find all matches without partitioning you could do something like
ReplaceList[data, ({___, {_, a_}, {t_, b_}, {_, c_}, ___} /;
Or[a < b > c, a > b < c]) :> {t, b}]
which returns
{{4, 2}, {5, 1}, {8, 4}}
Your "clumsy" solution is fairly fast, because it heavily restricts what gets looked at.
Here is an example.
m = 10^4;
n = 10^6;
ll = Transpose[{Range[n], RandomInteger[m, n]}];
In[266]:=
Timing[extrema =
Cases[Partition[ll, 3,
1], {{ta_, a_}, {tb_, b_}, {tc_, c_}} /;
Or[a < b > c, a > b < c] :> {tb, b}];][[1]]
Out[266]= 3.88
In[267]:= Length[extrema]
Out[267]= 666463
This seems to be faster than using replacement rules.
Faster still is to create a sign table of products of differences. Then pick entries not on the ends of the list that correspond to sign products of 1.
In[268]:= Timing[ordinates = ll[[All, 2]];
signs =
Table[Sign[(ordinates[[j + 1]] -
ordinates[[j]])*(ordinates[[j - 1]] - ordinates[[j]])], {j, 2,
Length[ll] - 1}];
extrema2 = Pick[ll[[2 ;; -2]], signs, 1];][[1]]
Out[268]= 0.23
In[269]:= extrema2 === extrema
Out[269]= True
Handling of consecutive equal ordinates is not considered in these methods. Doing that would take more work since one must consider neighborhoods larger than three consecutive elements. (My spell checker wants me to add a 'u' to the middle syllable of "neighborhoods". My spell checker must think we are in Canada.)
Daniel Lichtblau
Another alternative:
Part[#,Flatten[Position[Differences[Sign[Differences[#[[All, 2]]]]], 2|-2] + 1]] &#data
(* ==> {{4, 2}, {5, 1}, {8, 4}} *)
Extract[#, Position[Differences[Sign[Differences[#]]], {_, 2} | {_, -2}] + 1] &#data
(* ==> {{4, 2}, {5, 1}, {8, 4}} *)
This may be not exactly the implementation you ask, but along those lines:
ClearAll[localMaxPositions];
localMaxPositions[lst : {___?NumericQ}] :=
Part[#, All, 2] &#
ReplaceList[
MapIndexed[List, lst],
{___, {x_, _}, y : {t_, _} .., {z_, _}, ___} /; x < t && z < t :> y];
Example:
In[2]:= test = RandomInteger[{1,20},30]
Out[2]= {13,9,5,9,3,20,2,5,18,13,2,20,13,12,4,7,16,14,8,16,19,20,5,18,3,15,8,8,12,9}
In[3]:= localMaxPositions[test]
Out[3]= {{4},{6},{9},{12},{17},{22},{24},{26},{29}}
Once you have positions, you may extract the elements:
In[4]:= Extract[test,%]
Out[4]= {9,20,18,20,16,20,18,15,12}
Note that this will also work for plateau-s where you have more than one same maximal element in a row. To get minima, one needs to trivially change the code. I actually think that ReplaceList is a better choice than Cases here.
To use it with your data:
In[7]:= Extract[data,localMaxPositions[data[[All,2]]]]
Out[7]= {{4,2},{8,4}}
and the same for the minima. If you want to combine, the change in the above rule is also trivial.
Since one of your primary concerns about your "clumsy" method is the data expansion that takes place with Partition, you may care to know about the Developer` function PartitionMap, which does not partition all the data at once. I use Sequence[] to delete the elements that I don't want.
Developer`PartitionMap[
# /. {{{_, a_}, x : {_, b_}, {_, c_}} /; a < b > c || a > b < c :> x,
_ :> Sequence[]} &,
data, 3, 1
]

Plotting arrows at the edges of a curve

Inspired by this question at ask.sagemath, what is the best way of adding arrows to the end of curves produced by Plot, ContourPlot, etc...? These are the types of plots seen in high school, indicating the curve continues off the end of the page.
After some searching, I could not find a built-in way or up-to-date package to do this. (There is ArrowExtended, but it's quite old).
The solution given in the ask.sagemath question relies on the knowledge of the function and its endpoints and (maybe) the ability to take derivatives. Its translation into Mathematica is
f[x_] := Cos[12 x^2]; xmin = -1; xmax = 1; small = .01;
Plot[f[x],{x,xmin,xmax}, PlotLabel -> y==f[x], AxesLabel->{x,y},
Epilog->{Blue,
Arrow[{{xmin,f[xmin]},{xmin-small,f[xmin-small]}}],
Arrow[{{xmax,f[xmax]},{xmax+small,f[xmax+small]}}]
}]
An alternative method is to simply replace the Line[] objects generate by Plot[] with Arrow[]. For example
Plot[{x^2, Sin[10 x], UnitStep[x]}, {x, -1, 1},
PlotStyle -> {Red, Green, {Thick, Blue}},
(*AxesStyle -> Arrowheads[.03],*) PlotRange -> All] /.
Line[x__] :> Sequence[Arrowheads[{-.04, .04}], Arrow[x]]
But this has the problem that any discontinuities in the lines generate arrow heads where you don't want them (this can often be fixed by the option Exclusions -> None). More importantly, this approach is hopeless with CountourPlots. Eg try
ContourPlot[x^2 + y^3 == 1, {x, -2, 2}, {y, -2, 1}] /.
Line[x__] :> Sequence[Arrowheads[{-.04, .04}], Arrow[x]]
(the problems in the above case can be fixed by the rule, e.g., {a___, l1_Line, l2_Line, b___} :> {a, Line[Join[l2[[1]], l1[[1]]]], b} or by using appropriate single headed arrows.).
As you can see, neither of the above (quick hacks) are particularly robust or flexible. Does anyone know an approach that is?
The following seems to work, by sorting the segments first:
f[x_] := {E^-x^2, Sin[10 x], Sign[x], Tan[x], UnitBox[x],
IntegerPart[x], Gamma[x],
Piecewise[{{x^2, x < 0}, {x, x > 0}}], {x, x^2}};
arrowPlot[f_] :=
Plot[{#}, {x, -2, 2}, Axes -> False, Frame -> True, PlotRangePadding -> .2] /.
{Hue[qq__], a___, x___Line} :> {Hue[qq], a, SortBy[{x}, #[[1, 1, 1]] &]} /.
{a___,{Line[x___], d___, Line[z__]}} :>
List[Arrowheads[{-.06, 0}], a, Arrow[x], {d},
Arrowheads[{0, .06}], Arrow[z]] /.
{a___,{Line[x__]}}:> List[Arrowheads[{-.06, 0.06}], a, Arrow[x]] & /# f[x];
arrowPlot[f]
Inspired by both Alexey's comment and belisarius's answers, here's my attempt.
makeArrowPlot[g_Graphics, ah_: 0.06, dx_: 1*^-6, dy_: 1*^-6] :=
Module[{pr = PlotRange /. Options[g, PlotRange], gg, lhs, rhs},
gg = g /. GraphicsComplex -> (Normal[GraphicsComplex[##]] &);
lhs := Or##Flatten[{Thread[Abs[#[[1, 1, 1]] - pr[[1]]] < dx],
Thread[Abs[#[[1, 1, 2]] - pr[[2]]] < dy]}]&;
rhs := Or##Flatten[{Thread[Abs[#[[1, -1, 1]] - pr[[1]]] < dx],
Thread[Abs[#[[1, -1, 2]] - pr[[2]]] < dy]}]&;
gg = gg /. x_Line?(lhs[#]&&rhs[#]&) :> {Arrowheads[{-ah, ah}], Arrow##x};
gg = gg /. x_Line?lhs :> {Arrowheads[{-ah, 0}], Arrow##x};
gg = gg /. x_Line?rhs :> {Arrowheads[{0, ah}], Arrow##x};
gg
]
We can test this on some functions
Plot[{x^2, IntegerPart[x], Tan[x]}, {x, -3, 3}, PlotStyle -> Thick]//makeArrowPlot
And on some contour plots
ContourPlot[{x^2 + y^2 == 1, x^2 + y^2 == 6, x^3 + y^3 == {1, -1}},
{x, -2, 2}, {y, -2, 2}] // makeArrowPlot
One place where this fails is where you have horizontal or vertical lines on the edge of the plot;
Plot[IntegerPart[x],{x,-2.5,2.5}]//makeArrowPlot[#,.03]&
This can be fixed by options such as PlotRange->{-2.1,2.1} or Exclusions->None.
Finally, it would be nice to add an option so that each "curve" can arrow heads only on their boundaries. This would give plots like those in Belisarius's answer (it would also avoid the problem mentioned above). But this is a matter of taste.
The following construct has the advantage of not messing with the internal structure of the Graphics structure, and is more general than the one suggested in ask.sagemath, as it manage PlotRange and infinities better.
f[x_] = Gamma[x]
{plot, evals} =
Reap[Plot[f[x], {x, -2, 2}, Axes -> False, Frame -> True,
PlotRangePadding -> .2, EvaluationMonitor :> Sow[{x, f[x]}]]];
{{minX, maxX}, {minY, maxY}} = Options[plot, PlotRange] /. {_ -> y_} -> y;
ev = Select[evals[[1]], minX <= #[[1]] <= maxX && minY <= #[[2]] <= maxY &];
seq = SortBy[ev, #[[1]] &];
arr = {Arrow[{seq[[2]], seq[[1]]}], Arrow[{seq[[-2]], seq[[-1]]}]};
Show[plot, Graphics[{Red, arr}]]
Edit
As a function:
arrowPlot[f_, interval_] := Module[{plot, evals, within, seq, arr},
within[p_, r_] :=
r[[1, 1]] <= p[[1]] <= r[[1, 2]] &&
r[[2, 1]] <= p[[2]] <= r[[2, 2]];
{plot, evals} = Reap[
Plot[f[x], Evaluate#{x, interval /. List -> Sequence},
Axes -> False,
Frame -> True,
PlotRangePadding -> .2,
EvaluationMonitor :> Sow[{x, f[x]}]]];
seq = SortBy[Select[evals[[1]],
within[#,
Options[plot, PlotRange] /. {_ -> y_} -> y] &], #[[1]] &];
arr = {Arrow[{seq[[2]], seq[[1]]}], Arrow[{seq[[-2]], seq[[-1]]}]};
Show[plot, Graphics[{Red, arr}]]
];
arrowPlot[Gamma, {-3, 4}]
Still thinking what is better for ListPlot & al.

Resources