@@ -12,6 +12,10 @@ DENSITYPLOT_FIXTURE_JSON = JSON.parse(File.read(DENSITYPLOT_FIXTURE_PATH))
1212DENSITYPLOT_X = DENSITYPLOT_FIXTURE_JSON [" x" ].as_a.map(& .as_f)
1313DENSITYPLOT_Y = DENSITYPLOT_FIXTURE_JSON [" y" ].as_a.map(& .as_f)
1414
15+ # Spy fixtures generated by spec/fixtures/generate_julia_spy_data.jl
16+ SPY_FIXTURE_PATH = File .join(__DIR__, " fixtures" , " julia_spy_data.json" )
17+ SPY_FIXTURE_JSON = JSON .parse(File .read(SPY_FIXTURE_PATH ))
18+
1519# Returns a matrix fixture by key ("60x60", "10x10", "10x11").
1620# The parsed matrix is cached because multiple examples reuse the same payload.
1721def heatmap_fixture_matrix (key : String ) : Array (Array (Float64 ))
@@ -44,6 +48,32 @@ def matrix_columns(rows : Array(Array(Float64))) : Array(Array(Float64))
4448 end
4549end
4650
51+ # Reconstruct a dense matrix from the spy fixture JSON entry (sparse COO format, 1-indexed).
52+ def spy_fixture_matrix (key : String ) : Array (Array (Float64 ))
53+ entry = SPY_FIXTURE_JSON [key]
54+ nrows = entry[" nrows" ].as_i
55+ ncols = entry[" ncols" ].as_i
56+ rows_a = entry[" rows" ].as_a.map(& .as_i)
57+ cols_a = entry[" cols" ].as_a.map(& .as_i)
58+ vals_a = entry[" vals" ].as_a.map(& .as_f)
59+ matrix = Array .new(nrows) { Array .new(ncols, 0.0 ) }
60+ rows_a.each_with_index do |r , idx |
61+ matrix[r - 1 ][cols_a[idx] - 1 ] = vals_a[idx]
62+ end
63+ matrix
64+ end
65+
66+ # Deterministic sparse matrix matching Julia's flip test:
67+ # I = [1,4,3,5], J = [4,7,18,9], V = [1,2,-5,3]
68+ def spy_flip_matrix : Array (Array (Float64 ))
69+ a = Array .new(5 ) { Array .new(18 , 0.0 ) }
70+ a[0 ][3 ] = 1.0
71+ a[3 ][6 ] = 2.0
72+ a[2 ][17 ] = -5.0
73+ a[4 ][8 ] = 3.0
74+ a
75+ end
76+
4777def linspace (start_v : Float64 , end_v : Float64 , length : Int32 ) : Array (Float64 )
4878 return [] of Float64 if length <= 0
4979 return [start_v] if length == 1
@@ -1083,4 +1113,106 @@ describe "Julia reference output compatibility" do
10831113 test_ref(" densityplot/densityplot_dscale_custom.txt" , p)
10841114 end
10851115 end
1116+
1117+ describe " spy" do
1118+ describe " flip" do
1119+ a = spy_flip_matrix
1120+
1121+ it " matches spy/flip_xflip-false_yflip-true" do
1122+ p = UnicodePlot .spy(a, xflip: false , yflip: true )
1123+ test_ref(" spy/flip_xflip-false_yflip-true.txt" , p)
1124+ end
1125+
1126+ it " matches spy/flip_xflip-true_yflip-false" do
1127+ p = UnicodePlot .spy(a, xflip: true , yflip: false )
1128+ test_ref(" spy/flip_xflip-true_yflip-false.txt" , p)
1129+ end
1130+
1131+ it " matches spy/flip_xflip-false_yflip-false" do
1132+ p = UnicodePlot .spy(a, xflip: false , yflip: false )
1133+ test_ref(" spy/flip_xflip-false_yflip-false.txt" , p)
1134+ end
1135+
1136+ it " matches spy/flip_xflip-true_yflip-true" do
1137+ p = UnicodePlot .spy(a, xflip: true , yflip: true )
1138+ test_ref(" spy/flip_xflip-true_yflip-true.txt" , p)
1139+ end
1140+ end
1141+
1142+ describe " sizing" do
1143+ it " matches spy/default_10x10" do
1144+ p = UnicodePlot .spy(spy_fixture_matrix(" 10x10" ))
1145+ test_ref(" spy/default_10x10.txt" , p)
1146+ end
1147+
1148+ it " matches spy/default_10x15" do
1149+ p = UnicodePlot .spy(spy_fixture_matrix(" 10x15" ))
1150+ test_ref(" spy/default_10x15.txt" , p)
1151+ end
1152+
1153+ it " matches spy/default_15x10" do
1154+ p = UnicodePlot .spy(spy_fixture_matrix(" 15x10" ))
1155+ test_ref(" spy/default_15x10.txt" , p)
1156+ end
1157+
1158+ it " matches spy/default_200x200_normal" do
1159+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x200_normal" ))
1160+ test_ref(" spy/default_200x200_normal.txt" , p)
1161+ end
1162+
1163+ it " matches spy/default_200x200_normal_nocolor" do
1164+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x200_normal" ))
1165+ test_ref(" spy/default_200x200_normal_nocolor.txt" , p)
1166+ end
1167+
1168+ it " matches spy/default_200x200_normal_small (width: 10)" do
1169+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x200_normal" ), width: 10 )
1170+ test_ref(" spy/default_200x200_normal_small.txt" , p)
1171+ end
1172+
1173+ it " matches spy/default_200x200_normal_misshaped (height: 5, width: 20)" do
1174+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x200_normal" ), height: 5 , width: 20 )
1175+ test_ref(" spy/default_200x200_normal_misshaped.txt" , p)
1176+ end
1177+
1178+ it " matches spy/default_2000x200" do
1179+ p = UnicodePlot .spy(spy_fixture_matrix(" 2000x200" ))
1180+ test_ref(" spy/default_2000x200.txt" , p)
1181+ end
1182+
1183+ it " matches spy/default_200x2000" do
1184+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x2000" ))
1185+ test_ref(" spy/default_200x2000.txt" , p)
1186+ end
1187+ end
1188+
1189+ describe " parameters" do
1190+ it " matches spy/parameters_200x200_green" do
1191+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x200_normal" ), color: :green )
1192+ test_ref(" spy/parameters_200x200_green.txt" , p)
1193+ end
1194+
1195+ it " matches spy/parameters_200x200_green_nocolor" do
1196+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x200_normal" ), color: :green )
1197+ test_ref(" spy/parameters_200x200_green_nocolor.txt" , p)
1198+ end
1199+
1200+ it " matches spy/parameters_200x200_dotcanvas" do
1201+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x200_normal" ), canvas: :dot , border: :ascii , title: " Custom Title" )
1202+ test_ref(" spy/parameters_200x200_dotcanvas.txt" , p)
1203+ end
1204+
1205+ it " matches spy/parameters_200x200_zeros" do
1206+ p = UnicodePlot .spy(spy_fixture_matrix(" 200x200_zeros" ), show_zeros: true , compact_labels: true )
1207+ test_ref(" spy/parameters_200x200_zeros.txt" , p)
1208+ end
1209+ end
1210+
1211+ describe " fix_aspect_ratio" do
1212+ it " matches spy/fix_aspect_ratio_80x80_" do
1213+ p = UnicodePlot .spy(spy_fixture_matrix(" 80x80" ), fix_ar: true )
1214+ test_ref(" spy/fix_aspect_ratio_80x80_.txt" , p)
1215+ end
1216+ end
1217+ end
10861218end
0 commit comments