4
$\begingroup$

I am looking for a way to plot the difference of two tables, where some elements may be missing in the first or in the second table.

A simple example, given two tables:

A = {{0., 9.84}, {0.5, 9.34}, {1.5, 8.34}, {2., 7.84}, {2.5, 7.34}, {3., 6.84}, {3.5, 6.34}, {4., 5.84}, {4.5, 5.34}, {5., 4.84}}; 
B = {{0., 10.01}, {0.5, 10.51}, {1., 11.01}, {1.5, 11.51}, {2., 12.01}, {2.5, 12.51}, {3., 13.01},  {4., 14.01}, {4.5, 14.51}, {5., 15.01}};

In the table A the element with the x-value (first elements in the tables) 1 is missing, and in the table B there is no element with x-value 3.5. I need to plot the difference of y-values (second elements in the table) vs x-values. Basically, I need to generate a difference table like this:

{{0., -0.17}, {0.5, -1.17}, {1.5, -3.17}, {2., -4.17}, {2.5, -5.17}, {3., -6.17}, {4., -8.17}, {4.5, -9.17}, {5, -10.17}}
$\endgroup$

4 Answers 4

3
$\begingroup$

Here is one way:

Cases[GatherBy[Flatten[{A, B}, 1], First], {a_, b_} :> {First@a, a[[2]] - b[[2]]}]
Cases[GatherBy[Flatten[{A, B}, 1], First], {{a1_, b1_}, {a1_, b2_}} :> {a1, b1 - b2}]

Alternatively, first find the x-coordinates they share, use this list to prune A and B, and then do the subtraction:

xs = Intersection[A[[All, 1]], B[[All, 1]]]
prunedLists = Cases[#, {Alternatives @@ xs, _}] & /@ {A, B}
{#1[[1]], #1[[2]] - #2[[2]]} & @@@Transpose@prunedLists
(* {0., 0.5, 1.5, 2., 2.5, 3., 4., 4.5, 5.}
(* {{{0., 9.84}, {0.5, 9.34}, {1.5, 8.34}, {2., 7.84}, {2.5, 7.34}, {3., 6.84}, {4., 5.84}, {4.5, 5.34}, {5., 4.84}},
    {{0., 10.01}, {0.5, 10.51}, {1.5, 11.51}, {2., 12.01}, {2.5, 12.51}, {3., 13.01}, {4., 14.01}, {4.5, 14.51}, {5., 15.01}}} *)
(* {{0., -0.17}, {0.5, -1.17}, {1.5, -3.17}, {2., -4.17}, {2.5, -5.17}, {3., -6.17}, {4., -8.17}, {4.5, -9.17}, {5., -10.17}} *)
$\endgroup$
3
$\begingroup$

Not my best, but here's another one-liner:

List @@@ Normal@GroupBy[Join[A, B], First -> Last, 
  If[Length[#] > 1, Subtract @@ #, Nothing] &] /. {_} :> Nothing

{{0., -0.17}, {0.5, -1.17}, {1.5, -3.17}, {2., -4.17}, {2.5, -5.17}, {3., -6.17}, {4., -8.17}, {4.5, -9.17}, {5., -10.17}}

$\endgroup$
3
$\begingroup$
xlist = Intersection[A[[;; , 1]], B[[;; , 1]]];
Transpose[{xlist, (xlist /. 
     Thread[A[[;; , 1]] -> A[[;; , 2]]]) - (xlist /. 
     Thread[B[[;; , 1]] -> B[[;; , 2]]])}]

or equivalently,

Transpose[{xlist, (xlist /. Thread[Rule @@ Transpose@A]) - (xlist /. 
     Thread[Rule @@ Transpose@B])}]
$\endgroup$
2
$\begingroup$

I would just interpolate both lists, and then find the difference for each shared x value. The only difference with respect to matheorem's solution is that you can use any x values common to the range of the lists if you need to.

a = {{0., 9.84}, {0.5, 9.34}, {1.5, 8.34}, {2., 7.84}, {2.5, 
    7.34}, {3., 6.84}, {3.5, 6.34}, {4., 5.84}, {4.5, 5.34}, {5., 
    4.84}};
b = {{0., 10.01}, {0.5, 10.51}, {1., 11.01}, {1.5, 11.51}, {2., 
    12.01}, {2.5, 12.51}, {3., 13.01}, {4., 14.01}, {4.5, 14.51}, {5.,
     15.01}};

{aint,bint} = Interpolation/@{a,b};
commonX = Intersection @@ {a[[All, 1]], b[[All, 1]]};
deltaAB = {#, aint[#] - bint[#]} & /@ commonX

Which gives:

{{0., -0.17}, {0.5, -1.17}, {1.5, -3.17}, {2., -4.17}, {2.5, -5.17}, {3., -6.17}, {4., -8.17}, {4.5, -9.17}, {5., -10.17}}
$\endgroup$
1
  • $\begingroup$ Thanks! I also thought about first interpolating the data. But I don't like this method, it may not work properly for the given data, and I really want to substract the elements in the data. $\endgroup$
    – Mikayel
    Commented Aug 26, 2016 at 6:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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