Tip: Select different dates in the inputs given below and/or change amount of money and the result will be updated automatically.
from IPython.display import display, HTML
display(HTML("""<div id="time-traveling-machine-container"></div>"""))
from datetime import datetime, timedelta
nb_st = datetime.utcnow()
print(f"\nNotebook START time: {nb_st} UTC\n")
%%HTML
<style>
@media (max-width: 540px) {
.output .output_subarea {
max-width: 100%;
}
}
</style>
<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('🔎 Show Python Code')
} else {
$('div.input').show('500');
$('#toggleButton').val('⌦ Hide Python Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide();
$('div.input:contains("%%HTML")').removeClass( "input")
$('div.input:contains("%%capture")').removeClass("input")
});
</script>
<form action="javascript:code_toggle()">
<input type="submit" id="toggleButton" value="🔎 Show Python Code"
class="btn btn-default btn-lg">
</form>
For the past time it uses actual CPI data and for the future time it uses CPI values predicted by the selected model from the models created in this document.
Let's recall concepts of nominal value of money and purchasing power of money:
Nowadays, if you live normal life between the two speciphic dates, then the nominal value of your money during the time is genrally fixed and the purchasing power is generally varying. For example lets say you have 100 GEL banknote:
The GEL Time Traveling Machine works in a very similar way as a normal CPI Inflation Calculator would work, a slight difference is that if you time travel between the two speciphic dates using the GEL Time Traveling Machine, then it has a side effect of inverting the above mentioned properties of the nominal value and purchasing power, which allows to see a different perspective of the same event, this is how the time travel works:
Let's highlight the difference between the GEL Time Traveling Machine (implemented in this notebook) and the GEL CPI Inflation Calculator (not implemented in this notebook):
where the ${t_1}$ and ${t_2}$ denote "from" and "to" dates, respectively. Thus, technically the final effect is just to exchange places of the "from" and "to" dates in the GEL Time Traveling Machine relative to the GEL CPI Inflation Calculator, other than that they work alike. Needless to say that even numbers are the same - just in a different order. Well, that is what a time machine usually do, they exchange "from" and "to" times in a blink of an eye.
In conclusion, the GEL Time Traveling Machine shows what would happen in a scenario where the purchasing power is a fixed constant and nominal value of the money in your pocket is varying instead. With only these two changes and all other things being equal, all the final practical effects are equivalent of what could happen in reality, because the varying nominal value in this scenario is compensated by the fixed purchasing power, so the result you get in the GEL Time Traveling Machine above is just a slightly different angle of view into the same actual reality and it can give you some practical insights into inflation and helps you to understand how your pocket is actually affected by the inflation.
Currently Geostat is using 2010 as the base year for the CPI data.
Data sources:
DOWNLOAD_UPDATE
flag is set to True
in order to use latest available version in this notebook.BASE_YEAR = 2010
VERBOSE = False
DOWNLOAD_UPDATE = False
import numpy as np
import pandas as pd
from pathlib import Path
import wget
from sklearn import linear_model
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
from sklearn.metrics import make_scorer
from sklearn.model_selection import train_test_split, cross_validate
import matplotlib.pyplot as plt
import seaborn as sns
import json
sns.set_theme()
cpi_data_url = ("https://www.geostat.ge/media/"
f"46069/Consumer-Price-Index-({BASE_YEAR}=100).xlsx")
cpi_data_file = Path.cwd() / "data/geostat/EN/Excel/CPI.xlsx"
backup_file_name = "{}_old{}".format(cpi_data_file.stem, cpi_data_file.suffix)
backup_file = cpi_data_file.with_name(backup_file_name)
if DOWNLOAD_UPDATE:
if cpi_data_file.exists():
cpi_data_file.rename(backup_file)
print("Downloading CPI data from Geostat:")
cpi_data_file = Path(wget.download(cpi_data_url, out=str(cpi_data_file)))
cpi_df = pd.read_excel(cpi_data_file, skiprows=2)
cpi_df = cpi_df.rename({'Unnamed: 0': 'Year'}, axis=1)
if VERBOSE:
display(cpi_df.tail())
df = (cpi_df
.melt(id_vars=['Year'], var_name='Month', value_name='CPI')
.replace({
'I': 1,
'II': 2,
'III': 3,
'IV': 4,
'V': 5,
'VI': 6,
'VII': 7,
'VIII': 8,
'IX': 9,
'X': 10,
'XI': 11,
'XII': 12
})
.set_index(['Year','Month'])
.sort_index()
.dropna()
)
if VERBOSE:
display(df.tail(14))
start_month, end_month = [
pd.Timestamp(year=idx[0], month=idx[1], day=1)
for idx in (df.index.min(), df.index.max())]
print("\nGiven CPI data covers the interval of time "
f"from {start_month:%B %Y} to {end_month:%B %Y} (inclusive).\n")
if df.loc[BASE_YEAR, 'CPI'].mean().item() != 100:
if backup_file.exists():
backup_file.rename(backup_file.with_stem(f"CPI_base_{BASE_YEAR}"))
cpi_data_file.unlink()
raise Exception("ERROR: CPI of base year != 100. Please verify the data.")
elif backup_file.exists():
backup_file.unlink()
if VERBOSE:
display(df.info())
display(df.describe())
Before starting to build a linear model, let's visually inspect actual data points versus fitted line, using a regression plot of the CPI data, in order to determine if a linear regression model would be an appropriate choice for the given CPI data or not.
def get_month_number(year: int, month: int) -> int:
return 12 - start_month.month + 12*(year-start_month.year-1) + month
if VERBOSE:
print("December 1999 =>", get_month_number(year=1999, month=12))
if VERBOSE:
for idx, item in df.iterrows():
print(idx, "=>", get_month_number(*idx))
fig = plt.figure(figsize=(18,12))
sns.regplot(y=df['CPI'], x=[get_month_number(*idx) for idx in df.index], ci=99)
plt.title("CPI (Consumer Price Index)", fontweight="bold")
plt.gca().set(
xticks=[get_month_number(year, 1)
for year in df.index.get_level_values('Year').unique()],
xticklabels=df.index.get_level_values('Year').unique().tolist(),
xlabel='')
plt.show()
plt.close(fig)
Let's first build and evaluate some models and select one of them later:
LinearRegression
is a linear model representing an Ordinary least squares Linear Regression.RANSACRegressor
is a linear model which tries to detect and ignore outliers using the RANSAC (RANdom SAmple Consensus) algorithm.TEST_SIZE = 0.33
RAND_STATE = 2022 # fix random state for reproducibility
# Linear model
lr = linear_model.LinearRegression()
# Robust linear model with RANSAC algorithm
ransac = linear_model.RANSACRegressor(max_trials=100000,
random_state=RAND_STATE)
# Prepare data for training
Y = df['CPI'].to_numpy()
X = np.array([[get_month_number(*idx)] for idx in df.index])
X_train, X_test, Y_train, Y_test = train_test_split(X, Y,
test_size=TEST_SIZE,
random_state=RAND_STATE)
Let's evaluate models by measuring select metrics in different contexts.
The following metrics are used for validation:
CV=3
cv_results_lr, cv_results_ransac = [
cross_validate(model, X, Y, cv=CV,
scoring=[
"neg_mean_absolute_error",
"neg_mean_squared_error",
"r2",
],
return_train_score=True,
)
for model in (lr, ransac)]
print(
f"""In-sample cross-validated performance using {CV} folds:
{lr.__class__.__name__}:
MAE = {-cv_results_lr["train_neg_mean_absolute_error"].mean():.2f}
MSE = {-cv_results_lr["train_neg_mean_squared_error"].mean():.2f}
R\u00b2 = {cv_results_lr["train_r2"].mean():.2f}
{ransac.__class__.__name__}:
MAE = {-cv_results_ransac["train_neg_mean_absolute_error"].mean():.2f}
MSE = {-cv_results_ransac["train_neg_mean_squared_error"].mean():.2f}
R\u00b2 = {cv_results_ransac["train_r2"].mean():.2f}
""")
print(
f"""Out-of-sample cross-validated performance using {CV} folds:
{lr.__class__.__name__}:
MAE = {-cv_results_lr["test_neg_mean_absolute_error"].mean():.2f}
MSE = {-cv_results_lr["test_neg_mean_squared_error"].mean():.2f}
R\u00b2 = {cv_results_lr["test_r2"].mean():.2f}
{ransac.__class__.__name__}:
MAE = {-cv_results_ransac["test_neg_mean_absolute_error"].mean():.2f}
MSE = {-cv_results_ransac["test_neg_mean_squared_error"].mean():.2f}
R\u00b2 = {cv_results_ransac["test_r2"].mean():.2f}
""")
lr.fit(X_train, Y_train)
ransac.fit(X_train, Y_train)
Y_train_pred = lr.predict(X_train)
Y_train_pred_ransac = ransac.predict(X_train)
Y_pred = lr.predict(X_test)
Y_pred_ransac = ransac.predict(X_test)
print(
f'''\n\nPreliminary models trained on {
(1-TEST_SIZE)*100
:.1f}% of data for evaluation:
"{lr.__class__.__name__}":
Coefficient (slope) = {lr.coef_[0]:.4f}
Intercept = {lr.intercept_:.2f}
"{ransac.__class__.__name__}":
Coefficient (slope) = {ransac.estimator_.coef_[0]:.4f}
Intercept = {ransac.estimator_.intercept_:.2f}
''')
print(f"""
In-sample performance on the {(1-TEST_SIZE)*100:.1f}% train data:
{lr.__class__.__name__}:
MAE = {mean_absolute_error(Y_train, Y_train_pred):.2f}
MSE = {mean_squared_error(Y_train, Y_train_pred):.2f}
R\u00b2 = {r2_score(Y_train, Y_train_pred):.2f}
{ransac.__class__.__name__}:
MAE = {mean_absolute_error(Y_train, Y_train_pred_ransac):.2f}
MSE = {mean_squared_error(Y_train, Y_train_pred_ransac):.2f}
R\u00b2 = {r2_score(Y_train, Y_train_pred_ransac):.2f}
""")
print(f"""
Out-of-sample performance on the {TEST_SIZE*100:.1f}% test data:
{lr.__class__.__name__}:
MAE = {mean_absolute_error(Y_test, Y_pred):.2f}
MSE = {mean_squared_error(Y_test, Y_pred):.2f}
R\u00b2 = {r2_score(Y_test, Y_pred):.2f}
{ransac.__class__.__name__}:
MAE = {mean_absolute_error(Y_test, Y_pred_ransac):.2f}
MSE = {mean_squared_error(Y_test, Y_pred_ransac):.2f}
R\u00b2 = {r2_score(Y_test, Y_pred_ransac):.2f}
""")
Let's use all the available data to train final versions of the models. We can additionally validate in-sample performance here.
# Train final models using all data:
lr.fit(X, Y)
ransac.fit(X, Y)
print(
f'''\nFinal models trained on 100% of data:
"{lr.__class__.__name__}":
Coefficient (slope) = {lr.coef_[0]:.4f}
Intercept = {lr.intercept_:.2f}
"{ransac.__class__.__name__}":
Coefficient (slope) = {ransac.estimator_.coef_[0]:.4f}
Intercept = {ransac.estimator_.intercept_:.2f}
''')
Y_pred = lr.predict(X)
Y_pred_ransac = ransac.predict(X)
print(
f"""
In-sample performance of the final models:
{lr.__class__.__name__}:
MAE = {mean_absolute_error(Y, Y_pred):.2f}
MSE = {mean_squared_error(Y, Y_pred):.2f}
R\u00b2 = {r2_score(Y, Y_pred):.2f}
{ransac.__class__.__name__}:
MAE = {mean_absolute_error(Y, Y_pred_ransac):.2f}
MSE = {mean_squared_error(Y, Y_pred_ransac):.2f}
R\u00b2 = {r2_score(Y, Y_pred_ransac):.2f}
""")
Let's see how many outliers has RANSACRegressor
model detected this time.
inlier_mask = ransac.inlier_mask_
outlier_mask = np.logical_not(inlier_mask)
print(f"RANSAC algorithm has detected {outlier_mask.sum()} outliers "
"in the CPI data.")
Plot the data and final versions of models together to see how well do they fit the data.
fig = plt.figure(figsize=(18,12))
plt.scatter(X[inlier_mask], Y[inlier_mask], color="yellowgreen", marker=".",
label="Inliers")
plt.scatter(X[outlier_mask], Y[outlier_mask], color="gold", marker=".",
label="Outliers")
line_X = np.arange(X.min(), X.max())[:, np.newaxis]
line_y = lr.predict(line_X)
line_y_ransac = ransac.predict(line_X)
plt.plot(line_X, line_y, color="navy", linewidth=2,
label="Linear regressor")
plt.plot(line_X, line_y_ransac, color="cornflowerblue", linewidth=2,
label="RANSAC regressor")
plt.legend(loc="upper left")
plt.title("Linear models for CPI (Consumer Price Index) prediction",
fontweight="bold")
plt.gca().set(
xticks=[get_month_number(year, 1)
for year in df.index.get_level_values('Year').unique()],
xticklabels=df.index.get_level_values('Year').unique().tolist(),
xlabel='',
ylabel='CPI',
)
plt.show()
plt.close(fig)
Select one of the models we built for usage in the GEL Time Traveling machine.
SELECTED_MODEL = 1
model = [
lr, # 0
ransac, # 1
][SELECTED_MODEL]
model_color = [
"navy",
"cornflowerblue",
][SELECTED_MODEL]
print(f'Selected model is: {model.__class__.__name__}')
pred_years = tuple(range(start_month.year, end_month.year + 11))
df_pred = pd.DataFrame(
index=pd.MultiIndex.from_tuples([(Y,M)
for Y in pred_years
for M in range(1, 13)
], names=['Year', 'Month']))
pred_month_num = np.array([get_month_number(*idx) for idx in df_pred.index])
df_pred['CPI_pred'] = model.predict(pred_month_num.reshape(-1, 1))
if VERBOSE:
display(df_pred)
fig = plt.figure(figsize=(20,12))
plt.scatter(pred_month_num, df_pred['CPI_pred'], color=model_color, marker=".",
label="Predicted CPI")
plt.scatter(X, Y, color="yellowgreen", marker=".",
label="Actual CPI")
plt.legend(loc="upper left")
plt.title("CPI (Consumer Price Index) prediction using "
f"{model.__class__.__name__} model", fontweight="bold")
plt.gca().set(
xticks=[get_month_number(year, 1)
for year in df_pred.index.get_level_values('Year').unique()],
xticklabels=df_pred.index.get_level_values('Year').unique().tolist(),
xlabel='',
ylabel='CPI',
)
plt.show()
plt.close(fig)
Building here the solution for the interactive calculations, but instead of displaying it here it is sent back to the beggining of the notebook. See the result in the beggining of this notebook - that is where the solugion built below is displayed.
##
# Prepare actual and predicted CPI data for the interactive calculations:
##
CPI_data = {
y:{}
for y in df.index.get_level_values('Year').unique()}
CPI_pred_data = {
y:{}
for y in df_pred.index.get_level_values('Year').unique()}
for ym in df.index:
CPI_data[ym[0]][ym[1]] = df.loc[ym,'CPI']
for ym in df_pred.index:
CPI_pred_data[ym[0]][ym[1]] = df_pred.loc[ym,'CPI_pred']
if VERBOSE:
print("CPI_data: ", json.dumps(CPI_data))
print("CPI_pred_data: ", json.dumps(CPI_pred_data))
MONTH_NUM_2_NAME = {
M: pd.Timestamp(year=BASE_YEAR, month=M, day=1).month_name()
for M in df.loc[BASE_YEAR].index}
MONTH_NUM_2_NAME_KA = {
M: pd.Timestamp(year=BASE_YEAR, month=M, day=1).month_name(locale='ka_GE.UTF-8')
for M in df.loc[BASE_YEAR].index}
if VERBOSE:
print(json.dumps(MONTH_NUM_2_NAME))
print(json.dumps(MONTH_NUM_2_NAME_KA))
##
# Build the solution for the interactive calculations:
##
def get_raw_html(lang: str = "en"):
return (f"""
<br>
{"If I will be time traveling" if lang == "en"
else "თუ დროში ვიმოგზაურებ" }<br>
{"from" if lang == "en" else "საიდან:"}
<select id="from-month-{lang}" name="travel-start-month">
{''.join([f'''<option value="{i}">{MONTH_NUM_2_NAME[i] if lang == "en"
else MONTH_NUM_2_NAME_KA[i]}</option>'''
for i in range(1,13)])}
</select>
{"of" if lang == "en" else ""}
<select id="from-year-{lang}" name="travel-start-year">
{' '.join([f'<option value="{Y}">{Y}</option>'
for Y in df_pred.index.get_level_values('Year').unique()])}
</select>
{"year" if lang == "en" else "-დან"} <br>
{"to" if lang == "en" else "სად:"}
<select id="to-month-{lang}" name="travel-end-month">
{''.join([f'''<option value="{i}">{MONTH_NUM_2_NAME[i] if lang == "en"
else MONTH_NUM_2_NAME_KA[i]}</option>'''
for i in range(1,13)])}
</select>
{"of" if lang == "en" else ""}
<select id="to-year-{lang}" name="travel-end-year">
{' '.join([f'<option value="{Y}" '
f'{"selected" if Y == BASE_YEAR else ""}>{Y}</option>'
for Y in df_pred.index.get_level_values('Year').unique()])}
</select>
{"year" if lang == "en" else "-ში"}<br>
{"and I got initially" if lang == "en" else "და დასაწყისისთვის მაქვს"}
<input type="number" id="money-before-{lang}" name="travel-start-money"
min="1" value="100">
GEL {"in my pocket," if lang == "en" else "ჩემს ჯიბეში,"}<br>
{"then I will have" if lang == "en" else "მაშინ მე მექნება"}
<u><span id="result-certitude-{lang}"></span>
<strong id="money-after-{lang}">#.##</strong> GEL</u>
{"in the pocket when I reach the destination." if lang == "en"
else "ჯიბეში როცა ჩავალ დანიშნულების ადგილას."}
<br><br>
<div>{"Explanation of the above result:" if lang == "en"
else "ზემოთ მიღებული შედეგის განმარტება:"}</div>
<div id="result-explanation-title-{lang}"
style="font-size: larger; margin-top:3px;margin-bottom:3px;"></div>
<div id="result-explanation-body-{lang}"
style="max-width:32em; font-size:small;"></div>
""")
def get_raw_js(lang="en"):
return (f"""
//<script type="application/javascript">
var CPI_data = {json.dumps(CPI_data)};
var CPI_pred_data = {json.dumps(CPI_pred_data)};
var MONTH_NUM_2_NAME = {json.dumps(MONTH_NUM_2_NAME) if lang == "en"
else json.dumps(MONTH_NUM_2_NAME_KA)};
var MODEL_NAME = "{model.__class__.__name__}";
""""""
((fn)=>{
if (document.readyState != 'loading'){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
})(()=>{
"""f"""
//console.log("Time Traveling Machine is READY!!!");
let inFromMonth = document.getElementById("from-month-{lang}");
let inFromYear = document.getElementById("from-year-{lang}");
let inToMonth = document.getElementById("to-month-{lang}");
let inToYear = document.getElementById("to-year-{lang}");
let inMoneyBefore = document.getElementById("money-before-{lang}");
let outResultCertitude = document.getElementById("result-certitude-{lang}");
let outMoneyAfter = document.getElementById("money-after-{lang}");
let outExplanationTitle = document.getElementById(
"result-explanation-title-{lang}"
);
let outExplanationBody = document.getElementById(
"result-explanation-body-{lang}"
);
""""""
let isRecordInData = (year, month, data) => {
return data.hasOwnProperty(year) && data[year].hasOwnProperty(month);
}
let getCPI = (year, month, data) => data[year][month];
let doTimeTravel = (startYear, startMonth, endYear, endMonth, moneyBefore) => {
moneyBefore = parseFloat(moneyBefore);
let isDataAvailable = isRecordInData(startYear, startMonth, CPI_data) &&
isRecordInData(endYear, endMonth, CPI_data);
if (isDataAvailable) {
"""f"""
outResultCertitude.innerText = "{"exactly" if lang == "en"
else "ზუსტად"}";
var data = CPI_data;
var toBeWorthText = "{"is worth" if lang == "en"
else "არის ღირებული როგორც"}";
}} else {{
outResultCertitude.innerText = "{"approximately" if lang == "en"
else "მიახლოებით"}";
var data = CPI_pred_data;
var toBeWorthText = "{"is estimated to be worth" if lang == "en"
else "სავარაუდოა იყოს ღირებული როგორც"}";
}}
let startCPI = getCPI(startYear, startMonth, data);
let endCPI = getCPI(endYear, endMonth, data);
let moneyAfter = startCPI * (moneyBefore/endCPI);
moneyAfter = moneyAfter.toFixed(2);
moneyBefore = moneyBefore.toFixed(2);
outMoneyAfter.innerText = moneyAfter;
outExplanationTitle.innerText = [
moneyBefore + "₾ {"in" if lang == "en" else ""}",
MONTH_NUM_2_NAME[endMonth],
endYear + "{"" if lang == "en" else "-ში"}",
toBeWorthText,
moneyAfter + "₾ {"in" if lang == "en" else ""}",
MONTH_NUM_2_NAME[startMonth],
startYear + "{"" if lang == "en" else "-ში"}",
].join(" ");
if (isDataAvailable) {{
outExplanationBody.innerHTML = (
" {"Selected dates" if lang == "en" else "შერჩეული თარიღებიდან"} ("
+ MONTH_NUM_2_NAME[startMonth]
+ " "
+ startYear
+ " {"and" if lang == "en" else "და"} "
+ MONTH_NUM_2_NAME[endMonth]
+ " "
+ endYear
+ ")"
+ " {"are both present in the actual CPI data from Geostat,"
if lang == "en" else "ორივე მოცემულია საქსტატის სფი მონაცემებში,"}"
+ " {"thus the result is directly calculated from the data."
if lang == "en" else
"შესაბამისად ეს შედეგი პირდაპირ გამოთვლილია მონაცემებზე დაყრდნობით."}"
);
}} else {{
outExplanationBody.innerHTML = (
" {"One (or both) of the selected dates"
if lang == "en" else "შერჩეული თარიღებიდან"} ("
+ MONTH_NUM_2_NAME[startMonth]
+ " "
+ startYear
+ " {"and" if lang == "en" else "და"} "
+ MONTH_NUM_2_NAME[endMonth]
+ " "
+ endYear
+ ")"
+ " {"is not present in the CPI data from Geostat,"
if lang == "en" else
" ერთ-ერთი (ან ორივე) არ არის მოცემული საქსტატის სფი მონაცემებში,"}"
+ " {"thus the result is obtained using the "
if lang == "en" else
"შესაბამისად ეს შედეგი მიღებულია "}"
+ MODEL_NAME
+ " {"model." if lang == "en" else "მოდელის გამოყენებით."}"
);
""""""
}
};
let inputHandler = (e) => {
doTimeTravel(inFromYear.value, inFromMonth.value,
inToYear.value, inToMonth.value, inMoneyBefore.value);
};
for (let el of [inFromYear, inFromMonth, inToYear, inToMonth, inMoneyBefore]){
el.addEventListener('input', inputHandler);
}
let event = document.createEvent('HTMLEvents');
event.initEvent('input', true, false);
inMoneyBefore.dispatchEvent(event);
});
//</script>
""")
with open("GEL_TTM_ka.html", "w") as f:
f.write(get_raw_html(lang="ka"))
with open("GEL_TTM_ka.js", "w") as f:
f.write(get_raw_js(lang="ka"))
raw_html = get_raw_html()
raw_js = get_raw_js()
if VERBOSE:
print(raw_html)
print(raw_js)
##
# Send it back to the beggining of the notebook instead of showing here:
##
display(HTML("""<script type="application/javascript">
((fn)=>{
if (document.readyState != 'loading'){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
})(()=>{
let ttm_container = document.getElementById("time-traveling-machine-container");
"""f"""
ttm_container.insertAdjacentHTML("afterbegin", `{raw_html}`);
let script = document.createElement('script');
script.type="application/javascript";
script.textContent = `"""
+ raw_js.replace("</script>", "<\/script>")
+ """`;
ttm_container.parentNode.appendChild(script);
""""""
});
</script>
"""))
print(f"\n ** Total Elapsed time: {datetime.utcnow() - nb_st} ** \n")
print(f"Notebook END time: {datetime.utcnow()} UTC\n")
%%capture
%mkdir OGP_classic
%%capture
%%file "OGP_classic/conf.json"
{
"base_template": "classic",
"preprocessors": {
"500-metadata": {
"type": "nbconvert.preprocessors.ClearMetadataPreprocessor",
"enabled": true,
"clear_notebook_metadata": true,
"clear_cell_metadata": true
},
"900-files": {
"type": "nbconvert.preprocessors.ExtractOutputPreprocessor",
"enabled": true
}
}
}
%%capture
%%file "OGP_classic/index.html.j2"
{%- extends 'classic/index.html.j2' -%}
{%- block html_head -%}
{# OGP attributes for shareability #}
<meta property="og:url" content="https://sentinel-1.github.io/GEL_time_traveling_machine/" />
<meta property="og:type" content="article" />
<meta property="og:title" content="GEL (₾) Time Traveling Machine" />
<meta property="og:description" content="How much does inflation affect your pocket in Georgia?" />
<meta property="og:image" content="https://raw.githubusercontent.com/sentinel-1/GEL_time_traveling_machine/master/images/GEL_rocket_orange_light_alt_(1200x628).png" />
<meta property="og:image:alt" content="Logo of the GEL Time Traveling Machine" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="628" />
<meta property="article:published_time" content="2022-06-26T23:07:36+00:00" />
<meta property="article:modified_time" content="{{ resources.iso8610_datetime_utcnow }}" />
<meta property="article:publisher" content="https://sentinel-1.github.io" />
<meta property="article:author" content="https://github.com/sentinel-1" />
<meta property="article:section" content="datascience" />
<meta property="article:tag" content="datascience" />
<meta property="article:tag" content="Python" />
<meta property="article:tag" content="data" />
<meta property="article:tag" content="analytics" />
<meta property="article:tag" content="datavisualization" />
<meta property="article:tag" content="bigdataunit" />
<meta property="article:tag" content="visualization" />
<meta property="article:tag" content="inflation" />
<meta property="article:tag" content="GEL" />
<meta property="article:tag" content="Lari" />
<meta property="article:tag" content="CPI" />
<meta property="article:tag" content="timetravelingmachine" />
{{ super() }}
{%- endblock html_head -%}
{% block body_header %}
<body>
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<ul class="nav nav-pills navbar-left">
<li role="presentation">
<a href="/">
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 576 512" width="1em">
<path
fill="#999999"
d="M 288,0 574,288 511,288 511,511 352,511 352,352 223,352 223,511 62,511 64,288 0,288 Z"
/>
</svg> Home
</a>
</li>
</ul>
<ul class="nav nav-pills navbar-right">
<li role="presentation" class="active">
<a href="/GEL_time_traveling_machine/">🇬🇧 English </a>
</li>
<li role="presentation">
<a href="/GEL_time_traveling_machine/ka/">🇬🇪 ქართული</a>
</li>
</ul>
</div>
</nav>
</div>
<div tabindex="-1" id="notebook" class="border-box-sizing">
<div class="container" id="notebook-container">
{% endblock body_header %}
{% block body_footer %}
</div>
</div>
<footer>
<div class="container"
style="display:flex; flex-direction: row; justify-content: center; align-items: center;">
<p style="margin: 3.7em auto;"> © 2022
<a href="https://github.com/sentinel-1" target="_blank">Sentinel-1</a>
</p>
<!-- TOP.GE ASYNC COUNTER CODE -->
<div id="top-ge-counter-container" data-site-id="116052"
style="margin-right: 3.7em;float: right;"></div>
<script async src="//counter.top.ge/counter.js"></script>
<!-- / END OF TOP.GE COUNTER CODE -->
<!-- ANALYTICS.LAGOGAL.COM -->
<div id="analytics-lagogal-com-access" data-site-id="20221"
style="margin: 0;padding: 0;"></div>
<script async src="//analytics.lagogal.com/access.js"></script>
<!-- / END OF ANALYTICS.LAGOGAL.COM -->
</div>
</footer>
</body>
{% endblock body_footer %}
This notebook is originally published under the Apache License (Version 2.0) at the following GitHub repository: sentinel-1/GEL_time_traveling_machine
For the issues, feedback or suggestions regarding the original notebook (if any) feel free to open an issue at the corresponding Issues page of the repository