| |
| """ |
| Script to create a graph visualization of DECA SCDC competition participants and their events. |
| """ |
|
|
| import re |
| import matplotlib.pyplot as plt |
| import networkx as nx |
| from collections import defaultdict |
| import numpy as np |
|
|
| def parse_pdf_data(pdf_path): |
| """Parse the PDF text data to extract participant-event relationships.""" |
| try: |
| with open(pdf_path, 'r', encoding='utf-8') as f: |
| content = f.read() |
| except: |
| import sys |
| print(f"Warning: Could not read {pdf_path}") |
| return {}, {} |
| |
| |
| lines = [l.strip() for l in content.split('\n') if l.strip()] |
| |
| |
| event_counts = defaultdict(int) |
| |
| i = 0 |
| while i < len(lines): |
| line = lines[i] |
| |
| |
| if not line or 'SCHEDULES' in line or line == 'Name' or 'Page' in line or 'Created:' in line or '--' in line: |
| i += 1 |
| continue |
| |
| |
| if len(line) == 1 and line.isalpha(): |
| i += 1 |
| continue |
| |
| |
| |
| |
| is_name_line = False |
| if ',' in line: |
| is_name_line = True |
| elif len(line.split()) >= 2 and line[0].isupper(): |
| is_name_line = True |
| elif len(line.split()) == 1 and line[0].isupper() and len(line) > 2: |
| |
| |
| if i + 1 < len(lines): |
| next_line = lines[i + 1] |
| if (len(next_line) >= 15 and any(keyword in next_line for keyword in |
| ['Marketing', 'Business', 'Finance', 'Hospitality', 'Tourism', 'Entrepreneurship', |
| 'Operations', 'Team Decision', 'Role Play', 'Presentation', 'Series', 'Event', 'Project', 'Plan', |
| 'Growth', 'Solutions', 'Awareness', 'Giving', 'Development', 'Literacy', 'Selling'])) or \ |
| (len(next_line) > 20): |
| is_name_line = True |
| |
| if is_name_line: |
| |
| names_str = line |
| |
| |
| |
| if i + 1 < len(lines): |
| next_line = lines[i + 1] |
| |
| |
| if (len(next_line) >= 15 and any(keyword in next_line for keyword in |
| ['Marketing', 'Business', 'Finance', 'Hospitality', 'Tourism', 'Entrepreneurship', |
| 'Operations', 'Team Decision', 'Role Play', 'Presentation', 'Series', 'Event', 'Project', 'Plan', |
| 'Growth', 'Solutions', 'Awareness', 'Giving', 'Development', 'Literacy', 'Selling'])) or \ |
| (len(next_line) > 20): |
| event = next_line |
| i += 2 |
| else: |
| |
| parts = line.split('\t') |
| if len(parts) >= 2: |
| names_str = parts[0] |
| event = parts[1] |
| i += 1 |
| else: |
| i += 1 |
| continue |
| else: |
| i += 1 |
| continue |
| |
| |
| if names_str and event and len(event) > 5: |
| |
| excluded_terms = ['Preparation Area Time', 'Presentation Time', 'Holding Time', |
| 'Role Play', 'Presentation', 'Schedule', 'Section', 'Date', |
| 'Time', 'AM', 'PM', 'of 34', 'Created:'] |
| if any(term in event for term in excluded_terms): |
| i += 1 |
| continue |
| |
| |
| name_parts = [n.strip() for n in names_str.split(',')] |
| has_valid_name = False |
| for name_part in name_parts: |
| name_part = name_part.strip() |
| if name_part and len(name_part) > 1 and name_part[0].isalpha(): |
| has_valid_name = True |
| break |
| |
| if has_valid_name: |
| event_counts[event] += 1 |
| else: |
| i += 1 |
| |
| |
| |
| event_participants = {event: set(range(count)) for event, count in event_counts.items()} |
| participant_events = {} |
| |
| return event_participants, participant_events, event_counts |
|
|
| def create_graph(event_participants, participant_events): |
| """Create a bipartite graph from the data.""" |
| G = nx.Graph() |
| |
| |
| for event in event_participants.keys(): |
| G.add_node(event, node_type='event') |
| |
| |
| for participant in participant_events.keys(): |
| G.add_node(participant, node_type='participant') |
| |
| |
| for event, participants in event_participants.items(): |
| for participant in participants: |
| G.add_edge(participant, event) |
| |
| return G |
|
|
| def visualize_graph(event_participants, output_path='deca_event_graph.png', event_counts=None): |
| """Create a bar chart showing number of teams/entries per event.""" |
| |
| if event_counts: |
| counts_dict = event_counts |
| else: |
| counts_dict = {event: len(participants) for event, participants in event_participants.items()} |
| |
| |
| sorted_events = sorted(counts_dict.items(), key=lambda x: x[1], reverse=True) |
| events = [e[0] for e in sorted_events] |
| counts = [e[1] for e in sorted_events] |
| |
| |
| fig, ax = plt.subplots(figsize=(16, max(10, len(events) * 0.4))) |
| |
| |
| bars = ax.barh(range(len(events)), counts, color='steelblue', alpha=0.8) |
| |
| |
| ax.set_yticks(range(len(events))) |
| ax.set_yticklabels(events, fontsize=9) |
| |
| |
| ax.set_xlabel('Number of Teams/Entries', fontsize=12, fontweight='bold') |
| |
| |
| for i, (bar, count) in enumerate(zip(bars, counts)): |
| ax.text(count + 0.5, i, str(count), |
| va='center', fontsize=9, fontweight='bold') |
| |
| |
| ax.set_title('DECA SCDC Competition: Number of Teams/Entries per Event', |
| fontsize=14, fontweight='bold', pad=20) |
| |
| |
| ax.invert_yaxis() |
| |
| |
| ax.grid(axis='x', alpha=0.3, linestyle='--') |
| |
| |
| plt.tight_layout() |
| plt.savefig(output_path, dpi=300, bbox_inches='tight') |
| print(f"Bar chart saved to {output_path}") |
| |
| return sorted_events |
|
|
| def create_summary_statistics(event_participants, participant_events, event_counts=None): |
| """Print summary statistics.""" |
| print("\n" + "="*60) |
| print("DECA SCDC Competition Summary Statistics") |
| print("="*60) |
| |
| if event_counts: |
| counts_dict = event_counts |
| else: |
| counts_dict = {event: len(participants) for event, participants in event_participants.items()} |
| |
| print(f"Total number of events: {len(counts_dict)}") |
| print(f"Total number of teams/entries: {sum(counts_dict.values())}") |
| |
| |
| print("\nTop 10 Events by Number of Teams/Entries:") |
| sorted_events = sorted(counts_dict.items(), key=lambda x: x[1], reverse=True) |
| for i, (event, count) in enumerate(sorted_events[:10], 1): |
| print(f"{i:2d}. {event}: {count} teams/entries") |
| |
| |
| print("\nParticipants in Multiple Events:") |
| multi_event_participants = {p: events for p, events in participant_events.items() if len(events) > 1} |
| if multi_event_participants: |
| sorted_participants = sorted(multi_event_participants.items(), key=lambda x: len(x[1]), reverse=True) |
| for participant, events in sorted_participants[:10]: |
| print(f" {participant}: {len(events)} events - {', '.join(list(events)[:3])}...") |
| else: |
| print(" None found") |
| |
| print("="*60 + "\n") |
|
|
| def main(): |
| import os |
| |
| script_dir = os.path.dirname(os.path.abspath(__file__)) |
| text_path = os.path.join(os.path.dirname(script_dir), 'scdc_data.txt') |
| output_path = '/Users/havishkunchanapalli/cropintel/deca_event_graph.png' |
| |
| print("Parsing PDF data...") |
| if not os.path.exists(text_path): |
| |
| pdf_path = '/Users/havishkunchanapalli/Downloads/SCDC Event Schedules (1).pdf' |
| if os.path.exists(pdf_path): |
| text_path = pdf_path |
| |
| event_participants, participant_events, event_counts = parse_pdf_data(text_path) |
| |
| print("Generating bar chart visualization...") |
| visualize_graph(event_participants, output_path, event_counts) |
| |
| print("Generating summary statistics...") |
| create_summary_statistics(event_participants, participant_events, event_counts) |
| |
| print(f"\nGraph visualization saved to: {output_path}") |
|
|
| if __name__ == '__main__': |
| main() |
|
|