Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- # Filename: Trend_AV.py
- # Version: 1.27
- # Author: Jeoi Reqi
- # Date: February 2024
- '''
- [DESCRIPTION]:
- Trend_AV is a Python script designed to analyze and visualize Google Trends data using the Google Trends API. It facilitates the exploration of interest trends over time for user-specified topics. The script offers the following functionalities:
- 1. Line Plots: Generates monthly-separated line plots with solid markers, depicting the trend of interest over time.
- 2. 3D Bar Plots: Creates visualizations illustrating interest levels for specified topics over time using 3D bar plots.
- 3. Pie Charts: Generates pie charts with average values, providing insights into the distribution of interest across different topics.
- 4. Scatter Plots: Displays scatter plots with average values, showing the relationship between time and interest level for specified topics.
- 5. Stack Plots: Generates stack plots illustrating the contribution of each topic to the overall interest level over time.
- 6. Word Clouds: Utilizes related top and rising topics fetched from Google Trends to generate word clouds, offering a visually appealing representation of related queries.
- [REQUIRED FILES]:
- - header.txt: Contains header information for the script.
- URL: https://pastebin.com/PhGW7s6i
- - about.py: Provides information about the script and its functionalities.
- URL: https://pastebin.com/14xC5Mji
- - promo.txt: Contains promotional content for the script.
- URL: https://pastebin.com/xkedg3n5
- - requirements.txt: Lists the required dependencies for running the script.
- URL: https://pastebin.com/wutgrtpn
- [NOTE]:
- Ensure that all required files are saved in the current working directory with the correct file extensions.
- '''
- # GET IMPORTS
- import sys
- import subprocess
- import importlib
- import numpy as np
- import warnings
- import matplotlib.pyplot as plt
- import matplotlib.animation as animation
- import matplotlib.lines as mlines
- from matplotlib.lines import Line2D
- from mpl_toolkits.mplot3d.art3d import Poly3DCollection
- from mpl_toolkits.mplot3d import Axes3D
- from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
- from pytrends.request import TrendReq
- from dateutil.relativedelta import relativedelta
- from typing import List
- from datetime import datetime
- from wordcloud import WordCloud
- # INSTALLATIONS
- def import_module_or_install(package_name):
- try:
- return importlib.import_module(package_name)
- except ImportError:
- print(f"Error: {package_name} module not found. Installing...")
- subprocess.run([sys.executable, "-m", "pip", "install", package_name], check=True)
- print(f"Successfully installed {package_name}.")
- return importlib.import_module(package_name)
- # Try importing these libraries or install them if not found
- pytrends = import_module_or_install('pytrends')
- plt = import_module_or_install('matplotlib.pyplot')
- np = import_module_or_install('numpy')
- # CLEAR SCREEN
- def wipe():
- print('\n' * 100)
- # INSTALL PACKAGES
- def install_packages(packages):
- try:
- for package in packages:
- if not isinstance(package, str):
- raise ValueError(f"Package name must be a string, but found: {package}")
- # Suppress output during installation for python-dateutil
- stdout_arg = subprocess.PIPE if package == 'python-dateutil' else sys.stdout
- stderr_arg = subprocess.PIPE if package == 'python-dateutil' else sys.stderr
- subprocess.run([sys.executable, "-m", "pip", "install", package], check=True, stdout=stdout_arg, stderr=stderr_arg)
- except subprocess.CalledProcessError as e:
- print(f"Error: Failed to install packages. Please install them manually.\n")
- sys.exit(1)
- if __name__ == "__main__":
- print("\nChecking and installing required packages...\n")
- # Check if python-dateutil is installed
- python_dateutil_installed = importlib.util.find_spec('dateutil') is not None
- if not python_dateutil_installed:
- print("Installing python-dateutil...")
- install_packages(['python-dateutil'])
- print("\npython-dateutil installed successfully.\n\n\n\n")
- wipe()
- else:
- print("\nAll requirements have been satisfied.\n\n\n\n")
- input("\n\nPress [ENTER] to continue.\n")
- wipe()
- warnings.simplefilter(action='ignore', category=FutureWarning)
- # Now you should be able to use TrendReq
- pytrends = TrendReq(hl='en-US', tz=-480)
- ''' [GLOBAL HEADER]'''
- # Read the content of header.txt
- with open('header.txt', 'r', encoding='utf-8') as file:
- header_content = file.read()
- def header(): # Function to print the header
- wipe()
- print(header_content)
- header() # Call the header function
- ''' [GLOBAL VARIABLES & CONSTANTS]'''
- # User Input for Topics and Timeframe
- interest_over_time = None # Initialize interest_over_time as a global variable
- num_months = None # Initialize num_months as a global variable
- # Initialize global Keywords list
- keywords: list[str] = []
- # Set the constant max values for topics & results
- max_topics = 5
- max_top = 24
- max_rising = 24
- max_months = 240
- # For use with 3D Bar Plot (Bar Sizes: Eg; 70% width/40% depth)
- bar_width = 0.70 # Width on the x-axis as a percent Using dx
- bar_depth = 0.40 # Width on the x-axis as a percent Using dx
- ''' [SYSTEM FUNCTIONS]'''
- # Define the reset program function
- def reset_program():
- global keywords
- global related_data_displayed
- # Clear user inputs and related data
- keywords = []
- related_data_displayed = False
- print("\nProgram reset. All data cleared.\n")
- input("Press [ENTER] to continue.")
- # Call the user_input function to get user input
- user_input()
- # Flag to track if related data has been displayed
- related_data_displayed = False
- ''' [USER INPUT]'''
- '''
- THIS IS AN INTERACTIVE FUNCTION TO GATHER USER INPUT FOR TOPICS AND TIMEFRAME.
- '''
- # Function to get user input for topics
- def user_input():
- global interest_over_time # Declare interest_over_time as a global variable
- global num_months # Declare num_months as a global variable
- # User Input for Topics
- while len(keywords) < 1 or len(keywords) > max_topics:
- try:
- # Prompt user for the number of topics they want to analyze
- num_topics = int(input(f"\nEnter the number of topics (1 to {max_topics}): "))
- # Validate user input to ensure it falls within the specified range
- if 1 <= num_topics <= max_topics:
- for i in range(num_topics):
- keyword = input(f"Enter topic/query {i + 1}: ")
- keywords.append(keyword.lower()) # Automatically convert to lowercase
- else:
- # Display an error message for an invalid number of topics
- print(f"\nInvalid number of topics. Please enter a number between 1 and {max_topics}.\n")
- except ValueError:
- # Handle the case where the user enters a non-integer value
- print("\nInvalid input. Please enter a valid number.\n")
- # User Input for Timeframe
- while True:
- try:
- # Prompt user for the number of months to display in the analysis
- num_months = int(input(f"\nEnter the number of months to display between this month (1) and 2004 ({max_months}): "))
- # Validate user input for the timeframe
- if 1 <= num_months <= max_months:
- # Calculate the end date
- end_date = datetime.today().strftime('%Y-%m-%d')
- # Calculate the start date based on the number of months
- start_date = (datetime.today() - relativedelta(months=num_months)).strftime('%Y-%m-%d')
- # Fetch data from Google Trends based on user-specified topics & timeframe
- timeframe = f'{start_date} {end_date}'
- print(f"\nFetching data from Google Trends with timeframe: {timeframe}\n")
- pytrends.build_payload(keywords, timeframe=timeframe)
- interest_over_time = pytrends.interest_over_time()
- # Wait for the user to hit [ENTER] to continue to the Menu
- input("\nPress [ENTER] to continue to the main menu.\n")
- if interest_over_time.empty:
- raise ValueError("No data retrieved from Google Trends.")
- break # Exit the loop if input is valid
- else:
- # Display an error message for an invalid number of months
- print(f"\nInvalid number of months. Please enter a number between 1 and {max_months}.\n")
- except ValueError as ve:
- print(f"\nError: {ve}\n")
- # Call the user_input function to get user input
- user_input()
- ''' [GENERATE THE PLOTS]'''
- '''
- [GENERATE THE PLOTS]:
- THIS SECTION OF THE CODE CONTAINS THE FUNCTIONS TO GENERATE & VISUALIZE VARIOUS TYPES OF PLOTS BASED ON
- GOOGLE TRENDS DATA. EACH FUNCTION IS DESIGNED TO PRESENT DIFFERENT INSIGHTS INTO THE INTEREST OVER TIME
- FOR USER-SPECIFIED TOPICS OR QUERIES. THE PLOTS INCLUDE ANIMATED AND STATIC VERSIONS OF LINE PLOTS,
- BAR PLOTS (2D AND 3D), PIE CHARTS, SCATTER PLOTS, AND STACK PLOTS. THE USER CAN CHOOSE TO DISPLAY THESE
- PLOTS INDIVIDUALLY OR IN COMBINATIONS. THE FUNCTIONS PROVIDE INTERACTIVE AND DYNAMIC VISUALIZATIONS,
- ALLOWING USERS TO EXPLORE TRENDS, COMPARE TOPICS, AND UNDERSTAND THE RELATIVE STRENGTH AND INTEREST
- PATTERNS OVER SPECIFIED TIMEFRAMES.
- '''
- ''' [LINE PLOTS]'''
- # ANIMATED LINE PLOT
- def animate_line_plot(interest_over_time, keywords, num_months):
- '''
- GENERATE AND DISPLAY ANIMATED LINE PLOTS WITH SOLID MARKERS.
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO PLOT.
- - NUM_MONTHS (INT): NUMBER OF MONTHS FOR THE PLOT.
- '''
- print("\nAnimating line plots with solid markers...")
- fig, ax = plt.subplots(figsize=(16, 8))
- def update(frame):
- ax.clear()
- # Calculate the percentage of completion
- percent_complete = (frame + 1) / total_frames * 100
- for keyword in keywords:
- # Plot the line for the current frame with hollow markers
- end_index = frame * len(interest_over_time) // total_frames
- ax.plot(interest_over_time.index[:end_index + 1], interest_over_time[keyword][:end_index + 1],
- label=keyword, marker='o', markersize=8, linestyle='solid', mec='none')
- ax.set_title(f'Animated Line Plot\n{percent_complete:.2f}% Complete')
- ax.set_xlabel('Date')
- ax.set_ylabel('Interest Level')
- ax.legend(loc='upper left')
- # Set y-axis ticks from 0 to 100 in increments of 10
- ax.set_yticks(np.arange(0, 110, 10))
- # Set the fixed height for the y-axis
- ax.set_ylim(0, 100)
- # Calculate total frames
- total_frames = len(interest_over_time)
- # Create the animation
- animation_line_plots = animation.FuncAnimation(fig, update, frames=total_frames, interval=250, repeat=False)
- plt.show()
- # GENERATE LINE PLOT
- def generate_line_plot(interest_over_time, keywords, num_months):
- '''
- GENERATE AND DISPLAY LINE PLOTS WITH SOLID MARKERS.
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO PLOT.
- - NUM_MONTHS (INT): NUMBER OF MONTHS FOR THE PLOT.
- '''
- print("\nGenerating line plots with solid markers...")
- plt.figure(figsize=(16, 8))
- for keyword in keywords:
- # Plot the line with hollow markers
- plt.plot(interest_over_time.index, interest_over_time[keyword], label=keyword, marker='o', markersize=8,
- linestyle='solid', mec='none')
- plt.title(f'Static Line Plot')
- plt.xlabel('Date')
- plt.ylabel('Interest Level')
- plt.legend(loc='upper left')
- # Set y-axis ticks from 0 to 100 in increments of 10
- plt.yticks(np.arange(0, 110, 10))
- # Set the fixed height for the y-axis
- plt.ylim(0, 100)
- plt.show()
- ''' [BAR PLOTS]'''
- # ANIMATE 2D BAR PLOT
- def animate_2d_bar_plot(interest_over_time, keywords):
- """
- Generate and display an animated 2D bar plot.
- Parameters:
- - interest_over_time (DataFrame): Dataframe containing interest over time.
- - keywords (List[str]): List of keywords to plot.
- """
- global num_months # Declare num_months as a global variable
- print("\nAnimating 2D Bar Plot...")
- fig, ax = plt.subplots(figsize=(8, 8))
- colors = plt.cm.viridis(np.linspace(0, 1, len(keywords)))
- # Sort keywords based on their mean values
- sorted_keywords = sorted(keywords, key=lambda keyword: interest_over_time[keyword].mean())
- def update(frame):
- ax.clear()
- # Calculate the percentage completed
- percent_complete = (frame + 1) / total_frames * 100
- # Extract data for the current frame
- start_index = frame * len(interest_over_time) // num_months
- end_index = (frame + 1) * len(interest_over_time) // num_months
- ys = interest_over_time.iloc[start_index:end_index][sorted_keywords]
- # Plot the 2D bar chart for the current frame
- bars = ax.bar(sorted_keywords, ys.mean(), color=colors)
- # Dynamically display the current month number
- current_month = frame + 1
- ax.set_title(f'Animated 2D Bar Plot - Month {current_month} / {num_months}\n({percent_complete:.1f}% Complete)', fontsize=14, fontweight='bold')
- ax.set_ylabel('Interest Level')
- # Annotate each bar with its value
- for bar, y in zip(bars, ys.mean()):
- height = bar.get_height()
- ax.annotate(f'{y:.2f}', xy=(bar.get_x() + bar.get_width() / 2, height),
- xytext=(0, 3), textcoords='offset points',
- ha='center', va='bottom')
- # Set x-axis ticks and labels based on sorted keywords
- ax.set_xticks(np.arange(len(sorted_keywords)))
- ax.set_xticklabels(sorted_keywords, rotation=45, ha='right') # Adjust rotation and alignment as needed
- # Set y-axis ticks from 0 to 100 in increments of 10
- ax.set_yticks(np.arange(0, 110, 10))
- # Set the fixed height for the y-axis
- ax.set_ylim(0, 100)
- # Calculate total frames
- total_frames = min(len(interest_over_time), num_months)
- # Create the animation
- animation_2d_bar = animation.FuncAnimation(fig, update, frames=total_frames, interval=250, repeat=False)
- plt.show()
- # ANIMATE 3D BAR PLOT
- def animate_3d_bar_plot(interest_over_time, keywords, num_months=num_months):
- """
- Generate and display an animated 3D bar plot.
- Parameters:
- - interest_over_time (DataFrame): Dataframe containing interest over time.
- - keywords (List[str]): List of keywords to plot.
- - num_months (int): Number of months to display in the animation.
- """
- print("\nAnimating 3D Bar Plot...")
- fig = plt.figure(figsize=(8, 8))
- ax = fig.add_subplot(projection='3d')
- # Set figure elevation, azimuth & roll
- ax.view_init(elev=10, azim=40, roll=0)
- # Sort keywords based on their mean values in descending order (from largest to smallest)
- sorted_keywords = sorted(keywords, key=lambda keyword: interest_over_time[keyword].mean(), reverse=True)
- # Generate a color map with a different color for each keyword
- colors = plt.cm.tab10(np.arange(len(keywords)))
- # Calculate total frames
- total_frames = min(len(interest_over_time), num_months)
- def update(frame):
- # Calculate the month
- month = frame + 1
- # Calculate percent_complete based on the current frame and total frames
- percent_complete = (frame + 1) / total_frames * 100
- # Calculate the number of elements in each frame
- elements_per_frame = len(interest_over_time) // num_months
- # Calculate the start and end indices for the current frame
- start_index = frame * elements_per_frame
- end_index = (frame + 1) * elements_per_frame
- # Use iloc to ensure consistent slicing
- ys = interest_over_time.iloc[start_index:end_index][sorted_keywords]
- ax.clear() # Clear the previous frame
- for k, keyword in enumerate(sorted_keywords):
- xs = np.arange(len(ys))
- zs = np.full(len(ys), k) # Use np.full to create an array with the same value (k) for each element
- # Create 3D bars using bar3d function with defined width and depth
- ax.bar3d(xs, zs, np.zeros(len(xs)), dx=bar_width, dy=bar_depth, dz=ys[keyword], color=colors[k])
- # Display the values of the topics outside the plot
- for k, keyword in enumerate(sorted_keywords):
- value_text = f'{keyword}: {ys[keyword].values[frame] if frame < len(ys[keyword]) else ys[keyword].values[-1]:.1f}'
- ax.text(len(sorted_keywords), k, -10, value_text, fontsize=10, verticalalignment='baseline', color=colors[k])
- # Dynamically display the current month number
- current_month = frame + 1
- # Set Titles & Labels
- ax.set_title(f'Animated 3D Bar Plot - Month {current_month} / {num_months}\n({percent_complete:.1f}% Complete)', fontsize=14, fontweight='bold')
- ax.set_xlabel('Months', labelpad=20)
- ax.xaxis.label.set_position((-20, 0))
- ax.set_ylabel('Topics', labelpad=20)
- ax.yaxis.label.set_position((-20, 0))
- ax.set_zlabel('Interest Level', labelpad=20)
- ax.zaxis.label.set_position((0, 0))
- # Directly set x-axis ticks to match the number of topics
- ax.set_xticks(np.arange(len(sorted_keywords)))
- # Set x-axis ticks to display topics
- ax.set_xticklabels([])
- # Set y-axis ticks to match the number of sorted_keywords
- ax.set_yticks(np.arange(len(sorted_keywords)))
- # Set y-axis ticks to display sorted_keywords
- ax.set_yticklabels([])
- # Set z-axis ticks from 0 to 100
- ax.set_zticks(np.arange(0, 110, 10))
- # Set z-axis limit 0 to 100
- ax.set_zlim(0, 100)
- # Create the animation
- animation_3d_bar = animation.FuncAnimation(fig, update, frames=total_frames, interval=250, repeat=False)
- plt.show()
- # STATIC 3D BAR PLOT
- def generate_3d_bar_plot(interest_over_time, keywords):
- """
- Generate and display a static 3D bar plot.
- Parameters:
- - interest_over_time (DataFrame): Dataframe containing interest over time.
- - keywords (List[str]): List of keywords to plot.
- """
- print("\nGenerating 3D Bar Plot...")
- fig = plt.figure(figsize=(8, 8))
- ax = fig.add_subplot(projection='3d')
- # Set figure elevation, azimuth & roll
- ax.view_init(elev=10, azim=40, roll=0)
- # Calculate mean values for each keyword
- mean_values = [interest_over_time[keyword].mean() for keyword in keywords]
- # Sort keywords and mean values based on mean values in descending order
- sorted_data = sorted(zip(keywords, mean_values), key=lambda x: x[1], reverse=True)
- sorted_keywords, sorted_mean_values = zip(*sorted_data)
- # Generate a color map with a different color for each keyword
- colors = plt.cm.tab10(np.arange(len(sorted_keywords)))
- max_rows = min(len(sorted_keywords), 5) # Set a maximum of 5 rows
- max_cells = min(len(interest_over_time), 5) # Set a maximum of 5 cells (1 row * 5 columns)
- for k, keyword in enumerate(sorted_keywords):
- xs = np.arange(max_cells)
- zs = np.full(len(xs), k) # Use np.full to create an array with the same value (k) for each element
- ys = np.full(len(xs), sorted_mean_values[k])
- # Create 3D bars using bar3d function with defined width and depth
- ax.bar3d(xs, zs, np.zeros(len(xs)), dx=1, dy=1, dz=ys, color=colors[k])
- # Display the values of the topics outside the plot
- for k, (keyword, mean_value) in enumerate(zip(sorted_keywords, sorted_mean_values)):
- value_text = f'{keyword}: {mean_value:.1f}'
- ax.text(max_cells + 0.5, k - 0.5, -10, value_text, fontsize=10, verticalalignment='baseline', color=colors[k])
- # Set Titles & Labels
- ax.set_title('Static 3D Bar Plot', fontsize=14, fontweight='bold')
- ax.set_xlabel('Months', labelpad=20)
- ax.xaxis.label.set_position((-20, 0))
- ax.set_ylabel('Topics')
- ax.set_zlabel('Interest Level', labelpad=20)
- ax.zaxis.label.set_position((0, 0))
- # Directly set x-axis ticks to match the number of months
- ax.set_xticks(np.arange(max_cells))
- # Set x-axis ticks to display months
- ax.set_xticklabels([])
- # Set y-axis ticks to match the number of sorted_keywords
- ax.set_yticks(np.arange(max_rows))
- # Set y-axis ticks to display sorted_keywords
- ax.set_yticklabels([])
- # Set z-axis ticks from 0 to the total value
- ax.set_zticks(np.arange(0, 110, 10))
- # Set z-axis limit 0 to the total value
- ax.set_zlim(0, 100)
- plt.show()
- # GENERATE BAR PLOT
- def generate_bar_plot(interest_over_time, keywords):
- '''
- GENERATE AND DISPLAY A BAR PLOT BASED ON USER'S CHOICE (2D OR 3D).
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO PLOT.
- '''
- try:
- # Ask the user if they want 2D or 3D
- bar_type = input("\nChoose the bar plot type: \n1: 2D\n2: 3D\nYour Choice (1 or 2): ")
- if bar_type == '1':
- generate_2d_bar_plot(interest_over_time, keywords)
- elif bar_type == '2':
- generate_3d_bar_plot(interest_over_time, keywords)
- else:
- print("Invalid choice. Please enter 1 for 2D or 2 for 3D.")
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- ''' [PIE CHARTS]'''
- # ANIMATED PIE CHART
- def animate_pie_chart(interest_over_time, keywords, num_months):
- '''
- GENERATE AND DISPLAY AN ANIMATED PIE CHART WITH AVERAGE VALUES.
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO INCLUDE IN THE PIE CHART.
- - NUM_MONTHS (INT): NUMBER OF MONTHS FOR WHICH THE AVERAGE VALUES ARE CALCULATED.
- '''
- print("\nAnimating Pie Chart (Average)...")
- average_values = interest_over_time[keywords].mean()
- # Calculate total frames
- total_frames = len(interest_over_time)
- fig, ax = plt.subplots(figsize=(8, 8))
- def update(frame):
- ax.clear()
- # Calculate the percentage of completion
- percent_complete = (frame + 1) / total_frames * 100
- # Calculate the average values for the current frame
- current_frame = frame * len(interest_over_time) // total_frames
- current_values = interest_over_time.iloc[current_frame][keywords]
- # Create a pie chart for the current frame
- wedges, texts, autotexts = ax.pie(current_values, labels=[f'{keyword}\nAverage: {current_values[keyword]:.2f}' for keyword in keywords],
- autopct='', startangle=140, wedgeprops=dict(width=0.3))
- # Calculate the center of the pie chart
- center_x, center_y = np.mean([wedge.center for wedge in wedges], axis=0)
- # Adjust the starting offset and offset
- start_offset = -1.80
- offset = -0.20
- for i, keyword in enumerate(keywords):
- ax.text(center_x, center_y - (start_offset + i) * offset, f'{keyword}\nAverage: {current_values[keyword]:.2f}', ha='center', va='center', color='black', fontsize=10)
- ax.set_title(f'Animated Pie Chart - (Average Strength)\n{percent_complete:.2f}% Complete')
- # Create the animation
- animation_pie_chart = animation.FuncAnimation(fig, update, frames=total_frames, interval=250, repeat=False)
- plt.show()
- # GENERATE PIE CHART
- def generate_pie_chart(interest_over_time, keywords, num_months):
- '''
- GENERATE AND DISPLAY A STATIC PIE CHART WITH AVERAGE VALUES.
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO INCLUDE IN THE PIE CHART.
- - NUM_MONTHS (INT): NUMBER OF MONTHS FOR WHICH THE AVERAGE VALUES ARE CALCULATED.
- '''
- print("\nGenerating Pie Chart (Average Strength)...")
- average_values = interest_over_time[keywords].mean()
- plt.figure(figsize=(8, 8))
- wedges, texts, autotexts = plt.pie(average_values, labels=[f'{keyword}\nAverage: {average_values[keyword]:.2f}' for keyword in keywords],
- autopct='', startangle=140, wedgeprops=dict(width=0.3))
- # Calculate the center of the pie chart
- center_x, center_y = np.mean([wedge.center for wedge in wedges], axis=0)
- # Adjust the starting offset and offset
- start_offset = -1.80
- offset = -0.20
- for i, keyword in enumerate(keywords):
- plt.text(center_x, center_y - (start_offset + i) * offset, f'{keyword}\nAverage: {average_values[keyword]:.2f}', ha='center', va='center', color='black', fontsize=10)
- plt.title(f'Static Pie Chart (Average)')
- plt.show()
- ''' [SCATTER PLOTS]'''
- # ANIMATED SCATTER PLOT
- def animate_scatter_plot(interest_over_time, keywords, max_months=240):
- '''
- GENERATE AND DISPLAY AN ANIMATED SCATTER PLOT WITH AVERAGES & SOLID MARKERS.
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO PLOT.
- - MAX_MONTHS (INT): MAXIMUM NUMBER OF MONTHS TO ANIMATE (MAX IS 240).
- '''
- print("\nAnimating Scatter Plot...")
- fig, ax = plt.subplots(figsize=(16, 8))
- colors = plt.cm.viridis(np.linspace(0, 1, len(keywords)))
- def update(frame):
- ax.clear()
- # Calculate the month
- month = frame + 1
- # Plot the scatter chart for the current month
- start_index = frame * len(interest_over_time) // max_months
- end_index = (frame + 1) * len(interest_over_time) // max_months
- xs = interest_over_time.index[:end_index]
- for k, keyword in enumerate(keywords):
- ys = interest_over_time[keyword][:end_index]
- # Use different colors for each keyword
- color = colors[k]
- # Plot the scatter plot for the current keyword
- scatter = ax.scatter(xs, ys, color=color, label=f'{keyword} - Avg: {ys.mean():.2f}')
- # Plot the average line for the current keyword
- avg_interest = ys.mean()
- ax.axhline(y=avg_interest, color=color, linestyle='--', linewidth=1)
- # Calculate the percentage of completion
- percent_complete = (month / max_months) * 100
- ax.set_title(f'Animated Scatter Plot - (Percent Complete - {percent_complete:.2f}%)')
- ax.set_xlabel('Month')
- ax.set_ylabel('Interest Level')
- ax.legend(loc='upper left')
- # Set y-axis ticks from 0 to 100 in increments of 10
- ax.set_yticks(np.arange(0, 110, 10))
- # Set the fixed height for the y-axis
- ax.set_ylim(0, 100)
- # Calculate total frames
- total_frames = min(len(interest_over_time), max_months)
- # Create the animation
- animation_scatter = animation.FuncAnimation(fig, update, frames=total_frames, interval=100, repeat=False)
- plt.show()
- # GENERATE SCATTER PLOT
- def generate_scatter_plot(interest_over_time, keywords):
- '''
- GENERATE AND DISPLAY A SCATTER PLOT.
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO PLOT.
- '''
- print("\nGenerating Scatter Plot...")
- plt.figure(figsize=(16, 8))
- # Set a list of distinct colors and markers for each keyword
- colors = plt.cm.viridis(np.linspace(0, 1, len(keywords)))
- # Markers Used: 'X': X, '^': Up triangle, '<': Left triangle, '>': Right triangle, 'o': Circle.
- markers = ['X', '^', '<', '>', 'o'] # Set the 5 markers to display
- # Calculate strengths based on the maximum interest value for each keyword
- strengths = [interest_over_time[keyword].max() for keyword in keywords]
- for i, keyword in enumerate(keywords):
- # Use strengths (divided by 0.50) to set the size of the points
- # Use different markers for each keyword
- plt.scatter(interest_over_time.index, interest_over_time[keyword],
- label=None, s=strengths[i]/0.50, color=colors[i], marker=markers[i])
- # Draw the average lines outside the loop
- avg_values = []
- for i, keyword in enumerate(keywords):
- avg_interest = interest_over_time[keyword].mean()
- avg_values.append(avg_interest)
- plt.axhline(y=avg_interest, color=colors[i], linestyle='--', linewidth=1, label=f'{keyword} - Avg: {avg_interest:.2f}')
- # Create custom legend with correct markers
- custom_legend = [Line2D([0], [0], marker=markers[i], color=colors[i], label=f'{keywords[i]}') for i in range(len(keywords))]
- plt.legend(handles=custom_legend, loc='upper left')
- plt.title('Static Scatter Plot')
- plt.xlabel('Date')
- plt.ylabel('Interest Level')
- # Set y-axis ticks from 0 to 100 in increments of 10
- plt.yticks(np.arange(0, 110, 10))
- # Set the fixed height for the y-axis
- plt.ylim(0, 100)
- plt.show()
- ''' [STACK PLOTS]'''
- # ANIMATED STACK PLOT
- def animate_stack_plot(interest_over_time, keywords):
- '''
- GENERATE AND DISPLAY AN ANIMATED STACK PLOT.
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO PLOT.
- '''
- print("\nAnimating Stack Plot...")
- fig, ax = plt.subplots(figsize=(16, 8))
- colors = plt.cm.viridis(np.linspace(0, 1, len(keywords)))
- def update(frame):
- ax.clear()
- # Calculate the percentage of completion
- percent_complete = (frame + 1) / total_frames * 100
- # Extract interest values for each keyword
- y_values = [interest_over_time[keyword].iloc[:frame + 1] for keyword in keywords]
- # Create a stack plot for the current frame
- ax.stackplot(interest_over_time.index[:frame + 1], y_values, labels=keywords, colors=colors, alpha=0.7)
- ax.set_title(f'Animated Stack Plot - ({percent_complete:.2f}% Complete)')
- ax.set_xlabel('Date')
- ax.set_ylabel('Interest Level')
- ax.legend(loc='upper left')
- # Set y-axis ticks from 0 to 300 in increments of 20
- ax.set_yticks(np.arange(0, 320, 20))
- # Set the fixed height for the y-axis
- ax.set_ylim(0, 300)
- # Calculate total frames
- total_frames = len(interest_over_time)
- # Create the animation
- animation_stack_plot = animation.FuncAnimation(fig, update, frames=total_frames, interval=250, repeat=False)
- plt.show()
- # GENERATE STACK PLOT
- def generate_stack_plot(interest_over_time, keywords):
- '''
- GENERATE AND DISPLAY A STATIC STACK PLOT.
- PARAMETERS:
- - INTEREST_OVER_TIME (DATAFRAME): DATAFRAME CONTAINING INTEREST OVER TIME.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS TO PLOT.
- '''
- print("\nGenerating Stack Plot...")
- fig, ax = plt.subplots(figsize=(16, 8)) # Create a new figure and axes
- # Extract interest values for each keyword
- y_values = [interest_over_time[keyword] for keyword in keywords]
- # Create a stack plot
- ax.stackplot(interest_over_time.index, y_values, labels=keywords, alpha=0.7)
- plt.title('Static Stack Plot')
- plt.xlabel('Date')
- plt.ylabel('Interest Level')
- plt.legend(loc='upper left')
- # Set y-axis ticks from 0 to 300 in increments of 20
- ax.set_yticks(np.arange(0, 320, 20))
- # Set the fixed height for the y-axis
- ax.set_ylim(0, 300)
- plt.show()
- ''' [WORDCLOUD] '''
- '''
- GENERATE AND DISPLAY A WORD CLOUD WITH RELATED (TOP/RISING) DATA OR USER-INPUT TOPICS.
- PARAMETERS:
- - PYTRENDS (TrendReq): AN INSTANCE OF THE pytrends LIBRARY FOR FETCHING DATA.
- - KEYWORDS (LIST[STR]): LIST OF KEYWORDS FOR WHICH RELATED DATA IS FETCHED.
- - NUM_RELATED_TOP (INT): NUMBER OF TOP RELATED QUERIES TO FETCH FOR EACH KEYWORD.
- - NUM_RELATED_RISING (INT): NUMBER OF RISING RELATED QUERIES TO FETCH FOR EACH KEYWORD.
- - RELATED_DATA_DISPLAYED (BOOL): FLAG TO INDICATE WHETHER RELATED DATA SHOULD BE DISPLAYED (DEFAULT: FALSE).
- '''
- # GENERATE WORD CLOUD WITH RELATED (TOP/RISING)
- def generate_word_cloud(pytrends, keywords, num_related_top, num_related_rising, related_data_displayed=False):
- try:
- related_queries_data = {'top': [], 'rising': []}
- def process_related_data(keyword):
- nonlocal related_queries_data
- try:
- related_queries_top = pytrends.related_queries()[keyword]['top'].head(num_related_top)
- if not related_queries_top.empty:
- related_queries_data['top'].extend(related_queries_top['query'])
- except Exception as e:
- print(f"Failed to get related top queries for '{keyword}'. Error: {e}")
- try:
- related_queries_rising = pytrends.related_queries()[keyword]['rising'].head(num_related_rising)
- if not related_queries_rising.empty:
- related_queries_data['rising'].extend(related_queries_rising['query'])
- except Exception as e:
- print(f"Failed to get related rising queries for '{keyword}'. Error: {e}")
- if not related_data_displayed:
- use_related_data = '1'
- if use_related_data == '1':
- print("\nGenerating Word Cloud with Related Data...\nThis may take some time to process...")
- for keyword in keywords:
- process_related_data(keyword)
- all_queries = ' '.join(related_queries_data['top'] + related_queries_data['rising'])
- elif use_related_data == '2':
- print("\nGenerating Word Cloud with User Input Topics...\nThis may take some time to process...")
- all_queries = ' '.join(keywords)
- else:
- print("\nInvalid choice. Please enter 1 for Related Data or 2 for User Input Topics.")
- return
- else:
- all_queries = ' '.join(keywords)
- wordcloud = WordCloud(width=800, height=800, background_color='white').generate(all_queries)
- plt.figure(figsize=(8, 8))
- plt.imshow(wordcloud, interpolation='bilinear')
- plt.axis('off')
- plt.title('') # Add a title if you need it here
- plt.show()
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- ''' [MAIN LOGIC]'''
- '''
- [MAIN LOGIC]:
- THIS SECTION CONTAINS THE CORE LOGIC FOR EXECUTING THE GOOGLE TRENDS DATA ANALYSIS AND VISUALIZATION TOOL.
- IT ENCOMPASSES THE MAIN PROGRAM FLOW, INCLUDING USER INPUT COLLECTION, DATA FETCHING FROM GOOGLE TRENDS,
- AND THE MAIN MENU-DRIVEN INTERFACE FOR GENERATING VARIOUS PLOTS AND ANALYSES. THE CODE STRUCTURE IS
- ORGANIZED INTO MODULAR FUNCTIONS, OFFERING CLARITY AND MAINTAINABILITY. THE MAIN LOOP ENSURES CONTINUOUS
- INTERACTION WITH THE USER UNTIL THE PROGRAM IS EXITED. ERROR HANDLING IS IMPLEMENTED TO MANAGE INVALID
- INPUTS, ENSURING A SMOOTH USER EXPERIENCE. ADDITIONALLY, A SYSTEM RESET FUNCTION IS DEFINED TO CLEAR DATA
- AND RESTART THE ANALYSIS. OVERALL, THIS SECTION FORMS THE BACKBONE OF THE SCRIPT, ORCHESTRATING THE
- INTERACTION BETWEEN THE USER, DATA, & VISUALIZATION COMPONENTS.
- '''
- ''' [MAIN MENU]'''
- try:
- while True:
- header() # Call the global header
- # Get user selection
- print("\n\t::[SELECT FROM THE MENU OPTIONS]::\n")
- print("::[SINGLE PLOTS]::\t\t::[DISPLAY]::\n")
- print("1: LINE PLOT\t\t\t6: WORDCLOUD + (TOP/RISING)")
- print("2: 3D BAR PLOT\t\t\t7: ALL PLOTS (2D & 3D)")
- print("3: PIE CHART (AVERAGE)")
- print("4: SCATTER PLOT (AVERAGE)")
- print("5: STACK PLOT")
- print("\n\t\t ::[SYSTEM]::\n\n\t\t 9: RESET PROGRAM\n\t\t 0: Quit\n")
- plot_option = input("\nSelect Your Option or... Press [ENTER] For More Information : ")
- try:
- # Check if the user pressed [ENTER]
- if not plot_option:
- # Import and display the content of about.py
- import about
- about.display_about_text()
- input("Press [ENTER] to continue to the main menu.")
- # Check if the user pressed [ENTER]
- if not plot_option.strip():
- # Display a message and continue to the main menu
- print("\nContinuing To The Menu...\n")
- continue # Go back to the main menu after displaying the "About" text
- # Check if the user input is not empty after removing leading and trailing whitespace
- if plot_option.strip():
- try: # Attempt to convert the user input to an integer
- plot_option = int(plot_option)
- except ValueError:
- # If conversion to an integer fails (due to a non-numeric input), do nothing (pass)
- pass
- # Attempt to convert the user input (plot_option) to an integer
- plot_option = int(plot_option)
- ''' [PLOT OPTIONS]'''
- if 0 <= plot_option <= 9:
- if plot_option == 0:
- print("\nProgram Exiting...\tGoodBye!\n")
- break # Exit the loop and end the script
- elif plot_option == 1:
- try:
- # Ask the user if they want static or animated plots
- plot_type = input("\nChoose the plot type: \n1: Static\n2: Animated\nYour Choice (1 or 2): ")
- if plot_type == '1':
- generate_line_plot(interest_over_time, keywords, num_months)
- elif plot_type == '2':
- animate_line_plot(interest_over_time, keywords, num_months)
- else:
- print("Invalid choice. Please enter 1 for static or 2 for animated.")
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- elif plot_option == 2:
- try:
- # Ask the user if they want static or animated plots
- plot_type = input("\nChoose the plot type: \n1: Static\n2: Animated\nYour Choice (1 or 2): ")
- if plot_type == '1':
- # Ask the user for 2D or 3D static plot
- static_plot_type = input("\nChoose the static plot type: \n1: 2D\n2: 3D\nYour Choice (1 or 2): ")
- if static_plot_type == '1':
- generate_2d_bar_plot(interest_over_time, keywords)
- elif static_plot_type == '2':
- generate_3d_bar_plot(interest_over_time, keywords)
- else:
- print("Invalid choice. Please enter 1 for 2D or 2 for 3D.")
- elif plot_type == '2':
- # Ask the user for 2D or 3D animated plot
- animated_plot_type = input("\nChoose the animated plot type: \n1: 2D\n2: 3D\nYour Choice (1 or 2): ")
- if animated_plot_type == '1':
- animate_2d_bar_plot(interest_over_time, keywords)
- elif animated_plot_type == '2':
- animate_3d_bar_plot(interest_over_time, keywords)
- else:
- print("Invalid choice. Please enter 1 for 2D or 2 for 3D.")
- else:
- print("Invalid choice. Please enter 1 for static or 2 for animated.")
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- elif plot_option == 3:
- try:
- # Ask the user if they want static or animated pie chart
- plot_type = input("\nChoose the pie chart type: \n1: Static\n2: Animated\nYour Choice (1 or 2): ")
- if plot_type == '1':
- generate_pie_chart(interest_over_time, keywords, num_months)
- elif plot_type == '2':
- animate_pie_chart(interest_over_time, keywords, num_months)
- else:
- print("Invalid choice. Please enter 1 for static or 2 for animated.")
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- elif plot_option == 4:
- try:
- # Ask the user if they want static or animated plots
- plot_type = input("\nChoose the plot type: \n1: Static\n2: Animated\nYour Choice (1 or 2): ")
- if plot_type == '1':
- generate_scatter_plot(interest_over_time, keywords)
- elif plot_type == '2':
- animate_scatter_plot(interest_over_time, keywords)
- else:
- print("Invalid choice. Please enter 1 for static or 2 for animated.")
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- elif plot_option == 5:
- try:
- # Ask the user if they want static or animated plots
- plot_type = input("\nChoose the plot type: \n1: Static\n2: Animated\nYour Choice (1 or 2): ")
- if plot_type == '1':
- generate_stack_plot(interest_over_time, keywords)
- elif plot_type == '2':
- animate_stack_plot(interest_over_time, keywords)
- else:
- print("Invalid choice. Please enter 1 for static or 2 for animated.")
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- elif plot_option == 6:
- try:
- num_related_top = int(input("\nEnter the number of related top queries to include in the word cloud (Max 24):\n"))
- num_related_rising = int(input("\nEnter the number of related rising queries to include in the word cloud (Max 24):\n"))
- # Call the generate_word_cloud function and get the words
- wordcloud_words = generate_word_cloud(pytrends, keywords, num_related_top, num_related_rising)
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- elif plot_option == 7:
- # Ask the user if they want static or animated plots
- plot_type = input("\nChoose plot type:\n1: Static\n2: Animated\nYour Choice (1 or 2): ")
- if plot_type == '1':
- # Ask the user for 2D or 3D static plot
- static_plot_type = input("\nChoose the static plot type: \n1: 2D\n2: 3D\nYour Choice (1 or 2): ")
- if static_plot_type == '1':
- generate_line_plot(interest_over_time, keywords, num_months)
- generate_scatter_plot(interest_over_time, keywords)
- generate_stack_plot(interest_over_time, keywords)
- generate_2d_bar_plot(interest_over_time, keywords)
- generate_pie_chart(interest_over_time, keywords, num_months)
- elif static_plot_type == '2':
- generate_line_plot(interest_over_time, keywords, num_months)
- generate_scatter_plot(interest_over_time, keywords)
- generate_stack_plot(interest_over_time, keywords)
- generate_3d_bar_plot(interest_over_time, keywords)
- generate_pie_chart(interest_over_time, keywords, num_months)
- else:
- print("Invalid choice for static plot type. Please enter 1 for 2D or 2 for 3D.")
- elif plot_type == '2':
- # Ask the user for 2D or 3D animated plot
- animated_plot_type = input("\nChoose the animated plot type: \n1: 2D\n2: 3D\nYour Choice (1 or 2): ")
- if animated_plot_type == '1':
- animate_line_plot(interest_over_time, keywords, num_months)
- animate_scatter_plot(interest_over_time, keywords)
- animate_stack_plot(interest_over_time, keywords)
- animate_2d_bar_plot(interest_over_time, keywords)
- animate_pie_chart(interest_over_time, keywords, num_months)
- elif animated_plot_type == '2':
- animate_line_plot(interest_over_time, keywords, num_months)
- animate_scatter_plot(interest_over_time, keywords)
- animate_stack_plot(interest_over_time, keywords)
- animate_3d_bar_plot(interest_over_time, keywords)
- animate_pie_chart(interest_over_time, keywords, num_months)
- else:
- print("Invalid choice for animated plot type. Please enter 1 for 2D or 2 for 3D.")
- if related_data_displayed:
- wordcloud = generate_word_cloud(pytrends, keywords, num_related_top, num_related_rising, related_data_displayed)
- if wordcloud:
- # Display the word cloud using matplotlib
- plt.figure(figsize=(8, 8))
- plt.imshow(wordcloud, interpolation='bilinear')
- plt.axis('off')
- plt.title('Word Cloud of Related Queries')
- plt.show()
- elif plot_option == 9:
- # Reset the program and clear data
- reset_program()
- # Continue directly to the main menu
- continue
- else:
- # Handling Invalid Options
- print("\nInvalid option. Please enter a valid number between 0 and 7.\n")
- # Exception Handling for Non-Integer Option
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
- else:
- # Exception Handling for Invalid Number of Months
- print("\nInvalid number of months. Please enter a number between 1 and 240.\n")
- except ValueError:
- print("\nInvalid input. Please enter a valid number.\n")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement