summaryrefslogtreecommitdiff
path: root/main.py
diff options
context:
space:
mode:
Diffstat (limited to 'main.py')
-rw-r--r--main.py569
1 files changed, 307 insertions, 262 deletions
diff --git a/main.py b/main.py
index 0369861..b5a0f15 100644
--- a/main.py
+++ b/main.py
@@ -12,6 +12,10 @@ import darkdetect
import os
from os import path
+from docx import Document
+from docx.shared import Inches
+from docx.enum.text import WD_ALIGN_PARAGRAPH
+
canadian_companies = []
def pyramid_list(lst, sort_canadian=True):
@@ -198,301 +202,342 @@ class CompanySelector:
def create_pyramid(self):
selected_companies_tmp = [self.company_listbox.listbox.get(index) for index in self.company_listbox.listbox.curselection()]
+ print(f'Selected {len(selected_companies_tmp)} companies')
selected_companies = [x.split(" - ")[0].strip() for x in selected_companies_tmp]
+ print(f'Symbols: {len(selected_companies)}')
selected_df = self.df[self.df["Symbol"].isin(selected_companies)].sort_values(by="Weighting", ascending=False)
+ print(f'DF: {len(selected_df)}')
#pyramid_file_path = asksaveasfilename(defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx *.xls")])
+ if self.generate_word_doc.get() == 1:
+ word_file_path = asksaveasfilename(defaultextension=".docx", filetypes=[("Word files", "*.docx")])
+ if not word_file_path:
+ return
- 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, dividend, currency in zip(selected_df["Company Name"], selected_df["Symbol"], selected_df["Weighting"], selected_df["Dividend?"], selected_df["Currency"]):
- extra_char = ""
- if dividend.strip() == "Y":
- extra_char = "*"
- if currency == "CAD":
- canadian_companies.append(f'{company} ({ticker}){extra_char}')
- company_scores[f'{company} ({ticker}){extra_char}'] = 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
- pyramid_width = 3000
- img_height = 1550 #2550
- overall_height = 2550
- block_color = (3, 37, 126) # Blue color
- dividend_color = block_color #(1,50,32) # Green color
- font_color = (255, 255, 255) # White color
- normal_block = (3, 37, 126) # Dark Blue
- padding = 15 # Padding around blocks
- radius = 10
- logo_padding = 100 # top padding for logo
- pyramid_padding_bottom = 350 # bottom padding for pyramid
- max_companies_in_row = 5
- base_path = "assets"
- primary_font = path.join(base_path, "baskerville.ttf")
- secondary_font = path.join(base_path, "gill_sans_bold.ttf")
-
- # 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())
-
- companies = []
-
-
- for key in sorted_keys:
- if pyramid[key] == []:
- continue
- if len(pyramid[key])<=max_companies_in_row:
- companies.append(pyramid[key])
- else:
- temp_list = []
- for x in range(len(pyramid[key])//max_companies_in_row):
- temp_list.append(pyramid[key][x*max_companies_in_row:max_companies_in_row])
-
- temp_list.append(pyramid[key][::-1][:len(pyramid[key])%max_companies_in_row])
- for row in temp_list[::-1]:
- if row != []:
- companies.append(row)
-
- everything_list = []
- for row in companies:
- if row == []:
- continue
- for company in row:
- everything_list.append(company)
-
- companies = everything_list
-
- companies = pyramid_list(companies)
-
- for company_row in companies:
- print(company_row)
-
- # Calculate the maximum number of companies in a group (this will be the width of your pyramid)
- max_companies = max(len(row) for row in companies) #max(len(v) for v in pyramid.values())
-
- # Calculate the total number of groups (the height of your pyramid)
- total_groups = len(companies) #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((pyramid_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 = (pyramid_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 = (pyramid_width - total_width) // 2
- start_y = (img_height - total_height) // 2
-
-
- # Create an image big enough to hold the pyramid
- img = Image.new('RGB', (pyramid_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)
-
- min_font_size = 100_000_000
-
- for i, row in enumerate(companies):
- for j, company in enumerate(row):
- font_size = min(block_width // (len(company) // 2 + 1), block_height // 2)
- if font_size < min_font_size:
- min_font_size = font_size
-
- num_dividends = 0
+ document = Document("assets/doc_template.docx")
- # Loop over each level of the pyramid
- for i, row in enumerate(companies):
- for j, company in enumerate(row):
- # Calculate the position of the block
- x = start_x + j * (block_width + padding) + (max_companies - len(row)) * (block_width + padding) // 2
- y = start_y + i * (block_size + padding)
-
- # Calculate the color of the block
- if company[-1] == "*":
- block_color = dividend_color
- num_dividends += 1
+ advisor = self.advisor_string.get()
+ today = datetime.today()
+
+ document.paragraphs[0].text = document.paragraphs[0].text.replace("{{ADVISOR}}", advisor)
+
+ to_replace = document.paragraphs[3].text
+
+ to_replace = to_replace.replace("{{MONTH}}" , today.strftime("%B"))
+ to_replace = to_replace.replace("{{YEAR}}" , today.strftime("%Y"))
+
+ document.paragraphs[3].text = to_replace
+
+ for company, ticker, dividend, currency, desc in zip(selected_df["Company Name"], selected_df["Symbol"], selected_df["Dividend?"], selected_df["Currency"], selected_df["Blurb"]):
+ extra_char = ""
+ if dividend.strip() == "Y":
+ extra_char = "***"
+
+ new_paragraph = document.add_paragraph()
+ temp_run = new_paragraph.add_run(f'{company}{extra_char} ({ticker})')
+ temp_run.bold = True
+ new_paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
+ document.paragraphs.pop()
+ desc_paragraph = document.add_paragraph(f"\n{desc}\n")
+ desc_paragraph.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
+ desc_paragraph.bold = False
+
+ document.save(word_file_path)
+
+ if self.generate_pyramid_var.get() == 0:
+ None
+ else:
+ 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, dividend, currency in zip(selected_df["Company Name"], selected_df["Symbol"], selected_df["Weighting"], selected_df["Dividend?"], selected_df["Currency"]):
+ extra_char = ""
+ if dividend.strip() == "Y":
+ extra_char = "*"
+ if currency == "CAD":
+ canadian_companies.append(f'{company} ({ticker}){extra_char}')
+ company_scores[f'{company} ({ticker}){extra_char}'] = 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
+ pyramid_width = 3000
+ img_height = 1550 #2550
+ overall_height = 2550
+ block_color = (3, 37, 126) # Blue color
+ dividend_color = block_color #(1,50,32) # Green color
+ font_color = (255, 255, 255) # White color
+ normal_block = (3, 37, 126) # Dark Blue
+ padding = 15 # Padding around blocks
+ radius = 10
+ logo_padding = 100 # top padding for logo
+ pyramid_padding_bottom = 350 # bottom padding for pyramid
+ max_companies_in_row = 10
+ base_path = "assets"
+ primary_font = path.join(base_path, "baskerville.ttf")
+ secondary_font = path.join(base_path, "gill_sans_bold.ttf")
+
+ # 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())
+
+ companies = []
+
+
+ for key in sorted_keys:
+ if pyramid[key] == []:
+ continue
+ if len(pyramid[key])<=max_companies_in_row:
+ companies.append(pyramid[key])
else:
- block_color = normal_block
+ temp_list = []
+ for x in range(len(pyramid[key])//max_companies_in_row):
+ temp_list.append(pyramid[key][x*max_companies_in_row:max_companies_in_row])
+
+ temp_list.append(pyramid[key][::-1][:len(pyramid[key])%max_companies_in_row])
+ for row in temp_list[::-1]:
+ if row != []:
+ companies.append(row)
+
+ everything_list = []
+ for row in companies:
+ if row == []:
+ continue
+ for company in row:
+ everything_list.append(company)
+
+ companies = everything_list
+ print(f"Still have {len(companies)}")
- # Draw the block
- d.rounded_rectangle([x, y, x + block_width, y + block_height], fill=block_color, radius=radius)
+ companies = pyramid_list(companies)
- # Adjust font size based on the length of the company name and block size
- font_size = min_font_size #min(block_width // (len(company) // 2 + 1), block_height // 2)
- fnt = ImageFont.truetype(secondary_font, font_size)
+ for company_row in companies:
+ print(company_row)
- # Implement word wrap for the company name
- wrapped_company = wrap_text(company, (block_width // font_size)*1.5)
-
- # 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, align='center', spacing=10)
-
-
- print(image_file_path)
-
- # Save the image
- if not image_file_path:
- return
+ # Calculate the maximum number of companies in a group (this will be the width of your pyramid)
+ max_companies = max(len(row) for row in companies) #max(len(v) for v in pyramid.values())
- image_logo = Image.open("./assets/GentryCapitalRGB.jpg")
- _, l_height = image_logo.size
+ # Calculate the total number of groups (the height of your pyramid)
+ total_groups = len(companies) #len(pyramid)
- new_img = Image.new("RGB", (img_width, l_height), "white")
- left = (new_img.width - image_logo.width) // 2
- top = (new_img.height - image_logo.height) // 2
+ # Calculate the size of each block based on the width and height of the image and the number of blocks
+ block_size = min((pyramid_width - padding) // max_companies - padding, (img_height - padding) // total_groups - padding)
- new_img.paste(image_logo, (left, top))
+ # Calculate the size of each block based on the width and height of the image and the number of blocks
+ block_width = (pyramid_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 = (pyramid_width - total_width) // 2
+ start_y = (img_height - total_height) // 2
+
+
+ # Create an image big enough to hold the pyramid
+ img = Image.new('RGB', (pyramid_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)
+
+ min_font_size = 100_000_000
+
+ for i, row in enumerate(companies):
+ for j, company in enumerate(row):
+ font_size = min(block_width // (len(company) // 2 + 1), block_height // 2)
+ if font_size < min_font_size:
+ min_font_size = font_size
+
+ num_dividends = 0
+
+ # Loop over each level of the pyramid
+ for i, row in enumerate(companies):
+ for j, company in enumerate(row):
+ # Calculate the position of the block
+ x = start_x + j * (block_width + padding) + (max_companies - len(row)) * (block_width + padding) // 2
+ y = start_y + i * (block_size + padding)
+
+ # Calculate the color of the block
+ if company[-1] == "*":
+ block_color = dividend_color
+ num_dividends += 1
+ else:
+ block_color = normal_block
+
+ # 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_font_size #min(block_width // (len(company) // 2 + 1), block_height // 2)
+ fnt = ImageFont.truetype(secondary_font, font_size)
+
+ # Implement word wrap for the company name
+ wrapped_company = wrap_text(company, (block_width // font_size)*1.5)
+
+ # 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, align='center', spacing=10)
+
+
+ print(image_file_path)
+
+ # Save the image
+ if not image_file_path:
+ return
- final_img = Image.new("RGB", (img_width, overall_height), "white")
- final_img.paste(new_img, (0, logo_padding))
-
- text1 = self.pyramid_title_string.get()
- text2 = f"({num_dividends} Dividend payors - all identified by asterisk)"
- text3 = "FOR INTERNAL USE ONLY"
- text4 = datetime.today().strftime("%B %d, %Y")
- text5 = ""
-
- if self.prepared_for_string.get() != "":
- print(f"Prepared for string present - {self.prepared_for_string.get()}")
- text5 += f"Prepared for {self.prepared_for_string.get()}"
- if self.advisor_string.get() != "":
- advisor = self.advisor_string.get()
- if text5 != "":
- tmp_var = [text5, f"By {advisor}"]
- text5 = tmp_var
- else:
- text5 = f"By {advisor}"
+ image_logo = Image.open("./assets/GentryCapitalRGB.jpg")
+ _, l_height = image_logo.size
+
+ new_img = Image.new("RGB", (img_width, l_height), "white")
+ left = (new_img.width - image_logo.width) // 2
+ top = (new_img.height - image_logo.height) // 2
+
+ new_img.paste(image_logo, (left, top))
+
+ final_img = Image.new("RGB", (img_width, overall_height), "white")
+ final_img.paste(new_img, (0, logo_padding))
+
+ text1 = self.pyramid_title_string.get()
+ text2 = f"({num_dividends} Dividend payors - all identified by asterisk)"
+ text3 = "FOR INTERNAL USE ONLY"
+ text4 = datetime.today().strftime("%B %d, %Y")
+ text5 = ""
+
+ if self.prepared_for_string.get() != "":
+ print(f"Prepared for string present - {self.prepared_for_string.get()}")
+ text5 += f"Prepared for {self.prepared_for_string.get()}"
+ if self.advisor_string.get() != "":
+ advisor = self.advisor_string.get()
+ if text5 != "":
+ tmp_var = [text5, f"By {advisor}"]
+ text5 = tmp_var
+ else:
+ text5 = f"By {advisor}"
- print(text5)
- draw = ImageDraw.Draw(final_img)
- font_size = 60
+ print(text5)
+ draw = ImageDraw.Draw(final_img)
+ font_size = 60
- font1 = ImageFont.truetype(primary_font, font_size)
- text_width1 = draw.textlength(text1, font=font1)
- while text_width1 > final_img.width:
- font_size -= 1
font1 = ImageFont.truetype(primary_font, font_size)
text_width1 = draw.textlength(text1, font=font1)
+ while text_width1 > final_img.width:
+ font_size -= 1
+ font1 = ImageFont.truetype(primary_font, font_size)
+ text_width1 = draw.textlength(text1, font=font1)
- font2_size = font_size - 10
- font2 = ImageFont.truetype(primary_font, font2_size)
- text_width2 = draw.textlength(text2, font=font2)
- while text_width2 > final_img.width:
- font_size -= 1
+ font2_size = font_size - 10
font2 = ImageFont.truetype(primary_font, font2_size)
text_width2 = draw.textlength(text2, font=font2)
+ while text_width2 > final_img.width:
+ font_size -= 1
+ font2 = ImageFont.truetype(primary_font, font2_size)
+ text_width2 = draw.textlength(text2, font=font2)
- new_font_size = 30
- font3 = ImageFont.truetype(secondary_font, new_font_size)
- _,t,_,b = draw.textbbox((100,100), text3, font=font3)
- while (b-t) < (0.4*pyramid_padding_bottom):
- new_font_size += 1
+ new_font_size = 30
font3 = ImageFont.truetype(secondary_font, new_font_size)
_,t,_,b = draw.textbbox((100,100), text3, font=font3)
- text_width3 = draw.textlength(text3, font=font3)
- while text_width3 > (final_img.width*0.8):
- new_font_size -= 1
- font3 = ImageFont.truetype(secondary_font, new_font_size)
+ while (b-t) < (0.4*pyramid_padding_bottom):
+ new_font_size += 1
+ font3 = ImageFont.truetype(secondary_font, new_font_size)
+ _,t,_,b = draw.textbbox((100,100), text3, font=font3)
text_width3 = draw.textlength(text3, font=font3)
- _,t,_,b = draw.textbbox((100,100),text3,font=font3)
+ while text_width3 > (final_img.width*0.8):
+ new_font_size -= 1
+ font3 = ImageFont.truetype(secondary_font, new_font_size)
+ text_width3 = draw.textlength(text3, font=font3)
+ _,t,_,b = draw.textbbox((100,100),text3,font=font3)
- font4_size = font2_size - 5
- font4 = ImageFont.truetype(primary_font, font4_size)
- text_width4 = draw.textlength(text4, font=font4)
+ font4_size = font2_size - 5
+ font4 = ImageFont.truetype(primary_font, font4_size)
+ text_width4 = draw.textlength(text4, font=font4)
- start_x1 = (final_img.width - text_width1) // 2
- start_y1 = image_logo.height + logo_padding + 50
+ start_x1 = (final_img.width - text_width1) // 2
+ start_y1 = image_logo.height + logo_padding + 50
- start_x2 = (final_img.width - text_width2) // 2
- start_y2 = image_logo.height + logo_padding + 125
+ start_x2 = (final_img.width - text_width2) // 2
+ start_y2 = image_logo.height + logo_padding + 125
- start_x3 = (final_img.width - text_width3) // 2
- start_y3 = (final_img.height - pyramid_padding_bottom + ((pyramid_padding_bottom)-(b-t))//2)
+ start_x3 = (final_img.width - text_width3) // 2
+ start_y3 = (final_img.height - pyramid_padding_bottom + ((pyramid_padding_bottom)-(b-t))//2)
- start_x4 = (final_img.width - text_width4) - 150
- start_y4 = logo_padding + 30
+ start_x4 = (final_img.width - text_width4) - 150
+ start_y4 = logo_padding + 30
- start_x5 = 150
- start_y5 = start_y4
-
- draw.text((start_x1, start_y1), text1, font=font1, fill="black")
- draw.text((start_x2, start_y2), text2, font=font2, fill="black")
- draw.text((start_x3, start_y3), text3, font=font3, fill=(158,161,162))
- draw.text((start_x4, start_y4), text4, font=font4, fill="black")
- if type(text5) == str:
- draw.text((start_x5, start_y5), text5, font=font4, fill="black")
- else:
- for idx, text2write in enumerate(text5):
- draw.text((start_x5, start_y5 + (idx*69)), text2write, font=font4, fill="black")
-
- final_img.paste(img, ((img_width-pyramid_width)//2, l_height + (overall_height - l_height - img_height) - pyramid_padding_bottom) )
-
- # draw = ImageDraw.Draw(final_img)
- # watermark_text = "FOR INTERNAL USE ONLY"
- # watermark_font = ImageFont.truetype(secondary_font, 72)
- # watermark_width = draw.textlength(watermark_text, watermark_font)
- # draw.text(
- # ((final_img.width - watermark_width)//2,overall_height-pyramid_padding_bottom),
- # watermark_text,
- # font=watermark_font,
- # align='center'
- # )
-
- final_img.save(image_file_path)
- final_img.show()
- #img.show()
-
- """if not pyramid_file_path:
- return
-
- with pd.ExcelWriter(pyramid_file_path) as writer:
- selected_df.to_excel(writer, index=False)"""
-
- #self.master.quit()
+ start_x5 = 150
+ start_y5 = start_y4
+
+ draw.text((start_x1, start_y1), text1, font=font1, fill="black")
+ draw.text((start_x2, start_y2), text2, font=font2, fill="black")
+ draw.text((start_x3, start_y3), text3, font=font3, fill=(158,161,162))
+ draw.text((start_x4, start_y4), text4, font=font4, fill="black")
+ if type(text5) == str:
+ draw.text((start_x5, start_y5), text5, font=font4, fill="black")
+ else:
+ for idx, text2write in enumerate(text5):
+ draw.text((start_x5, start_y5 + (idx*69)), text2write, font=font4, fill="black")
+
+ final_img.paste(img, ((img_width-pyramid_width)//2, l_height + (overall_height - l_height - img_height) - pyramid_padding_bottom) )
+
+ # draw = ImageDraw.Draw(final_img)
+ # watermark_text = "FOR INTERNAL USE ONLY"
+ # watermark_font = ImageFont.truetype(secondary_font, 72)
+ # watermark_width = draw.textlength(watermark_text, watermark_font)
+ # draw.text(
+ # ((final_img.width - watermark_width)//2,overall_height-pyramid_padding_bottom),
+ # watermark_text,
+ # font=watermark_font,
+ # align='center'
+ # )
+
+ final_img.save(image_file_path)
+ final_img.show()
+ #img.show()
+
+ """if not pyramid_file_path:
+ return
+
+ with pd.ExcelWriter(pyramid_file_path) as writer:
+ selected_df.to_excel(writer, index=False)"""
+
+ #self.master.quit()
if __name__ == "__main__":
import sentry_sdk