diff options
-rw-r--r-- | arial.ttf | bin | 0 -> 367112 bytes | |||
-rw-r--r-- | assets/arial.ttf | bin | 0 -> 367112 bytes | |||
-rw-r--r-- | main.py | 164 | ||||
-rw-r--r-- | main.spec | 56 | ||||
-rw-r--r-- | poetry.lock | 380 | ||||
-rw-r--r-- | pyproject.toml | 20 |
6 files changed, 620 insertions, 0 deletions
diff --git a/arial.ttf b/arial.ttf Binary files differnew file mode 100644 index 0000000..ff0815c --- /dev/null +++ b/arial.ttf diff --git a/assets/arial.ttf b/assets/arial.ttf Binary files differnew file mode 100644 index 0000000..ff0815c --- /dev/null +++ b/assets/arial.ttf @@ -0,0 +1,164 @@ +import pandas as pd +import tkinter as tk +from tkinter import ttk +from tkinter.filedialog import askopenfilename, asksaveasfilename + +class CompanySelector: + def __init__(self, master): + self.master = master + self.master.title("Company Selector") + + self.select_file_button = tk.Button(self.master, text="Select Excel File", command=self.load_file) + self.select_file_button.pack() + + def load_file(self): + file_path = askopenfilename(filetypes=[("Excel files", "*.xlsx *.xls")]) + if not file_path: + return + + self.df = pd.read_excel(file_path) + self.show_companies() + + def show_companies(self): + self.select_file_button.pack_forget() + + self.company_listbox = tk.Listbox(self.master, selectmode=tk.MULTIPLE, exportselection=False) + self.company_listbox.pack() + + for company in self.df["Company Name"]: + self.company_listbox.insert(tk.END, company) + + self.create_pyramid_button = tk.Button(self.master, text="Create Pyramid", command=self.create_pyramid) + self.create_pyramid_button.pack() + + def create_pyramid(self): + selected_companies = [self.company_listbox.get(index) for index in self.company_listbox.curselection()] + selected_df = self.df[self.df["Company Name"].isin(selected_companies)].sort_values(by="Weighting", ascending=False) + pyramid_file_path = asksaveasfilename(defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx *.xls")]) + + if not pyramid_file_path: + return + + with pd.ExcelWriter(pyramid_file_path) as writer: + selected_df.to_excel(writer, index=False) + + image_file_path = asksaveasfilename(defaultextension=".png", filetypes=[("Image files","*.png")]) + + company_scores = {} + + # For each 'Company Name', company_scores[company] = 'Weighting' for that company + for company, ticker, weighting in zip(selected_df["Company Name"], selected_df["Symbol"], selected_df["Weighting"]): + company_scores[f'{company} ({ticker})'] = weighting + + from PIL import Image, ImageDraw, ImageFont + import math + # Sort the dictionary by score in ascending order + company_scores = {k: v for k, v in sorted(company_scores.items(), key=lambda item: item[1])} + + # Group the companies by their scores + pyramid = {i: [] for i in range(1, 7)} + for company, score in company_scores.items(): + pyramid[score].append(company) + + # Initialize some parameters + img_width = 3300 + img_height = 2550 + block_color = (0, 0, 255) # Blue color + font_color = (255, 255, 255) # White color + padding = 10 # Padding around blocks + radius = 20 + + # Group the companies by their scores + pyramid = {} + for company, score in company_scores.items(): + if score not in pyramid: + pyramid[score] = [] + pyramid[score].append(company) + + # Sort the pyramid keys in ascending order to have a pyramid shape + sorted_keys = sorted(pyramid.keys()) + + # Calculate the maximum number of companies in a group (this will be the width of your pyramid) + max_companies = max(len(v) for v in pyramid.values()) + + # Calculate the total number of groups (the height of your pyramid) + total_groups = len(pyramid) + + # Calculate the total number of groups (the height of your pyramid) + total_groups = len(pyramid) + + # Calculate the size of each block based on the width and height of the image and the number of blocks + block_size = min((img_width - padding) // max_companies - padding, (img_height - padding) // total_groups - padding) + + # Calculate the size of each block based on the width and height of the image and the number of blocks + block_width = (img_width - padding) // max_companies - padding + block_height = (img_height - padding) // total_groups - padding + + # Calculate the total width and height of the blocks (including padding) + total_width = max_companies * (block_width + padding) + total_height = total_groups * (block_height + padding) + + # Calculate the starting position for the first block + start_x = (img_width - total_width) // 2 + start_y = (img_height - total_height) // 2 + + # Create an image big enough to hold the pyramid + img = Image.new('RGB', (img_width, img_height), "white") + d = ImageDraw.Draw(img) + + def wrap_text(text, max_length): + words = text.split() + lines = [] + current_line = [] + + for word in words: + if len(' '.join(current_line + [word])) <= max_length: + current_line.append(word) + else: + lines.append(' '.join(current_line)) + current_line = [word] + lines.append(' '.join(current_line)) + + return '\n'.join(lines) + + + # Loop over each level of the pyramid + for i, score in enumerate(sorted_keys): + companies = pyramid[score] + for j, company in enumerate(companies): + # Calculate the position of the block + x = start_x + j * (block_width + padding) + (total_width - len(companies) * (block_width + padding)) // 2 + y = start_y + i * (block_size + padding) + + # Draw the block + d.rounded_rectangle([x, y, x + block_width, y + block_height], fill=block_color, radius=radius) + + # Adjust font size based on the length of the company name and block size + font_size = min(block_width // (len(company) // 2 + 1), block_height // 2) + fnt = ImageFont.truetype('./assets/arial.ttf', font_size) + + # Implement word wrap for the company name + wrapped_company = wrap_text(company, block_width // font_size) + + # Draw the company name + bbox = d.textbbox((x, y), wrapped_company, font=fnt) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + text_x = x + (block_width - text_width) // 2 + text_y = y + (block_height - text_height) // 2 + d.text((text_x, text_y), wrapped_company, font=fnt, fill=font_color) + + + # Save the image + if not image_file_path: + return + + img.save(image_file_path) + + + self.master.quit() + +if __name__ == "__main__": + root = tk.Tk() + app = CompanySelector(root) + root.mainloop() diff --git a/main.spec b/main.spec new file mode 100644 index 0000000..0d3af44 --- /dev/null +++ b/main.spec @@ -0,0 +1,56 @@ +# -*- mode: python ; coding: utf-8 -*- + + +block_cipher = None + + +a = Analysis( + ['main.py'], + pathex=[], + binaries=[], + datas=[('assets', 'assets')], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name='main', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) +coll = COLLECT( + exe, + a.binaries, + a.zipfiles, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='main', +) +app = BUNDLE( + coll, + name='main.app', + icon=None, + bundle_identifier=None, +) diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..8593ea0 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,380 @@ +[[package]] +name = "altgraph" +version = "0.17.3" +description = "Python graph (network) package" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "contourpy" +version = "1.0.7" +description = "Python library for calculating contours of 2D quadrilateral grids" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "chromedriver", "selenium"] +docs = ["furo", "sphinx-copybutton"] +mypy = ["contourpy", "docutils-stubs", "mypy (==0.991)", "types-pillow"] +test = ["matplotlib", "pillow", "pytest"] +test-no-images = ["pytest"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "et-xmlfile" +version = "1.1.0" +description = "An implementation of lxml.xmlfile for the standard library" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "fonttools" +version = "4.39.4" +description = "Tools to manipulate font files" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.extras] +all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=15.0.0)", "xattr"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["scipy", "munkres"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.0.0)"] +woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"] + +[[package]] +name = "importlib-resources" +version = "5.12.0" +description = "Read resources from Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "sphinx-lint", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "pytest-flake8"] + +[[package]] +name = "kiwisolver" +version = "1.4.4" +description = "A fast implementation of the Cassowary constraint solver" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "macholib" +version = "1.16.2" +description = "Mach-O header analysis and editing" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +altgraph = ">=0.17" + +[[package]] +name = "matplotlib" +version = "3.7.1" +description = "Python plotting package" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} +kiwisolver = ">=1.0.1" +numpy = ">=1.20" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" +setuptools_scm = ">=7" + +[[package]] +name = "numpy" +version = "1.24.2" +description = "Fundamental package for array computing in Python" +category = "main" +optional = false +python-versions = ">=3.8" + +[[package]] +name = "openpyxl" +version = "3.1.2" +description = "A Python library to read/write Excel 2010 xlsx/xlsm files" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +et-xmlfile = "*" + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pandas" +version = "2.0.0" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = [ + {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.1" + +[package.extras] +all = ["beautifulsoup4 (>=4.9.3)", "bottleneck (>=1.3.2)", "brotlipy (>=0.7.0)", "fastparquet (>=0.6.3)", "fsspec (>=2021.07.0)", "gcsfs (>=2021.07.0)", "html5lib (>=1.1)", "hypothesis (>=6.34.2)", "jinja2 (>=3.0.0)", "lxml (>=4.6.3)", "matplotlib (>=3.6.1)", "numba (>=0.53.1)", "numexpr (>=2.7.3)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pandas-gbq (>=0.15.0)", "psycopg2 (>=2.8.6)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "PyQt5 (>=5.15.1)", "pyreadstat (>=1.1.2)", "pytest (>=7.0.0)", "pytest-xdist (>=2.2.0)", "pytest-asyncio (>=0.17.0)", "python-snappy (>=0.6.0)", "pyxlsb (>=1.0.8)", "qtpy (>=2.2.0)", "scipy (>=1.7.1)", "s3fs (>=2021.08.0)", "SQLAlchemy (>=1.4.16)", "tables (>=3.6.1)", "tabulate (>=0.8.9)", "xarray (>=0.21.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)", "zstandard (>=0.15.2)"] +aws = ["s3fs (>=2021.08.0)"] +clipboard = ["PyQt5 (>=5.15.1)", "qtpy (>=2.2.0)"] +compression = ["brotlipy (>=0.7.0)", "python-snappy (>=0.6.0)", "zstandard (>=0.15.2)"] +computation = ["scipy (>=1.7.1)", "xarray (>=0.21.0)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pyxlsb (>=1.0.8)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)"] +feather = ["pyarrow (>=7.0.0)"] +fss = ["fsspec (>=2021.07.0)"] +gcp = ["gcsfs (>=2021.07.0)", "pandas-gbq (>=0.15.0)"] +hdf5 = ["tables (>=3.6.1)"] +html = ["beautifulsoup4 (>=4.9.3)", "html5lib (>=1.1)", "lxml (>=4.6.3)"] +mysql = ["SQLAlchemy (>=1.4.16)", "pymysql (>=1.0.2)"] +output_formatting = ["jinja2 (>=3.0.0)", "tabulate (>=0.8.9)"] +parquet = ["pyarrow (>=7.0.0)"] +performance = ["bottleneck (>=1.3.2)", "numba (>=0.53.1)", "numexpr (>=2.7.1)"] +plot = ["matplotlib (>=3.6.1)"] +postgresql = ["SQLAlchemy (>=1.4.16)", "psycopg2 (>=2.8.6)"] +spss = ["pyreadstat (>=1.1.2)"] +sql-other = ["SQLAlchemy (>=1.4.16)"] +test = ["hypothesis (>=6.34.2)", "pytest (>=7.0.0)", "pytest-xdist (>=2.2.0)", "pytest-asyncio (>=0.17.0)"] +xml = ["lxml (>=4.6.3)"] + +[[package]] +name = "pefile" +version = "2023.2.7" +description = "Python PE parsing module" +category = "main" +optional = false +python-versions = ">=3.6.0" + +[[package]] +name = "pillow" +version = "9.5.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "pyinstaller" +version = "5.11.0" +description = "PyInstaller bundles a Python application and all its dependencies into a single package." +category = "main" +optional = false +python-versions = "<3.12,>=3.7" + +[package.dependencies] +altgraph = "*" +macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} +pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""} +pyinstaller-hooks-contrib = ">=2021.4" +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} + +[package.extras] +encryption = ["tinyaes (>=1.0.0)"] +hook_testing = ["pytest (>=2.7.3)", "execnet (>=1.5.0)", "psutil"] + +[[package]] +name = "pyinstaller-hooks-contrib" +version = "2023.3" +description = "Community maintained hooks for PyInstaller" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "main" +optional = false +python-versions = ">=3.6.8" + +[package.extras] +diagrams = ["railroad-diagrams", "jinja2"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2023.3" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pywin32-ctypes" +version = "0.2.0" +description = "" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "setuptools-scm" +version = "7.1.0" +description = "the blessed package to manage your versions by scm tags" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +packaging = ">=20.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +typing-extensions = "*" + +[package.extras] +test = ["pytest (>=6.2)", "virtualenv (>20)"] +toml = ["setuptools (>=42)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "typing-extensions" +version = "4.5.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +category = "main" +optional = false +python-versions = ">=2" + +[[package]] +name = "xlrd" +version = "2.0.1" +description = "Library for developers to extract data from Microsoft Excel (tm) .xls spreadsheet files" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.extras] +build = ["wheel", "twine"] +docs = ["sphinx"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "zipp" +version = "3.15.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "sphinx-lint", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "jaraco.functools", "more-itertools", "big-o", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "pytest-flake8"] + +[metadata] +lock-version = "1.1" +python-versions = ">=3.9,<3.12" +content-hash = "31737a76d2d951406282db0245184cb876d50a65624ce7aa9bc4f307c3be8429" + +[metadata.files] +altgraph = [] +contourpy = [] +cycler = [] +et-xmlfile = [] +fonttools = [] +importlib-resources = [] +kiwisolver = [] +macholib = [] +matplotlib = [] +numpy = [] +openpyxl = [] +packaging = [] +pandas = [] +pefile = [] +pillow = [] +pyinstaller = [] +pyinstaller-hooks-contrib = [] +pyparsing = [] +python-dateutil = [] +pytz = [] +pywin32-ctypes = [] +setuptools-scm = [] +six = [] +tomli = [] +typing-extensions = [] +tzdata = [] +xlrd = [] +zipp = [] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b487a21 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,20 @@ +[tool.poetry] +name = "gcpyramid" +version = "0.1.0" +description = "" +authors = ["navanchauhan <navanchauhan@gmail.com>"] + +[tool.poetry.dependencies] +python = ">=3.9,<3.12" +pandas = "^2.0.0" +xlrd = "^2.0.1" +openpyxl = "^3.1.2" +Pillow = "^9.5.0" +matplotlib = "^3.7.1" +pyinstaller = "^5.11.0" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" |