Spaces:
Paused
Paused
| """ | |
| Nepal Federal Election - Constituency Utilities Module | |
| ======================================================== | |
| Reusable utilities for constituency-wise analysis and data management. | |
| This module provides: | |
| - Comprehensive constituency mapping (165 federal constituencies) | |
| - Province-District-Constituency hierarchical relationships | |
| - Constituency validation and lookup functions | |
| - Helper functions for constituency-based queries | |
| - Integration with election results and voter databases | |
| Author: Election Analysis Project | |
| Date: January 2026 | |
| """ | |
| import json | |
| from typing import Dict, List, Optional, Tuple | |
| import pandas as pd | |
| # ============================================================================ | |
| # CONSTITUENCY DATABASE - Nepal Federal Election 2079 (165 Constituencies) | |
| # ============================================================================ | |
| # Province Names (English and Nepali) | |
| PROVINCE_NAMES = { | |
| 1: {"en": "Koshi", "np": "कोशी"}, | |
| 2: {"en": "Madhesh", "np": "मधेश"}, | |
| 3: {"en": "Bagmati", "np": "बागमती"}, | |
| 4: {"en": "Gandaki", "np": "गण्डकी"}, | |
| 5: {"en": "Lumbini", "np": "लुम्बिनी"}, | |
| 6: {"en": "Karnali", "np": "कर्णाली"}, | |
| 7: {"en": "Sudurpashchim", "np": "सुदूरपश्चिम"} | |
| } | |
| # Complete District-to-Constituency Mapping (Based on Election 2079 Data) | |
| # Each constituency is uniquely identified by combining district and constituency number | |
| # Format: "District-ConstNumber" (e.g., "Jhapa-1", "Kathmandu-5") | |
| CONSTITUENCY_MAPPING = { | |
| # ========== Province 1: कोशी (28 constituencies) ========== | |
| 1: { | |
| "ताप्लेजुंग": ["ताप्लेजुंग-१"], | |
| "पाँचथर": ["पाँचथर-१"], | |
| "इलाम": ["इलाम-१", "इलाम-२"], | |
| "झापा": ["झापा-१", "झापा-२", "झापा-३", "झापा-४", "झापा-५"], | |
| "संखुवासभा": ["संखुवासभा-१"], | |
| "तेर्हथुम": ["तेर्हथुम-१"], | |
| "भोजपुर": ["भोजपुर-१"], | |
| "धनकुटा": ["धनकुटा-१"], | |
| "मोरङ्ग": ["मोरङ्ग-१", "मोरङ्ग-२", "मोरङ्ग-३", "मोरङ्ग-४", "मोरङ्ग-५", "मोरङ्ग-६"], | |
| "सुनसरी": ["सुनसरी-१", "सुनसरी-२", "सुनसरी-३"], | |
| "सोलुखुम्बु": ["सोलुखुम्बु-१"], | |
| "खोटाङ्ग": ["खोटाङ्ग-१"], | |
| "ओखलढुंगा": ["ओखलढुंगा-१"], | |
| "उदयपुर": ["उदयपुर-१"], | |
| }, | |
| # ========== Province 2: मधेश (32 constituencies) ========== | |
| 2: { | |
| "सप्तरी": ["सप्तरी-१", "सप्तरी-२", "सप्तरी-३"], | |
| "सिराहा": ["सिराहा-१", "सिराहा-२", "सिराहा-३"], | |
| "धनुषा": ["धनुषा-१", "धनुषा-२", "धनुषा-३", "धनुषा-४"], | |
| "महोत्तरी": ["महोत्तरी-१", "महोत्तरी-२", "महोत्तरी-३", "महोत्तरी-४"], | |
| "सर्लाही": ["सर्लाही-१", "सर्लाही-२", "सर्लाही-३", "सर्लाही-४"], | |
| "रौतहट": ["रौतहट-१", "रौतहट-२", "रौतहट-३"], | |
| "बारा": ["बारा-१", "बारा-२", "बारा-३", "बारा-४"], | |
| "पर्सा": ["पर्सा-१", "पर्सा-२", "पर्सा-३", "पर्सा-४"], | |
| }, | |
| # ========== Province 3: बागमती (52 constituencies) ========== | |
| 3: { | |
| "सिन्धुली": ["सिन्धुली-१", "सिन्धुली-२"], | |
| "रामेछाप": ["रामेछाप-१"], | |
| "दोलखा": ["दोलखा-१"], | |
| "भक्तपुर": ["भक्तपुर-१", "भक्तपुर-२"], | |
| "धादिङ्ग": ["धादिङ्ग-१", "धादिङ्ग-२"], | |
| "काठमाडौं": ["काठमाडौं-१", "काठमाडौं-२", "काठमाडौं-३", "काठमाडौं-४", | |
| "काठमाडौं-५", "काठमाडौं-६", "काठमाडौं-७", "काठमाडौं-८", | |
| "काठमाडौं-९", "काठमाडौं-१०"], | |
| "काभ्रेपलाञ्चोक": ["काभ्रेपलाञ्चोक-१", "काभ्रेपलाञ्चोक-२", "काभ्रेपलाञ्चोक-३"], | |
| "ललितपुर": ["ललितपुर-१", "ललितपुर-२", "ललितपुर-३"], | |
| "नुवाकोट": ["नुवाकोट-१"], | |
| "रसुवा": ["रसुवा-१"], | |
| "सिन्धुपाल्चोक": ["सिन्धुपाल्चोक-१", "सिन्धुपाल्चोक-२"], | |
| "चितवन": ["चितवन-१", "चितवन-२", "चितवन-३"], | |
| "मकवानपुर": ["मकवानपुर-१", "मकवानपुर-२", "मकवानपुर-३"], | |
| }, | |
| # ========== Province 4: गण्डकी (18 constituencies) ========== | |
| 4: { | |
| "गोरखा": ["गोरखा-१", "गोरखा-२"], | |
| "लमजुंग": ["लमजुंग-१"], | |
| "तनहुँ": ["तनहुँ-१", "तनहुँ-२"], | |
| "स्याङ्जा": ["स्याङ्जा-१", "स्याङ्जा-२"], | |
| "कास्की": ["कास्की-१", "कास्की-२", "कास्की-३"], | |
| "मनाङ्ग": ["मनाङ्ग-१"], | |
| "मुस्तांग": ["मुस्तांग-१"], | |
| "पर्वत": ["पर्वत-१"], | |
| "म्याग्दी": ["म्याग्दी-१"], | |
| "बागलुङ": ["बागलुङ-१", "बागलुङ-२"], | |
| "नवलपरासी (बर्दघाट सुस्ता पूर्व)": ["नवलपरासी (बर्दघाट सुस्ता पूर्व)-१", "नवलपरासी (बर्दघाट सुस्ता पूर्व)-२"], | |
| }, | |
| # ========== Province 5: लुम्बिनी (24 constituencies) ========== | |
| 5: { | |
| "गुल्मी": ["गुल्मी-१", "गुल्मी-२"], | |
| "पाल्पा": ["पाल्पा-१", "पाल्पा-२"], | |
| "रुपन्देही": ["रुपन्देही-१", "रुपन्देही-२", "रुपन्देही-३", "रुपन्देही-४", "रुपन्देही-५"], | |
| "अर्घाखांची": ["अर्घाखांची-१"], | |
| "कपिलवस्तु": ["कपिलवस्तु-१", "कपिलवस्तु-२", "कपिलवस्तु-३"], | |
| "नवलपरासी (बर्दघाट सुस्ता पश्चिम)": ["नवलपरासी (बर्दघाट सुस्ता पश्चिम)-१"], | |
| "प्यूठान": ["प्यूठान-१"], | |
| "रोल्पा": ["रोल्पा-१"], | |
| "रुकुम पूर्व": ["रुकुम पूर्व-१"], | |
| "दाङ": ["दाङ-१", "दाङ-२", "दाङ-३"], | |
| "बाँके": ["बाँके-१", "बाँके-२", "बाँके-३"], | |
| "बर्दिया": ["बर्दिया-१", "बर्दिया-२"], | |
| }, | |
| # ========== Province 6: कर्णाली (12 constituencies) ========== | |
| 6: { | |
| "रुकुम पश्चिम": ["रुकुम पश्चिम-१"], | |
| "सल्यान": ["सल्यान-१"], | |
| "डोल्पा": ["डोल्पा-१"], | |
| "जुम्ला": ["जुम्ला-१"], | |
| "कालिकोट": ["कालिकोट-१"], | |
| "मुगु": ["मुगु-१"], | |
| "हुम्ला": ["हुम्ला-१"], | |
| "दैलेख": ["दैलेख-१"], | |
| "जाजरकोट": ["जाजरकोट-१"], | |
| "सुर्खेत": ["सुर्खेत-१", "सुर्खेत-२"], | |
| }, | |
| # ========== Province 7: सुदूरपश्चिम (19 constituencies) ========== | |
| 7: { | |
| "बाजुरा": ["बाजुरा-१"], | |
| "बझाङ्ग": ["बझाङ्ग-१"], | |
| "अछाम": ["अछाम-१", "अछाम-२"], | |
| "डोटी": ["डोटी-१"], | |
| "कैलाली": ["कैलाली-१", "कैलाली-२", "कैलाली-३", "कैलाली-४"], | |
| "कन्चनपुर": ["कन्चनपुर-१", "कन्चनपुर-२"], | |
| "डडेलधुरा": ["डडेलधुरा-१"], | |
| "बैतडी": ["बैतडी-१"], | |
| "दार्चुला": ["दार्चुला-१"], | |
| } | |
| } | |
| # ============================================================================ | |
| # HELPER FUNCTIONS | |
| # ============================================================================ | |
| def get_all_constituencies() -> List[str]: | |
| """ | |
| Get a complete list of all 165 federal constituencies. | |
| Returns: | |
| List[str]: List of all constituency identifiers | |
| """ | |
| all_constituencies = [] | |
| for province_id, districts in CONSTITUENCY_MAPPING.items(): | |
| for district_name, constituencies in districts.items(): | |
| all_constituencies.extend(constituencies) | |
| return sorted(all_constituencies) | |
| def get_constituencies_by_province(province_id: int) -> List[str]: | |
| """ | |
| Get all constituencies for a specific province. | |
| Args: | |
| province_id (int): Province ID (1-7) | |
| Returns: | |
| List[str]: List of constituencies in the province | |
| """ | |
| if province_id not in CONSTITUENCY_MAPPING: | |
| return [] | |
| constituencies = [] | |
| for district_name, const_list in CONSTITUENCY_MAPPING[province_id].items(): | |
| constituencies.extend(const_list) | |
| return sorted(constituencies) | |
| def get_constituencies_by_district(district_name: str, province_id: Optional[int] = None) -> List[str]: | |
| """ | |
| Get all constituencies for a specific district. | |
| Args: | |
| district_name (str): District name in Nepali | |
| province_id (int, optional): Province ID to narrow down search | |
| Returns: | |
| List[str]: List of constituencies in the district | |
| """ | |
| if province_id: | |
| if province_id in CONSTITUENCY_MAPPING and district_name in CONSTITUENCY_MAPPING[province_id]: | |
| return CONSTITUENCY_MAPPING[province_id][district_name] | |
| return [] | |
| # Search across all provinces | |
| for prov_id, districts in CONSTITUENCY_MAPPING.items(): | |
| if district_name in districts: | |
| return districts[district_name] | |
| return [] | |
| def get_district_from_constituency(constituency: str) -> Optional[str]: | |
| """ | |
| Extract district name from constituency identifier. | |
| Args: | |
| constituency (str): Constituency identifier (e.g., "काठमाडौं-५") | |
| Returns: | |
| Optional[str]: District name or None if invalid | |
| """ | |
| if '-' not in constituency: | |
| return None | |
| return constituency.split('-')[0] | |
| def get_constituency_number(constituency: str) -> Optional[str]: | |
| """ | |
| Extract constituency number from constituency identifier. | |
| Args: | |
| constituency (str): Constituency identifier (e.g., "काठमाडौं-५") | |
| Returns: | |
| Optional[str]: Constituency number or None if invalid | |
| """ | |
| if '-' not in constituency: | |
| return None | |
| parts = constituency.split('-') | |
| return parts[-1] if len(parts) == 2 else None | |
| def get_province_from_constituency(constituency: str) -> Optional[int]: | |
| """ | |
| Get province ID for a given constituency. | |
| Args: | |
| constituency (str): Constituency identifier | |
| Returns: | |
| Optional[int]: Province ID (1-7) or None if not found | |
| """ | |
| district = get_district_from_constituency(constituency) | |
| if not district: | |
| return None | |
| for province_id, districts in CONSTITUENCY_MAPPING.items(): | |
| if district in districts: | |
| return province_id | |
| return None | |
| def validate_constituency(constituency: str) -> bool: | |
| """ | |
| Validate if a constituency identifier is valid. | |
| Args: | |
| constituency (str): Constituency identifier to validate | |
| Returns: | |
| bool: True if valid, False otherwise | |
| """ | |
| return constituency in get_all_constituencies() | |
| def get_constituency_info(constituency: str) -> Optional[Dict]: | |
| """ | |
| Get detailed information about a constituency. | |
| Args: | |
| constituency (str): Constituency identifier | |
| Returns: | |
| Optional[Dict]: Dictionary with constituency details or None | |
| """ | |
| if not validate_constituency(constituency): | |
| return None | |
| district = get_district_from_constituency(constituency) | |
| number = get_constituency_number(constituency) | |
| province_id = get_province_from_constituency(constituency) | |
| if not all([district, number, province_id]): | |
| return None | |
| return { | |
| 'constituency_id': constituency, | |
| 'district': district, | |
| 'number': number, | |
| 'province_id': province_id, | |
| 'province_name_np': PROVINCE_NAMES[province_id]['np'], | |
| 'province_name_en': PROVINCE_NAMES[province_id]['en'] | |
| } | |
| def get_constituency_summary_stats() -> Dict: | |
| """ | |
| Get summary statistics about constituencies. | |
| Returns: | |
| Dict: Summary statistics including counts by province | |
| """ | |
| total = 0 | |
| by_province = {} | |
| for province_id, districts in CONSTITUENCY_MAPPING.items(): | |
| count = sum(len(constituencies) for constituencies in districts.values()) | |
| by_province[province_id] = { | |
| 'count': count, | |
| 'name_np': PROVINCE_NAMES[province_id]['np'], | |
| 'name_en': PROVINCE_NAMES[province_id]['en'] | |
| } | |
| total += count | |
| return { | |
| 'total_constituencies': total, | |
| 'total_provinces': 7, | |
| 'by_province': by_province | |
| } | |
| def create_constituency_dataframe() -> pd.DataFrame: | |
| """ | |
| Create a pandas DataFrame with all constituency information. | |
| Returns: | |
| pd.DataFrame: DataFrame with columns: constituency_id, district, number, province_id, province_name | |
| """ | |
| data = [] | |
| for province_id, districts in CONSTITUENCY_MAPPING.items(): | |
| for district_name, constituencies in districts.items(): | |
| for constituency in constituencies: | |
| number = get_constituency_number(constituency) | |
| data.append({ | |
| 'constituency_id': constituency, | |
| 'district': district_name, | |
| 'constituency_number': number, | |
| 'province_id': province_id, | |
| 'province_name_np': PROVINCE_NAMES[province_id]['np'], | |
| 'province_name_en': PROVINCE_NAMES[province_id]['en'] | |
| }) | |
| return pd.DataFrame(data) | |
| def search_constituencies(search_term: str, search_in: str = 'all') -> List[Dict]: | |
| """ | |
| Search constituencies by name, district, or province. | |
| Args: | |
| search_term (str): Term to search for | |
| search_in (str): Where to search - 'all', 'district', 'constituency' | |
| Returns: | |
| List[Dict]: List of matching constituency information | |
| """ | |
| results = [] | |
| search_term = search_term.lower() | |
| for province_id, districts in CONSTITUENCY_MAPPING.items(): | |
| for district_name, constituencies in districts.items(): | |
| for constituency in constituencies: | |
| include = False | |
| if search_in == 'all': | |
| include = (search_term in constituency.lower() or | |
| search_term in district_name.lower() or | |
| search_term in PROVINCE_NAMES[province_id]['np'].lower()) | |
| elif search_in == 'district': | |
| include = search_term in district_name.lower() | |
| elif search_in == 'constituency': | |
| include = search_term in constituency.lower() | |
| if include: | |
| results.append(get_constituency_info(constituency)) | |
| return results | |
| def get_districts_by_province(province_id: int) -> List[str]: | |
| """ | |
| Get all districts in a province. | |
| Args: | |
| province_id (int): Province ID (1-7) | |
| Returns: | |
| List[str]: List of district names in Nepali | |
| """ | |
| if province_id not in CONSTITUENCY_MAPPING: | |
| return [] | |
| return sorted(list(CONSTITUENCY_MAPPING[province_id].keys())) | |
| def export_constituency_mapping_json(filepath: str = "constituency_mapping.json"): | |
| """ | |
| Export constituency mapping to JSON file. | |
| Args: | |
| filepath (str): Output file path | |
| """ | |
| export_data = { | |
| 'metadata': { | |
| 'total_constituencies': len(get_all_constituencies()), | |
| 'total_provinces': 7, | |
| 'total_districts': sum(len(districts) for districts in CONSTITUENCY_MAPPING.values()), | |
| 'created_date': '2026-01-28', | |
| 'election': 'Federal Election 2079' | |
| }, | |
| 'province_names': PROVINCE_NAMES, | |
| 'constituencies': CONSTITUENCY_MAPPING | |
| } | |
| with open(filepath, 'w', encoding='utf-8') as f: | |
| json.dump(export_data, f, ensure_ascii=False, indent=2) | |
| print(f"✅ Constituency mapping exported to: {filepath}") | |
| # ============================================================================ | |
| # INTEGRATION HELPERS FOR DATABASE QUERIES | |
| # ============================================================================ | |
| def build_constituency_filter_query(constituency: Optional[str] = None, | |
| district: Optional[str] = None, | |
| province_id: Optional[int] = None) -> Tuple[str, Dict]: | |
| """ | |
| Build SQL WHERE clause for filtering by constituency hierarchy. | |
| Args: | |
| constituency (str, optional): Specific constituency | |
| district (str, optional): District name | |
| province_id (int, optional): Province ID | |
| Returns: | |
| Tuple[str, Dict]: SQL WHERE clause and parameters dict | |
| """ | |
| conditions = [] | |
| params = {} | |
| if constituency: | |
| conditions.append("constituency_id = :constituency") | |
| params['constituency'] = constituency | |
| elif district: | |
| conditions.append("district = :district") | |
| params['district'] = district | |
| elif province_id: | |
| conditions.append("province_id = :province_id") | |
| params['province_id'] = province_id | |
| where_clause = " AND ".join(conditions) if conditions else "1=1" | |
| return where_clause, params | |
| def get_constituency_dropdown_options(province_id: Optional[int] = None, | |
| district: Optional[str] = None) -> List[Tuple[str, str]]: | |
| """ | |
| Get constituency options for dropdown/selectbox (display_text, value). | |
| Args: | |
| province_id (int, optional): Filter by province | |
| district (str, optional): Filter by district | |
| Returns: | |
| List[Tuple[str, str]]: List of (display_text, value) tuples | |
| """ | |
| if district: | |
| constituencies = get_constituencies_by_district(district, province_id) | |
| elif province_id: | |
| constituencies = get_constituencies_by_province(province_id) | |
| else: | |
| constituencies = get_all_constituencies() | |
| return [(f"🗳️ {const}", const) for const in constituencies] | |
| # ============================================================================ | |
| # EXAMPLE USAGE & TESTING | |
| # ============================================================================ | |
| def print_module_info(): | |
| """Print module information and usage examples.""" | |
| stats = get_constituency_summary_stats() | |
| print("=" * 70) | |
| print("🗳️ Nepal Federal Election - Constituency Utilities") | |
| print("=" * 70) | |
| print(f"\n📊 SUMMARY:") | |
| print(f" Total Constituencies: {stats['total_constituencies']}") | |
| print(f" Total Provinces: {stats['total_provinces']}") | |
| print(f"\n📍 CONSTITUENCIES BY PROVINCE:") | |
| for prov_id, info in stats['by_province'].items(): | |
| print(f" {prov_id}. {info['name_np']:<20} ({info['name_en']:<15}): {info['count']:>2} constituencies") | |
| print(f"\n✅ Module loaded successfully!") | |
| print(f" Available functions: {len([f for f in dir() if not f.startswith('_')])} functions") | |
| print("=" * 70) | |
| if __name__ == "__main__": | |
| # Test the module | |
| print_module_info() | |
| # Example usage | |
| print("\n🔍 EXAMPLE USAGE:\n") | |
| # Example 1: Get all constituencies in Province 3 | |
| print("1. Get constituencies in Bagmati Province:") | |
| bagmati_const = get_constituencies_by_province(3) | |
| print(f" Total: {len(bagmati_const)} constituencies") | |
| print(f" First 5: {bagmati_const[:5]}") | |
| # Example 2: Get constituency info | |
| print("\n2. Get info for 'काठमाडौं-५':") | |
| info = get_constituency_info("काठमाडौं-५") | |
| print(f" {info}") | |
| # Example 3: Search constituencies | |
| print("\n3. Search for 'काठमाडौं':") | |
| results = search_constituencies("काठमाडौं", "district") | |
| print(f" Found {len(results)} constituencies") | |
| # Example 4: Create DataFrame | |
| print("\n4. Create constituency DataFrame:") | |
| df = create_constituency_dataframe() | |
| print(f" Shape: {df.shape}") | |
| print(f" Columns: {df.columns.tolist()}") | |
| print(f"\n Sample rows:") | |
| print(df.head(3).to_string(index=False)) | |