7
$\begingroup$

Is there a way to reliably test the equality of two plots? Consider this:

plot1 = Plot[Sin[x], {x, 0, 2Pi}];
plot2 = Plot[Sin[x], {x, 0, 2Pi}];

You'd think these would be equal, but they're not.

Evaluate[plot1 == plot2]

Mathematica graphics

SameQ doesn't work either:

Evaluate[plot1 === plot2]
(* False *)

At least this works:

Evaluate[plot1 == plot1]
(* True *)

Edit:

@eyorble provided a nice answer, but the plot thickens. How can we also get False when two plots are not equal?

plot3 = Plot[Cos[x], {x, 0, 2Pi}];
(plot1 == plot3) /. (x_String :> StringReplace[x, "Charting`Private`Tag$" ~~ __ -> "Charting`Private`Tag"])

Mathematica graphics

$\endgroup$
  • $\begingroup$ The newer versions add some sort of unique tag each time Plot is executed. Makes comparison pretty much impossible $\endgroup$ – Michael E2 Feb 11 '18 at 23:25
  • $\begingroup$ Any thoughts on a workaround? $\endgroup$ – Chris K Feb 11 '18 at 23:30
  • $\begingroup$ Removing the tag (or remapping it as in the answer) would work. $\endgroup$ – Michael E2 Feb 12 '18 at 3:09
7
$\begingroup$
plot1 == plot2 /. 
  (x_String :> StringReplace[x, "Charting`Private`Tag$" ~~ __ -> "Charting`Private`Tag"])

True

Plots seem to be otherwise deterministic, so that appears to be the only necessary change for comparison with ==.

To get False when they aren't equal, perhaps something like this would suffice:

Activate[Inactive[SameQ][plot1, plot2]
   /. (x_String :> StringReplace[x, "Charting`Private`Tag$" ~~ __ -> "Charting`Private`Tag"])]

Inactive and Activate are simply to ensure that SameQ doesn't evaluate before the replacement takes place.

$\endgroup$
  • $\begingroup$ Thanks! I realized another important case is to get False when two plots are not equal. See my edit to the question. Any ideas there? $\endgroup$ – Chris K Feb 12 '18 at 2:39
  • $\begingroup$ @ChrisK Updated my answer for that. $\endgroup$ – eyorble Feb 12 '18 at 2:46
  • $\begingroup$ Seems to work. Thanks again! $\endgroup$ – Chris K Feb 12 '18 at 2:57
7
$\begingroup$

As I observed earlier, the tags are used in plots in the form Annotation[curve, tag] for each function plotted. One way to just get the curves is to override Annotation:

Block[{Annotation = #1 &},
 plot1 == plot2
 ]
(*  True  *)

Block[{Annotation = #1 &},
 plot1 === plot2
 ]
(*  True  *)

Since the tags are in the Charting`Private` context, it seems pointless to have them in the first place. (Even if they are used in constructing the plot, what good are they in the final output, ostensibly private and hidden from the user?)

Note on Equal vs. SameQ: Equal will evaluate to True when expressions are the same (as in SameQ), but it tends to remain unevaluated if there are symbols (which might take on arbitrary values). To be sure to get a False, use SameQ:

Plus == Automatic
(*  Plus == Automatic  *)

Plus === Automatic
(*  False  *)

See 1 is not the SameQ as Null, but why might 1 be Equal to Null?

Also related: (4390), (8796), (17909).

$\endgroup$
  • $\begingroup$ I have a Hash@expr based caching procedure for my APIFunctions and now I need to patch it because of that -.- I'd call it a minor bug. $\endgroup$ – Kuba Mar 8 '18 at 22:32
3
$\begingroup$

If by equal you mean the plots look the same and are the same size then you can use Rasterize and ImageData.

samePlot[p1_, p2_] := Equal @@ (ImageData@Rasterize[#, "Image"] & /@ {p1, p2})

With

plot1 = Plot[Sin[x], {x, 0, 2 Pi}];
plot2 = Plot[Sin[x], {x, 0, 2 Pi}];
plot3 = Plot[Cos[x], {x, 0, 2 Pi}];

Then

samePlot[plot1, plot2]
True
samePlot[plot1, plot3]
False

Hope this helps.

$\endgroup$

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.