├── charts
├── dirichlet.png
├── unit_disc.svg
├── unit_circle.svg
├── exponential_exp1.svg
├── bernoulli.svg
└── standard_normal.svg
├── requirements.txt
├── src
├── distributions
│ ├── exponential_exp1.py
│ ├── standard_normal.py
│ ├── exponential.py
│ ├── cauchy.py
│ ├── normal.py
│ ├── gumbel.py
│ ├── pareto.py
│ ├── student_t.py
│ ├── log_normal.py
│ ├── skew_normal.py
│ ├── inverse_gaussian.py
│ ├── standard_geometric.py
│ ├── zeta.py
│ ├── beta.py
│ ├── chi_squared.py
│ ├── zipf.py
│ ├── gamma.py
│ ├── fisher_f.py
│ ├── normal_inverse_gaussian.py
│ ├── poisson.py
│ ├── binomial.py
│ ├── triangular.py
│ ├── frechet.py
│ ├── weibull.py
│ ├── hypergeometric.py
│ ├── unit_disc.py
│ ├── unit_circle.py
│ ├── bernoulli.py
│ ├── geometric.py
│ ├── unit_sphere.py
│ ├── unit_ball.py
│ ├── pert.py
│ └── dirichlet.py
└── main.py
├── .gitignore
└── LICENSE
/charts/dirichlet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-random/charts/main/charts/dirichlet.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy==1.26.4
2 | matplotlib==3.8.4
3 | scipy==1.13.0
4 | python-ternary==1.0.8
--------------------------------------------------------------------------------
/src/distributions/exponential_exp1.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import expon
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Fixed value for lambda
8 | lmbda = 1
9 | # Possible values for the distribution
10 | x = np.linspace(0, 5, 1000)
11 |
12 | # Creating the figure and the axis
13 | fig, ax = plt.subplots()
14 |
15 | # Plotting the PDF for each value of lambda
16 | ax.plot(x, expon.pdf(x, scale=1 / lmbda), label=f'λ = {lmbda}')
17 |
18 | # Adding title and labels
19 | ax.set_title('Exponential distribution')
20 | ax.set_xlabel('x')
21 | ax.set_ylabel('Probability density')
22 |
23 | # Adding a legend
24 | ax.legend()
25 | ax.grid()
26 | ax.margins(x=0, y=0)
27 |
28 | plt.savefig(f"{directory}/exponential_exp1.{extension}")
29 | plt.close()
30 |
--------------------------------------------------------------------------------
/src/distributions/standard_normal.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import norm
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Possible values for the distribution
8 | x = np.linspace(-5, 5, 1000)
9 |
10 | # Creating the figure and the axis
11 | fig, ax = plt.subplots()
12 |
13 | # Plotting the PDF for the standard normal distribution
14 | ax.plot(x, norm.pdf(x), label=f'μ = 0, σ = 1')
15 |
16 | # Adding title and labels
17 | ax.set_title('Standard normal distribution')
18 | ax.set_xlabel('x')
19 | ax.set_ylabel('Probability density')
20 |
21 | # Adding a legend
22 | ax.legend()
23 | ax.grid()
24 | ax.margins(x=0, y=0)
25 | ymin, ymax = ax.get_ylim()
26 | ax.set_ylim(ymin, ymax * 1.05)
27 |
28 | plt.savefig(f"{directory}/standard_normal.{extension}")
29 | plt.close()
30 |
--------------------------------------------------------------------------------
/src/distributions/exponential.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import expon
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Possible values of lambda for the distribution
8 | lambda_values = [1, 0.5, 2]
9 | # Possible values for the distribution
10 | x = np.linspace(0, 5, 1000)
11 |
12 | # Creating the figure and the axis
13 | fig, ax = plt.subplots()
14 |
15 | # Plotting the PDF for each value of lambda
16 | for lmbda in lambda_values:
17 | ax.plot(x, expon.pdf(x, scale=1 / lmbda), label=f'λ = {lmbda}')
18 |
19 | # Adding title and labels
20 | ax.set_title('Exponential distribution')
21 | ax.set_xlabel('x')
22 | ax.set_ylabel('Probability density')
23 |
24 | # Adding a legend
25 | ax.legend()
26 | ax.grid()
27 | ax.margins(x=0, y=0)
28 |
29 | plt.savefig(f"{directory}/exponential.{extension}")
30 | plt.close()
31 |
--------------------------------------------------------------------------------
/src/distributions/cauchy.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 |
4 |
5 | def save_to(directory: str, extension: str):
6 | # Possible values for the distribution
7 | x = np.linspace(-7, 7, 1000)
8 |
9 | # Creating the figure and the axis
10 | fig, ax = plt.subplots()
11 |
12 | inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)]
13 |
14 | # Plotting the PDF for the Cauchy distribution
15 | for x0, gamma in inputs:
16 | ax.plot(x, 1 / (np.pi * gamma * (1 + ((x - x0) / gamma)**2)), label=f'x₀ = {x0}, γ = {gamma}')
17 |
18 | # Adding title and labels
19 | ax.set_title('Cauchy distribution')
20 | ax.set_xlabel('x')
21 | ax.set_ylabel('Probability density')
22 |
23 | # Adding a legend
24 | ax.legend()
25 | ax.grid()
26 | ax.margins(x=0, y=0)
27 | ymin, ymax = ax.get_ylim()
28 | ax.set_ylim(ymin, ymax * 1.05)
29 |
30 | plt.savefig(f"{directory}/cauchy.{extension}")
31 | plt.close()
32 |
--------------------------------------------------------------------------------
/src/distributions/normal.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import norm
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)]
8 | # Possible values for the distribution
9 | x = np.linspace(-5, 5, 1000)
10 |
11 | # Creating the figure and the axis
12 | fig, ax = plt.subplots()
13 |
14 | # Plotting the PDF for each value of mu and sigma
15 | for mu, sigma in inputs:
16 | ax.plot(x, norm.pdf(x, loc=mu, scale=sigma), label=f'μ = {mu}, σ = {sigma}')
17 |
18 | # Adding title and labels
19 | ax.set_title('Normal distribution')
20 | ax.set_xlabel('x')
21 | ax.set_ylabel('Probability density')
22 |
23 | # Adding a legend
24 | ax.legend()
25 | ax.grid()
26 | ax.margins(x=0, y=0)
27 | ymin, ymax = ax.get_ylim()
28 | ax.set_ylim(ymin, ymax * 1.05)
29 |
30 | plt.savefig(f"{directory}/normal.{extension}")
31 | plt.close()
32 |
--------------------------------------------------------------------------------
/src/distributions/gumbel.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import gumbel_r
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)]
8 | # Possible values for the distribution
9 | x = np.linspace(-5, 5, 1000)
10 |
11 | # Creating the figure and the axis
12 | fig, ax = plt.subplots()
13 |
14 | # Plotting the PDF for each value of mu and beta
15 | for mu, beta in inputs:
16 | ax.plot(x, gumbel_r.pdf(x, loc=mu, scale=beta), label=f'μ = {mu}, β = {beta}')
17 |
18 | # Adding title and labels
19 | ax.set_title('Gumbel distribution')
20 | ax.set_xlabel('x')
21 | ax.set_ylabel('Probability density')
22 |
23 | # Adding a legend
24 | ax.legend()
25 | ax.grid()
26 | ax.margins(x=0, y=0)
27 | ymin, ymax = ax.get_ylim()
28 | ax.set_ylim(ymin, ymax * 1.05)
29 |
30 | plt.savefig(f"{directory}/gumbel.{extension}")
31 | plt.close()
32 |
--------------------------------------------------------------------------------
/src/distributions/pareto.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import pareto
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(1, 1), (1, 2), (1, 3), (2, 1)]
8 | # Possible values for the distribution
9 | x = np.linspace(0, 3, 1000)
10 |
11 | # Creating the figure and the axis
12 | fig, ax = plt.subplots()
13 |
14 | # Plotting the PDF for each value of alpha
15 | for scale, shape in inputs:
16 | ax.plot(x, pareto.pdf(x, shape, scale=scale), label=f'α = {shape}, x$_{{m}}$ = {scale}')
17 |
18 | # Adding title and labels
19 | ax.set_title('Pareto distribution')
20 | ax.set_xlabel('x')
21 | ax.set_ylabel('Probability density')
22 |
23 | # Adding a legend
24 | ax.legend()
25 | ax.grid()
26 | ax.margins(x=0, y=0)
27 | ymin, ymax = ax.get_ylim()
28 | ax.set_ylim(ymin, ymax * 1.05)
29 |
30 | plt.savefig(f"{directory}/pareto.{extension}")
31 | plt.close()
32 |
--------------------------------------------------------------------------------
/src/distributions/student_t.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import t
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Degrees of freedom for the distribution
8 | df_values = [0.1, 0.5, 1, 2, 5, np.inf]
9 | # Possible values for the distribution
10 | x = np.linspace(-5, 5, 1000)
11 |
12 | # Creating the figure and the axis
13 | fig, ax = plt.subplots()
14 |
15 | # Plotting the PDF for each value of the degrees of freedom
16 | for df in df_values:
17 | ax.plot(x, t.pdf(x, df), label=f'nu = {df}')
18 |
19 | # Adding title and labels
20 | ax.set_title('T-distribution')
21 | ax.set_xlabel('x')
22 | ax.set_ylabel('Probability density')
23 |
24 | # Adding a legend
25 | ax.legend()
26 | ax.grid()
27 | ax.margins(x=0, y=0)
28 | ymin, ymax = ax.get_ylim()
29 | ax.set_ylim(ymin, ymax * 1.05)
30 |
31 | plt.savefig(f"{directory}/student_t.{extension}")
32 | plt.close()
33 |
--------------------------------------------------------------------------------
/src/distributions/log_normal.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import lognorm
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(0, 1), (0, 0.5), (0, 2), (-0.5, 1), (1, 1)]
8 | # Possible values for the distribution
9 | x = np.linspace(0, 5, 1000)
10 |
11 | # Creating the figure and the axis
12 | fig, ax = plt.subplots()
13 |
14 | # Plotting the PDF for each value of mu and sigma
15 | for mu, sigma in inputs:
16 | ax.plot(x, lognorm.pdf(x, s=sigma, scale=np.exp(mu)), label=f'μ = {mu}, σ = {sigma}')
17 |
18 | # Adding title and labels
19 | ax.set_title('Log-normal distribution')
20 | ax.set_xlabel('x')
21 | ax.set_ylabel('Probability density')
22 |
23 | # Adding a legend
24 | ax.legend()
25 | ax.grid()
26 | ax.margins(x=0, y=0)
27 | ymin, ymax = ax.get_ylim()
28 | ax.set_ylim(ymin, ymax * 1.05)
29 |
30 | plt.savefig(f"{directory}/log_normal.{extension}")
31 | plt.close()
32 |
--------------------------------------------------------------------------------
/src/distributions/skew_normal.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import skewnorm
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(0, 1, -5), (0, 1, -2), (0, 1, 0), (0, 1, 2), (0, 1, 5)]
8 | # Possible values for the distribution
9 | x = np.linspace(-5, 5, 1000)
10 |
11 | # Creating the figure and the axis
12 | fig, ax = plt.subplots()
13 |
14 | # Plotting the PDF for each value of alpha
15 | for loc, scale, shape in inputs:
16 | ax.plot(x, skewnorm.pdf(x, shape, loc, scale), label=f'shape = {shape}')
17 |
18 | # Adding title and labels
19 | ax.set_title('Skew Normal distribution')
20 | ax.set_xlabel('x')
21 | ax.set_ylabel('Probability density')
22 |
23 | # Adding a legend
24 | ax.legend()
25 | ax.grid()
26 | ax.margins(x=0, y=0)
27 | ymin, ymax = ax.get_ylim()
28 | ax.set_ylim(ymin, ymax * 1.05)
29 |
30 | plt.savefig(f"{directory}/skew_normal.{extension}")
31 | plt.close()
32 |
--------------------------------------------------------------------------------
/src/distributions/inverse_gaussian.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import invgauss
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Possible values for the distribution
8 | x = np.linspace(0, 5, 1000)
9 |
10 | # Creating the figure and the axis
11 | fig, ax = plt.subplots()
12 |
13 | inputs = [(1, 1), (1, 2), (2, 1), (2, 2)]
14 |
15 | # Plotting the PDF for the Inverse Gaussian distribution
16 | for mu, lambda_ in inputs:
17 | ax.plot(x, invgauss.pdf(x, mu, scale=lambda_), label=f'μ = {mu}, λ = {lambda_}')
18 |
19 | # Adding title and labels
20 | ax.set_title('Inverse Gaussian distribution')
21 | ax.set_xlabel('x')
22 | ax.set_ylabel('Probability density')
23 |
24 | # Adding a legend
25 | ax.legend()
26 | ax.grid()
27 | ax.margins(x=0, y=0)
28 | ymin, ymax = ax.get_ylim()
29 | ax.set_ylim(ymin, ymax * 1.05)
30 |
31 | plt.savefig(f"{directory}/inverse_gaussian.{extension}")
32 | plt.close()
33 |
--------------------------------------------------------------------------------
/src/distributions/standard_geometric.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import geom
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Possible outcomes for a Geometric distributed variable
8 | outcomes = np.arange(1, 11)
9 |
10 | # Creating the figure and the axis
11 | fig, ax = plt.subplots()
12 |
13 | # Plotting the PMF for the standard Geometric distribution
14 | ax.bar(outcomes, geom.pmf(outcomes, 0.5), label=f'p = 0.5')
15 |
16 | # Adding title and labels
17 | ax.set_title('Standard Geometric distribution')
18 | ax.set_xlabel('Number of trials until first success')
19 | ax.set_ylabel('Probability')
20 | ax.set_xticks(outcomes) # set the ticks to be the outcome values
21 |
22 | # Adding a legend
23 | ax.legend()
24 | ax.grid()
25 | ax.margins(x=0, y=0)
26 | ymin, ymax = ax.get_ylim()
27 | ax.set_ylim(ymin, ymax * 1.05)
28 |
29 | plt.savefig(f"{directory}/standard_geometric.{extension}")
30 | plt.close()
31 |
--------------------------------------------------------------------------------
/src/distributions/zeta.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import zipf
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [3, 2, 1.5, 1.1] # Different values of s
8 | outcomes = np.arange(1, 11) # Outcomes from 1 to 10
9 |
10 | # Creating the figure
11 | fig, ax = plt.subplots()
12 | width = 0.2 # Bar width
13 |
14 | # Plotting the Zeta Distribution for each value of s
15 | for i, s in enumerate(inputs):
16 | ax.bar(outcomes + i * width - width * 3 / 2, zipf.pmf(outcomes, s), width=width, label=f's = {s}')
17 |
18 | ax.set_title('Zeta Distribution')
19 | ax.set_xlabel('Outcome')
20 | ax.set_ylabel('Probability')
21 | ax.set_xticks(outcomes) # Adjusting x-ticks to center
22 | ax.legend()
23 | ax.grid()
24 | ax.margins(x=0, y=0)
25 | ymin, ymax = ax.get_ylim()
26 | ax.set_ylim(ymin, ymax * 1.05)
27 |
28 | # Save the plot to a file
29 | plt.savefig(f"{directory}/zeta.{extension}")
30 | plt.close()
31 |
--------------------------------------------------------------------------------
/src/distributions/beta.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import beta
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Defining the Beta distribution PDF
8 | def y(a, b, x):
9 | y = beta.pdf(x, a, b)
10 | y[y > 4] = np.nan
11 | return y
12 |
13 | inputs = [(0.5, 0.5), (5, 1), (1, 3), (2, 2), (2, 5)]
14 | # Possible values for the distribution
15 | x = np.linspace(0, 1, 1000)
16 |
17 | # Creating the figure and the axis
18 | fig, ax = plt.subplots()
19 |
20 | # Plotting the PDF for each value of alpha and beta
21 | for a, b in inputs:
22 | ax.plot(x, y(a, b, x), label=f'α = {a}, β = {b}')
23 |
24 | # Adding title and labels
25 | ax.set_title('Beta distribution')
26 | ax.set_xlabel('x')
27 | ax.set_ylabel('Probability density')
28 |
29 | # Adding a legend
30 | ax.legend()
31 | ax.grid()
32 | ax.margins(x=0, y=0)
33 |
34 | plt.savefig(f"{directory}/beta.{extension}")
35 | plt.close()
36 |
--------------------------------------------------------------------------------
/src/distributions/chi_squared.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import chi2
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | def y(x, df):
8 | y = chi2.pdf(x, df)
9 | y[y > 1.05] = np.nan
10 | return y
11 | # Degrees of freedom for the distribution
12 | df_values = [1, 2, 3, 5, 9]
13 | # Possible values for the distribution
14 | x = np.linspace(0, 10, 1000)
15 |
16 | # Creating the figure and the axis
17 | fig, ax = plt.subplots()
18 |
19 | # Plotting the PDF for each value of the degrees of freedom
20 | for df in df_values:
21 | ax.plot(x, y(x, df), label=f'k = {df}')
22 |
23 | # Adding title and labels
24 | ax.set_title('Chi-squared distribution')
25 | ax.set_xlabel('Chi-squared statistic')
26 | ax.set_ylabel('Probability density')
27 |
28 | # Adding a legend
29 | ax.legend()
30 | ax.grid()
31 | ax.margins(x=0, y=0)
32 |
33 | plt.savefig(f"{directory}/chi_squared.{extension}")
34 | plt.close()
35 |
--------------------------------------------------------------------------------
/src/distributions/zipf.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import zipfian
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(2, 10), (1, 10), (0, 10)] # Different values of s and n
8 | outcomes = np.arange(1, 12) # Outcomes from 1 to 10
9 |
10 | # Creating the figure
11 | fig, ax = plt.subplots()
12 | width = 0.2 # Bar width
13 |
14 | # Plotting the Zipf Distribution for each value of s
15 | for i, (s, n) in enumerate(inputs):
16 | ax.bar(outcomes + i * width - width, zipfian.pmf(outcomes, s, n), width=width, label=f's = {s}, n = {n}')
17 |
18 | ax.set_title('Zipf Distribution')
19 | ax.set_xlabel('Outcome')
20 | ax.set_ylabel('Probability')
21 | ax.set_xticks(outcomes) # Adjusting x-ticks to center
22 | ax.legend()
23 | ax.grid()
24 | ax.margins(x=0, y=0)
25 | ymin, ymax = ax.get_ylim()
26 | ax.set_ylim(ymin, ymax * 1.05)
27 |
28 | # Save the plot to a file
29 | plt.savefig(f"{directory}/zipf.{extension}")
30 | plt.close()
31 |
--------------------------------------------------------------------------------
/src/distributions/gamma.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import gamma
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(1, 1), (2, 1), (3, 1), (1, 2), (2, 2), (3, 2)]
8 | # Possible values for the distribution
9 | x = np.linspace(0, 7, 1000)
10 |
11 | # Creating the figure and the axis
12 | fig, ax = plt.subplots()
13 | colors = ["blue", "red", "green", "blue", "red", "green"]
14 | alphas = [1.0, 1.0, 1.0, 0.6, 0.6, 0.6]
15 |
16 | # Plotting the PDF for each value of alpha and beta
17 | for i, (k, theta) in enumerate(inputs):
18 | ax.plot(x, gamma.pdf(x, k, scale=theta), label=f'k = {k}, θ = {theta}', color=colors[i], alpha=alphas[i])
19 |
20 | # Adding title and labels
21 | ax.set_title('Gamma distribution')
22 | ax.set_xlabel('x')
23 | ax.set_ylabel('Probability density')
24 |
25 | # Adding a legend
26 | ax.legend()
27 | ax.grid()
28 | ax.margins(x=0, y=0)
29 |
30 | plt.savefig(f"{directory}/gamma.{extension}")
31 | plt.close()
32 |
--------------------------------------------------------------------------------
/src/distributions/fisher_f.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import f
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | def y(x, dfn, dfd):
8 | y = f.pdf(x, dfn, dfd)
9 | y[y > 2.3] = np.nan
10 | return y
11 |
12 | # Degrees of freedom for the distribution
13 | d1_d2 = [(1, 1), (2, 1), (3, 1), (10, 1), (10, 10), (100, 100)]
14 | # Possible values for the distribution
15 | x = np.linspace(0, 5, 1000)
16 |
17 | # Creating the figure and the axis
18 | fig, ax = plt.subplots()
19 |
20 | # Plotting the PDF for each value of the degrees of freedom
21 | for m, n in d1_d2:
22 | ax.plot(x, y(x, m, n), label=f'm = {m}, n = {n}')
23 |
24 | # Adding title and labels
25 | ax.set_title('F-distribution')
26 | ax.set_xlabel('F-statistic')
27 | ax.set_ylabel('Probability density')
28 |
29 | # Adding a legend
30 | ax.legend()
31 | ax.grid()
32 | ax.margins(x=0, y=0)
33 |
34 | plt.savefig(f"{directory}/fisher_f.{extension}")
35 | plt.close()
36 |
--------------------------------------------------------------------------------
/src/distributions/normal_inverse_gaussian.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import norminvgauss
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(1, 0), (3, 0), (0.1, 0), (1, -0.99), (1, 0.99)]
8 | # Possible values for the distribution
9 | x = np.linspace(-5, 5, 1000)
10 |
11 | # Creating the figure and the axis
12 | fig, ax = plt.subplots(figsize=(8, 5))
13 |
14 | # Plotting the PDF for the Normal Inverse Gaussian distribution
15 | for alpha, beta in inputs:
16 | ax.plot(x, norminvgauss.pdf(x, alpha, beta, 0, 1), label=f'α = {alpha}, β = {beta}')
17 |
18 | # Adding title and labels
19 | ax.set_title('Normal Inverse Gaussian distribution')
20 | ax.set_xlabel('x')
21 | ax.set_ylabel('Probability density')
22 |
23 | # Adding a legend
24 | ax.legend()
25 | ax.grid()
26 | ax.margins(x=0, y=0)
27 | ymin, ymax = ax.get_ylim()
28 | ax.set_ylim(ymin, ymax * 1.05)
29 |
30 | plt.savefig(f"{directory}/normal_inverse_gaussian.{extension}")
31 | plt.close()
32 |
--------------------------------------------------------------------------------
/src/distributions/poisson.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import poisson
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Possible values of lambda for the distribution
8 | lambda_values = [0.5, 1, 2, 4, 10]
9 | # Possible outcomes for a Poisson distributed variable
10 | outcomes = np.arange(0, 15)
11 |
12 | # Creating the figure and the axis
13 | fig, ax = plt.subplots()
14 |
15 | # Plotting the PMF for each value of lambda
16 | for i, lmbda in enumerate(lambda_values):
17 | ax.plot(outcomes, poisson.pmf(outcomes, lmbda), 'o-', label=f'λ = {lmbda}')
18 |
19 | # Adding title and labels
20 | ax.set_title('Poisson distribution')
21 | ax.set_xlabel('Outcome')
22 | ax.set_ylabel('Probability')
23 | ax.set_xticks(outcomes) # set the ticks to be the outcome values
24 |
25 | # Adding a legend
26 | ax.legend()
27 | ax.grid()
28 | ax.margins(x=0, y=0)
29 | ymin, ymax = ax.get_ylim()
30 | ax.set_ylim(ymin, ymax * 1.05)
31 |
32 | plt.savefig(f"{directory}/poisson.{extension}")
33 | plt.close()
34 |
--------------------------------------------------------------------------------
/src/distributions/binomial.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import binom
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(10, 0.2), (10, 0.6)]
8 | # Possible outcomes for a Binomial distributed variable
9 | outcomes = np.arange(0, 11)
10 | width = 0.5
11 |
12 | # Creating the figure and the axis
13 | fig, ax = plt.subplots()
14 |
15 | # Plotting the PMF for each value of n and p
16 | for i, (n, p) in enumerate(inputs):
17 | ax.bar(outcomes + i * width - width / 2, binom.pmf(outcomes, n, p), width=width, label=f'n = {n}, p = {p}')
18 |
19 | # Adding title and labels
20 | ax.set_title('Binomial distribution')
21 | ax.set_xlabel('k (number of successes)')
22 | ax.set_ylabel('Probability')
23 | ax.set_xticks(outcomes) # set the ticks to be the outcome values
24 |
25 | # Adding a legend
26 | ax.legend()
27 | ax.grid()
28 | ax.margins(x=0, y=0)
29 | ymin, ymax = ax.get_ylim()
30 | ax.set_ylim(ymin, ymax * 1.05)
31 |
32 | plt.savefig(f"{directory}/binomial.{extension}")
33 | plt.close()
34 |
--------------------------------------------------------------------------------
/src/distributions/triangular.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import triang
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Defining the Triangular distribution PDF
8 | def y(a, b, c, x):
9 | return triang.pdf(x, c=(c - a) / (b - a), loc=a, scale=b - a)
10 |
11 | inputs = [(0, 1, 0.5), (0, 1, 0.25), (0, 1, 0.75), (-1, 1, 0)]
12 | # Possible values for the distribution
13 | x = np.linspace(-1, 1, 1000)
14 |
15 | # Creating the figure and the axis
16 | fig, ax = plt.subplots()
17 |
18 | # Plotting the PDF for each value of a, b, and c
19 | for a, b, c in inputs:
20 | ax.plot(x, y(a, b, c, x), label=f'a = {a}, b = {b}, c = {c}')
21 |
22 | # Adding title and labels
23 | ax.set_title('Triangular distribution')
24 | ax.set_xlabel('x')
25 | ax.set_ylabel('Probability density')
26 |
27 | # Adding a legend
28 | ax.legend()
29 | ax.grid()
30 | ax.margins(x=0, y=0)
31 | ymin, ymax = ax.get_ylim()
32 | ax.set_ylim(ymin, ymax * 1.05)
33 |
34 | plt.savefig(f"{directory}/triangular.{extension}")
35 | plt.close()
36 |
--------------------------------------------------------------------------------
/src/distributions/frechet.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import invweibull
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | def y(x, shape, loc, scale):
8 | return invweibull.pdf(x, shape, loc=loc, scale=scale)
9 | # Inputs for the distribution
10 | inputs = [(0, 1, 1), (1, 1, 1), (0, 0.5, 1), (0, 2, 1), (0, 1, 0.35), (0, 1, 2)]
11 | # x values for the distribution
12 | x = np.linspace(0, 5, 1000)
13 |
14 | # Creating the figure and the axis
15 | fig, ax = plt.subplots()
16 |
17 | # Plotting the PDF for each value of a
18 | for loc, scale, shape in inputs:
19 | ax.plot(x, y(x, shape, loc, scale), label=f'μ = {loc}, σ = {scale}, α = {shape}')
20 |
21 | # Adding title and labels
22 | ax.set_title('Fréchet distribution')
23 | ax.set_xlabel('x')
24 | ax.set_ylabel('Probability density')
25 |
26 | # Adding a legend
27 | ax.legend()
28 | ax.grid()
29 | ax.margins(x=0, y=0)
30 | ymin, ymax = ax.get_ylim()
31 | ax.set_ylim(ymin, ymax * 1.05)
32 |
33 | plt.savefig(f"{directory}/frechet.{extension}")
34 | plt.close()
35 |
--------------------------------------------------------------------------------
/src/distributions/weibull.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import weibull_min
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | def y(x, scale, shape):
8 | y = weibull_min.pdf(x, shape, scale=scale)
9 | y[y > 5] = np.nan
10 | return y
11 | # Possible values of alpha for the distribution
12 | inputs = [(1, 1), (2, 1), (3, 1), (1, 2), (1, 3), (2, 2)]
13 | # Possible values for the distribution
14 | x = np.linspace(0, 3, 1000)
15 |
16 | # Creating the figure and the axis
17 | fig, ax = plt.subplots()
18 |
19 | # Plotting the PDF for each value of alpha
20 | for scale, shape in inputs:
21 | ax.plot(x, y(x, scale, shape), label=f'λ = {scale}, k = {shape}')
22 |
23 | # Adding title and labels
24 | ax.set_title('Weibull distribution')
25 | ax.set_xlabel('x')
26 | ax.set_ylabel('Probability density')
27 |
28 | # Adding a legend
29 | ax.legend()
30 | ax.grid()
31 | ax.margins(x=0, y=0)
32 | ymin, ymax = ax.get_ylim()
33 | ax.set_ylim(ymin, ymax * 1.05)
34 |
35 | plt.savefig(f"{directory}/weibull.{extension}")
36 | plt.close()
37 |
--------------------------------------------------------------------------------
/src/distributions/hypergeometric.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import hypergeom
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | inputs = [(50, 12, 10), (50, 35, 10)]
8 | # Possible outcomes for a Hypergeometric distributed variable
9 | outcomes = np.arange(0, 11)
10 | width = 0.5
11 |
12 | # Creating the figure and the axis
13 | fig, ax = plt.subplots()
14 |
15 | # Plotting the PMF for each value of N, K, and n
16 | for i, (N, K, n) in enumerate(inputs):
17 | ax.bar(outcomes + i * width - width / 2, hypergeom.pmf(outcomes, N, K, n), width=width, label=f'N = {N}, K = {K}, n = {n}')
18 |
19 | # Adding title and labels
20 | ax.set_title('Hypergeometric distribution')
21 | ax.set_xlabel('k (number of successes)')
22 | ax.set_ylabel('Probability')
23 | ax.set_xticks(outcomes) # set the ticks to be the outcome values
24 |
25 | # Adding a legend
26 | ax.legend()
27 | ax.grid()
28 | ax.margins(x=0, y=0)
29 | ymin, ymax = ax.get_ylim()
30 | ax.set_ylim(ymin, ymax * 1.05)
31 |
32 | plt.savefig(f"{directory}/hypergeometric.{extension}")
33 | plt.close()
34 |
--------------------------------------------------------------------------------
/src/distributions/unit_disc.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 |
4 |
5 | def save_to(directory: str, extension: str):
6 | # Create a circle
7 | def plot_circle(radius=1, num_divisions=100):
8 | theta = np.linspace(0, 2 * np.pi, num_divisions)
9 | x = radius * np.cos(theta)
10 | y = radius * np.sin(theta)
11 |
12 | return x, y
13 |
14 | # Plotting parameters
15 | radius = 1
16 | num_divisions = 100 # Increase this for a smoother circle
17 |
18 | x, y = plot_circle(radius, num_divisions)
19 |
20 | # Create a plot
21 | fig, ax = plt.subplots(figsize=(8, 8))
22 | ax.fill(x, y, color='b', alpha=0.6)
23 |
24 | # Scaling the axes
25 | ax.set_xlim([-1, 1])
26 | ax.set_ylim([-1, 1])
27 | ax.set_aspect('equal')
28 |
29 | # Labels and title
30 | ax.set_xlabel('X')
31 | ax.set_ylabel('Y')
32 | ax.set_title('Unit Disc')
33 | ax.grid()
34 | ax.margins(x=0, y=0)
35 | ymin, ymax = ax.get_ylim()
36 | ax.set_ylim(ymin, ymax * 1.05)
37 |
38 | plt.tight_layout()
39 |
40 | # Save the figure
41 | plt.savefig(f"{directory}/unit_disc.{extension}")
42 | plt.close()
43 |
--------------------------------------------------------------------------------
/src/distributions/unit_circle.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 |
4 |
5 | def save_to(directory: str, extension: str):
6 | # Create a circle
7 | def plot_circle(radius=1, num_divisions=100):
8 | theta = np.linspace(0, 2 * np.pi, num_divisions)
9 | x = radius * np.cos(theta)
10 | y = radius * np.sin(theta)
11 |
12 | return x, y
13 |
14 | # Plotting parameters
15 | radius = 1
16 | num_divisions = 100 # Increase this for a smoother circle
17 |
18 | x, y = plot_circle(radius, num_divisions)
19 |
20 | # Create a plot
21 | fig, ax = plt.subplots(figsize=(8, 8))
22 | ax.plot(x, y, color='b', alpha=0.6)
23 |
24 | # Scaling the axes
25 | ax.set_xlim([-1, 1])
26 | ax.set_ylim([-1, 1])
27 | ax.set_aspect('equal')
28 |
29 | # Labels and title
30 | ax.set_xlabel('X')
31 | ax.set_ylabel('Y')
32 | ax.set_title('Unit Circle')
33 | ax.grid()
34 | ax.margins(x=0, y=0)
35 | ymin, ymax = ax.get_ylim()
36 | ax.set_ylim(ymin, ymax * 1.05)
37 |
38 | plt.tight_layout()
39 |
40 | # Save the figure
41 | plt.savefig(f"{directory}/unit_circle.{extension}")
42 | plt.close()
43 |
--------------------------------------------------------------------------------
/src/distributions/bernoulli.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import bernoulli
4 |
5 |
6 | # Bernoulli distribution
7 | def save_to(directory: str, extension: str):
8 | # Defining the Bernoulli distribution PMF
9 | def y(p):
10 | return np.array([1 - p, p])
11 |
12 | # Possible values of p for the distribution
13 | p_values = [0.1, 0.5, 0.9]
14 | # Possible outcomes for a Bernoulli distributed variable
15 | outcomes = np.array([0, 1])
16 |
17 | # Creating the figure and the axis
18 | fig, ax = plt.subplots()
19 | # Width of each bar
20 | width = 0.2
21 |
22 | # Plotting the PMF for each value of p
23 | for i, p in enumerate(p_values):
24 | ax.bar(outcomes - width / 2 + i * width - 0.1, y(p), width=width, label=f'p = {p}')
25 |
26 | # Adding title and labels
27 | ax.set_title('Bernoulli distribution')
28 | ax.set_xlabel('Outcome')
29 | ax.set_ylabel('Probability')
30 | ax.set_xticks(outcomes) # set the ticks to be the outcome values
31 |
32 | # Adding a legend
33 | ax.legend()
34 | ax.grid()
35 | ax.margins(x=0, y=0)
36 | ymin, ymax = ax.get_ylim()
37 | ax.set_ylim(ymin, 1)
38 |
39 | plt.savefig(f"{directory}/bernoulli.{extension}")
40 | plt.close()
41 |
--------------------------------------------------------------------------------
/src/distributions/geometric.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import geom
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | # Possible values of p for the distribution
8 | p_values = [0.2, 0.5, 0.8]
9 | # Possible outcomes for a Geometric distributed variable
10 | outcomes = np.arange(0, 10)
11 |
12 | # Creating the figure and the axis
13 | fig, ax = plt.subplots()
14 | width = 0.2
15 |
16 | # Plotting the PMF for each value of p
17 | for i, p in enumerate(p_values):
18 | # Specify loc=-1 correct for the difference in the definition of the geometric distribution in scipy
19 | # and the definition in the rand crate
20 | ax.bar(outcomes + i * width - width, geom.pmf(outcomes, p, loc=-1), width=width, label=f'p = {p}')
21 |
22 | # Adding title and labels
23 | ax.set_title('Geometric distribution')
24 | ax.set_xlabel('Number of failures before first success')
25 | ax.set_ylabel('Probability')
26 | ax.set_xticks(outcomes) # set the ticks to be the outcome values
27 |
28 | # Adding a legend
29 | ax.legend()
30 | ax.grid()
31 | ax.margins(x=0, y=0)
32 | ymin, ymax = ax.get_ylim()
33 | ax.set_ylim(ymin, ymax * 1.05)
34 |
35 | plt.savefig(f"{directory}/geometric.{extension}")
36 | plt.close()
37 |
--------------------------------------------------------------------------------
/src/distributions/unit_sphere.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 |
4 |
5 | def save_to(directory: str, extension: str):
6 | # Create a sphere
7 | def plot_sphere(radius=1, num_divisions=50):
8 | phi = np.linspace(0, np.pi, num_divisions) # polar angle
9 | theta = np.linspace(0, 2 * np.pi, num_divisions) # azimuthal angle
10 |
11 | # Meshgrid
12 | phi, theta = np.meshgrid(phi, theta)
13 | x = radius * np.sin(phi) * np.cos(theta)
14 | y = radius * np.sin(phi) * np.sin(theta)
15 | z = radius * np.cos(phi)
16 |
17 | return x, y, z
18 |
19 | # Plotting parameters
20 | radius = 1
21 | num_divisions = 50 # Increase this for a smoother sphere
22 |
23 | x, y, z = plot_sphere(radius, num_divisions)
24 |
25 | # Create a plot
26 | fig = plt.figure(figsize=(8, 6))
27 | ax = fig.add_subplot(111, projection='3d')
28 | ax.plot_wireframe(x, y, z, color='b', alpha=0.6, rstride=1, cstride=1)
29 |
30 | # Scaling the axes
31 | ax.set_xlim([-1, 1])
32 | ax.set_ylim([-1, 1])
33 | ax.set_zlim([-1, 1])
34 | ax.set_aspect('auto')
35 | ax.set_box_aspect([1, 1, 1])
36 |
37 | # Labels and title
38 | ax.set_xlabel('X')
39 | ax.set_ylabel('Y')
40 | ax.set_zlabel('Z')
41 | ax.set_title('Unit Sphere (shell)')
42 | ax.margins(x=0, y=0)
43 | ymin, ymax = ax.get_ylim()
44 | ax.set_ylim(ymin, ymax * 1.05)
45 |
46 | # Save the figure
47 | plt.savefig(f"{directory}/unit_sphere.{extension}")
48 | plt.close()
49 |
--------------------------------------------------------------------------------
/src/distributions/unit_ball.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from mpl_toolkits.mplot3d import Axes3D
4 | from scipy.spatial import ConvexHull
5 |
6 |
7 | def save_to(directory: str, extension: str):
8 | # Create a sphere
9 | def plot_sphere(radius=1, num_divisions=50):
10 | phi = np.linspace(0, np.pi, num_divisions) # polar angle
11 | theta = np.linspace(0, 2 * np.pi, num_divisions) # azimuthal angle
12 |
13 | # Meshgrid
14 | phi, theta = np.meshgrid(phi, theta)
15 | x = radius * np.sin(phi) * np.cos(theta)
16 | y = radius * np.sin(phi) * np.sin(theta)
17 | z = radius * np.cos(phi)
18 |
19 | return x, y, z
20 |
21 | # Plotting parameters
22 | radius = 1
23 | num_divisions = 50 # Increase this for a smoother sphere
24 |
25 | x, y, z = plot_sphere(radius, num_divisions)
26 |
27 | # Create a plot
28 | fig = plt.figure(figsize=(8, 6))
29 | ax = fig.add_subplot(111, projection='3d')
30 | ax.plot_surface(x, y, z, color='b', rstride=1, cstride=1, alpha=0.6, edgecolor='none')
31 |
32 | # Scaling the axes
33 | ax.set_xlim([-1, 1])
34 | ax.set_ylim([-1, 1])
35 | ax.set_zlim([-1, 1])
36 | ax.set_aspect('auto')
37 | ax.set_box_aspect([1, 1, 1])
38 |
39 | # Labels and title
40 | ax.set_xlabel('X')
41 | ax.set_ylabel('Y')
42 | ax.set_zlabel('Z')
43 | ax.set_title('Unit Ball (solid)')
44 | ax.margins(x=0, y=0)
45 | ymin, ymax = ax.get_ylim()
46 | ax.set_ylim(ymin, ymax * 1.05)
47 |
48 | # Save the figure
49 | plt.savefig(f"{directory}/unit_ball.{extension}")
50 | plt.close()
51 |
--------------------------------------------------------------------------------
/src/distributions/pert.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from scipy.stats import beta
4 |
5 |
6 | def save_to(directory: str, extension: str):
7 | def y(x, min_value, mode, max_value, shape):
8 | a = 1 + shape * (mode - min_value) / (max_value - min_value)
9 | b = 1 + shape * (max_value - mode) / (max_value - min_value)
10 | return beta.pdf(x, a, b, loc=min_value, scale=max_value - min_value)
11 |
12 | inputs = [(-1, 0, 1, 4), (-1, 0, 1, 1), (-1, 0, 1, 8), (-1, 0.5, 1, 4)]
13 | # Adjusting the range of x values to be more meaningful for the PERT distribution
14 | x = np.linspace(-1, 1, 1000) # max_value in inputs is 2, hence 3 is a reasonable upper bound
15 |
16 | # Creating the figure and the axis
17 | fig, ax = plt.subplots(figsize=(10, 5))
18 |
19 | # Plotting the PDF for each value of min_value, mode, max_value, and shape
20 | for min_value, mode, max_value, shape in inputs:
21 | ax.plot(x, y(x, min_value, mode, max_value, shape),
22 | label=f'min = {min_value}, mode = {mode}, max = {max_value}, shape = {shape}')
23 |
24 | # Adding title and labels
25 | ax.set_title('PERT Distribution')
26 | ax.set_xlabel('x')
27 | ax.set_ylabel('Probability density')
28 |
29 | # Adding a legend
30 | box = ax.get_position()
31 | ax.set_position([box.x0, box.y0, box.width * 0.6, box.height])
32 | ax.legend(loc='upper left', bbox_to_anchor=(1, 1))
33 | ax.grid()
34 | ax.margins(x=0, y=0)
35 | ymin, ymax = ax.get_ylim()
36 | ax.set_ylim(ymin, ymax * 1.05)
37 |
38 | plt.savefig(f"{directory}/pert.{extension}")
39 | plt.close()
40 |
--------------------------------------------------------------------------------
/src/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | from distributions import (
3 | bernoulli,
4 | beta,
5 | binomial,
6 | cauchy,
7 | chi_squared,
8 | dirichlet,
9 | exponential,
10 | exponential_exp1,
11 | fisher_f,
12 | frechet,
13 | gamma,
14 | geometric,
15 | gumbel,
16 | hypergeometric,
17 | inverse_gaussian,
18 | log_normal,
19 | normal,
20 | normal_inverse_gaussian,
21 | pareto,
22 | pert,
23 | poisson,
24 | skew_normal,
25 | standard_geometric,
26 | standard_normal,
27 | student_t,
28 | triangular,
29 | unit_ball,
30 | unit_circle,
31 | unit_disc,
32 | unit_sphere,
33 | weibull,
34 | zeta,
35 | zipf,
36 | )
37 |
38 | if __name__ == "__main__":
39 | out = "charts"
40 | ext = "svg"
41 | if not os.path.exists(out):
42 | os.makedirs(out)
43 | for distr in (
44 | bernoulli,
45 | beta,
46 | binomial,
47 | cauchy,
48 | chi_squared,
49 | dirichlet,
50 | exponential,
51 | exponential_exp1,
52 | fisher_f,
53 | frechet,
54 | gamma,
55 | geometric,
56 | gumbel,
57 | hypergeometric,
58 | inverse_gaussian,
59 | log_normal,
60 | normal,
61 | normal_inverse_gaussian,
62 | pareto,
63 | pert,
64 | poisson,
65 | skew_normal,
66 | standard_geometric,
67 | standard_normal,
68 | student_t,
69 | triangular,
70 | unit_ball,
71 | unit_circle,
72 | unit_disc,
73 | unit_sphere,
74 | weibull,
75 | zeta,
76 | zipf,
77 | ):
78 | distr.save_to(out, ext)
79 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | #.idea/
161 |
--------------------------------------------------------------------------------
/src/distributions/dirichlet.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 | #
3 | # Copyright (c) 2024 Developers of the Rand project
4 | # Copyright (c) 2014 Thomas Boggs
5 | #
6 | # Permission is hereby granted, free of charge, to any
7 | # person obtaining a copy of this software and associated
8 | # documentation files (the "Software"), to deal in the
9 | # Software without restriction, including without
10 | # limitation the rights to use, copy, modify, merge,
11 | # publish, distribute, sublicense, and/or sell copies of
12 | # the Software, and to permit persons to whom the Software
13 | # is furnished to do so, subject to the following
14 | # conditions:
15 | #
16 | # The above copyright notice and this permission notice
17 | # shall be included in all copies or substantial portions
18 | # of the Software.
19 | #
20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
21 | # ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
22 | # TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
23 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
24 | # SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
27 | # IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 | # DEALINGS IN THE SOFTWARE.
29 | import numpy as np
30 | import matplotlib.pyplot as plt
31 | import matplotlib.tri as tri
32 | from math import gamma
33 | import ternary
34 |
35 |
36 | # Code source: https://blog.bogatron.net/blog/2014/02/02/visualizing-dirichlet-distributions/
37 | class Dirichlet(object):
38 | def __init__(self, alpha):
39 | self._alpha = np.array(alpha)
40 | self._coef = gamma(np.sum(self._alpha)) / np.multiply.reduce([gamma(a) for a in self._alpha])
41 |
42 | def pdf(self, x):
43 | """Returns pdf value for `x`."""
44 | return self._coef * np.multiply.reduce([xx ** (aa - 1) for (xx, aa) in zip(x, self._alpha)])
45 |
46 |
47 | def save_to(directory: str, _: str):
48 | extension = "png" # Hardcode png output format. SVG file size for this distribution is ~100x larger.
49 | corners = np.array([[0, 0], [1, 0], [0.5, np.sqrt(0.75)]])
50 | AREA = 0.5 * 1 * np.sqrt(0.75)
51 | triangle = tri.Triangulation(corners[:, 0], corners[:, 1])
52 |
53 | pairs = [corners[np.roll(range(3), -i)[1:]] for i in range(3)]
54 | tri_area = lambda xy, pair: 0.5 * np.linalg.norm(np.cross(*(pair - xy)))
55 |
56 | def xy2bc(xy, tol=1.e-4):
57 | coords = np.array([tri_area(xy, p) for p in pairs]) / AREA
58 | return np.clip(coords, tol, 1.0 - tol)
59 |
60 | def draw_pdf_contours(ax, alphas, nlevels=200, subdiv=8):
61 | refiner = tri.UniformTriRefiner(triangle)
62 | trimesh = refiner.refine_triangulation(subdiv=subdiv)
63 | pvals = [Dirichlet(alphas).pdf(xy2bc(xy)) for xy in zip(trimesh.x, trimesh.y)]
64 |
65 | contour = ax.tricontourf(trimesh, pvals, nlevels, cmap='plasma')
66 | ternary.plt.colorbar(contour, ax=ax, orientation='vertical', fraction=0.05, pad=0.05)
67 |
68 | ax.axis('equal')
69 | ax.spines['top'].set_visible(False)
70 | ax.spines['right'].set_visible(False)
71 | ax.spines['bottom'].set_visible(False)
72 | ax.spines['left'].set_visible(False)
73 |
74 | tax = ternary.TernaryAxesSubplot(ax=ax, scale=1.0)
75 |
76 | tax.boundary(linewidth=1.0)
77 |
78 | tax.ticks(axis='lbr', linewidth=1, multiple=0.2, tick_formats="%.1f", offset=0.02)
79 |
80 | fontsize = 13
81 | tax.set_title(f"α = {alphas}", fontsize=fontsize, pad=20)
82 | tax.right_axis_label("$x_3$", fontsize=fontsize, offset=0.15)
83 | tax.left_axis_label("$x_1$", fontsize=fontsize, offset=0.15)
84 | tax.bottom_axis_label("$x_2$", fontsize=fontsize)
85 | tax._redraw_labels() # Won't do this automatically because of the way we are saving the plot
86 |
87 | tax.clear_matplotlib_ticks()
88 |
89 | inputs = [
90 | [1.5, 1.5, 1.5],
91 | [5.0, 5.0, 5.0],
92 | [1.0, 2.0, 2.0],
93 | [2.0, 4.0, 8.0]
94 | ]
95 |
96 | fig, axes = plt.subplots(2, 2, figsize=(12, 10))
97 | for ax, alphas in zip(axes.flatten(), inputs):
98 | draw_pdf_contours(ax, alphas)
99 |
100 | # Adding the main title and colorbar
101 | ternary.plt.suptitle('Dirichlet Distribution', fontsize=16)
102 |
103 | ternary.plt.savefig(f"{directory}/dirichlet.{extension}", bbox_inches='tight', pad_inches=0.5)
104 | plt.close()
105 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/charts/unit_disc.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
887 |
--------------------------------------------------------------------------------
/charts/unit_circle.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
908 |
--------------------------------------------------------------------------------
/charts/exponential_exp1.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
1057 |
--------------------------------------------------------------------------------
/charts/bernoulli.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
1094 |
--------------------------------------------------------------------------------
/charts/standard_normal.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
1160 |
--------------------------------------------------------------------------------