From faabe5977566f9fa9a033cc07d9c3c1427a8b9e6 Mon Sep 17 00:00:00 2001 From: Crinibus <57172157+Crinibus@users.noreply.github.com> Date: Sat, 1 Oct 2022 00:49:03 +0200 Subject: [PATCH 1/5] Add defaults to arguments --id and --name --- scraper/arguments.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scraper/arguments.py b/scraper/arguments.py index 4edefe9a..36496948 100644 --- a/scraper/arguments.py +++ b/scraper/arguments.py @@ -57,6 +57,7 @@ def argparse_setup() -> ArgumentParser.parse_args: nargs="*", action="extend", dest="id", + default=[], ) parser.add_argument( @@ -67,6 +68,7 @@ def argparse_setup() -> ArgumentParser.parse_args: nargs="*", action="extend", dest="name", + default=[], ) parser.add_argument( From 6fdaa83e833934c6054e89dabfa0d6becbee38ae Mon Sep 17 00:00:00 2001 From: Crinibus <57172157+Crinibus@users.noreply.github.com> Date: Sat, 1 Oct 2022 00:51:03 +0200 Subject: [PATCH 2/5] Make function add_scatter_plot more flexible/dynamic Add optional parameters: - name - color - hover_text --- scraper/visualize.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scraper/visualize.py b/scraper/visualize.py index f78ed1d5..4305f05e 100644 --- a/scraper/visualize.py +++ b/scraper/visualize.py @@ -202,14 +202,21 @@ def add_scatter_plot( currency: str, dates: list, prices: list, + name=None, + color=None, + hover_text=None, ) -> None: + scatter_name = name if name else f"{website_name.capitalize()} - {id}" + scatter_color = color if color else WEBSITE_COLORS[website_name] + scatter_hover_text = hover_text if hover_text else "Price: %{y:.0f}" + f" {currency}" + figure.add_trace( go.Scatter( - name=f"{website_name.capitalize()} - {id}", + name=scatter_name, x=dates, y=prices, - line={"color": WEBSITE_COLORS[website_name], "width": 2}, - hovertemplate="Price: %{y:.0f}" + f" {currency}", + line={"color": scatter_color, "width": 2}, + hovertemplate=scatter_hover_text, ) ) From 2ffbf11e22df878527e7d0beb0bc1d90042ed38c Mon Sep 17 00:00:00 2001 From: Crinibus <57172157+Crinibus@users.noreply.github.com> Date: Sat, 1 Oct 2022 00:55:46 +0200 Subject: [PATCH 3/5] Add argument --compare --- main.py | 2 +- scraper/arguments.py | 11 ++++++- scraper/visualize.py | 78 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 60ade4c5..7c0752e3 100644 --- a/main.py +++ b/main.py @@ -12,7 +12,7 @@ def main(): scraper.clean_records_data() if args.visualize: - scraper.visualize_data(args.all, args.category, args.id, args.name, args.up_to_date) + scraper.visualize_data(args.all, args.category, args.id, args.name, args.up_to_date, args.compare) if args.reset: scraper.reset() diff --git a/scraper/arguments.py b/scraper/arguments.py index 36496948..16c22f47 100644 --- a/scraper/arguments.py +++ b/scraper/arguments.py @@ -89,6 +89,13 @@ def argparse_setup() -> ArgumentParser.parse_args: metavar="SEARCH_TERM", ) + parser.add_argument( + "--compare", + help="use with --visualize and --id to compare two or more products on one graph", + action="store_true", + dest="compare", + ) + parser.add_argument( "--reset", help="delete data for each product in records.json, such as prices of each recorded day", @@ -143,8 +150,10 @@ def validate_arguments(parser: ArgumentParser) -> None: parser.error("Specified more urls than categories") if args.visualize: - if not any([args.all, args.category, args.id, args.name]): + if not any([args.all, args.category, args.id, args.name, args.compare]): parser.error("When using --visualize, then one of the following is required: --all, --category, --id, --name") + if args.compare and not any([args.id, args.name]): + parser.error("When using --visualize and --compare, then one of the following is required: --id, --name") if args.latest_datapoint: if not args.name and not args.id: diff --git a/scraper/visualize.py b/scraper/visualize.py index 4305f05e..d8a737c6 100644 --- a/scraper/visualize.py +++ b/scraper/visualize.py @@ -5,9 +5,15 @@ from datetime import datetime -def visualize_data(show_all: bool, categories: List[str], ids: List[str], names: List[str], only_up_to_date: bool): +def visualize_data( + show_all: bool, categories: List[str], ids: List[str], names: List[str], only_up_to_date: bool, compare: bool +) -> None: print("Visualizing...") + if compare: + compare_products(ids, names) + return + if show_all: show_all_products(only_up_to_date) @@ -156,6 +162,43 @@ def show_all_products(only_up_to_date: bool) -> None: fig.show() +def compare_products(ids: List[str], names: List[str]) -> None: + products_with_ids = get_products_with_ids(ids) + products_with_name = get_products_with_names(names) + + products = [*products_with_ids, *products_with_name] + + if len(products_with_ids) < len(ids) or len(products_with_name) < len(names): + print("\nCouldn't find all products that have the specified id(s) or name(s), only comparing those that are found\n") + + product_ids = [product["info"]["id"] for product in products] + product_ids_string = ", ".join(product_ids) + + print(f"Comparing products with ids: {product_ids_string}") + + fig = go.Figure() + + for product in products: + product_name = product["name"] + product_info = product["info"] + product_id = product_info["id"] + + add_scatter_plot( + fig, + product_info["website_name"], + str(product_id), + product_info["currency"], + product_info["dates"], + product_info["prices"], + name=f"{product_id} - {product_name}", + ) + + title = f"Comparing products with ids {product_ids_string}" + + config_figure(fig, title) + fig.show() + + def format_data() -> Generator[dict, None, None]: records_data = Filemanager.get_record_data() @@ -239,6 +282,21 @@ def get_product_with_id(id: str) -> dict: return None +def get_products_with_ids(ids: List[str]) -> List[dict]: + products = [] + for product_info in format_data(): + for website_info in product_info["websites"]: + if str(website_info["id"]) in ids: + products.append( + { + "name": product_info["name"], + "category": product_info["category"], + "info": website_info, + } + ) + return products + + def get_product_with_name(name: str) -> dict: for product_info in format_data(): if product_info["name"].lower() == name.lower(): @@ -246,6 +304,24 @@ def get_product_with_name(name: str) -> dict: return None +def get_products_with_names(names: List[str]) -> List[str]: + names_lowercase = [name.lower() for name in names] + products = [] + for product_info in format_data(): + if not product_info["name"].lower() in names_lowercase: + continue + + for website_info in product_info["websites"]: + products.append( + { + "name": product_info["name"], + "category": product_info["category"], + "info": website_info, + } + ) + return products + + def get_all_products() -> Generator[dict, None, None]: for product_info in format_data(): yield product_info From a3ebb2bccdc5aa59a4c71407652a3fc853639014 Mon Sep 17 00:00:00 2001 From: Crinibus <57172157+Crinibus@users.noreply.github.com> Date: Sat, 1 Oct 2022 00:57:44 +0200 Subject: [PATCH 4/5] Fix spacing in visualizing example commands section --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3814b7d0..cc5c5eca 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,8 @@ To show graphs for all products, run the following command: python3 main.py -v --all ``` +
+ **Show graph(s) for specific products** To show a graph for only one product, run the following command where `````` is the id of the product you want a graph for: @@ -245,6 +247,7 @@ For multiple products, just add another id, like so: python3 main.py -v --id ``` +
**Show graphs for products in one or more categories** @@ -258,6 +261,7 @@ For multiple categories, just add another category, like so: python3 main.py -v -c ``` +
**Show graps for products with a specific name** @@ -273,6 +277,7 @@ python3 main.py -v --name If the name of a product has multiple words in it, then just add quotation marks around the name. +
**Only show graph for products that are up to date** @@ -282,5 +287,5 @@ python3 main.py -v --all -utd ``` The use of the flag ```-utd``` is only implemented when visualizing all products like the example above or when visualizing all products in a category: ``` -python3 main.py -v -c gpu -utd +python3 main.py -v -c -utd ``` From 0cb9e5b42414cf5614c84b9897a4649da9de9c36 Mon Sep 17 00:00:00 2001 From: Crinibus <57172157+Crinibus@users.noreply.github.com> Date: Sat, 1 Oct 2022 00:58:53 +0200 Subject: [PATCH 5/5] Add explanation usage of argument --compare to README --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index cc5c5eca..dbf9f74c 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ To visualize your data, just run main.py with the ```-v``` or ```--visualize``` - ```-c [ [ ...]]``` or ```--category [ [ ...]]``` to visualize all products in one or more categories - ```--id [ [ ...]]``` to visualize one or more products with the specified id(s) - ```-n [ [ ...]]``` or ```--name [ ...]]``` to visualize one or more products with the specified name(s) +- ```--compare``` to compare two or more products with the specified id(s) and/or name(s) on one graph. Use with ```--id``` and/or ```--name``` ### Example graph ![](https://user-images.githubusercontent.com/57172157/171033112-908f6420-6c7a-44ef-ba67-8a4a73bbd96e.png) @@ -289,3 +290,20 @@ The use of the flag ```-utd``` is only implemented when visualizing all products ``` python3 main.py -v -c -utd ``` + +
+ +**Compare two products** + +To compare two products on one graph, use the flag ```--compare``` with flag ```--id``` and/or ```--name```, like so: +``` +python3 main.py -v --compare --id +``` +``` +python3 main.py -v --compare --name +``` +``` +python3 main.py -v --compare --id --name +``` + +***OBS** when using ```--name``` multiple products can be visualized*