import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from io import StringIO
from sklearn.preprocessing import PowerTransformer, QuantileTransformer

plt.rcParams.update({'text.color': 'gray', 'axes.labelcolor': 'gray', 'axes.edgecolor': 'gray',
                     'xtick.color': 'gray', 'ytick.color': 'gray'})

url = "https://raw.githubusercontent.com/hsandmann/biblio/refs/heads/main/ml/aula04/titanic/train.csv"
fare = pd.read_csv(url)[['Fare']]
yj = PowerTransformer(method='yeo-johnson', standardize=False).fit(fare)
qt = QuantileTransformer(n_quantiles=100, output_distribution='normal').fit(fare)
versions = [('raw Fare (£)', fare['Fare'].to_numpy(), '#ff7b72'),
            ('log1p(Fare)', np.log1p(fare['Fare']).to_numpy(), '#f0883e'),
            (f'Yeo-Johnson (λ = {yj.lambdas_[0]:.3f})', yj.transform(fare).ravel(), '#3fb950'),
            ('QuantileTransformer (normal)', qt.transform(fare).ravel(), '#58a6ff')]

fig, axes = plt.subplots(1, 4, figsize=(10, 2.9))
for ax, (name, v, col) in zip(axes, versions):
    ax.hist(v, bins=40, color=col, alpha=0.85)
    ax.set_title(f'{name}\nskewness {pd.Series(v).skew():.2f}', fontsize=9)
    ax.tick_params(labelsize=7.5)
    ax.set_yticks([])
    for side in ['left', 'right', 'top']:
        ax.spines[side].set_visible(False)
zero = qt.transform(pd.DataFrame({'Fare': [0.0]}))[0, 0]
axes[3].annotate('15 free tickets\n(Fare = 0)', xy=(zero, 16), xytext=(zero + 0.6, 90), fontsize=8,
                 color='#58a6ff', arrowprops=dict(arrowstyle='->', color='#58a6ff'))
axes[0].annotate('£512', xy=(512, 3), xytext=(380, 150), fontsize=8, color='#ff7b72',
                 arrowprops=dict(arrowstyle='->', color='#ff7b72'))
fig.suptitle('Titanic fares: a scaler cannot change this shape, a transformation can', fontsize=10)
plt.tight_layout()

buffer = StringIO()
plt.savefig(buffer, format="svg", transparent=True)
print(buffer.getvalue())

plt.close()
