@@ -41,6 +41,67 @@ def compare_json(json1, json2, _parent_key=None) -> bool:
4141 print (f'Key mismatch at { _parent_key } : { keys1 ^ keys2 } ' )
4242 return False
4343
44+ # Special handling for traces with both y (bdata) and customdata
45+ # Need to sort them together to maintain correspondence
46+ if ('y' in keys1 and 'customdata' in keys1 and
47+ isinstance (json1 ['y' ], dict ) and 'bdata' in json1 ['y' ] and
48+ isinstance (json1 ['customdata' ], list ) and
49+ isinstance (json2 ['y' ], dict ) and 'bdata' in json2 ['y' ] and
50+ isinstance (json2 ['customdata' ], list )):
51+
52+ # Decode y arrays
53+ dtype = json1 ['y' ].get ('dtype' , 'f8' )
54+ y1 = PlotlySnapshotExtension ._decode_bdata (json1 ['y' ]['bdata' ], dtype )
55+ y2 = PlotlySnapshotExtension ._decode_bdata (json2 ['y' ]['bdata' ], dtype )
56+
57+ if y1 is not None and y2 is not None and len (y1 ) == len (json1 ['customdata' ]) and len (y2 ) == len (json2 ['customdata' ]):
58+ # Sort by customdata, keeping y values aligned
59+ def make_sort_key (item ):
60+ result = []
61+ for val in item :
62+ if isinstance (val , str ):
63+ result .append ((1 , val ))
64+ elif isinstance (val , (int , float )):
65+ result .append ((0 , val ))
66+ else :
67+ result .append ((2 , str (val )))
68+ return tuple (result )
69+
70+ # Create (y_value, customdata_row) pairs and sort them
71+ pairs1 = list (zip (y1 , json1 ['customdata' ]))
72+ pairs2 = list (zip (y2 , json2 ['customdata' ]))
73+
74+ try :
75+ pairs1_sorted = sorted (pairs1 , key = lambda p : make_sort_key (p [1 ]))
76+ pairs2_sorted = sorted (pairs2 , key = lambda p : make_sort_key (p [1 ]))
77+
78+ # Extract sorted y values and customdata
79+ y1_sorted = _np .array ([p [0 ] for p in pairs1_sorted ])
80+ y2_sorted = _np .array ([p [0 ] for p in pairs2_sorted ])
81+ cd1_sorted = [p [1 ] for p in pairs1_sorted ]
82+ cd2_sorted = [p [1 ] for p in pairs2_sorted ]
83+
84+ # Compare sorted y values
85+ if not _np .allclose (y1_sorted , y2_sorted , rtol = 1e-6 , atol = 1e-9 ):
86+ print (f'Sorted y values differ at { _parent_key } ' )
87+ return False
88+
89+ # Compare sorted customdata
90+ if not PlotlySnapshotExtension .compare_json (cd1_sorted , cd2_sorted , 'customdata' ):
91+ return False
92+
93+ # Compare all other keys except y and customdata
94+ remaining_keys = keys1 - {'y' , 'customdata' }
95+ for key in remaining_keys :
96+ if not PlotlySnapshotExtension .compare_json (json1 [key ], json2 [key ], key ):
97+ print (f'Values for key { key } not equal' )
98+ return False
99+
100+ return True
101+ except (TypeError , ValueError ) as e :
102+ print (f'Error sorting y/customdata together: { e } ' )
103+ # Fall through to regular comparison
104+
44105 for key in keys1 :
45106 # Special handling for 'bdata' - decode and compare numerically
46107 if key == 'bdata' and isinstance (json1 [key ], str ) and isinstance (json2 [key ], str ):
0 commit comments