18
18
def test_coordination_hist_single_structure (structures : Sequence [Structure ]) -> None :
19
19
"""Test coordination_hist with a single structure."""
20
20
fig = coordination_hist (structures [0 ])
21
- assert fig .data
22
21
assert len (fig .data ) == len ({site .specie .symbol for site in structures [0 ]})
23
22
23
+ # Test y-axis range
24
+ expected_y_max = max (max (trace .y ) for trace in fig .data ) # get max CN count
25
+ y_min , y_max = fig .layout .yaxis .range
26
+ assert y_min == 0
27
+ assert y_max == pytest .approx (expected_y_max , rel = 0.1 )
28
+
29
+ # Test x-axis properties
30
+ assert fig .layout .xaxis .tick0 is not None
31
+ assert fig .layout .xaxis .dtick == 1
32
+ assert fig .layout .xaxis .range [0 ] < min (trace .x [0 ] for trace in fig .data )
33
+
34
+ # Test y-axis properties
35
+ assert fig .layout .yaxis .range [0 ] == 0
36
+ assert fig .layout .yaxis .title .text == "Count"
37
+
24
38
25
39
def test_coordination_hist_multiple_structures (structures : Sequence [Structure ]) -> None :
26
40
"""Test coordination_hist with multiple structures."""
27
41
struct_dict = {f"Structure_{ i } " : struct for i , struct in enumerate (structures )}
28
42
fig = coordination_hist (struct_dict )
29
- assert fig .data
30
43
expected_traces = sum (
31
44
len ({site .specie .symbol for site in struct }) for struct in structures
32
45
)
@@ -39,7 +52,6 @@ def test_coordination_hist_split_modes(
39
52
) -> None :
40
53
"""Test coordination_hist with different split modes."""
41
54
fig = coordination_hist (structures [0 ], split_mode = split_mode )
42
- assert fig .data
43
55
44
56
if split_mode in (SplitMode .none , SplitMode .by_element ):
45
57
assert len (fig .data ) == len ({site .specie .symbol for site in structures [0 ]})
@@ -58,7 +70,6 @@ def test_coordination_hist_custom_strategy(
58
70
) -> None :
59
71
"""Test coordination_hist with a custom strategy."""
60
72
fig = coordination_hist (structures [1 ], strategy = strategy )
61
- assert fig .data
62
73
assert len (fig .data ) == 3
63
74
expected_max_x = {
64
75
3.0 : 9 ,
@@ -95,7 +106,6 @@ def test_coordination_hist_hover_data(structures: Sequence[Structure]) -> None:
95
106
"""Test coordination_hist with custom hover data."""
96
107
structures [0 ].add_site_property ("test_property" , list (range (len (structures [0 ]))))
97
108
fig = coordination_hist (structures [0 ], hover_data = ["test_property" ])
98
- assert fig .data
99
109
assert "test_property" in fig .data [0 ].hovertext [0 ]
100
110
101
111
@@ -107,15 +117,13 @@ def test_coordination_hist_element_color_scheme(
107
117
colors = ("red" , "blue" , "green" , "yellow" , "purple" , "orange" , "pink" , "brown" )
108
118
custom_colors = dict (zip (elements , colors , strict = False ))
109
119
fig = coordination_hist (structures [0 ], element_color_scheme = custom_colors )
110
- assert fig .data
111
120
for trace in fig .data :
112
121
assert trace .marker .color == custom_colors [trace .name .split (" - " )[1 ]]
113
122
114
123
115
124
def test_coordination_hist_annotate_bars (structures : Sequence [Structure ]) -> None :
116
125
"""Test coordination_hist with bar annotations."""
117
126
fig = coordination_hist (structures [0 ], annotate_bars = True )
118
- assert fig .data
119
127
elements = {site .specie .symbol for site in structures [0 ]} | {"" }
120
128
for trace in fig .data :
121
129
assert {trace .text } <= elements , f"Invalid text: { trace .text } "
@@ -125,21 +133,11 @@ def test_coordination_hist_bar_kwargs(structures: Sequence[Structure]) -> None:
125
133
"""Test coordination_hist with custom bar kwargs."""
126
134
bar_kwargs = {"opacity" : 0.5 , "width" : 0.5 }
127
135
fig = coordination_hist (structures [0 ], bar_kwargs = bar_kwargs )
128
- assert fig .data
129
136
for trace in fig .data :
130
137
assert trace .opacity == 0.5
131
138
assert trace .width == 0.5
132
139
133
140
134
- def test_coordination_hist_y_axis_range (structures : Sequence [Structure ]) -> None :
135
- """Test if y-axis range is 10% higher than the max count."""
136
- fig = coordination_hist (structures [0 ])
137
- assert fig .data
138
- max_count = max (max (trace .y ) for trace in fig .data )
139
- expected_y_max = max_count * 1.1
140
- assert fig .layout .yaxis .range [1 ] == pytest .approx (expected_y_max , rel = 1e-6 )
141
-
142
-
143
141
def test_coordination_hist_invalid_input () -> None :
144
142
"""Test coordination_hist with invalid input."""
145
143
with pytest .raises (TypeError ):
@@ -169,7 +167,6 @@ def test_coordination_vs_cutoff_line(
169
167
"""Test coordination_vs_cutoff_line function with different strategies."""
170
168
# Test with a single structure
171
169
fig = coordination_vs_cutoff_line (structures [0 ], strategy = strategy )
172
- assert fig .data
173
170
assert len (fig .data ) == len ({site .specie .symbol for site in structures [0 ]})
174
171
175
172
# Test with multiple structures
@@ -232,3 +229,106 @@ def test_coordination_vs_cutoff_line_invalid_strategy() -> None:
232
229
structure = Structure (Lattice .cubic (5 ), ["Si" ], [[0 , 0 , 0 ]])
233
230
with pytest .raises (TypeError , match = "Invalid strategy=" ):
234
231
coordination_vs_cutoff_line (structure , strategy = "invalid" )
232
+
233
+
234
+ def test_coordination_hist_hover_text_formatting (
235
+ structures : Sequence [Structure ],
236
+ ) -> None :
237
+ """Test hover text formatting in coordination_hist."""
238
+ # Add test property
239
+ structures [0 ].add_site_property ("test_prop" , list (range (len (structures [0 ]))))
240
+
241
+ # Test with single structure
242
+ fig = coordination_hist (structures [0 ], hover_data = ["test_prop" ])
243
+ hover_text = fig .data [0 ].hovertext [0 ]
244
+ assert "Element:" in hover_text
245
+ assert "Coordination number:" in hover_text
246
+ assert "test_prop:" in hover_text
247
+
248
+ # Test with multiple structures
249
+ struct_dict = {"struct1" : structures [0 ], "struct2" : structures [1 ]}
250
+ fig_multi = coordination_hist (struct_dict , hover_data = ["test_prop" ])
251
+ hover_text_multi = fig_multi .data [0 ].hovertext [0 ]
252
+ assert "Formula:" in hover_text_multi
253
+
254
+
255
+ def test_coordination_hist_subplot_layout (structures : Sequence [Structure ]) -> None :
256
+ """Test subplot layout in coordination_hist."""
257
+ struct_dict = {f"s{ i } " : struct for i , struct in enumerate (structures [:3 ])}
258
+
259
+ # Test by_structure layout
260
+ fig = coordination_hist (struct_dict , split_mode = SplitMode .by_structure )
261
+ assert len (fig .layout .annotations ) == len (struct_dict ) # subplot titles
262
+
263
+ # Test by_element layout
264
+ elements = {
265
+ site .specie .symbol for struct in struct_dict .values () for site in struct
266
+ }
267
+ fig_elem = coordination_hist (struct_dict , split_mode = SplitMode .by_element )
268
+ assert len (fig_elem .layout .annotations ) == len (elements )
269
+
270
+
271
+ def test_coordination_hist_bar_customization (structures : Sequence [Structure ]) -> None :
272
+ """Test bar customization options in coordination_hist."""
273
+ # Test bar width
274
+ bar_kwargs = {"width" : 0.5 }
275
+ fig = coordination_hist (structures [0 ], bar_kwargs = bar_kwargs )
276
+ assert all (trace .width == 0.5 for trace in fig .data )
277
+
278
+ # Test bar opacity
279
+ bar_kwargs = {"opacity" : 0.7 }
280
+ fig = coordination_hist (structures [0 ], bar_kwargs = bar_kwargs )
281
+ assert all (trace .opacity == 0.7 for trace in fig .data )
282
+
283
+
284
+ def test_coordination_hist_color_schemes (structures : Sequence [Structure ]) -> None :
285
+ """Test different color schemes in coordination_hist."""
286
+ # Test JMOL colors
287
+ fig_jmol = coordination_hist (
288
+ structures [0 ], element_color_scheme = ElemColorScheme .jmol
289
+ )
290
+
291
+ # Test VESTA colors
292
+ fig_vesta = coordination_hist (
293
+ structures [0 ], element_color_scheme = ElemColorScheme .vesta
294
+ )
295
+
296
+ # Colors should be different between schemes
297
+ assert any (
298
+ t1 .marker .color != t2 .marker .color
299
+ for t1 , t2 in zip (fig_jmol .data , fig_vesta .data , strict = True )
300
+ )
301
+
302
+
303
+ def test_coordination_hist_invalid_elem_colors (structures : Sequence [Structure ]) -> None :
304
+ """Test invalid color scheme handling."""
305
+ with pytest .raises (ValueError , match = "Invalid.*element_color_scheme" ):
306
+ coordination_hist (structures [0 ], element_color_scheme = "invalid" ) # type: ignore[arg-type]
307
+
308
+
309
+ def test_coordination_hist_invalid_hover_data (structures : Sequence [Structure ]) -> None :
310
+ """Test invalid hover_data handling."""
311
+ with pytest .raises (TypeError , match = "Invalid hover_data" ):
312
+ coordination_hist (structures [0 ], hover_data = 123 ) # type: ignore[arg-type]
313
+
314
+
315
+ def test_coordination_hist_invalid_split_mode (structures : Sequence [Structure ]) -> None :
316
+ """Test invalid split_mode handling."""
317
+ split_mode = "invalid_mode"
318
+ with pytest .raises (ValueError , match = f"Invalid { split_mode = } " ):
319
+ coordination_hist (structures [0 ], split_mode = split_mode )
320
+
321
+
322
+ def test_coordination_hist_bar_annotations (structures : Sequence [Structure ]) -> None :
323
+ """Test bar annotation functionality."""
324
+ # Test default annotation settings
325
+ fig = coordination_hist (structures [0 ], annotate_bars = True )
326
+ assert all (trace .text is not None for trace in fig .data )
327
+
328
+ # Test custom annotation settings
329
+ custom_annotations = {"size" : 14 , "color" : "red" }
330
+ fig = coordination_hist (structures [0 ], annotate_bars = custom_annotations )
331
+ assert all (
332
+ trace .textfont .size == 14 and trace .textfont .color == "red"
333
+ for trace in fig .data
334
+ )
0 commit comments