.. SPDX-FileCopyrightText: Copyright © 2025 Idiap Research Institute .. .. SPDX-License-Identifier: GPL-3.0-or-later .. _fairical.usage.api: ============= API Example ============= By directly accessing the :ref:`Fairical Python API ` you may use functionality functionality of the library. For example, all :ref:`fairical.cli` provide a comprehensive correspondence in API, including further customisation parameters. You will find below the equivalent :ref:`fairical.usage.cli` directly using the available API. .. note:: See :ref:`fairical.usage.cli` for obtaining sample data for this example. .. testsetup:: api import os os.chdir("doc/usage/_static") 1. **Generate solutions or operating modes**: .. testcode:: api import numpy import fairical.scores thresholds = list(numpy.linspace(0, 1, 10, dtype=float)) metrics = ["acc", "eod+gender"] scores1 = fairical.scores.Scores.load("sample/system_1.json") scores2 = fairical.scores.Scores.load("sample/system_2.json") sol1 = scores1.solutions_a_posteriori(metrics, thresholds).deduplicate() sol2 = scores2.solutions_a_posteriori(metrics, thresholds).deduplicate() .. note:: **Computing a-priori solutions** To compute a-priori solutions, just pass the solutions calculated a previous step. For example, to apply operating models from ``sol2`` on ``scores1`` above, just do: .. testcode:: api import pathlib metrics = list(sol2.points.keys()) # apply all operating modes @system_2.json to scores of system_1.json sol1_a_priori = scores1.solutions_a_priori(metrics, sol2).deduplicate() # apply only non-dominated solutions sol1_a_priori = scores1.solutions_a_priori(metrics, sol2, dominated=False).deduplicate() # apply only dominated solutions sol1_a_priori = scores1.solutions_a_priori(metrics, sol2, dominated=True).deduplicate() # record prior solutions filename on metadata (just for informational purposes) sol1_a_priori.metadata["prior-solution-from"] = "sample/system_2.json" .. note:: **Save/load data** It's possible to save (or load) the solutions directly to (from) a JSON representation (see :ref:`fairical.usage.io.solutions`). .. testcode:: api import pathlib import tempfile with tempfile.TemporaryDirectory() as p: sol1.save(pathlib.Path(p) / "system_1.json") sol2.save(pathlib.Path(p) / "system_2.json") To save the non-dominated solutions: .. testcode:: api import pathlib import tempfile nds, _ = sol1.non_dominated_solutions() with tempfile.TemporaryDirectory() as p: nds.save(pathlib.Path(p) / "system_1_nds.json") 2. **Evaluate indicators** (of estimated Pareto front - non-dominated solutions), print table and radar chart: .. testcode:: api import fairical.utils ind1 = sol1.indicators() ind2 = sol2.indicators() indicators = {"system 1": ind1, "system 2": ind2} table = fairical.utils.make_table(indicators, fmt="simple") print(table) .. testoutput:: api System RELATIVE-ONVG ONVGR UD AS HV Area -------- --------------- ------- ---- ---- ---- ------ system 1 1.00 0.33 0.66 0.15 0.70 0.29 system 2 0.85 0.08 0.56 0.13 0.74 0.18 To plot a graphical representation of this table, do the following: .. testcode:: api import fairical.plot fig, ax = fairical.plot.radar_chart(indicators) fig.savefig("radar.pdf") This code should generate a plot like the following: .. image:: img/radar.svg :width: 80% :align: center :alt: Simple radar chart in SVG format 3. **Visualize the Pareto front (estimate)**: .. testcode:: api nds_ds = { "system 1": sol1.non_dominated_solutions(), "system 2": sol2.non_dominated_solutions() } for label, (nds, _) in nds_ds.items(): table = nds.tabulate() print(f"Pareto front for {label}") print(table) fig, ax = fairical.plot.pareto_plot(nds_ds) fig.savefig("pareto.pdf") .. testoutput:: api :hide: Pareto front for system 1 (acc, eod+gender) thresholds identifiers ------------------------------------------ ------------ ------------- (0.5433333333333333, 0.0) 0 model-1 (0.5811111111111111, 0.05247311827956991) 0.333333 model-1 (0.6811111111111111, 0.10530303030303034) 0.444444 model-1 (0.7166666666666667, 0.12055555555555564) 0.555556 model-1 (0.5555555555555556, 0.02898989898989901) 0.333333 model-2 (0.7122222222222222, 0.11530303030303035) 0.555556 model-3 (0.6377777777777778, 0.07464646464646463) 0.444444 model-4 (0.6211111111111111, 0.06752688172043009) 0.444444 model-5 (0.6877777777777778, 0.1123737373737374) 0.555556 model-5 (0.5788888888888889, 0.04989247311827949) 0.444444 model-6 (0.6777777777777778, 0.09000000000000002) 0.555556 model-6 (0.5488888888888889, 0.027383512544802868) 0.444444 model-7 (0.6022222222222222, 0.059292929292929286) 0.555556 model-8 Pareto front for system 2 (acc, eod+gender) thresholds identifiers ------------------------------------------ ------------ ------------- (0.5433333333333333, 0.0) 0 model-1 (0.7277777777777777, 0.04671717171717171) 0.333333 model-1 (0.5444444444444444, 0.004444444444444473) 0.111111 model-6 (0.7422222222222222, 0.05464646464646472) 0.444444 model-6 (0.6711111111111111, 0.033333333333333326) 0.333333 model-8 (0.6577777777777778, 0.024595959595959616) 0.333333 model-9 (0.56, 0.011254480286738366) 0.333333 model-16 (0.6588888888888889, 0.031010101010101043) 0.444444 model-19 (0.6322222222222222, 0.02111111111111119) 0.444444 model-20 (0.5922222222222222, 0.014838709677419404) 0.444444 model-21 (0.5533333333333333, 0.008888888888888835) 0.444444 model-22 This code should generate the following tables in the terminal ========================================== ========== =========== (acc, eod+gender) thresholds identifiers ========================================== ========== =========== (0.5433333333333333, 0.0) 0 model-1 (0.5811111111111111, 0.05247311827956991) 0.333333 model-1 (0.6811111111111111, 0.10530303030303034) 0.444444 model-1 (0.7166666666666667, 0.12055555555555564) 0.555556 model-1 (0.5555555555555556, 0.02898989898989901) 0.333333 model-2 (0.7122222222222222, 0.11530303030303035) 0.555556 model-3 (0.6377777777777778, 0.07464646464646463) 0.444444 model-4 (0.6211111111111111, 0.06752688172043009) 0.444444 model-5 (0.6877777777777778, 0.1123737373737374) 0.555556 model-5 (0.5788888888888889, 0.04989247311827949) 0.444444 model-6 (0.6777777777777778, 0.09000000000000002) 0.555556 model-6 (0.5488888888888889, 0.027383512544802868) 0.444444 model-7 (0.6022222222222222, 0.059292929292929286) 0.555556 model-8 ========================================== ========== =========== ========================================== ========== =========== (acc, eod+gender) thresholds identifiers ========================================== ========== =========== (0.5433333333333333, 0.0) 0 model-1 (0.7277777777777777, 0.04671717171717171) 0.333333 model-1 (0.5444444444444444, 0.004444444444444473) 0.111111 model-6 (0.7422222222222222, 0.05464646464646472) 0.444444 model-6 (0.6711111111111111, 0.033333333333333326) 0.333333 model-8 (0.6577777777777778, 0.024595959595959616) 0.333333 model-9 (0.56, 0.011254480286738366) 0.333333 model-16 (0.6588888888888889, 0.031010101010101043) 0.444444 model-19 (0.6322222222222222, 0.02111111111111119) 0.444444 model-20 (0.5922222222222222, 0.014838709677419404) 0.444444 model-21 (0.5533333333333333, 0.008888888888888835) 0.444444 model-22 ========================================== ========== =========== and save the following plot: .. image:: img/pareto.svg :width: 80% :align: center :alt: Simple pareto plot in SVG format .. testcleanup:: api os.chdir("../../..")