Notations et rappels

On considère un espace probabilisé (\Omega, {\mathcal{F}}, \mathbb{P}), composé d’un ensemble \Omega, d’une tribu \mathcal{F}, et d’une mesure de probabilité \mathbb{P}.

Définition 1 (Variable aléatoire)

Soit (E, \mathcal{E}) un espace mesurable. Une variable aléatoire (ou v.a.) est une application mesurable \begin{array}{ccccc} X & : & \Omega & \to & E \\ & & \omega & \mapsto & X(\omega)\,. \end{array} C’est-à-dire que pour tout B \in \mathcal{E}, \{\omega \in \Omega : X(\omega) \in B\} \in \mathcal{F}. Cet ensemble se réécrit souvent sous la forme \begin{align*} \{\omega \in \Omega : X(\omega) \in B\} & = X^{-1}(B) \\ & = \{X \in B\} \, . \end{align*}

Cette définition permet de transposer l’aléa qui provient de \Omega dans l’espace E. L’hypothèse \{X \in B\} \in \mathcal{F} assure que cet ensemble est bien un évènement et donc que l’on peut calculer sa probabilité.

Une fois que l’aléa a été transposé de \Omega vers E, on souhaite également transposer la probabilité \mathbb{P} sur E. Ceci motive l’introduction de la notion de loi.

Définition 2 (Loi d’une variable aléatoire)

Soit X : (\Omega, \mathcal{F}, \mathbb{P}) \to (E, \mathcal{E}) une variable aléatoire. On appelle loi de X la mesure de probabilité \begin{array}{ccccc} \mathbb{P}_X & : & \mathcal{E} & \to & [0,1] \\ & & B & \mapsto & \mathbb{P}(X \in B) \enspace. \end{array}

Les propriétés de \mathbb{P} assurent que \mathbb{P}_X est bien une loi de probabilité sur l’espace mesurable (E, \mathcal{E}).

Loi discrètes

Les variables aléatoires discrètes sont celles à valeurs dans un ensemble E discret, le plus souvent \mathbb{N}, muni de la tribu pleine \mathcal{F} = \mathcal{P}(E).

Exemple 1 (Loi de Bernoulli) La loi la plus simple est la loi de Bernoulli de paramètre p \in [0,1], définie sur \{0,1\} par \mathbb{P}(X=1) = 1-\mathbb{P}(X=0) = p qui modélise une expérience aléatoire à deux issues (succès = 1 et échec = 0).

Exemple 2 (Loi binomiale) En sommant des variables aléatoires indépendantes de loi de Bernoulli on obtient une loi binomiale : \mathbb{P}(X=k) = \binom{n}{k} p^k (1-p)^{n-k}, pour k \in \{0,\ldots,n\}, qui modélise le nombre de succès parmi n lancers.

Exemple 3 (Loi géométrique) En observant le nombre d’expériences nécessaires avant d’obtenir un succès, on obtient une loi géométrique : \mathbb{P}(X=k) = p (1-p)^{k-1}, pour k \geq 1. C’est une loi de probabilité discrète qui décrit le comportement du nombre d’événements se produisant dans un intervalle de temps fixé, si ces événements se produisent avec une fréquence moyenne ou espérance connue, et indépendamment du temps écoulé depuis l’événement précédent (e.g., nombre de clients dans une file d’attente, nombre de mutations dans un gène, etc.).

Exemple 4 (Loi de Poisson) La loi de Poisson de paramètre \lambda > 0 est définie par \mathbb{P}(X=k) = e^{-\lambda} \lambda^k / k!, pour k \in \mathbb{N}

Lois continues

Parmi les variables aléatoires réelles non discrètes, beaucoup peuvent se représenter avec une densité, c’est-à-dire qu’il existe une fonction mesurable f : \mathbb{R} \to [0, \infty[ d’intégrale 1. La loi d’une telle variable aléatoire X est alors donnée pour tout A \in \mathcal{B}(\mathbb{R}) par \mathbb{P}(X \in A) = \int_A f(x) \, \mathrm d x \enspace. Les propriétés de l’intégrale de Lebesgue assure que cette formule définit bien une loi de probabilité.

Exemple 5 (Loi uniforme) La loi uniforme sur un ensemble B \in \mathcal{B}(\mathbb{R}), s’obtient avec la densité définie par f(x) = {1\hspace{-3.8pt} 1}_B(x) / \lambda (B) \enspace, \lambda (B) représente la mesure de Lebesgue de l’ensemble B. En particulier pour la loi uniforme sur le segment [0,1] on obtient la fonction suivante: f(x) = {1\hspace{-3.8pt} 1}_{[0,1]}(x)\enspace. Si une variable aléatoire U suit une telle loi on note U \sim \mathcal{U}([0,1]).

Exemple 6 (Loi exponentielle) La loi exponentielle de paramètre \gamma > 0 est obtenue avec la densité donnée par f(x) = \gamma e^{-\gamma x} {1\hspace{-3.8pt} 1}_{\mathbb{R}_+}(x)\enspace. Si une variable aléatoire X suit cette loi on note X \sim \mathcal{Exp}(\gamma).

Exemple 7 (Loi normale/gaussienne univariée) On obtient la loi normale de paramètre \mu \in \mathbb{R} et \sigma^2 > 0 correspond à loi dont la densité est donnée par la fonction réelle: f(x) = \frac{1}{\sqrt{2 \pi} \sigma}e^{-\frac{1}{2 \sigma^2}(x-\mu)^2} \enspace. Si une variable aléatoire X suit une telle loi on note X \sim \mathcal{N}(\mu,\sigma^2), \mu correspondant à l’espérance de la loi, et \sigma^2 à sa variance. On nomme loi normale centrée réduite le cas correspondant à \mu = 0 et \sigma^2 = 1.

Exemple 8 (Loi normale multivariée) On peut étendre les lois normales au cas multi-dimensionnel. Fixons d\in\mathbb{N}^* un entier non nul. Pour un vecteur \mu \in \mathbb{R}^d et une matrice symétrique-définie positive \Sigma\in \mathbb{R^{d\times d}}, la densité normale mutlivariée associée est donnée par la fonction: f(x) = \frac{1}{{(2 \pi)}^{\frac{d}{2}} {\mathrm det}(\Sigma)} e^{-\frac{1}{2}(x-\mu)^\top \Sigma ^{-1}(x-\mu)} Notons que \mu est l’espérance de la loi et \Sigma la matrice de variance-covariance.

Fonction de répartition

La notion de variable aléatoire n’est pas facile à manipuler puisqu’elle part d’un espace \Omega dont on ne sait rien. On souhaite donc caractériser la loi d’une variable aléatoire en ne considérant que l’espace d’arrivée (E, \mathcal{E}) .

Plusieurs outils existent : la fonction de répartition (pour des variables aléatoires réelles), la fonction caractéristique (pour des variables aléatoires dans \mathbb{R}^d), la fonction génératrice des moments (pour des variables aléatoires discrètes), etc. On se contente ici de la fonction de répartition qui nous sera utile pour simuler des variables aléatoires, ainsi que son inverse au sens de Levy.

Définition 3 (Fonction de répartition 🇬🇧: cumulative distribution function)

Soit X une variable aléatoire sur (\mathbb{R}, \mathcal{B}(\mathbb{R})). La fonction de répartition de X est la fonction F_X définie sur \mathbb{R} par \begin{align*} F_X(x) & = \mathbb{P}(X \leq x)\\ & = \mathbb{P}(X \in ]-\infty, x]) \enspace. \end{align*}

Exemple 9 (Cas discret) Soit (x_i)_{i \in I} une suite ordonnée de réels, avec I \subset \mathbb{N}. Si X est une variable aléatoire discrète prenant les valeurs (x_i)_{i \in I} et de loi (p_i = \mathbb{P}(X=x_i))_{i \in I}, alors F_X(x) = \sum_{i \in I} p_i {1\hspace{-3.8pt} 1}_{[x_i, \infty[}(x) \enspace.

Exemple 10 (Cas continu) Si X est une variable aléatoire de densité f, alors F_X(x) = \int_{-\infty}^x f(t) \, \mathrm dt \enspace.

Le graphe des fonctions de répartition des loi de Bernoulli, uniforme et normale sont représentées dans le widget ci-dessous. Notons que la fonction de répartition de la loi normale \mathcal{N}(0,1), souvent notée \Phi, n’admet pas d’expression explicite autre que \Phi(x) = \dfrac{1}{\sqrt{2\pi}} \int_{-\infty}^x e^{-\frac{t^2}{2}}\, \mathrm d t\enspace, Les valeurs numériques de \Phi(x) étaient autrefois reportées dans des tables1. Par transformation affine, si X \sim \mathcal{N}(\mu, \sigma^2) — ce que l’on peut aussi écrire : X=\mu + \sigma Y, avec Y\sim \mathcal{N}(0,1) — alors sa fonction de répartition est donnée par F_X(x)=\Phi((x-\mu)/\sigma).

Proposition 1 (Propriétés de la fonction de répartition) Soit X une variable aléatoire de fonction de répartition F_X.

  1. F_X est une fonction croissante, de limite 0 en -\infty et de limite 1 en +\infty.
  2. F_X est continue à droite en tout point.
  3. Pour tout x \in \mathbb{R}, on a \mathbb{P}(X=x) = F_X(x) - F_X(x-), où F_X(x-) = \lim_{\epsilon \to 0+} F_X(x- \epsilon).
  4. Si X a pour densité f, alors F_X est dérivable \lambda-presque partout de dérivée f.

Pour les démonstrations, voir par exemple [@Barbe_Ledoux06].

La propriété 3. est utile dans le cas discret : les valeurs prises par X correspondent aux points de discontinuité de F_X et les probabilités associées correspondent à la hauteur du saut.

La propriété 4. donne le lien entre la fonction de répartition d’une variable aléatoire à densité et sa densité. On peut donc retrouver la loi de X à partir de sa fonction de répartition. Le théorème suivant généralise ce résultat à toute variable aléatoire réelle (pas nécessairement discrète ou à densité).

Théorème 1 (Caractérisation de la loi d’une variable aléatoire réelle) La fonction de répartition d’une variable aléatoire caractérise sa loi : deux variables aléatoires ont même loi si et seulement si elles ont même fonction de répartition.

Démonstration: voir Wikipedia

On rappelle que la tribu des boréliens est engendrée par la famille d’ensembles \{]-\infty,x], x \in \mathbb{R}\}. Le théorème précédent assure que si on connaît la mesure \mathbb{P}_X sur cette famille d’ensembles alors on la connaît partout.

Exemple 11 (Loi exponentielle depuis une loi uniforme) On considère une variable aléatoire U de loi uniforme sur [0,1] et on pose X = -\ln(1-U). Déterminons la loi de X en calculant sa fonction de répartition. Pour tout x \in \mathbb{R}, \begin{align*} F_X(x) = & \mathbb{P}(X \leq x) \\ = & \mathbb{P}(-\ln(1-U) \leq x) \\ = & \mathbb{P}(U \leq 1-e^{-x}) \\ = & \begin{cases} 0 & \text{ si }x < 0\,, \\ 1 - e^{-x} & \text{ si }x \geq 0\,, \end{cases} \end{align*} où on a utilisé l’égalité \mathbb{P}(U \leq t) = t pour tout t \in [0,1]. Ainsi la variable aléatoire X a la même fonction de répartition qu’une loi exponentielle de paramètre 1. On en conclut que X \sim \mathcal{Exp}(1). Notons que l’on peut aussi montrer que -\ln(X)\sim\mathcal{E}(1), sachant que U et 1-U ont la même loi.

Fonction quantile, inverse généralisée à gauche

La fonction de répartition étant une fonction croissante on peut donner un sens à son inverse généralisée de la manière suivante.

Définition 4 (Fonction quantile/ inverse généralisée 🇬🇧: quantile distribution function)

Soit X une variable aléatoire sur (\mathbb{R}, \mathcal{B}(\mathbb{R})) et F_X sa fonction de répartition. La fonction quantile associée F_X^\leftarrow: ]0,1[ \rightarrow \mathbb{R} est définie par F_X^\leftarrow(p)= \inf\{ x \in \mathbb{R} \colon F_X(x)\geq p\} \enspace.

On parle parfois aussi d’inverse au sens de Levy pour cette inverse généralisée.

Dans le cas où la fonction de répartition F_X est bijective, alors l’inverse de la fonction de répartition coincide avec la fonction quantile.

La médiane est égale à F_X^\leftarrow(1/2), les premiers et troisièmes quartiles sont égaux à F_X^\leftarrow(1/4) et F_X^\leftarrow(3/4). Enfin, les déciles sont les quantiles F_X^\leftarrow(k/10) pour k=1,\dots, 9.

Visualisation: densité, fonction de répartition, quantiles, etc.

Cas des variables continues

#| standalone: true
#| viewerHeight: 830
import numpy as np
from scipy import stats
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from shiny import ui, render, App
from shinywidgets import output_widget, render_widget


def keep_no_param_distribution():
    distributions = stats._continuous_distns._distn_names
    distributions_0 = []
    for _, name in enumerate(distributions):
        dist = getattr(stats, name)
        if not dist.shapes or len(dist.shapes) == 0:
            distributions_0.append(name)
    distributions_0_val = [
        getattr(stats.distributions, string) for string in distributions_0
    ]
    distributions_0_dict = dict(zip(distributions_0, distributions_0_val))
    return distributions_0_dict


distributions_0_dict = keep_no_param_distribution()

mu = 0
sigma = 1

app_ui = ui.page_fluid(
    ui.div(
        ui.input_slider("alpha", "Quantile", 0.01, 0.99, value=0.5, step=0.01),
        ui.input_slider("xrange", "x-range", -10, 10, value=(-5, 5), step=0.2),
        ui.input_select(
            "distrib",
            "Distribution",
            list(distributions_0_dict.keys()),
            selected='norm'
        ),
        class_="d-flex gap-3",
    ),
    output_widget("my_widget"),
)


def server(input, output, session):
    @output
    @render_widget
    def my_widget():
        fig = make_subplots(
            rows=3,
            cols=2,
            vertical_spacing=0.1,
            horizontal_spacing=0.15,
            subplot_titles=(
                "Fonction quantile",
                "",
                "",
                "Fonction de répartition",
                "",
                "Densité et quantile",
            ),
            column_widths=[0.2, 0.5],
            row_heights=[0.35, 0.17, 0.17],
        )

        alpha = input.alpha()
        distribution = distributions_0_dict[input.distrib()]
        x = np.linspace(input.xrange()[0], input.xrange()[1], num=400)
        cdf_data = distribution.cdf(x, loc=mu, scale=sigma)
        pdf_data = distribution.pdf(x, loc=mu, scale=sigma)
        q_alpha = distribution.ppf(alpha, loc=mu, scale=sigma)

        fig.update_layout(autosize=True, height=700)

        # Quantile plot
        fig.add_trace(
            go.Scatter(
                x=cdf_data, y=x, mode="lines", marker={"color": "black"}
            ),
            row=1,
            col=1,
        )
        # Diagonal
        fig.add_trace(
            go.Scatter(
                x=cdf_data, y=cdf_data, mode="lines", marker={"color": "black"}
            ),
            row=2,
            col=1,
        )
        # Cdf part
        fig.add_trace(
            go.Scatter(
                x=x, y=cdf_data, mode="lines", marker={"color": "black"}
            ),
            row=2,
            col=2,
        )
        # pdf part
        fig.add_scatter(
            x=x[x < q_alpha],
            y=pdf_data[x < q_alpha],
            fill="tozeroy",
            mode="none",
            fillcolor="rgb(66, 139, 202)",
            row=3,
            col=2,
        )

        fig.add_trace(
            go.Scatter(
                x=x, y=pdf_data, mode="lines", marker={"color": "black"}
            ),
            row=3,
            col=2,
        )

        # Dots
        fig.add_trace(
            go.Scatter(
                x=[alpha],
                y=[q_alpha],
                mode="markers",
                marker={"color": "rgb(66, 139, 202)"},
                marker_symbol="x",
                marker_size=8,
            ),
            row=1,
            col=1,
        )

        fig.add_trace(
            go.Scatter(
                x=[alpha],
                y=[alpha],
                mode="markers",
                marker={"color": "rgb(66, 139, 202)"},
                marker_symbol="x",
                marker_size=8,
            ),
            row=2,
            col=1,
        )

        fig.add_trace(
            go.Scatter(
                x=[q_alpha],
                y=[alpha],
                mode="markers",
                marker={"color": "rgb(66, 139, 202)"},
                marker_symbol="x",
                marker_size=8,
            ),
            row=2,
            col=2,
        )

        # Lines
        fig.add_trace(
            go.Scatter(
                x=[alpha, alpha],
                y=[x[0], q_alpha],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=1,
            col=1
        )

        fig.add_trace(
            go.Scatter(
                x=[alpha, alpha],
                y=[alpha, 1.],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=2,
            col=1
        )
        fig.add_trace(
            go.Scatter(
                x=[alpha, 1],
                y=[alpha, alpha],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=2,
            col=1
        )
        fig.add_trace(
            go.Scatter(
                x=[x[0], q_alpha],
                y=[alpha, alpha],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=2,
            col=2
        )
        fig.add_trace(
            go.Scatter(
                x=[x[0], q_alpha],
                y=[x[0], 0],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=2,
            col=2
        )
        # Axes ranges
        fig.update_xaxes(range=[0, 1.], row=1, col=1)
        fig.update_yaxes(matches="x6", row=1, col=1)

        fig.update_yaxes(range=[0, 1.], row=2, col=1)
        fig.update_xaxes(matches="x1", row=2, col=1)

        fig.update_yaxes(rangemode="tozero", row=3, col=2)
        fig.update_xaxes(range=[x[0], x[-1]], row=3, col=2)

        fig.update_xaxes(matches="x6", row=2, col=2)
        fig.update_yaxes(matches="y3", row=2, col=2)

        # Add dropdown
        fig.update_layout(
            showlegend=False,
            template="simple_white",
        )
        return fig


app = App(app_ui, server)

Cas des variables discrètes

#| standalone: true
#| viewerHeight: 830
import numpy as np
from scipy import stats
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from shiny import ui, render, App
from shinywidgets import output_widget, render_widget


def keep_no_param_distribution_disc():
    distributions = stats._discrete_distns._distn_names
    distributions_0 = [name for name in distributions if not getattr(stats, name).shapes or len(getattr(stats, name).shapes) in [1, 2]]
    distributions_0_val = [getattr(stats.distributions, string) for string in distributions_0]
    distributions_0_dict = dict(zip(distributions_0, distributions_0_val))
    return distributions_0_dict

def cdf_tool(x, dtype='int64'):
    y = np.zeros(2*(len(x)), dtype=dtype)
    y[::2]=x
    y[1::2]=x
    return y[1::], y[:-1], y

def pmf_tool(x, dtype='int64'):
    y = np.zeros(2*(len(x)), dtype=dtype)
    y[::2]=x
    return y[1::], y[:-1], y

def insert_nones(my_list):
    for i, val in enumerate(my_list):
        if i % 3 == 2:
            my_list.insert(i, None)
    return my_list

distributions_0_dict = keep_no_param_distribution_disc()

app_ui = ui.page_fluid(
    ui.div(
        ui.input_slider("alpha", "Quantile", 0.01, 0.99, value=0.5, step=0.01),
        ui.input_slider("xrange", "x-range", -10, 10, value=(-5.5, 5.5), step=0.2),
        ui.input_select(
            "distrib",
            "Distribution",
            list(distributions_0_dict.keys()),
            selected='poisson'
        ),
        class_="d-flex gap-3",
    ),
    output_widget("my_widget"),
)


def server(input, output, session):
    @output
    @render_widget
    def my_widget():
        fig = make_subplots(
            rows=3,
            cols=2,
            vertical_spacing=0.1,
            horizontal_spacing=0.15,
            subplot_titles=(
                "Fonction quantile",
                "",
                "",
                "Fonction de répartition",
                "",
                "Fonction de masse et quantile",
            ),
            column_widths=[0.2, 0.5],
            row_heights=[0.35, 0.17, 0.17],
        )


        alpha = input.alpha()
        # alpha=0.5

        mu = 0.5  # Param needed for some distribution
        if input.distrib()=='zipf':
            mu = 2
        distribution = distributions_0_dict[input.distrib()]
        # distribution=distributions_0_dict['poisson']
        x = np.arange(np.floor(input.xrange()[0]), np.ceil(input.xrange()[1]))
        # x = np.arange(np.floor(-5.5), np.ceil(5.5))

        cdf_data = distribution.cdf(x, mu)
        pmf_data = distribution.pmf(x, mu)
        q_alpha = distribution.ppf(alpha, mu)
        support = pmf_data.nonzero()[0]
        fig.update_layout(autosize=True, height=700)

        # Quantile plot
        new_x, new_y, new_z = cdf_tool(support)
        _, _, new_pmf = pmf_tool(support)

        fig.add_trace(
            go.Scatter(
                x=insert_nones(list(np.append(cdf_data[new_y[::-1]], distribution.cdf(x[0], mu)))),
                y=insert_nones(list(np.append(x[new_x[::-1]], x[new_x[0]]))),
                mode="lines",
                line=dict(color="black")
            ),
            row=1,
            col=1,
        )
        fig.add_trace(
             go.Scatter(
                x=cdf_data[support], y=x[support],
                mode="markers", marker={"color": "black"}
            ),
            row=1,
            col=1,
        )
        # Diagonal
        fig.add_trace(
            go.Scatter(
                x=cdf_data, y=cdf_data, mode="lines", marker={"color": "black"}
            ),
            row=2,
            col=1,
        )
        # Cdf part
        fig.add_trace(
            go.Scatter(
                x=x[support], y=cdf_data[support],
                mode="markers", marker={"color": "black"}
            ),
            row=2,
            col=2,
        )
        fig.add_trace(
            go.Scatter(
                x=insert_nones(list(np.append(np.insert(x[new_x], 0, [x[0], x[new_x[0]]]),x[-1]))),
                y=insert_nones(list(np.append(np.insert(cdf_data[new_y], 0, [0,0]), cdf_data[-1]))),
                mode="lines",
                line=dict(color="black")
            ),
            row=2,
            col=2
        )

        fig.add_trace(
            go.Scatter(
                x=x, y=pmf_data, mode="markers", marker={"color": "black"}
            ),
            row=3,
            col=2,
        )
        fig.add_trace(
            go.Scatter(
                x=x, y=pmf_data, mode="markers", marker={"color": "black"}
            ),
            row=3,
            col=2,
        )
        x_bar = insert_nones(list(x[new_z]))
        y_bar = insert_nones(list(pmf_data[new_pmf]))
        fig.add_trace(
            go.Scatter(
                x=x_bar,
                y=y_bar,
                mode="lines",
                line=dict(color="black")
            ),
            row=3,
            col=2
        )
        _,_, devil_x = cdf_tool(x[x<=q_alpha])
        _,_, devil_y = cdf_tool(pmf_data[x<q_alpha], dtype='float64')

        x_bar_blue = insert_nones(list(devil_x))
        y_bar_blue = np.array(insert_nones(list(devil_y)))
        y_bar_blue[::-3]=0.
        y_bar_blue = list(y_bar_blue)
        fig.add_trace(
            go.Scatter(
                x=x_bar_blue,
                y=y_bar_blue,
                mode="lines",
                line=dict(color="rgb(66, 139, 202)")
            ),
            row=3,
            col=2
        )
        # pdf part
        fig.add_scatter(
            x=x[x <= q_alpha],
            y=pmf_data[x <= q_alpha],
            mode="markers",
            marker={"color":"rgb(66, 139, 202)"},
            row=3,
            col=2,
        )

        # Dots
        fig.add_trace(
            go.Scatter(
                x=[alpha],
                y=[q_alpha],
                mode="markers",
                marker={"color": "rgb(66, 139, 202)"},
                marker_symbol="x",
                marker_size=8,
            ),
            row=1,
            col=1,
        )

        fig.add_trace(
            go.Scatter(
                x=[alpha],
                y=[alpha],
                mode="markers",
                marker={"color": "rgb(66, 139, 202)"},
                marker_symbol="x",
                marker_size=8,
            ),
            row=2,
            col=1,
        )

        fig.add_trace(
            go.Scatter(
                x=[q_alpha],
                y=[alpha],
                mode="markers",
                marker={"color": "rgb(66, 139, 202)"},
                marker_symbol="x",
                marker_size=8,
            ),
            row=2,
            col=2,
        )

        # Lines
        fig.add_trace(
            go.Scatter(
                x=[alpha, alpha],
                y=[x[0], q_alpha],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=1,
            col=1
        )

        fig.add_trace(
            go.Scatter(
                x=[alpha, alpha],
                y=[alpha, 1.],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=2,
            col=1
        )
        fig.add_trace(
            go.Scatter(
                x=[alpha, 1],
                y=[alpha, alpha],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=2,
            col=1
        )
        fig.add_trace(
            go.Scatter(
                x=[x[0], q_alpha],
                y=[alpha, alpha],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=2,
            col=2
        )
        fig.add_trace(
            go.Scatter(
                x=[x[0], q_alpha],
                y=[x[0], 0],
                mode="lines",
                line=dict(dash="dash", color="rgb(66, 139, 202)")
            ),
            row=2,
            col=2
        )
        # Axes ranges
        fig.update_xaxes(range=[0, 1.05], row=1, col=1)
        fig.update_yaxes(matches="x6", row=1, col=1)

        fig.update_yaxes(range=[0, 1.05], row=2, col=1)
        fig.update_xaxes(matches="x1", row=2, col=1)

        fig.update_yaxes(rangemode="tozero", row=3, col=2)
        fig.update_xaxes(range=[x[0], x[-1]], row=3, col=2)

        fig.update_xaxes(matches="x6", row=2, col=2)
        fig.update_yaxes(matches="y3", row=2, col=2)

        # Add dropdown
        fig.update_layout(
            showlegend=False,
            template="simple_white",
        )
        return fig


app = App(app_ui, server)
Retour au sommet