Coverage for continuous/tests/test_signal.py: 100%

228 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-16 22:49 +1300

1"""Define the unit tests for the :mod:`colour.continuous.signal` module.""" 

2 

3from __future__ import annotations 

4 

5import pickle 

6import textwrap 

7 

8import numpy as np 

9import pytest 

10 

11from colour.algebra import CubicSplineInterpolator, Extrapolator, KernelInterpolator 

12from colour.constants import DTYPE_FLOAT_DEFAULT, TOLERANCE_ABSOLUTE_TESTS 

13from colour.continuous import Signal 

14from colour.utilities import ( 

15 ColourRuntimeWarning, 

16 attest, 

17 is_pandas_installed, 

18 is_scipy_installed, 

19) 

20 

21__author__ = "Colour Developers" 

22__copyright__ = "Copyright 2013 Colour Developers" 

23__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause" 

24__maintainer__ = "Colour Developers" 

25__email__ = "colour-developers@colour-science.org" 

26__status__ = "Production" 

27 

28__all__ = [ 

29 "TestSignal", 

30] 

31 

32 

33class TestSignal: 

34 """Define :class:`colour.continuous.signal.Signal` class unit tests methods.""" 

35 

36 def setup_method(self) -> None: 

37 """Initialise the common tests attributes.""" 

38 

39 self._range = np.linspace(10, 100, 10) 

40 self._domain = np.arange(100, 1100, 100) 

41 

42 self._signal = Signal(self._range) 

43 

44 def test_required_attributes(self) -> None: 

45 """Test the presence of required attributes.""" 

46 

47 required_attributes = ( 

48 "dtype", 

49 "domain", 

50 "range", 

51 "interpolator", 

52 "interpolator_kwargs", 

53 "extrapolator", 

54 "extrapolator_kwargs", 

55 "function", 

56 ) 

57 

58 for attribute in required_attributes: 

59 assert attribute in dir(Signal) 

60 

61 def test_required_methods(self) -> None: 

62 """Test the presence of required methods.""" 

63 

64 required_methods = ( 

65 "__init__", 

66 "__str__", 

67 "__repr__", 

68 "__hash__", 

69 "__getitem__", 

70 "__setitem__", 

71 "__contains__", 

72 "__iter__", 

73 "__eq__", 

74 "__ne__", 

75 "arithmetical_operation", 

76 "signal_unpack_data", 

77 "fill_nan", 

78 "domain_distance", 

79 "to_series", 

80 ) 

81 

82 for method in required_methods: 

83 assert method in dir(Signal) 

84 

85 def test_pickling(self) -> None: 

86 """ 

87 Test whether the :class:``colour.continuous.signal.Signal` class can be 

88 pickled. 

89 """ 

90 

91 data = pickle.dumps(self._signal) 

92 data = pickle.loads(data) # noqa: S301 

93 assert self._signal == data 

94 

95 def test_dtype(self) -> None: 

96 """Test :func:`colour.continuous.signal.Signal.dtype` property.""" 

97 

98 assert self._signal.dtype == DTYPE_FLOAT_DEFAULT 

99 

100 signal = self._signal.copy() 

101 signal.dtype = np.float32 

102 assert signal.dtype == np.float32 

103 

104 def test_domain(self) -> None: 

105 """Test :func:`colour.continuous.signal.Signal.domain` property.""" 

106 

107 signal = self._signal.copy() 

108 

109 np.testing.assert_allclose( 

110 signal[np.array([0, 1, 2])], 

111 np.array([10.0, 20.0, 30.0]), 

112 atol=TOLERANCE_ABSOLUTE_TESTS, 

113 ) 

114 

115 signal.domain = np.arange(0, 10, 1) * 10 

116 

117 np.testing.assert_array_equal(signal.domain, np.arange(0, 10, 1) * 10) 

118 

119 np.testing.assert_allclose( 

120 signal[np.array([0, 1, 2]) * 10], 

121 np.array([10.0, 20.0, 30.0]), 

122 atol=TOLERANCE_ABSOLUTE_TESTS, 

123 ) 

124 

125 domain = np.linspace(0, 1, 10) 

126 domain[0] = -np.inf 

127 

128 def assert_warns() -> None: 

129 """Help to test the runtime warning.""" 

130 

131 signal.domain = domain 

132 

133 pytest.warns(ColourRuntimeWarning, assert_warns) 

134 

135 def test_range(self) -> None: 

136 """Test :func:`colour.continuous.signal.Signal.range` property.""" 

137 

138 signal = self._signal.copy() 

139 

140 np.testing.assert_allclose( 

141 signal[np.array([0, 1, 2])], 

142 np.array([10.0, 20.0, 30.0]), 

143 atol=TOLERANCE_ABSOLUTE_TESTS, 

144 ) 

145 

146 signal.range = self._range * 10 

147 

148 np.testing.assert_array_equal(signal.range, self._range * 10) 

149 

150 np.testing.assert_allclose( 

151 signal[np.array([0, 1, 2])], 

152 np.array([10.0, 20.0, 30.0]) * 10, 

153 atol=TOLERANCE_ABSOLUTE_TESTS, 

154 ) 

155 

156 def assert_warns() -> None: 

157 """Help to test the runtime warning.""" 

158 

159 signal.range = self._range * np.inf 

160 

161 pytest.warns(ColourRuntimeWarning, assert_warns) 

162 

163 def test_interpolator(self) -> None: 

164 """Test :func:`colour.continuous.signal.Signal.interpolator` property.""" 

165 

166 if not is_scipy_installed(): # pragma: no cover 

167 return 

168 

169 signal = self._signal.copy() 

170 

171 np.testing.assert_allclose( 

172 signal[np.linspace(0, 5, 5)], 

173 np.array( 

174 [ 

175 10.00000000, 

176 22.83489024, 

177 34.80044921, 

178 47.55353925, 

179 60.00000000, 

180 ] 

181 ), 

182 atol=TOLERANCE_ABSOLUTE_TESTS, 

183 ) 

184 

185 signal.interpolator = CubicSplineInterpolator 

186 

187 np.testing.assert_allclose( 

188 signal[np.linspace(0, 5, 5)], 

189 np.array([10.0, 22.5, 35.0, 47.5, 60.0]), 

190 atol=TOLERANCE_ABSOLUTE_TESTS, 

191 ) 

192 

193 def test_interpolator_kwargs(self) -> None: 

194 """ 

195 Test :func:`colour.continuous.signal.Signal.interpolator_kwargs` 

196 property. 

197 """ 

198 

199 signal = self._signal.copy() 

200 

201 np.testing.assert_allclose( 

202 signal[np.linspace(0, 5, 5)], 

203 np.array( 

204 [ 

205 10.00000000, 

206 22.83489024, 

207 34.80044921, 

208 47.55353925, 

209 60.00000000, 

210 ] 

211 ), 

212 atol=TOLERANCE_ABSOLUTE_TESTS, 

213 ) 

214 

215 signal.interpolator_kwargs = {"window": 1, "kernel_kwargs": {"a": 1}} 

216 

217 np.testing.assert_allclose( 

218 signal[np.linspace(0, 5, 5)], 

219 np.array( 

220 [ 

221 10.00000000, 

222 18.91328761, 

223 28.36993142, 

224 44.13100443, 

225 60.00000000, 

226 ] 

227 ), 

228 atol=TOLERANCE_ABSOLUTE_TESTS, 

229 ) 

230 

231 def test_extrapolator(self) -> None: 

232 """Test :func:`colour.continuous.signal.Signal.extrapolator` property.""" 

233 

234 assert isinstance(self._signal.extrapolator(), Extrapolator) 

235 

236 def test_extrapolator_kwargs(self) -> None: 

237 """ 

238 Test :func:`colour.continuous.signal.Signal.extrapolator_kwargs` 

239 property. 

240 """ 

241 

242 signal = self._signal.copy() 

243 

244 attest(np.all(np.isnan(signal[np.array([-1000, 1000])]))) 

245 

246 signal.extrapolator_kwargs = { 

247 "method": "Linear", 

248 } 

249 

250 np.testing.assert_allclose( 

251 signal[np.array([-1000, 1000])], 

252 np.array([-9990.0, 10010.0]), 

253 atol=TOLERANCE_ABSOLUTE_TESTS, 

254 ) 

255 

256 def test_function(self) -> None: 

257 """Test :func:`colour.continuous.signal.Signal.function` property.""" 

258 

259 attest(callable(self._signal.function)) 

260 

261 def test_raise_exception_function(self) -> None: 

262 """ 

263 Test :func:`colour.continuous.signal.Signal.function` property raised 

264 exception. 

265 """ 

266 

267 pytest.raises(ValueError, Signal().function, 0) 

268 

269 def test__init__(self) -> None: 

270 """Test :func:`colour.continuous.signal.Signal.__init__` method.""" 

271 

272 signal = Signal(self._range) 

273 np.testing.assert_array_equal(signal.domain, np.arange(0, 10, 1)) 

274 np.testing.assert_array_equal(signal.range, self._range) 

275 

276 signal = Signal(self._range, self._domain) 

277 np.testing.assert_array_equal(signal.domain, self._domain) 

278 np.testing.assert_array_equal(signal.range, self._range) 

279 

280 signal = Signal(dict(zip(self._domain, self._range, strict=True))) 

281 np.testing.assert_array_equal(signal.domain, self._domain) 

282 np.testing.assert_array_equal(signal.range, self._range) 

283 

284 signal = Signal(signal) 

285 np.testing.assert_array_equal(signal.domain, self._domain) 

286 np.testing.assert_array_equal(signal.range, self._range) 

287 

288 if is_pandas_installed(): 

289 from pandas import Series # noqa: PLC0415 

290 

291 signal = Signal(Series(dict(zip(self._domain, self._range, strict=True)))) 

292 np.testing.assert_array_equal(signal.domain, self._domain) 

293 np.testing.assert_array_equal(signal.range, self._range) 

294 

295 def test__hash__(self) -> None: 

296 """Test :func:`colour.continuous.signal.Signal.__hash__` method.""" 

297 

298 assert isinstance(hash(self._signal), int) 

299 

300 def test__str__(self) -> None: 

301 """Test :func:`colour.continuous.signal.Signal.__str__` method.""" 

302 

303 assert ( 

304 str(self._signal) 

305 == ( 

306 textwrap.dedent( 

307 """ 

308 [[ 0. 10.] 

309 [ 1. 20.] 

310 [ 2. 30.] 

311 [ 3. 40.] 

312 [ 4. 50.] 

313 [ 5. 60.] 

314 [ 6. 70.] 

315 [ 7. 80.] 

316 [ 8. 90.] 

317 [ 9. 100.]]""" 

318 )[1:] 

319 ) 

320 ) 

321 

322 assert isinstance(str(Signal()), str) 

323 

324 def test__repr__(self) -> None: 

325 """Test :func:`colour.continuous.signal.Signal.__repr__` method.""" 

326 

327 assert repr(self._signal) == ( 

328 textwrap.dedent( 

329 """ 

330 Signal([[ 0., 10.], 

331 [ 1., 20.], 

332 [ 2., 30.], 

333 [ 3., 40.], 

334 [ 4., 50.], 

335 [ 5., 60.], 

336 [ 6., 70.], 

337 [ 7., 80.], 

338 [ 8., 90.], 

339 [ 9., 100.]], 

340 KernelInterpolator, 

341 {}, 

342 Extrapolator, 

343 {'method': 'Constant', 'left': nan, 'right': nan}) 

344 """ 

345 ).strip() 

346 ) 

347 

348 assert isinstance(repr(Signal()), str) 

349 

350 def test__getitem__(self) -> None: 

351 """Test :func:`colour.continuous.signal.Signal.__getitem__` method.""" 

352 

353 assert self._signal[0] == 10.0 

354 

355 np.testing.assert_allclose( 

356 self._signal[np.array([0, 1, 2])], 

357 np.array([10.0, 20.0, 30.0]), 

358 atol=TOLERANCE_ABSOLUTE_TESTS, 

359 ) 

360 

361 np.testing.assert_allclose( 

362 self._signal[np.linspace(0, 5, 5)], 

363 np.array( 

364 [ 

365 10.00000000, 

366 22.83489024, 

367 34.80044921, 

368 47.55353925, 

369 60.00000000, 

370 ] 

371 ), 

372 atol=TOLERANCE_ABSOLUTE_TESTS, 

373 ) 

374 

375 attest(np.all(np.isnan(self._signal[np.array([-1000, 1000])]))) 

376 

377 signal = self._signal.copy() 

378 signal.extrapolator_kwargs = { 

379 "method": "Linear", 

380 } 

381 np.testing.assert_array_equal( 

382 signal[np.array([-1000, 1000])], np.array([-9990.0, 10010.0]) 

383 ) 

384 

385 signal.extrapolator_kwargs = { 

386 "method": "Constant", 

387 "left": 0, 

388 "right": 1, 

389 } 

390 np.testing.assert_array_equal( 

391 signal[np.array([-1000, 1000])], np.array([0.0, 1.0]) 

392 ) 

393 

394 def test__setitem__(self) -> None: 

395 """Test :func:`colour.continuous.signal.Signal.__setitem__` method.""" 

396 

397 signal = self._signal.copy() 

398 

399 signal[0] = 20 

400 np.testing.assert_allclose( 

401 signal.range, 

402 np.array([20.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0]), 

403 ) 

404 

405 signal[np.array([0, 1, 2])] = 30 

406 np.testing.assert_allclose( 

407 signal.range, 

408 np.array([30.0, 30.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0]), 

409 atol=TOLERANCE_ABSOLUTE_TESTS, 

410 ) 

411 

412 signal[0:3] = 40 

413 np.testing.assert_allclose( 

414 signal.range, 

415 np.array([40.0, 40.0, 40.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0]), 

416 atol=TOLERANCE_ABSOLUTE_TESTS, 

417 ) 

418 

419 signal[np.linspace(0, 5, 5)] = 50 

420 np.testing.assert_allclose( 

421 signal.domain, 

422 np.array( 

423 [ 

424 0.00, 

425 1.00, 

426 1.25, 

427 2.00, 

428 2.50, 

429 3.00, 

430 3.75, 

431 4.00, 

432 5.00, 

433 6.00, 

434 7.00, 

435 8.00, 

436 9.00, 

437 ] 

438 ), 

439 atol=TOLERANCE_ABSOLUTE_TESTS, 

440 ) 

441 np.testing.assert_allclose( 

442 signal.range, 

443 np.array( 

444 [ 

445 50.0, 

446 40.0, 

447 50.0, 

448 40.0, 

449 50.0, 

450 40.0, 

451 50.0, 

452 50.0, 

453 50.0, 

454 70.0, 

455 80.0, 

456 90.0, 

457 100.0, 

458 ] 

459 ), 

460 atol=TOLERANCE_ABSOLUTE_TESTS, 

461 ) 

462 

463 signal[np.array([0, 1, 2])] = np.array([10, 20, 30]) 

464 np.testing.assert_allclose( 

465 signal.range, 

466 np.array( 

467 [ 

468 10.0, 

469 20.0, 

470 50.0, 

471 30.0, 

472 50.0, 

473 40.0, 

474 50.0, 

475 50.0, 

476 50.0, 

477 70.0, 

478 80.0, 

479 90.0, 

480 100.0, 

481 ] 

482 ), 

483 atol=TOLERANCE_ABSOLUTE_TESTS, 

484 ) 

485 

486 def test__contains__(self) -> None: 

487 """Test :func:`colour.continuous.signal.Signal.__contains__` method.""" 

488 

489 assert 0 in self._signal 

490 assert 0.5 in self._signal 

491 assert 1000 not in self._signal 

492 

493 def test__iter__(self) -> None: 

494 """Test :func:`colour.continuous.signal.Signal.__iter__` method.""" 

495 

496 domain = np.arange(0, 10) 

497 for i, (domain_value, range_value) in enumerate(self._signal): 

498 np.testing.assert_array_equal(domain_value, domain[i]) 

499 np.testing.assert_array_equal(range_value, self._range[i]) 

500 

501 def test__len__(self) -> None: 

502 """Test :func:`colour.continuous.signal.Signal.__len__` method.""" 

503 

504 assert len(self._signal) == 10 

505 

506 def test__eq__(self) -> None: 

507 """Test :func:`colour.continuous.signal.Signal.__eq__` method.""" 

508 

509 signal_1 = self._signal.copy() 

510 signal_2 = self._signal.copy() 

511 

512 assert signal_1 == signal_2 

513 

514 def test__ne__(self) -> None: 

515 """Test :func:`colour.continuous.signal.Signal.__ne__` method.""" 

516 

517 signal_1 = self._signal.copy() 

518 signal_2 = self._signal.copy() 

519 

520 signal_2[0] = 20 

521 assert signal_1 != signal_2 

522 

523 signal_2[0] = 10 

524 assert signal_1 == signal_2 

525 

526 signal_2.interpolator = CubicSplineInterpolator 

527 assert signal_1 != signal_2 

528 

529 signal_2.interpolator = KernelInterpolator 

530 assert signal_1 == signal_2 

531 

532 signal_2.interpolator_kwargs = {"window": 1} 

533 assert signal_1 != signal_2 

534 

535 signal_2.interpolator_kwargs = {} 

536 assert signal_1 == signal_2 

537 

538 class NotExtrapolator(Extrapolator): 

539 """Not :class:`Extrapolator` class.""" 

540 

541 signal_2.extrapolator = NotExtrapolator 

542 assert signal_1 != signal_2 

543 

544 signal_2.extrapolator = Extrapolator 

545 assert signal_1 == signal_2 

546 

547 signal_2.extrapolator_kwargs = {} 

548 assert signal_1 != signal_2 

549 

550 signal_2.extrapolator_kwargs = { 

551 "method": "Constant", 

552 "left": np.nan, 

553 "right": np.nan, 

554 } 

555 assert signal_1 == signal_2 

556 

557 def test_arithmetical_operation(self) -> None: 

558 """ 

559 Test :meth:`colour.continuous.signal.Signal.arithmetical_operation` 

560 method. 

561 """ 

562 

563 np.testing.assert_allclose( 

564 self._signal.arithmetical_operation(10, "+", False).range, 

565 self._range + 10, 

566 atol=TOLERANCE_ABSOLUTE_TESTS, 

567 ) 

568 

569 np.testing.assert_allclose( 

570 self._signal.arithmetical_operation(10, "-", False).range, 

571 self._range - 10, 

572 atol=TOLERANCE_ABSOLUTE_TESTS, 

573 ) 

574 

575 np.testing.assert_allclose( 

576 self._signal.arithmetical_operation(10, "*", False).range, 

577 self._range * 10, 

578 atol=TOLERANCE_ABSOLUTE_TESTS, 

579 ) 

580 

581 np.testing.assert_allclose( 

582 self._signal.arithmetical_operation(10, "/", False).range, 

583 self._range / 10, 

584 atol=TOLERANCE_ABSOLUTE_TESTS, 

585 ) 

586 

587 np.testing.assert_allclose( 

588 self._signal.arithmetical_operation(10, "**", False).range, 

589 self._range**10, 

590 atol=TOLERANCE_ABSOLUTE_TESTS, 

591 ) 

592 

593 np.testing.assert_allclose( 

594 (self._signal + 10).range, 

595 self._range + 10, 

596 atol=TOLERANCE_ABSOLUTE_TESTS, 

597 ) 

598 

599 np.testing.assert_allclose( 

600 (self._signal - 10).range, 

601 self._range - 10, 

602 atol=TOLERANCE_ABSOLUTE_TESTS, 

603 ) 

604 

605 np.testing.assert_allclose( 

606 (self._signal * 10).range, 

607 self._range * 10, 

608 atol=TOLERANCE_ABSOLUTE_TESTS, 

609 ) 

610 

611 np.testing.assert_allclose( 

612 (self._signal / 10).range, 

613 self._range / 10, 

614 atol=TOLERANCE_ABSOLUTE_TESTS, 

615 ) 

616 

617 np.testing.assert_allclose( 

618 (self._signal**10).range, 

619 self._range**10, 

620 atol=TOLERANCE_ABSOLUTE_TESTS, 

621 ) 

622 

623 signal = self._signal.copy() 

624 

625 np.testing.assert_allclose( 

626 signal.arithmetical_operation(10, "+", True).range, 

627 self._range + 10, 

628 atol=TOLERANCE_ABSOLUTE_TESTS, 

629 ) 

630 

631 np.testing.assert_allclose( 

632 signal.arithmetical_operation(10, "-", True).range, 

633 self._range, 

634 atol=TOLERANCE_ABSOLUTE_TESTS, 

635 ) 

636 

637 np.testing.assert_allclose( 

638 signal.arithmetical_operation(10, "*", True).range, 

639 self._range * 10, 

640 atol=TOLERANCE_ABSOLUTE_TESTS, 

641 ) 

642 

643 np.testing.assert_allclose( 

644 signal.arithmetical_operation(10, "/", True).range, 

645 self._range, 

646 atol=TOLERANCE_ABSOLUTE_TESTS, 

647 ) 

648 

649 np.testing.assert_allclose( 

650 signal.arithmetical_operation(10, "**", True).range, 

651 self._range**10, 

652 atol=TOLERANCE_ABSOLUTE_TESTS, 

653 ) 

654 

655 signal = self._signal.copy() 

656 

657 np.testing.assert_allclose( 

658 signal.arithmetical_operation(self._range, "+", False).range, 

659 signal.range + self._range, 

660 atol=TOLERANCE_ABSOLUTE_TESTS, 

661 ) 

662 

663 np.testing.assert_allclose( 

664 signal.arithmetical_operation(signal, "+", False).range, 

665 signal.range + signal.range, 

666 atol=TOLERANCE_ABSOLUTE_TESTS, 

667 ) 

668 

669 def test_is_uniform(self) -> None: 

670 """Test :func:`colour.continuous.signal.Signal.is_uniform` method.""" 

671 

672 assert self._signal.is_uniform() 

673 

674 signal = self._signal.copy() 

675 signal[0.5] = 1.0 

676 assert not signal.is_uniform() 

677 

678 def test_copy(self) -> None: 

679 """Test :func:`colour.continuous.signal.Signal.copy` method.""" 

680 

681 assert self._signal is not self._signal.copy() 

682 assert self._signal == self._signal.copy() 

683 

684 def test_signal_unpack_data(self) -> None: 

685 """ 

686 Test :meth:`colour.continuous.signal.Signal.signal_unpack_data` 

687 method. 

688 """ 

689 

690 domain, range_ = Signal.signal_unpack_data(self._range) 

691 np.testing.assert_array_equal(range_, self._range) 

692 np.testing.assert_array_equal(domain, np.arange(0, 10, 1)) 

693 

694 domain, range_ = Signal.signal_unpack_data(self._range, self._domain) 

695 np.testing.assert_array_equal(range_, self._range) 

696 np.testing.assert_array_equal(domain, self._domain) 

697 

698 domain, range_ = Signal.signal_unpack_data( 

699 self._range, dict(zip(self._domain, self._range, strict=True)).keys() 

700 ) 

701 np.testing.assert_array_equal(domain, self._domain) 

702 

703 domain, range_ = Signal.signal_unpack_data( 

704 dict(zip(self._domain, self._range, strict=True)) 

705 ) 

706 np.testing.assert_array_equal(range_, self._range) 

707 np.testing.assert_array_equal(domain, self._domain) 

708 

709 domain, range_ = Signal.signal_unpack_data(Signal(self._range, self._domain)) 

710 np.testing.assert_array_equal(range_, self._range) 

711 np.testing.assert_array_equal(domain, self._domain) 

712 

713 if is_pandas_installed(): 

714 from pandas import Series # noqa: PLC0415 

715 

716 domain, range_ = Signal.signal_unpack_data( 

717 Series(dict(zip(self._domain, self._range, strict=True))) 

718 ) 

719 np.testing.assert_array_equal(range_, self._range) 

720 np.testing.assert_array_equal(domain, self._domain) 

721 

722 def test_fill_nan(self) -> None: 

723 """Test :func:`colour.continuous.signal.Signal.fill_nan` method.""" 

724 

725 signal = self._signal.copy() 

726 

727 signal[3:7] = np.nan 

728 

729 np.testing.assert_allclose( 

730 signal.fill_nan().range, 

731 np.array([10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0]), 

732 atol=TOLERANCE_ABSOLUTE_TESTS, 

733 ) 

734 

735 signal[3:7] = np.nan 

736 

737 np.testing.assert_allclose( 

738 signal.fill_nan(method="Constant").range, 

739 np.array([10.0, 20.0, 30.0, 0.0, 0.0, 0.0, 0.0, 80.0, 90.0, 100.0]), 

740 atol=TOLERANCE_ABSOLUTE_TESTS, 

741 ) 

742 

743 def test_domain_distance(self) -> None: 

744 """Test :func:`colour.continuous.signal.Signal.domain_distance` method.""" 

745 

746 np.testing.assert_allclose( 

747 self._signal.domain_distance(0.5), 

748 0.5, 

749 atol=TOLERANCE_ABSOLUTE_TESTS, 

750 ) 

751 

752 np.testing.assert_allclose( 

753 self._signal.domain_distance(np.linspace(0, 9, 10) + 0.5), 

754 np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]), 

755 atol=TOLERANCE_ABSOLUTE_TESTS, 

756 ) 

757 

758 def test_to_series(self) -> None: 

759 """Test :func:`colour.continuous.signal.Signal.to_series` method.""" 

760 

761 if is_pandas_installed(): 

762 from pandas import Series # noqa: PLC0415 

763 

764 assert ( 

765 Signal(self._range, self._domain).to_series().all() 

766 == Series(dict(zip(self._domain, self._range, strict=True))).all() 

767 )