diff --git a/charts/beta.svg b/charts/beta.svg
new file mode 100644
index 0000000..f8559fc
--- /dev/null
+++ b/charts/beta.svg
@@ -0,0 +1,1531 @@
+
+
+
diff --git a/charts/binomial.svg b/charts/binomial.svg
new file mode 100644
index 0000000..d634adb
--- /dev/null
+++ b/charts/binomial.svg
@@ -0,0 +1,1517 @@
+
+
+
diff --git a/charts/cauchy.svg b/charts/cauchy.svg
new file mode 100644
index 0000000..3b4fcf9
--- /dev/null
+++ b/charts/cauchy.svg
@@ -0,0 +1,1470 @@
+
+
+
diff --git a/charts/chi_squared.svg b/charts/chi_squared.svg
new file mode 100644
index 0000000..6d5fd02
--- /dev/null
+++ b/charts/chi_squared.svg
@@ -0,0 +1,1402 @@
+
+
+
diff --git a/charts/dirichlet.png b/charts/dirichlet.png
new file mode 100644
index 0000000..f7ce5f9
Binary files /dev/null and b/charts/dirichlet.png differ
diff --git a/charts/exponential.svg b/charts/exponential.svg
new file mode 100644
index 0000000..1f84251
--- /dev/null
+++ b/charts/exponential.svg
@@ -0,0 +1,1171 @@
+
+
+
diff --git a/charts/exponential_exp1.svg b/charts/exponential_exp1.svg
new file mode 100644
index 0000000..f317213
--- /dev/null
+++ b/charts/exponential_exp1.svg
@@ -0,0 +1,1056 @@
+
+
+
diff --git a/charts/fisher_f.svg b/charts/fisher_f.svg
new file mode 100644
index 0000000..e4b6e1c
--- /dev/null
+++ b/charts/fisher_f.svg
@@ -0,0 +1,1520 @@
+
+
+
diff --git a/charts/frechet.svg b/charts/frechet.svg
new file mode 100644
index 0000000..04ba0a4
--- /dev/null
+++ b/charts/frechet.svg
@@ -0,0 +1,1744 @@
+
+
+
diff --git a/charts/gamma.svg b/charts/gamma.svg
new file mode 100644
index 0000000..1c6d03d
--- /dev/null
+++ b/charts/gamma.svg
@@ -0,0 +1,1532 @@
+
+
+
diff --git a/charts/geometric.svg b/charts/geometric.svg
new file mode 100644
index 0000000..d0ae692
--- /dev/null
+++ b/charts/geometric.svg
@@ -0,0 +1,1571 @@
+
+
+
diff --git a/charts/gumbel.svg b/charts/gumbel.svg
new file mode 100644
index 0000000..cdf42cc
--- /dev/null
+++ b/charts/gumbel.svg
@@ -0,0 +1,1466 @@
+
+
+
diff --git a/charts/hypergeometric.svg b/charts/hypergeometric.svg
new file mode 100644
index 0000000..f796c2d
--- /dev/null
+++ b/charts/hypergeometric.svg
@@ -0,0 +1,1581 @@
+
+
+
diff --git a/charts/inverse_gaussian.svg b/charts/inverse_gaussian.svg
new file mode 100644
index 0000000..7567f99
--- /dev/null
+++ b/charts/inverse_gaussian.svg
@@ -0,0 +1,1436 @@
+
+
+
diff --git a/charts/log_normal.svg b/charts/log_normal.svg
new file mode 100644
index 0000000..effe64b
--- /dev/null
+++ b/charts/log_normal.svg
@@ -0,0 +1,1575 @@
+
+
+
diff --git a/charts/normal.svg b/charts/normal.svg
new file mode 100644
index 0000000..d869ba7
--- /dev/null
+++ b/charts/normal.svg
@@ -0,0 +1,1516 @@
+
+
+
diff --git a/charts/normal_inverse_gaussian.svg b/charts/normal_inverse_gaussian.svg
new file mode 100644
index 0000000..edffd91
--- /dev/null
+++ b/charts/normal_inverse_gaussian.svg
@@ -0,0 +1,1740 @@
+
+
+
diff --git a/charts/pareto.svg b/charts/pareto.svg
new file mode 100644
index 0000000..e7ac1ce
--- /dev/null
+++ b/charts/pareto.svg
@@ -0,0 +1,1228 @@
+
+
+
diff --git a/charts/pert.svg b/charts/pert.svg
new file mode 100644
index 0000000..44fe3e3
--- /dev/null
+++ b/charts/pert.svg
@@ -0,0 +1,1744 @@
+
+
+
diff --git a/charts/poisson.svg b/charts/poisson.svg
new file mode 100644
index 0000000..c10659f
--- /dev/null
+++ b/charts/poisson.svg
@@ -0,0 +1,1583 @@
+
+
+
diff --git a/charts/skew_normal.svg b/charts/skew_normal.svg
new file mode 100644
index 0000000..8fb7d08
--- /dev/null
+++ b/charts/skew_normal.svg
@@ -0,0 +1,1586 @@
+
+
+
diff --git a/charts/standard_geometric.svg b/charts/standard_geometric.svg
new file mode 100644
index 0000000..a1ee29b
--- /dev/null
+++ b/charts/standard_geometric.svg
@@ -0,0 +1,1351 @@
+
+
+
diff --git a/charts/standard_normal.svg b/charts/standard_normal.svg
new file mode 100644
index 0000000..8f2c87d
--- /dev/null
+++ b/charts/standard_normal.svg
@@ -0,0 +1,1159 @@
+
+
+
diff --git a/charts/student_t.svg b/charts/student_t.svg
new file mode 100644
index 0000000..b20a27e
--- /dev/null
+++ b/charts/student_t.svg
@@ -0,0 +1,1615 @@
+
+
+
diff --git a/charts/triangular.svg b/charts/triangular.svg
new file mode 100644
index 0000000..425b622
--- /dev/null
+++ b/charts/triangular.svg
@@ -0,0 +1,1237 @@
+
+
+
diff --git a/charts/unit_ball.svg b/charts/unit_ball.svg
new file mode 100644
index 0000000..bfc8e4c
--- /dev/null
+++ b/charts/unit_ball.svg
@@ -0,0 +1,15516 @@
+
+
+
diff --git a/charts/unit_circle.svg b/charts/unit_circle.svg
new file mode 100644
index 0000000..3144bd7
--- /dev/null
+++ b/charts/unit_circle.svg
@@ -0,0 +1,907 @@
+
+
+
diff --git a/charts/unit_disc.svg b/charts/unit_disc.svg
new file mode 100644
index 0000000..a6ca34d
--- /dev/null
+++ b/charts/unit_disc.svg
@@ -0,0 +1,886 @@
+
+
+
diff --git a/charts/unit_sphere.svg b/charts/unit_sphere.svg
new file mode 100644
index 0000000..75a17da
--- /dev/null
+++ b/charts/unit_sphere.svg
@@ -0,0 +1,6218 @@
+
+
+
diff --git a/charts/weibull.svg b/charts/weibull.svg
new file mode 100644
index 0000000..2c6efc6
--- /dev/null
+++ b/charts/weibull.svg
@@ -0,0 +1,1500 @@
+
+
+
diff --git a/charts/zeta.svg b/charts/zeta.svg
new file mode 100644
index 0000000..7017266
--- /dev/null
+++ b/charts/zeta.svg
@@ -0,0 +1,1575 @@
+
+
+
diff --git a/charts/zipf.svg b/charts/zipf.svg
new file mode 100644
index 0000000..326c2c9
--- /dev/null
+++ b/charts/zipf.svg
@@ -0,0 +1,1556 @@
+
+
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..9190d30
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,4 @@
+numpy==1.26.4
+matplotlib==3.8.4
+scipy==1.13.0
+python-ternary==1.0.8
\ No newline at end of file
diff --git a/src/distributions/beta.py b/src/distributions/beta.py
new file mode 100644
index 0000000..3d94d83
--- /dev/null
+++ b/src/distributions/beta.py
@@ -0,0 +1,35 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import beta
+
+
+def save_to(directory: str, extension: str):
+ # Defining the Beta distribution PDF
+ def y(a, b, x):
+ y = beta.pdf(x, a, b)
+ y[y > 4] = np.nan
+ return y
+
+ inputs = [(0.5, 0.5), (5, 1), (1, 3), (2, 2), (2, 5)]
+ # Possible values for the distribution
+ x = np.linspace(0, 1, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of alpha and beta
+ for a, b in inputs:
+ ax.plot(x, y(a, b, x), label=f'α = {a}, β = {b}')
+
+ # Adding title and labels
+ ax.set_title('Beta distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+
+ plt.savefig(f"{directory}/beta.{extension}")
+ plt.close()
diff --git a/src/distributions/binomial.py b/src/distributions/binomial.py
new file mode 100644
index 0000000..12fad0f
--- /dev/null
+++ b/src/distributions/binomial.py
@@ -0,0 +1,33 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import binom
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(10, 0.2), (10, 0.6)]
+ # Possible outcomes for a Binomial distributed variable
+ outcomes = np.arange(0, 11)
+ width = 0.5
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PMF for each value of n and p
+ for i, (n, p) in enumerate(inputs):
+ ax.bar(outcomes + i * width - width / 2, binom.pmf(outcomes, n, p), width=width, label=f'n = {n}, p = {p}')
+
+ # Adding title and labels
+ ax.set_title('Binomial distribution')
+ ax.set_xlabel('k (number of successes)')
+ ax.set_ylabel('Probability')
+ ax.set_xticks(outcomes) # set the ticks to be the outcome values
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/binomial.{extension}")
+ plt.close()
diff --git a/src/distributions/cauchy.py b/src/distributions/cauchy.py
new file mode 100644
index 0000000..edf56d1
--- /dev/null
+++ b/src/distributions/cauchy.py
@@ -0,0 +1,31 @@
+import numpy as np
+import matplotlib.pyplot as plt
+
+
+def save_to(directory: str, extension: str):
+ # Possible values for the distribution
+ x = np.linspace(-7, 7, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)]
+
+ # Plotting the PDF for the Cauchy distribution
+ for x0, gamma in inputs:
+ ax.plot(x, 1 / (np.pi * gamma * (1 + ((x - x0) / gamma)**2)), label=f'x₀ = {x0}, γ = {gamma}')
+
+ # Adding title and labels
+ ax.set_title('Cauchy distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/cauchy.{extension}")
+ plt.close()
diff --git a/src/distributions/chi_squared.py b/src/distributions/chi_squared.py
new file mode 100644
index 0000000..667e48b
--- /dev/null
+++ b/src/distributions/chi_squared.py
@@ -0,0 +1,34 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import chi2
+
+
+def save_to(directory: str, extension: str):
+ def y(x, df):
+ y = chi2.pdf(x, df)
+ y[y > 1.05] = np.nan
+ return y
+ # Degrees of freedom for the distribution
+ df_values = [1, 2, 3, 5, 9]
+ # Possible values for the distribution
+ x = np.linspace(0, 10, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of the degrees of freedom
+ for df in df_values:
+ ax.plot(x, y(x, df), label=f'k = {df}')
+
+ # Adding title and labels
+ ax.set_title('Chi-squared distribution')
+ ax.set_xlabel('Chi-squared statistic')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+
+ plt.savefig(f"{directory}/chi_squared.{extension}")
+ plt.close()
diff --git a/src/distributions/dirichlet.py b/src/distributions/dirichlet.py
new file mode 100644
index 0000000..7bc2cc8
--- /dev/null
+++ b/src/distributions/dirichlet.py
@@ -0,0 +1,76 @@
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.tri as tri
+from math import gamma
+import ternary
+
+
+# Code source: https://blog.bogatron.net/blog/2014/02/02/visualizing-dirichlet-distributions/
+class Dirichlet(object):
+ def __init__(self, alpha):
+ self._alpha = np.array(alpha)
+ self._coef = gamma(np.sum(self._alpha)) / np.multiply.reduce([gamma(a) for a in self._alpha])
+
+ def pdf(self, x):
+ """Returns pdf value for `x`."""
+ return self._coef * np.multiply.reduce([xx ** (aa - 1) for (xx, aa) in zip(x, self._alpha)])
+
+
+def save_to(directory: str, _: str):
+ extension = "png" # Hardcode png output format. SVG file size for this distribution is ~100x larger.
+ corners = np.array([[0, 0], [1, 0], [0.5, np.sqrt(0.75)]])
+ AREA = 0.5 * 1 * np.sqrt(0.75)
+ triangle = tri.Triangulation(corners[:, 0], corners[:, 1])
+
+ pairs = [corners[np.roll(range(3), -i)[1:]] for i in range(3)]
+ tri_area = lambda xy, pair: 0.5 * np.linalg.norm(np.cross(*(pair - xy)))
+
+ def xy2bc(xy, tol=1.e-4):
+ coords = np.array([tri_area(xy, p) for p in pairs]) / AREA
+ return np.clip(coords, tol, 1.0 - tol)
+
+ def draw_pdf_contours(ax, alphas, nlevels=200, subdiv=8):
+ refiner = tri.UniformTriRefiner(triangle)
+ trimesh = refiner.refine_triangulation(subdiv=subdiv)
+ pvals = [Dirichlet(alphas).pdf(xy2bc(xy)) for xy in zip(trimesh.x, trimesh.y)]
+
+ contour = ax.tricontourf(trimesh, pvals, nlevels, cmap='plasma')
+ ternary.plt.colorbar(contour, ax=ax, orientation='vertical', fraction=0.05, pad=0.05)
+
+ ax.axis('equal')
+ ax.spines['top'].set_visible(False)
+ ax.spines['right'].set_visible(False)
+ ax.spines['bottom'].set_visible(False)
+ ax.spines['left'].set_visible(False)
+
+ tax = ternary.TernaryAxesSubplot(ax=ax, scale=1.0)
+
+ tax.boundary(linewidth=1.0)
+
+ tax.ticks(axis='lbr', linewidth=1, multiple=0.2, tick_formats="%.1f", offset=0.02)
+
+ fontsize = 13
+ tax.set_title(f"α = {alphas}", fontsize=fontsize, pad=20)
+ tax.right_axis_label("$x_3$", fontsize=fontsize, offset=0.15)
+ tax.left_axis_label("$x_1$", fontsize=fontsize, offset=0.15)
+ tax.bottom_axis_label("$x_2$", fontsize=fontsize)
+ tax._redraw_labels() # Won't do this automatically because of the way we are saving the plot
+
+ tax.clear_matplotlib_ticks()
+
+ inputs = [
+ [1.5, 1.5, 1.5],
+ [5.0, 5.0, 5.0],
+ [1.0, 2.0, 2.0],
+ [2.0, 4.0, 8.0]
+ ]
+
+ fig, axes = plt.subplots(2, 2, figsize=(12, 10))
+ for ax, alphas in zip(axes.flatten(), inputs):
+ draw_pdf_contours(ax, alphas)
+
+ # Adding the main title and colorbar
+ ternary.plt.suptitle('Dirichlet Distribution', fontsize=16)
+
+ ternary.plt.savefig(f"{directory}/dirichlet.{extension}", bbox_inches='tight', pad_inches=0.5)
+ plt.close()
diff --git a/src/distributions/exponential.py b/src/distributions/exponential.py
new file mode 100644
index 0000000..c0b845e
--- /dev/null
+++ b/src/distributions/exponential.py
@@ -0,0 +1,30 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import expon
+
+
+def save_to(directory: str, extension: str):
+ # Possible values of lambda for the distribution
+ lambda_values = [1, 0.5, 2]
+ # Possible values for the distribution
+ x = np.linspace(0, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of lambda
+ for lmbda in lambda_values:
+ ax.plot(x, expon.pdf(x, scale=1 / lmbda), label=f'λ = {lmbda}')
+
+ # Adding title and labels
+ ax.set_title('Exponential distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+
+ plt.savefig(f"{directory}/exponential.{extension}")
+ plt.close()
diff --git a/src/distributions/exponential_exp1.py b/src/distributions/exponential_exp1.py
new file mode 100644
index 0000000..fc28c38
--- /dev/null
+++ b/src/distributions/exponential_exp1.py
@@ -0,0 +1,29 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import expon
+
+
+def save_to(directory: str, extension: str):
+ # Fixed value for lambda
+ lmbda = 1
+ # Possible values for the distribution
+ x = np.linspace(0, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of lambda
+ ax.plot(x, expon.pdf(x, scale=1 / lmbda), label=f'λ = {lmbda}')
+
+ # Adding title and labels
+ ax.set_title('Exponential distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+
+ plt.savefig(f"{directory}/exponential_exp1.{extension}")
+ plt.close()
diff --git a/src/distributions/fisher_f.py b/src/distributions/fisher_f.py
new file mode 100644
index 0000000..01be603
--- /dev/null
+++ b/src/distributions/fisher_f.py
@@ -0,0 +1,35 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import f
+
+
+def save_to(directory: str, extension: str):
+ def y(x, dfn, dfd):
+ y = f.pdf(x, dfn, dfd)
+ y[y > 2.3] = np.nan
+ return y
+
+ # Degrees of freedom for the distribution
+ d1_d2 = [(1, 1), (2, 1), (3, 1), (10, 1), (10, 10), (100, 100)]
+ # Possible values for the distribution
+ x = np.linspace(0, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of the degrees of freedom
+ for m, n in d1_d2:
+ ax.plot(x, y(x, m, n), label=f'm = {m}, n = {n}')
+
+ # Adding title and labels
+ ax.set_title('F-distribution')
+ ax.set_xlabel('F-statistic')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+
+ plt.savefig(f"{directory}/fisher_f.{extension}")
+ plt.close()
diff --git a/src/distributions/frechet.py b/src/distributions/frechet.py
new file mode 100644
index 0000000..c57afb4
--- /dev/null
+++ b/src/distributions/frechet.py
@@ -0,0 +1,34 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import invweibull
+
+
+def save_to(directory: str, extension: str):
+ def y(x, shape, loc, scale):
+ return invweibull.pdf(x, shape, loc=loc, scale=scale)
+ # Inputs for the distribution
+ inputs = [(0, 1, 1), (1, 1, 1), (0, 0.5, 1), (0, 2, 1), (0, 1, 0.35), (0, 1, 2)]
+ # x values for the distribution
+ x = np.linspace(0, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of a
+ for loc, scale, shape in inputs:
+ ax.plot(x, y(x, shape, loc, scale), label=f'μ = {loc}, σ = {scale}, α = {shape}')
+
+ # Adding title and labels
+ ax.set_title('Fréchet distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/frechet.{extension}")
+ plt.close()
diff --git a/src/distributions/gamma.py b/src/distributions/gamma.py
new file mode 100644
index 0000000..21077d5
--- /dev/null
+++ b/src/distributions/gamma.py
@@ -0,0 +1,31 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import gamma
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(1, 1), (2, 1), (3, 1), (1, 2), (2, 2), (3, 2)]
+ # Possible values for the distribution
+ x = np.linspace(0, 7, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+ colors = ["blue", "red", "green", "blue", "red", "green"]
+ alphas = [1.0, 1.0, 1.0, 0.6, 0.6, 0.6]
+
+ # Plotting the PDF for each value of alpha and beta
+ for i, (k, theta) in enumerate(inputs):
+ ax.plot(x, gamma.pdf(x, k, scale=theta), label=f'k = {k}, θ = {theta}', color=colors[i], alpha=alphas[i])
+
+ # Adding title and labels
+ ax.set_title('Gamma distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+
+ plt.savefig(f"{directory}/gamma.{extension}")
+ plt.close()
diff --git a/src/distributions/geometric.py b/src/distributions/geometric.py
new file mode 100644
index 0000000..57fed29
--- /dev/null
+++ b/src/distributions/geometric.py
@@ -0,0 +1,34 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import geom
+
+
+def save_to(directory: str, extension: str):
+ # Possible values of p for the distribution
+ p_values = [0.2, 0.5, 0.8]
+ # Possible outcomes for a Geometric distributed variable
+ outcomes = np.arange(1, 11)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+ width = 0.2
+
+ # Plotting the PMF for each value of p
+ for i, p in enumerate(p_values):
+ ax.bar(outcomes + i * width - width, geom.pmf(outcomes, p), width=width, label=f'p = {p}')
+
+ # Adding title and labels
+ ax.set_title('Geometric distribution')
+ ax.set_xlabel('Number of trials until first success')
+ ax.set_ylabel('Probability')
+ ax.set_xticks(outcomes) # set the ticks to be the outcome values
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/geometric.{extension}")
+ plt.close()
diff --git a/src/distributions/gumbel.py b/src/distributions/gumbel.py
new file mode 100644
index 0000000..ee30690
--- /dev/null
+++ b/src/distributions/gumbel.py
@@ -0,0 +1,31 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import gumbel_r
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)]
+ # Possible values for the distribution
+ x = np.linspace(-5, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of mu and beta
+ for mu, beta in inputs:
+ ax.plot(x, gumbel_r.pdf(x, loc=mu, scale=beta), label=f'μ = {mu}, β = {beta}')
+
+ # Adding title and labels
+ ax.set_title('Gumbel distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/gumbel.{extension}")
+ plt.close()
diff --git a/src/distributions/hypergeometric.py b/src/distributions/hypergeometric.py
new file mode 100644
index 0000000..70b18ae
--- /dev/null
+++ b/src/distributions/hypergeometric.py
@@ -0,0 +1,33 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import hypergeom
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(50, 12, 10), (50, 35, 10)]
+ # Possible outcomes for a Hypergeometric distributed variable
+ outcomes = np.arange(0, 11)
+ width = 0.5
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PMF for each value of N, K, and n
+ for i, (N, K, n) in enumerate(inputs):
+ ax.bar(outcomes + i * width - width / 2, hypergeom.pmf(outcomes, N, K, n), width=width, label=f'N = {N}, K = {K}, n = {n}')
+
+ # Adding title and labels
+ ax.set_title('Hypergeometric distribution')
+ ax.set_xlabel('k (number of successes)')
+ ax.set_ylabel('Probability')
+ ax.set_xticks(outcomes) # set the ticks to be the outcome values
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/hypergeometric.{extension}")
+ plt.close()
diff --git a/src/distributions/inverse_gaussian.py b/src/distributions/inverse_gaussian.py
new file mode 100644
index 0000000..10a94fa
--- /dev/null
+++ b/src/distributions/inverse_gaussian.py
@@ -0,0 +1,32 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import invgauss
+
+
+def save_to(directory: str, extension: str):
+ # Possible values for the distribution
+ x = np.linspace(0, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ inputs = [(1, 1), (1, 2), (2, 1), (2, 2)]
+
+ # Plotting the PDF for the Inverse Gaussian distribution
+ for mu, lambda_ in inputs:
+ ax.plot(x, invgauss.pdf(x, mu, scale=lambda_), label=f'μ = {mu}, λ = {lambda_}')
+
+ # Adding title and labels
+ ax.set_title('Inverse Gaussian distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/inverse_gaussian.{extension}")
+ plt.close()
diff --git a/src/distributions/log_normal.py b/src/distributions/log_normal.py
new file mode 100644
index 0000000..9418606
--- /dev/null
+++ b/src/distributions/log_normal.py
@@ -0,0 +1,31 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import lognorm
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(0, 1), (0, 0.5), (0, 2), (-0.5, 1), (1, 1)]
+ # Possible values for the distribution
+ x = np.linspace(0, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of mu and sigma
+ for mu, sigma in inputs:
+ ax.plot(x, lognorm.pdf(x, s=sigma, scale=np.exp(mu)), label=f'μ = {mu}, σ = {sigma}')
+
+ # Adding title and labels
+ ax.set_title('Log-normal distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/log_normal.{extension}")
+ plt.close()
diff --git a/src/distributions/normal.py b/src/distributions/normal.py
new file mode 100644
index 0000000..03d7257
--- /dev/null
+++ b/src/distributions/normal.py
@@ -0,0 +1,31 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import norm
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)]
+ # Possible values for the distribution
+ x = np.linspace(-5, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of mu and sigma
+ for mu, sigma in inputs:
+ ax.plot(x, norm.pdf(x, loc=mu, scale=sigma), label=f'μ = {mu}, σ = {sigma}')
+
+ # Adding title and labels
+ ax.set_title('Normal distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/normal.{extension}")
+ plt.close()
diff --git a/src/distributions/normal_inverse_gaussian.py b/src/distributions/normal_inverse_gaussian.py
new file mode 100644
index 0000000..c4cfb86
--- /dev/null
+++ b/src/distributions/normal_inverse_gaussian.py
@@ -0,0 +1,31 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import norminvgauss
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(1, 0), (3, 0), (0.1, 0), (1, -0.99), (1, 0.99)]
+ # Possible values for the distribution
+ x = np.linspace(-5, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots(figsize=(8, 5))
+
+ # Plotting the PDF for the Normal Inverse Gaussian distribution
+ for alpha, beta in inputs:
+ ax.plot(x, norminvgauss.pdf(x, alpha, beta, 0, 1), label=f'α = {alpha}, β = {beta}')
+
+ # Adding title and labels
+ ax.set_title('Normal Inverse Gaussian distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/normal_inverse_gaussian.{extension}")
+ plt.close()
diff --git a/src/distributions/pareto.py b/src/distributions/pareto.py
new file mode 100644
index 0000000..999ced4
--- /dev/null
+++ b/src/distributions/pareto.py
@@ -0,0 +1,31 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import pareto
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(1, 1), (1, 2), (1, 3), (2, 1)]
+ # Possible values for the distribution
+ x = np.linspace(0, 3, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of alpha
+ for scale, shape in inputs:
+ ax.plot(x, pareto.pdf(x, shape, scale=scale), label=f'x$_{{m}}$ = {scale}, α = {shape}')
+
+ # Adding title and labels
+ ax.set_title('Pareto distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/pareto.{extension}")
+ plt.close()
diff --git a/src/distributions/pert.py b/src/distributions/pert.py
new file mode 100644
index 0000000..1ad406d
--- /dev/null
+++ b/src/distributions/pert.py
@@ -0,0 +1,39 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import beta
+
+
+def save_to(directory: str, extension: str):
+ def y(x, min_value, mode, max_value, shape):
+ a = 1 + shape * (mode - min_value) / (max_value - min_value)
+ b = 1 + shape * (max_value - mode) / (max_value - min_value)
+ return beta.pdf(x, a, b, loc=min_value, scale=max_value - min_value)
+
+ inputs = [(-1, 0, 1, 4), (-1, 0, 1, 1), (-1, 0, 1, 8), (-1, 0.5, 1, 4)]
+ # Adjusting the range of x values to be more meaningful for the PERT distribution
+ x = np.linspace(-1, 1, 1000) # max_value in inputs is 2, hence 3 is a reasonable upper bound
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots(figsize=(10, 5))
+
+ # Plotting the PDF for each value of min_value, mode, max_value, and shape
+ for min_value, mode, max_value, shape in inputs:
+ ax.plot(x, y(x, min_value, mode, max_value, shape),
+ label=f'min = {min_value}, mode = {mode}, max = {max_value}, shape = {shape}')
+
+ # Adding title and labels
+ ax.set_title('PERT Distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ box = ax.get_position()
+ ax.set_position([box.x0, box.y0, box.width * 0.6, box.height])
+ ax.legend(loc='upper left', bbox_to_anchor=(1, 1))
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/pert.{extension}")
+ plt.close()
diff --git a/src/distributions/poisson.py b/src/distributions/poisson.py
new file mode 100644
index 0000000..93ae942
--- /dev/null
+++ b/src/distributions/poisson.py
@@ -0,0 +1,33 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import poisson
+
+
+def save_to(directory: str, extension: str):
+ # Possible values of lambda for the distribution
+ lambda_values = [0.5, 1, 2, 4, 10]
+ # Possible outcomes for a Poisson distributed variable
+ outcomes = np.arange(0, 15)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PMF for each value of lambda
+ for i, lmbda in enumerate(lambda_values):
+ ax.plot(outcomes, poisson.pmf(outcomes, lmbda), 'o-', label=f'λ = {lmbda}')
+
+ # Adding title and labels
+ ax.set_title('Poisson distribution')
+ ax.set_xlabel('Outcome')
+ ax.set_ylabel('Probability')
+ ax.set_xticks(outcomes) # set the ticks to be the outcome values
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/poisson.{extension}")
+ plt.close()
diff --git a/src/distributions/skew_normal.py b/src/distributions/skew_normal.py
new file mode 100644
index 0000000..b021694
--- /dev/null
+++ b/src/distributions/skew_normal.py
@@ -0,0 +1,31 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import skewnorm
+
+
+def save_to(directory: str, extension: str):
+ inputs = [-5, -2, 0, 2, 5]
+ # Possible values for the distribution
+ x = np.linspace(-5, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of alpha
+ for alpha in inputs:
+ ax.plot(x, skewnorm.pdf(x, alpha), label=f'α = {alpha}')
+
+ # Adding title and labels
+ ax.set_title('Skew Normal distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/skew_normal.{extension}")
+ plt.close()
diff --git a/src/distributions/standard_geometric.py b/src/distributions/standard_geometric.py
new file mode 100644
index 0000000..de796db
--- /dev/null
+++ b/src/distributions/standard_geometric.py
@@ -0,0 +1,30 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import geom
+
+
+def save_to(directory: str, extension: str):
+ # Possible outcomes for a Geometric distributed variable
+ outcomes = np.arange(1, 11)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PMF for the standard Geometric distribution
+ ax.bar(outcomes, geom.pmf(outcomes, 0.5), label=f'p = 0.5')
+
+ # Adding title and labels
+ ax.set_title('Standard Geometric distribution')
+ ax.set_xlabel('Number of trials until first success')
+ ax.set_ylabel('Probability')
+ ax.set_xticks(outcomes) # set the ticks to be the outcome values
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/standard_geometric.{extension}")
+ plt.close()
diff --git a/src/distributions/standard_normal.py b/src/distributions/standard_normal.py
new file mode 100644
index 0000000..5af1a65
--- /dev/null
+++ b/src/distributions/standard_normal.py
@@ -0,0 +1,29 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import norm
+
+
+def save_to(directory: str, extension: str):
+ # Possible values for the distribution
+ x = np.linspace(-5, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for the standard normal distribution
+ ax.plot(x, norm.pdf(x), label=f'μ = 0, σ = 1')
+
+ # Adding title and labels
+ ax.set_title('Standard normal distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/standard_normal.{extension}")
+ plt.close()
diff --git a/src/distributions/student_t.py b/src/distributions/student_t.py
new file mode 100644
index 0000000..217b844
--- /dev/null
+++ b/src/distributions/student_t.py
@@ -0,0 +1,32 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import t
+
+
+def save_to(directory: str, extension: str):
+ # Degrees of freedom for the distribution
+ df_values = [0.1, 0.5, 1, 2, 5, np.inf]
+ # Possible values for the distribution
+ x = np.linspace(-5, 5, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of the degrees of freedom
+ for df in df_values:
+ ax.plot(x, t.pdf(x, df), label=f'nu = {df}')
+
+ # Adding title and labels
+ ax.set_title('T-distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/student_t.{extension}")
+ plt.close()
diff --git a/src/distributions/triangular.py b/src/distributions/triangular.py
new file mode 100644
index 0000000..ac92d80
--- /dev/null
+++ b/src/distributions/triangular.py
@@ -0,0 +1,35 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import triang
+
+
+def save_to(directory: str, extension: str):
+ # Defining the Triangular distribution PDF
+ def y(a, b, c, x):
+ return triang.pdf(x, c=(c - a) / (b - a), loc=a, scale=b - a)
+
+ inputs = [(0, 1, 0.5), (0, 1, 0.25), (0, 1, 0.75), (-1, 1, 0)]
+ # Possible values for the distribution
+ x = np.linspace(-1, 1, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of a, b, and c
+ for a, b, c in inputs:
+ ax.plot(x, y(a, b, c, x), label=f'a = {a}, b = {b}, c = {c}')
+
+ # Adding title and labels
+ ax.set_title('Triangular distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/triangular.{extension}")
+ plt.close()
diff --git a/src/distributions/unit_ball.py b/src/distributions/unit_ball.py
new file mode 100644
index 0000000..a084da4
--- /dev/null
+++ b/src/distributions/unit_ball.py
@@ -0,0 +1,50 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from mpl_toolkits.mplot3d import Axes3D
+from scipy.spatial import ConvexHull
+
+
+def save_to(directory: str, extension: str):
+ # Create a sphere
+ def plot_sphere(radius=1, num_divisions=50):
+ phi = np.linspace(0, np.pi, num_divisions) # polar angle
+ theta = np.linspace(0, 2 * np.pi, num_divisions) # azimuthal angle
+
+ # Meshgrid
+ phi, theta = np.meshgrid(phi, theta)
+ x = radius * np.sin(phi) * np.cos(theta)
+ y = radius * np.sin(phi) * np.sin(theta)
+ z = radius * np.cos(phi)
+
+ return x, y, z
+
+ # Plotting parameters
+ radius = 1
+ num_divisions = 50 # Increase this for a smoother sphere
+
+ x, y, z = plot_sphere(radius, num_divisions)
+
+ # Create a plot
+ fig = plt.figure(figsize=(8, 6))
+ ax = fig.add_subplot(111, projection='3d')
+ ax.plot_surface(x, y, z, color='b', rstride=1, cstride=1, alpha=0.6, edgecolor='none')
+
+ # Scaling the axes
+ ax.set_xlim([-1, 1])
+ ax.set_ylim([-1, 1])
+ ax.set_zlim([-1, 1])
+ ax.set_aspect('auto')
+ ax.set_box_aspect([1, 1, 1])
+
+ # Labels and title
+ ax.set_xlabel('X')
+ ax.set_ylabel('Y')
+ ax.set_zlabel('Z')
+ ax.set_title('Unit Ball (solid)')
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ # Save the figure
+ plt.savefig(f"{directory}/unit_ball.{extension}")
+ plt.close()
diff --git a/src/distributions/unit_circle.py b/src/distributions/unit_circle.py
new file mode 100644
index 0000000..16a3e6e
--- /dev/null
+++ b/src/distributions/unit_circle.py
@@ -0,0 +1,42 @@
+import numpy as np
+import matplotlib.pyplot as plt
+
+
+def save_to(directory: str, extension: str):
+ # Create a circle
+ def plot_circle(radius=1, num_divisions=100):
+ theta = np.linspace(0, 2 * np.pi, num_divisions)
+ x = radius * np.cos(theta)
+ y = radius * np.sin(theta)
+
+ return x, y
+
+ # Plotting parameters
+ radius = 1
+ num_divisions = 100 # Increase this for a smoother circle
+
+ x, y = plot_circle(radius, num_divisions)
+
+ # Create a plot
+ fig, ax = plt.subplots(figsize=(8, 8))
+ ax.plot(x, y, color='b', alpha=0.6)
+
+ # Scaling the axes
+ ax.set_xlim([-1, 1])
+ ax.set_ylim([-1, 1])
+ ax.set_aspect('equal')
+
+ # Labels and title
+ ax.set_xlabel('X')
+ ax.set_ylabel('Y')
+ ax.set_title('Unit Circle')
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.tight_layout()
+
+ # Save the figure
+ plt.savefig(f"{directory}/unit_circle.{extension}")
+ plt.close()
diff --git a/src/distributions/unit_disc.py b/src/distributions/unit_disc.py
new file mode 100644
index 0000000..26e2f4c
--- /dev/null
+++ b/src/distributions/unit_disc.py
@@ -0,0 +1,42 @@
+import numpy as np
+import matplotlib.pyplot as plt
+
+
+def save_to(directory: str, extension: str):
+ # Create a circle
+ def plot_circle(radius=1, num_divisions=100):
+ theta = np.linspace(0, 2 * np.pi, num_divisions)
+ x = radius * np.cos(theta)
+ y = radius * np.sin(theta)
+
+ return x, y
+
+ # Plotting parameters
+ radius = 1
+ num_divisions = 100 # Increase this for a smoother circle
+
+ x, y = plot_circle(radius, num_divisions)
+
+ # Create a plot
+ fig, ax = plt.subplots(figsize=(8, 8))
+ ax.fill(x, y, color='b', alpha=0.6)
+
+ # Scaling the axes
+ ax.set_xlim([-1, 1])
+ ax.set_ylim([-1, 1])
+ ax.set_aspect('equal')
+
+ # Labels and title
+ ax.set_xlabel('X')
+ ax.set_ylabel('Y')
+ ax.set_title('Unit Disc')
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.tight_layout()
+
+ # Save the figure
+ plt.savefig(f"{directory}/unit_disc.{extension}")
+ plt.close()
diff --git a/src/distributions/unit_sphere.py b/src/distributions/unit_sphere.py
new file mode 100644
index 0000000..dff3cbe
--- /dev/null
+++ b/src/distributions/unit_sphere.py
@@ -0,0 +1,48 @@
+import numpy as np
+import matplotlib.pyplot as plt
+
+
+def save_to(directory: str, extension: str):
+ # Create a sphere
+ def plot_sphere(radius=1, num_divisions=50):
+ phi = np.linspace(0, np.pi, num_divisions) # polar angle
+ theta = np.linspace(0, 2 * np.pi, num_divisions) # azimuthal angle
+
+ # Meshgrid
+ phi, theta = np.meshgrid(phi, theta)
+ x = radius * np.sin(phi) * np.cos(theta)
+ y = radius * np.sin(phi) * np.sin(theta)
+ z = radius * np.cos(phi)
+
+ return x, y, z
+
+ # Plotting parameters
+ radius = 1
+ num_divisions = 50 # Increase this for a smoother sphere
+
+ x, y, z = plot_sphere(radius, num_divisions)
+
+ # Create a plot
+ fig = plt.figure(figsize=(8, 6))
+ ax = fig.add_subplot(111, projection='3d')
+ ax.plot_wireframe(x, y, z, color='b', alpha=0.6, rstride=1, cstride=1)
+
+ # Scaling the axes
+ ax.set_xlim([-1, 1])
+ ax.set_ylim([-1, 1])
+ ax.set_zlim([-1, 1])
+ ax.set_aspect('auto')
+ ax.set_box_aspect([1, 1, 1])
+
+ # Labels and title
+ ax.set_xlabel('X')
+ ax.set_ylabel('Y')
+ ax.set_zlabel('Z')
+ ax.set_title('Unit Sphere (shell)')
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ # Save the figure
+ plt.savefig(f"{directory}/unit_sphere.{extension}")
+ plt.close()
diff --git a/src/distributions/weibull.py b/src/distributions/weibull.py
new file mode 100644
index 0000000..5622eb4
--- /dev/null
+++ b/src/distributions/weibull.py
@@ -0,0 +1,36 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import weibull_min
+
+
+def save_to(directory: str, extension: str):
+ def y(x, scale, shape):
+ y = weibull_min.pdf(x, shape, scale=scale)
+ y[y > 5] = np.nan
+ return y
+ # Possible values of alpha for the distribution
+ inputs = [(1, 1), (2, 1), (3, 1), (1, 2), (1, 3), (2, 2)]
+ # Possible values for the distribution
+ x = np.linspace(0, 3, 1000)
+
+ # Creating the figure and the axis
+ fig, ax = plt.subplots()
+
+ # Plotting the PDF for each value of alpha
+ for scale, shape in inputs:
+ ax.plot(x, y(x, scale, shape), label=f'λ = {scale}, k = {shape}')
+
+ # Adding title and labels
+ ax.set_title('Weibull distribution')
+ ax.set_xlabel('x')
+ ax.set_ylabel('Probability density')
+
+ # Adding a legend
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ plt.savefig(f"{directory}/weibull.{extension}")
+ plt.close()
diff --git a/src/distributions/zeta.py b/src/distributions/zeta.py
new file mode 100644
index 0000000..5fcc027
--- /dev/null
+++ b/src/distributions/zeta.py
@@ -0,0 +1,30 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import zipf
+
+
+def save_to(directory: str, extension: str):
+ inputs = [3, 2, 1.5, 1.1] # Different values of s and n
+ outcomes = np.arange(1, 11) # Outcomes from 1 to 10
+
+ # Creating the figure
+ fig, ax = plt.subplots()
+ width = 0.2 # Bar width
+
+ # Plotting the Zipf Distribution for each value of s
+ for i, s in enumerate(inputs):
+ ax.bar(outcomes + i * width - width * 3 / 2, zipf.pmf(outcomes, s), width=width, label=f's = {s}')
+
+ ax.set_title('Zeta Distribution')
+ ax.set_xlabel('Outcome')
+ ax.set_ylabel('Probability')
+ ax.set_xticks(outcomes) # Adjusting x-ticks to center
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ # Save the plot to a file
+ plt.savefig(f"{directory}/zeta.{extension}")
+ plt.close()
diff --git a/src/distributions/zipf.py b/src/distributions/zipf.py
new file mode 100644
index 0000000..ddeb7c4
--- /dev/null
+++ b/src/distributions/zipf.py
@@ -0,0 +1,30 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import zipfian
+
+
+def save_to(directory: str, extension: str):
+ inputs = [(2, 10), (1, 10), (0, 10)] # Different values of s and n
+ outcomes = np.arange(1, 12) # Outcomes from 1 to 10
+
+ # Creating the figure
+ fig, ax = plt.subplots()
+ width = 0.2 # Bar width
+
+ # Plotting the Zipf Distribution for each value of s
+ for i, (s, n) in enumerate(inputs):
+ ax.bar(outcomes + i * width - width, zipfian.pmf(outcomes, s, n), width=width, label=f's = {s}, n = {n}')
+
+ ax.set_title('Zipf Distribution')
+ ax.set_xlabel('Outcome')
+ ax.set_ylabel('Probability')
+ ax.set_xticks(outcomes) # Adjusting x-ticks to center
+ ax.legend()
+ ax.grid()
+ ax.margins(x=0, y=0)
+ ymin, ymax = ax.get_ylim()
+ ax.set_ylim(ymin, ymax * 1.05)
+
+ # Save the plot to a file
+ plt.savefig(f"{directory}/zipf.{extension}")
+ plt.close()
diff --git a/src/main.py b/src/main.py
new file mode 100644
index 0000000..ce74756
--- /dev/null
+++ b/src/main.py
@@ -0,0 +1,76 @@
+import os
+from distributions import (
+ beta,
+ binomial,
+ cauchy,
+ chi_squared,
+ dirichlet,
+ exponential,
+ exponential_exp1,
+ fisher_f,
+ frechet,
+ gamma,
+ geometric,
+ gumbel,
+ hypergeometric,
+ inverse_gaussian,
+ log_normal,
+ normal,
+ normal_inverse_gaussian,
+ pareto,
+ pert,
+ poisson,
+ skew_normal,
+ standard_geometric,
+ standard_normal,
+ student_t,
+ triangular,
+ unit_ball,
+ unit_circle,
+ unit_disc,
+ unit_sphere,
+ weibull,
+ zeta,
+ zipf,
+)
+
+if __name__ == "__main__":
+ out = "charts"
+ ext = "svg"
+ if not os.path.exists(out):
+ os.makedirs(out)
+ for distr in (
+ beta,
+ binomial,
+ cauchy,
+ chi_squared,
+ dirichlet,
+ exponential,
+ exponential_exp1,
+ fisher_f,
+ frechet,
+ gamma,
+ geometric,
+ gumbel,
+ hypergeometric,
+ inverse_gaussian,
+ log_normal,
+ normal,
+ normal_inverse_gaussian,
+ pareto,
+ pert,
+ poisson,
+ skew_normal,
+ standard_geometric,
+ standard_normal,
+ student_t,
+ triangular,
+ unit_ball,
+ unit_circle,
+ unit_disc,
+ unit_sphere,
+ weibull,
+ zeta,
+ zipf,
+ ):
+ distr.save_to(out, ext)