# Visualization of two nearly identical datasets of 2D points

This question is similar to

Best way to plot nearly identically overlapping data?

In my case I have two clouds of 2D points that are nearly identical. If I draw them into the same coordinate system, the second one nearly overlaps the first one. Formally this should suffice, but the image is boring. I am looking for visually appealing ways of representing the similarity and stress out the (really small) discrepancies. Should I use something like log scaling?

Added: here are specific lists of points:

a:={{7.13, 10.093}, {4.141, 8.783}, {2.397, 8.783}, {2.282,
8.782}, {2.02, 8.783}, {1.463, 8.288}, {4.267, 8.306}, {4.263,
8.299}, {4.124, 8.346}, {4.12, 8.334}, {3.107, 8.339}, {3.137,
8.331}, {2.966, 8.335}, {2.971, 8.326}, {2.678, 8.418}, {2.681,
8.409}, {2.749, 8.413}, {2.742, 8.422}, {4.67, 8.414}, {4.668,
8.426}, {4.126, 8.217}, {4.125, 8.228}, {4.364, 8.13}, {4.358,
8.145}, {4.333, 8.102}, {4.04, 8.125}, {2.108, 8.126}, {2.109,
8.119}, {1.393, 8.049}, {1.512, 8.077}, {4.249, 8.041}, {4.248,
8.028}, {4.252, 8.05}, {3.522, 7.971}, {3.522, 7.981}, {3.523,
7.962}, {3.421, 8.002}, {3.33, 7.972}, {3.328, 7.963}, {3.329,
7.981}, {3.244, 7.94}, {3.171, 7.94}, {1.516, 7.94}, {1.35,
7.935}, {1.077, 7.919}, {1.075, 7.902}, {4.111, 7.905}, {4.195,
7.917}, {4.198, 7.903}, {4.301, 7.907}, {4.46, 7.929}, {4.463,
7.92}, {7.049, 7.818}, {4.191, 7.784}, {1.904, 7.656}, {1.901,
7.644}, {2.098, 7.657}, {2.097, 7.643}, {2.243, 7.656}, {2.243,
7.644}, {4.185, 7.655}, {4.187, 7.645}, {6.778, 7.661}, {3.087,
7.047}, {4.238, 4.33}, {4.11, 4.301}, {1.168, 4.332}, {1.078,
4.302}, {0.78, 4.194}, {1.168, 4.236}, {1.461, 4.213}, {1.642,
4.19}, {1.599, 4.191}, {1.9, 4.18}, {1.898, 4.19}, {2.028,
4.249}, {2.008, 4.257}, {2.092, 4.241}, {2.283, 4.246}, {3.106,
4.186}, {3.09, 4.108}, {3.086, 4.097}, {3.088, 4.086}, {2.244,
4.182}, {2.281, 4.146}, {2.281, 4.133}, {2.399, 4.145}, {2.39,
4.135}, {2.383, 4.126}, {2.363, 4.11}, {2.358, 4.121}, {2.095,
4.182}, {2.023, 4.146}, {2.022, 4.134}, {2.104, 4.12}, {2.109,
4.04}, {1.395, 4.068}, {1.512, 3.995}, {1.512, 3.981}, {0.885,
4.04}, {1.078, 4.109}, {1.145, 4.021}, {1.145, 4.012}, {1.145,
4.}, {1.145, 3.99}, {1.078, 4.117}, {1.077, 4.1}, {2.163,
3.789}, {0.953, 3.789}, {0.954, 3.779}, {0.873, 3.789}, {0.873,
3.78}, {3.327, 3.526}, {3.316, 3.516}, {1.519, 3.24}, {1.52,
3.23}, {1.519, 3.173}, {1.52, 3.162}, {1.769, 2.941}, {1.669,
2.95}, {1.672, 2.94}, {1.45, 2.952}, {1.445, 2.943}, {1.317,
2.946}, {1.311, 2.935}, {2.347, 2.475}, {2.353, 2.485}, {2.346,
2.498}, {2.279, 2.419}, {2.278, 2.388}, {2.01, 2.417}, {2.014,
2.39}, {2.013, 2.401}, {2.103, 2.365}, {2.101, 2.347}, {2.098,
2.337}, {2.095, 2.321}, {2.093, 2.308}, {2.031, 2.287}, {2.026,
2.276}, {2.1, 2.244}, {2.1, 2.233}, {1.903, 2.244}, {1.903,
2.232}, {1.903, 2.256}, {1.902, 2.094}, {1.451, 2.102}, {1.45,
2.09}, {1.45, 2.113}, {1.468, 2.163}, {1.128, 2.164}, {1.125,
2.152}, {1.11, 2.114}, {1.111, 2.102}, {1.11, 2.09}, {0.885,
2.113}, {0.885, 2.102}, {0.885, 2.123}, {0.886, 2.093}, {0.873,
2.161}, {0.955, 2.169}, {0.954, 2.162}, {0.952, 2.15}, {0.87,
1.988}, {0.872, 1.977}, {1.521, 1.905}, {1.518, 1.897}, {1.518,
1.865}, {1.519, 1.881}, {0.856, 1.826}, {0.863, 1.816}, {0.853,
1.803}, {1.611, 1.818}, {1.611, 1.81}, {1.608, 1.802}, {0.693,
1.704}, {0.782, 1.632}, {0.782, 1.612}, {0.781, 1.584}, {0.781,
1.622}, {1.114, 1.45}, {0.782, 1.486}, {0.775, 1.498}, {0.679,
1.439}, {0.681, 1.451}, {0.683, 1.42}, {1.351, 1.514}, {0.861,
1.284}, {0.865, 1.291}, {0.866, 1.275}, {0.874, 0.949}, {2.398,
8.79}, {2.279, 8.79}, {2.01, 4.239}, {2.244, 4.188}, {2.243,
4.17}, {2.242, 4.2}, {2.101, 2.256}, {2.031, 2.26}, {2.029,
2.25}, {1.9, 2.101}, {1.468, 2.152}, {4.141, 8.789}, {2.021,
8.789}, {1.511, 8.086}}

b:={{7.127, 10.092}, {4.137, 8.785}, {2.402, 8.785}, {2.281,
8.785}, {2.018, 8.783}, {1.458, 8.288}, {4.264, 8.312}, {4.263,
8.304}, {4.121, 8.343}, {4.116, 8.33}, {3.123, 8.341}, {3.123,
8.328}, {2.972, 8.336}, {2.97, 8.324}, {2.675, 8.415}, {2.676,
8.411}, {2.747, 8.41}, {2.742, 8.416}, {4.665, 8.408}, {4.66,
8.418}, {4.121, 8.216}, {4.123, 8.226}, {4.359, 8.134}, {4.359,
8.142}, {4.332, 8.098}, {4.038, 8.123}, {2.108, 8.128}, {2.108,
8.122}, {1.39, 8.048}, {1.51, 8.082}, {4.247, 8.039}, {4.244,
8.031}, {4.248, 8.049}, {3.518, 7.97}, {3.521, 7.978}, {3.517,
7.959}, {3.414, 7.995}, {3.328, 7.973}, {3.328, 7.963}, {3.328,
7.981}, {3.241, 7.939}, {3.166, 7.941}, {1.515, 7.94}, {1.343,
7.94}, {1.077, 7.918}, {1.075, 7.902}, {4.108, 7.913}, {4.194,
7.916}, {4.195, 7.909}, {4.302, 7.91}, {4.459, 7.927}, {4.454,
7.914}, {7.054, 7.827}, {4.192, 7.784}, {1.901, 7.653}, {1.901,
7.644}, {2.097, 7.656}, {2.096, 7.642}, {2.242, 7.654}, {2.241,
7.643}, {4.184, 7.652}, {4.184, 7.644}, {6.777, 7.66}, {3.094,
7.053}, {4.235, 4.328}, {4.109, 4.302}, {1.166, 4.332}, {1.075,
4.302}, {0.773, 4.191}, {1.166, 4.238}, {1.458, 4.211}, {1.627,
4.191}, {1.601, 4.191}, {1.899, 4.182}, {1.898, 4.189}, {2.022,
4.244}, {2.017, 4.254}, {2.091, 4.244}, {2.29, 4.248}, {3.103,
4.186}, {3.096, 4.121}, {3.094, 4.11}, {3.094, 4.1}, {2.241,
4.182}, {2.278, 4.146}, {2.277, 4.134}, {2.398, 4.146}, {2.392,
4.137}, {2.384, 4.123}, {2.352, 4.112}, {2.345, 4.122}, {2.094,
4.182}, {2.02, 4.142}, {2.02, 4.132}, {2.102, 4.119}, {2.107,
4.04}, {1.392, 4.066}, {1.51, 3.994}, {1.51, 3.982}, {0.884,
4.04}, {1.076, 4.11}, {1.143, 4.022}, {1.144, 4.012}, {1.144,
4.001}, {1.143, 3.992}, {1.075, 4.119}, {1.074, 4.101}, {2.163,
3.784}, {0.951, 3.79}, {0.951, 3.783}, {0.871, 3.789}, {0.872,
3.781}, {3.328, 3.526}, {3.32, 3.519}, {1.515, 3.241}, {1.516,
3.232}, {1.517, 3.174}, {1.516, 3.164}, {1.754, 2.947}, {1.676,
2.95}, {1.67, 2.943}, {1.456, 2.952}, {1.447, 2.941}, {1.314,
2.95}, {1.31, 2.941}, {2.35, 2.472}, {2.35, 2.482}, {2.345,
2.499}, {2.278, 2.423}, {2.278, 2.391}, {2.009, 2.421}, {2.012,
2.393}, {2.014, 2.403}, {2.104, 2.361}, {2.099, 2.345}, {2.099,
2.336}, {2.094, 2.322}, {2.095, 2.31}, {2.026, 2.287}, {2.022,
2.277}, {2.099, 2.244}, {2.098, 2.234}, {1.9, 2.244}, {1.899,
2.234}, {1.902, 2.255}, {1.9, 2.095}, {1.448, 2.102}, {1.447,
2.092}, {1.45, 2.113}, {1.466, 2.162}, {1.126, 2.164}, {1.123,
2.152}, {1.107, 2.114}, {1.108, 2.102}, {1.108, 2.091}, {0.883,
2.113}, {0.883, 2.103}, {0.887, 2.125}, {0.883, 2.093}, {0.874,
2.158}, {0.95, 2.166}, {0.95, 2.16}, {0.95, 2.151}, {0.869,
1.987}, {0.868, 1.977}, {1.516, 1.898}, {1.514, 1.887}, {1.516,
1.867}, {1.512, 1.88}, {0.857, 1.826}, {0.851, 1.817}, {0.852,
1.8}, {1.602, 1.812}, {1.605, 1.803}, {1.604, 1.797}, {0.687,
1.712}, {0.78, 1.639}, {0.777, 1.609}, {0.782, 1.584}, {0.774,
1.631}, {1.111, 1.449}, {0.78, 1.486}, {0.782, 1.498}, {0.69,
1.433}, {0.68, 1.443}, {0.686, 1.425}, {1.347, 1.511}, {0.862,
1.272}, {0.858, 1.287}, {0.858, 1.265}, {0.872, 0.949}, {2.399,
8.793}, {2.28, 8.791}, {2.023, 4.238}, {2.24, 4.189}, {2.239,
4.174}, {2.24, 4.198}, {2.099, 2.256}, {2.028, 2.261}, {2.024,
2.251}, {1.9, 2.102}, {1.463, 2.151}, {4.137, 8.791}, {2.017,
8.79}, {1.509, 8.091}}

• Posting your starting code and data would be very helpful. Then people would start solving your problem right away, instead wasting time on making up your code + data. Sep 21 at 15:24
• And please make it an example that has the "(really small) discrepancies" rather than just two random clouds of points.
– JimB
Sep 21 at 15:27
• You can add a fake 3rd dimension and use ListPointPlot3D
– I.M.
Sep 21 at 16:49
• ...and is there a point-to-point correspondence between clouds or just overlapping independent random points? As was said above more details and code would be helpful. Sep 21 at 17:40

Because in your case there is:

• 1-to-1 point correspondence

  In[]:= Length/@{a,b}
Out[]= {205,205}

• almost exact overlap which is much smaller in magnitude than points coordinates

  In[]:= MinMax[EuclideanDistance@@@Transpose[{a,b}]]
Out[]= {0.,0.0161555}


it is probably useful to see how much are actual points apart. You can highlight that difference between points with color or size. Idea:

• Place data markers at mean position for each point-pair in a & b
• Use color or size to indicate EuclideanDistance between points
• Use proper AspectRatio to get a better sense of your data

I suggest 2 such visualizations:

### (1)

ListPlot[
Style@@@Transpose[{Mean/@#,ColorData["Rainbow"]/@Rescale[EuclideanDistance@@@#]}&@Transpose[{a,b}]],
PlotStyle->Directive[PointSize[.02],Opacity[.9]],
PlotLegends->Placed[BarLegend["Rainbow"],Above],
AspectRatio->Automatic,BaseStyle->15,PlotTheme->"Detailed",ImageSize->400]


### (2)

BubbleChart[
Flatten/@Transpose[{Mean/@#,EuclideanDistance@@@#}&@Transpose[{a,b}]],
ChartStyle->Opacity[.5],AspectRatio->Automatic,PlotTheme->"Detailed",BaseStyle->15,ImageSize->400]


Note you can also add Tooltip to read out the value of differences - that is useful when points are very close to each other in clusters.

Lastly, a little observation note -- if you look only at the differences in x and y coordinates -- there is sort of a GRID-structure:

ListPlot[Subtract@@@Transpose[{a,b}],
PlotRange->All,PlotTheme->"Detailed",AspectRatio->Automatic,
BaseStyle->{15,Red},PlotStyle->Directive[PointSize[.02],Red]]


• I’m accepting this answer, since I’m going to use something along these lines. Otherwise i have seen some other great answers here. Thanks! Sep 29 at 13:16

One of many styling possibilities

 ListPlot[{a, b},
ImageSize -> Large,
PlotStyle -> {Directive[PointSize[0.02], Lighter @ Gray], Red}]


• +1 simple and elegant. Sep 22 at 18:11
• We use the points a to construct a region Point[a].
• We use RegionNearest to find the nearest points of every point of b to the Point[a] and add some arrows to show such projection.
reg = Point[a];
nst = RegionNearest[reg, #] & /@ b;
Legended[
Arrow[Transpose[{pts, nst}]]}, {Red, AbsolutePointSize[5],
Point[pts]}, {Blue, Point[nst]}}, ImageSize -> Large],
PointLegend[{Red, Blue}, {"start", "nearest"}]]


It depends little bit what you want to stress. I personally like if some quantitative information can be obtained from the graph. Therefore I suggest a minimalistic approach that emphasises large deviations.

th = 0.007;
rd = 0.001;
mx = Max[Table[EuclideanDistance[a[[i]], b[[i]]], {i, Length[a]}]];
ListPlot[Table[d = EuclideanDistance[a[[i]], b[[i]]];
c = Style[0.5 (a[[i]] + b[[i]]), Opacity[d/mx, LightRed]];
If[d > th, Callout[c, Round[d, rd]], c], {i, Length[a]}],
ImageSize -> Large, PlotStyle -> Black]


The points are placed at the midway between points from the two sets. A Callout is added if the distance between points exceeds some threshold (th=0.007). It is selected not to overload image with information. Furthermore, the points are minimally styled. Their color varies from Black (zero distance) to LightRed when the distance is maximal. Except Black, I avoid pure colors here as they are too strong in my opinion.

The majority of points should not be labelled to give the message to the two datasets are mostly indistinguishable.

One way to show the difference is to plot vectors. Their length and color show the differencse:

d = Transpose[{a, a + 50 (b - a)}];
ma = Max[50 (b - a)];
leg = BarLegend[{"Rainbow", {0, 0.015}}];
Legended[
Graphics[{Thickness[0.002],
0.02], {ColorData["Rainbow"][Norm[(#[[2]] - #[[1]])/ma]],
Arrow[#]} & /@ d}, Frame -> True], leg]


Just guessing that maybe an animation might be helpful...

n = 500;
SeedRandom[12345];
data1 = RandomVariate[BinormalDistribution[{0, 0}, {1, 1}, 0], n];
data2 = RandomVariate[BinormalDistribution[{0, 1}, {1, 2}, 0.5], n];
plots = ListPlot[{data1, data2}, PlotRange -> {{-4, 4}, {-7, 7}},
Frame -> True, PlotStyle -> {Opacity[#], Opacity[1 - #]},
ImageSize -> Large, PlotLegends -> {"Data 1", "Data 2"}] & /@
Join[Range[0, 1, 2/100], Range[98/100, 2/100, -2/100]];
Export["points.gif", plots]


(I haven't yet figured out why there's a "bump" in the animation.)

• Thanks, this is helpful for presentations. However, the final presentation needs to be more static, as it will be a part of a report. Sep 22 at 7:19

Another possibility?

ListPolarPlot[{a,-b},PlotStyle->PointSize[Large]]


To see the differences between two point sets we can also use DistanceMatrix

dmat = DistanceMatrix[a, b];


The default distance function of DistanceMatrix is EuclideanDistance:

EuclideanDistance[{u, v}, {x, y}]


We can visualize the distances with a variety of 2D plotting functions, f.e.

ReliefPlot[dmat,
ColorFunction -> "AlpineColors",
PlotLegends -> Automatic,
FrameTicks -> True,
Epilog -> {Red, PointSize[0.02], Point[{191, 1}]}]


The red point (lower right corner) marks the maximum distance between the first point of a and all points of b:

max = {First @ PositionLargest[#], Max[#]} & @ dmat[[1]]


{191, 11.0804}

Proof:

EuclideanDistance[a[[1]], b[[191]]]


11.0804

One can easily show an enlarged submatrix:

ReliefPlot[dmat[[1 ;; 50, 1 ;; 50]],
ColorFunction -> "AlpineColors",
PlotLegends -> Automatic,
FrameTicks -> True]


Visualize distances of point a[[1]] vs b:

ListPlot[dmat[[1]],
PlotStyle -> Gray,
Epilog -> {Red, PointSize[0.02], Point[max]}]


There should be other useful tools to inspect point cloud relationships. Some Classify or Cluster - functions come to my mind.

Plotting the data points over a background that highlights the differences:

Show[
ListDensityPlot[
({Splice[Max /@ Transpose@a], 0}*# & /@ {{0,1,0},{1,0,0},{0,0,0}})~Join~