From 2c28db0eb64faa3c6220b7648f0ec89742902600 Mon Sep 17 00:00:00 2001 From: Redume Date: Mon, 17 Feb 2025 19:50:24 +0300 Subject: [PATCH 1/7] feat(chart): Rounded the corners, reduced the number of dates --- chart/function/create_chart.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/chart/function/create_chart.py b/chart/function/create_chart.py index 5faf618..44213a1 100644 --- a/chart/function/create_chart.py +++ b/chart/function/create_chart.py @@ -6,6 +6,8 @@ based on historical data retrieved from the database. from datetime import datetime from matplotlib import pyplot as plt +from scipy.interpolate import make_interp_spline +import numpy as np from function.gen_unique_name import generate_unique_name from database.server import create_pool @@ -55,32 +57,32 @@ async def create_chart( return None date, rate = [], [] - fig = plt.gcf() for row in data: - date.append(str(row['date'])) + parsed_date = datetime.strptime(row['data'], '%Y-%m-%d%H:%M:%S.%fZ').date() + date.append(parsed_date) rate.append(row['rate']) - width = 18.5 + (len(date) // 5) * 3 - fig.set_size_inches(width, 9.5) + spline = make_interp_spline(range(len(date)), rate, k=2) + x = np.arange(len(date)) - if rate[0] < rate[-1]: - plt.plot(date, rate, color='green', marker='o') - elif rate[0] > rate[-1]: - plt.plot(date, rate, color='red', marker='o') - else: - plt.plot(date, rate, color='grey') + newx_2 = np.linspace(0, len(date) - 1, 200) + newy_2 = spline_2(newx_2) + fig, ax = plt.subplot(figsize=(15, 6)) - plt.xlabel('Date') - plt.ylabel('Rate') + for label in (ax.get_xticklabels() + ax.get_yticklabels()): + label.set_fontsize(10) + ax.set_xtick(np.linspace(0, len(date) - 1, 10)) + ax.set_xticklabels([date[int(i)].strftime('%Y-%m-%d') for i in np.linspace(0, len(date) - 1, 10).astype(int)]) name = await generate_unique_name( f'{from_currency.upper()}_{conv_currency.upper()}', datetime.now() ) - fig.savefig(f'../charts/{name}.png') + plt.plot(newx_2, newy_2) + plt.savefig(f'../charts/{name}.png') fig.clear() return name From 5407830125778a2deb4012794bbf6151f07f23f4 Mon Sep 17 00:00:00 2001 From: Redume Date: Wed, 19 Feb 2025 12:59:56 +0300 Subject: [PATCH 2/7] chore(chart): I made the hyphenation because of the big line. --- chart/function/create_chart.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/chart/function/create_chart.py b/chart/function/create_chart.py index 44213a1..4431ec7 100644 --- a/chart/function/create_chart.py +++ b/chart/function/create_chart.py @@ -46,7 +46,8 @@ async def create_chart( async with pool.acquire() as conn: data = await conn.fetch( 'SELECT date, rate FROM currency ' - 'WHERE (date BETWEEN $1 AND $2) AND from_currency = $3 AND conv_currency = $4 ORDER BY date', + 'WHERE (date BETWEEN $1 AND $2) ' + + 'AND from_currency = $3 AND conv_currency = $4 ORDER BY date', start_date_obj, end_date_obj, from_currency.upper(), @@ -74,7 +75,12 @@ async def create_chart( label.set_fontsize(10) ax.set_xtick(np.linspace(0, len(date) - 1, 10)) - ax.set_xticklabels([date[int(i)].strftime('%Y-%m-%d') for i in np.linspace(0, len(date) - 1, 10).astype(int)]) + ax.set_xticklabels( + [ + date[int(i)].strftime('%Y-%m-%d') + for i in np.linspace(0, len(date) - 1, 10).astype(int) + ] + ) name = await generate_unique_name( f'{from_currency.upper()}_{conv_currency.upper()}', From ab97ee1e62f08bee9a73f5903969416f3eef3c10 Mon Sep 17 00:00:00 2001 From: Redume Date: Wed, 19 Feb 2025 13:14:12 +0300 Subject: [PATCH 3/7] chore(chart): Added dependencies --- chart/requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chart/requirements.txt b/chart/requirements.txt index f286fcc..278ef87 100644 --- a/chart/requirements.txt +++ b/chart/requirements.txt @@ -4,4 +4,6 @@ uvicorn~=0.29.0 fastapi[standard]~=0.115.2 starlette~=0.40.0 user_agents==2.2.0 -asyncpg~=0.30.0 \ No newline at end of file +asyncpg~=0.30.0 +scipy~=1.15.2 +numpy~=2.2.0 \ No newline at end of file From ef2c126d68f69d93a35ce2924ab1759ecdb815b7 Mon Sep 17 00:00:00 2001 From: Redume Date: Wed, 19 Feb 2025 13:43:07 +0300 Subject: [PATCH 4/7] chore(chart): convert indent to tabs --- chart/function/create_chart.py | 145 ++++++++++++++++----------------- 1 file changed, 72 insertions(+), 73 deletions(-) diff --git a/chart/function/create_chart.py b/chart/function/create_chart.py index 4431ec7..7bf9eb9 100644 --- a/chart/function/create_chart.py +++ b/chart/function/create_chart.py @@ -13,99 +13,98 @@ from function.gen_unique_name import generate_unique_name from database.server import create_pool async def create_chart( - from_currency: str, - conv_currency: str, - start_date: str, - end_date: str + from_currency: str, + conv_currency: str, + start_date: str, + end_date: str ) -> (str, None): - """ - Generates a line chart of currency rates for a given date range. + """ + Generates a line chart of currency rates for a given date range. - The chart shows the exchange rate trend between `from_currency` and - `conv_currency` within the specified `start_date` and `end_date` range. - The generated chart is saved as a PNG file, and the function returns the - file name. If data is invalid or insufficient, the function returns `None`. + The chart shows the exchange rate trend between `from_currency` and + `conv_currency` within the specified `start_date` and `end_date` range. + The generated chart is saved as a PNG file, and the function returns the + file name. If data is invalid or insufficient, the function returns `None`. - Args: - from_currency (str): The base currency (e.g., "USD"). - conv_currency (str): The target currency (e.g., "EUR"). - start_date (str): The start date in the format 'YYYY-MM-DD'. - end_date (str): The end date in the format 'YYYY-MM-DD'. + Args: + from_currency (str): The base currency (e.g., "USD"). + conv_currency (str): The target currency (e.g., "EUR"). + start_date (str): The start date in the format 'YYYY-MM-DD'. + end_date (str): The end date in the format 'YYYY-MM-DD'. - Returns: - str | None: The name of the saved chart file, or `None` if the operation fails. - """ - pool = await create_pool() + Returns: + str | None: The name of the saved chart file, or `None` if the operation fails. + """ + pool = await create_pool() - if not validate_date(start_date) or not validate_date(end_date): - return None + if not validate_date(start_date) or not validate_date(end_date): + return None - start_date_obj = datetime.strptime(start_date, '%Y-%m-%d').date() - end_date_obj = datetime.strptime(end_date, '%Y-%m-%d').date() + start_date_obj = datetime.strptime(start_date, '%Y-%m-%d').date() + end_date_obj = datetime.strptime(end_date, '%Y-%m-%d').date() - async with pool.acquire() as conn: - data = await conn.fetch( - 'SELECT date, rate FROM currency ' - 'WHERE (date BETWEEN $1 AND $2) ' + + async with pool.acquire() as conn: + data = await conn.fetch( + 'SELECT date, rate FROM currency ' + 'WHERE (date BETWEEN $1 AND $2) ' + 'AND from_currency = $3 AND conv_currency = $4 ORDER BY date', - start_date_obj, - end_date_obj, - from_currency.upper(), - conv_currency.upper() - ) + start_date_obj, + end_date_obj, + from_currency.upper(), + conv_currency.upper() + ) - if not data or len(data) <= 1: - return None + if not data or len(data) <= 1: + return None - date, rate = [], [] + date, rate = [], [] - for row in data: - parsed_date = datetime.strptime(row['data'], '%Y-%m-%d%H:%M:%S.%fZ').date() - date.append(parsed_date) - rate.append(row['rate']) + for row in data: + parsed_date = datetime.strptime(row['data'], '%Y-%m-%d%H:%M:%S.%fZ').date() + date.append(parsed_date) + rate.append(row['rate']) - spline = make_interp_spline(range(len(date)), rate, k=2) - x = np.arange(len(date)) + spline = make_interp_spline(range(len(date)), rate, k=2) + x = np.arange(len(date)) - newx_2 = np.linspace(0, len(date) - 1, 200) - newy_2 = spline_2(newx_2) - fig, ax = plt.subplot(figsize=(15, 6)) + newx_2 = np.linspace(0, len(date) - 1, 200) + newy_2 = spline_2(newx_2) + fig, ax = plt.subplot(figsize=(15, 6)) - for label in (ax.get_xticklabels() + ax.get_yticklabels()): - label.set_fontsize(10) + for label in (ax.get_xticklabels() + ax.get_yticklabels()): + label.set_fontsize(10) - ax.set_xtick(np.linspace(0, len(date) - 1, 10)) - ax.set_xticklabels( - [ - date[int(i)].strftime('%Y-%m-%d') - for i in np.linspace(0, len(date) - 1, 10).astype(int) - ] - ) + ax.set_xtick(np.linspace(0, len(date) - 1, 10)) + ax.set_xticklabels( + [ + date[int(i)].strftime('%Y-%m-%d') + for i in np.linspace(0, len(date) - 1, 10).astype(int) + ] + ) - name = await generate_unique_name( - f'{from_currency.upper()}_{conv_currency.upper()}', - datetime.now() - ) + name = await generate_unique_name( + f'{from_currency.upper()}_{conv_currency.upper()}', + datetime.now() + ) - plt.plot(newx_2, newy_2) - plt.savefig(f'../charts/{name}.png') - fig.clear() + plt.savefig(f'../charts/{name}.png') + fig.clear() - return name + return name def validate_date(date_str: str) -> bool: - """ - Validates whether the provided string is a valid date in the format 'YYYY-MM-DD'. + """ + Validates whether the provided string is a valid date in the format 'YYYY-MM-DD'. - Args: - date_str (str): The date string to validate. + Args: + date_str (str): The date string to validate. - Returns: - bool: `True` if the string is a valid date, `False` otherwise. - """ - try: - datetime.strptime(date_str, '%Y-%m-%d') - return True - except ValueError: - return False + Returns: + bool: `True` if the string is a valid date, `False` otherwise. + """ + try: + datetime.strptime(date_str, '%Y-%m-%d') + return True + except ValueError: + return False From e1fdda4b5443abd9c5b0a074caf9e994c5d6c77f Mon Sep 17 00:00:00 2001 From: Redume Date: Wed, 19 Feb 2025 14:18:10 +0300 Subject: [PATCH 5/7] fix(chart): Fixed currency rate and date indexes and other minor fixes --- chart/function/create_chart.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/chart/function/create_chart.py b/chart/function/create_chart.py index 7bf9eb9..74cede3 100644 --- a/chart/function/create_chart.py +++ b/chart/function/create_chart.py @@ -60,21 +60,20 @@ async def create_chart( date, rate = [], [] for row in data: - parsed_date = datetime.strptime(row['data'], '%Y-%m-%d%H:%M:%S.%fZ').date() - date.append(parsed_date) - rate.append(row['rate']) + date.append(row[0]) + rate.append(row[1]) spline = make_interp_spline(range(len(date)), rate, k=2) x = np.arange(len(date)) newx_2 = np.linspace(0, len(date) - 1, 200) - newy_2 = spline_2(newx_2) - fig, ax = plt.subplot(figsize=(15, 6)) + newy_2 = spline(newx_2) + fig, ax = plt.subplots(figsize=(15, 6)) for label in (ax.get_xticklabels() + ax.get_yticklabels()): label.set_fontsize(10) - ax.set_xtick(np.linspace(0, len(date) - 1, 10)) + ax.set_xticks(np.linspace(0, len(date) - 1, 10)) ax.set_xticklabels( [ date[int(i)].strftime('%Y-%m-%d') @@ -87,6 +86,8 @@ async def create_chart( datetime.now() ) + + plt.plot(newx_2, newy_2) plt.savefig(f'../charts/{name}.png') fig.clear() From 77aaddb119459ae78a62eb540df4c20f86568acb Mon Sep 17 00:00:00 2001 From: Redume Date: Wed, 19 Feb 2025 14:19:18 +0300 Subject: [PATCH 6/7] feat(chart): Made colors for rising, falling and stagnant rates --- chart/function/create_chart.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/chart/function/create_chart.py b/chart/function/create_chart.py index 74cede3..ef866fa 100644 --- a/chart/function/create_chart.py +++ b/chart/function/create_chart.py @@ -87,7 +87,13 @@ async def create_chart( ) - plt.plot(newx_2, newy_2) + if rate[0] < rate[-1]: + plt.plot(newx_2, newy_2, color='green') + elif rate[0] > rate[-1]: + plt.plot(newx_2, newy_2, color='red', marker='o') + else: + plt.plot(newx_2, newy_2, color='grey') + plt.savefig(f'../charts/{name}.png') fig.clear() From 3daaedaa2d8842cc4891eaeb8dc70f7391942c45 Mon Sep 17 00:00:00 2001 From: Redume Date: Wed, 19 Feb 2025 14:24:39 +0300 Subject: [PATCH 7/7] fix(chart): delete chart marker 'o' --- chart/function/create_chart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chart/function/create_chart.py b/chart/function/create_chart.py index ef866fa..983da04 100644 --- a/chart/function/create_chart.py +++ b/chart/function/create_chart.py @@ -90,7 +90,7 @@ async def create_chart( if rate[0] < rate[-1]: plt.plot(newx_2, newy_2, color='green') elif rate[0] > rate[-1]: - plt.plot(newx_2, newy_2, color='red', marker='o') + plt.plot(newx_2, newy_2, color='red') else: plt.plot(newx_2, newy_2, color='grey')