diff --git a/assets/css/styles.css b/assets/css/styles.css index 0cdc0ea308bae7f77a01e04bad629ddfe9dbe510..afd12e95d5b4402aff1a44201061b3744dd7c33d 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -1,218 +1,65 @@ -/* Main styles for Satellite Latency Viewer */ - -body { - font-family: 'Source Sans Pro', sans-serif; - background-color: #f8f9fa; - color: #333; +/* Status indicators */ +.status-exists { + color: green; + font-weight: bold; } -/* Header Section */ -.header-section { - background: #003366; - color: white; - padding: 1.5rem 0; - border-radius: 0 0 6px 6px; - margin-bottom: 20px; - box-shadow: 0 2px 10px rgba(0,0,0,0.1); -} - -.app-title { - font-family: 'Merriweather', serif; - font-weight: 700; - font-size: 2rem; - text-align: center; - margin-bottom: 0.5rem; - letter-spacing: 0.5px; +.status-missing { + color: red; + font-weight: bold; } -.date-navigation { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.4rem 1rem; - background-color: rgba(255,255,255,0.15); - border-radius: 4px; - margin: 0.8rem auto; - max-width: 400px; - border: 1px solid rgba(255,255,255,0.2); +/* Ingest sources filter styling */ +#ingest-checkboxes { + max-height: 200px; + overflow-y: auto; } -.date-navigation button { - background: transparent; - border: none; - color: white; - font-size: 1rem; +.form-check-label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 250px; cursor: pointer; - transition: all 0.2s ease; - padding: 0.2rem 0.8rem; -} - -.date-navigation button:hover { - background-color: rgba(255,255,255,0.2); - border-radius: 4px; -} - -#currentDateDisplay { - font-size: 1.1rem; - font-weight: 500; -} - -/* Control Panel */ -.control-panel { - background: white; - border-radius: 6px; - padding: 1.25rem; - margin-bottom: 1.5rem; - box-shadow: 0 1px 6px rgba(0,0,0,0.05); - border: 1px solid #dee2e6; } -.form-label { +/* Range selector buttons styling */ +.plotly .rangeselector button { font-weight: 600; - color: #003366; - margin-bottom: 0.4rem; -} - -.form-select { - border: 1px solid #ced4da; - border-radius: 4px; - padding: 0.5rem; - transition: all 0.2s ease; - background-color: #f8f9fa; -} - -.form-select:focus { - border-color: #003366; - box-shadow: 0 0 0 0.2rem rgba(0, 51, 102, 0.25); -} - -/* Debug Toggle */ -.debug-toggle { - border-radius: 4px; - font-size: 0.85rem; - padding: 0.3rem 0.8rem; - background-color: #f1f5f9; - color: #003366; - border: 1px solid #d0d7de; - transition: all 0.2s ease; -} - -.debug-toggle:hover { - background-color: #e3e8ed; - border-color: #b6bfc9; -} - -/* Debug Info Panel */ -.debug-info { - background-color: #f8f9fa; - border: 1px solid #ddd; - border-radius: 6px; - padding: 15px; - margin-top: 20px; - font-family: monospace; - display: none; - box-shadow: inset 0 0 3px rgba(0,0,0,0.1); -} - -/* Loading and Error Indicators */ -.loading { - display: none; - text-align: center; - padding: 20px; -} - -.error-message { - color: #dc3545; - text-align: center; - padding: 15px; - display: none; - border-radius: 6px; - background-color: rgba(220, 53, 69, 0.1); - margin: 1rem 0; -} - -/* Time Range Selector */ -.time-range-selector { - margin-bottom: 15px; - display: flex; - gap: 10px; -} - -.time-btn { - padding: 6px 15px; - background-color: #e9ecef; + color: #495057; + background: white; border: 1px solid #ced4da; border-radius: 4px; - font-size: 0.9rem; - cursor: pointer; - transition: all 0.2s ease; + padding: 3px 8px; + margin-right: 5px; } -.time-btn:hover { - background-color: #d1d7dc; -} - -.time-btn.active { - background-color: #003366; +.plotly .rangeselector button.active { color: white; - border-color: #003366; + background: #0d6efd; + border-color: #0d6efd; } -/* Chart Section */ -.chart-wrapper { - background: white; - border-radius: 6px; - padding: 20px 15px; - margin-bottom: 1.5rem; - box-shadow: 0 1px 6px rgba(0,0,0,0.05); - border: 1px solid #dee2e6; - position: relative; +/* Satellite info display */ +.satellite-info { + margin-bottom: 0.5rem; } -.chart-title { - font-family: 'Merriweather', serif; - font-size: 1.5rem; +/* Loading and error indicators */ +#loading { text-align: center; - margin-bottom: 15px; - color: #002855; - font-weight: 600; + padding: 2rem; } -.chart-container { - height: 450px; - width: 100%; - overflow: hidden; +#errorMessage { + margin-top: 1rem; + margin-bottom: 1rem; } -/* Data Table */ -.table-responsive { - background: white; - border-radius: 6px; +#errorMessage pre { + max-height: 300px; + overflow-y: auto; + background-color: #f8f9fa; padding: 1rem; - box-shadow: 0 1px 6px rgba(0,0,0,0.05); - border: 1px solid #dee2e6; -} - -/* Responsive adjustments */ -@media (max-width: 768px) { - .app-title { - font-size: 1.5rem; - } - - .date-navigation { - max-width: 300px; - } - - .chart-title { - font-size: 1.2rem; - } - - .chart-container { - height: 350px; - } - - .time-btn { - padding: 5px 10px; - font-size: 0.8rem; - } + border-radius: 0.3rem; } \ No newline at end of file diff --git a/assets/python/generate_relationship.py b/assets/python/generate_relationship.py index ec64bd090283f2b39746d111a7239d3679a5cfc2..26abb685ba59204524eaf6f4d5a79584630c0041 100755 --- a/assets/python/generate_relationship.py +++ b/assets/python/generate_relationship.py @@ -2,14 +2,14 @@ """ End-to-end script to generate a satellite relationships JSON file. This script: -1. Automatically pulls data for the previous day using sat_latency_interface +1. Automatically pulls data for the previous 7 days using sat_latency_interface 2. Processes the data to extract relationship information 3. Generates the satellite_relationships.json file with consolidated IDs 4. Handles satellite ID variations (e.g., G16/g16, DMSP-17/dmsp17, etc.) Example usage: python generate_satellite_relationships.py -o satellite_relationships.json - python generate_satellite_relationships.py -d 2025-02-27 -o satellite_relationships.json + python generate_satellite_relationships.py -d 2025-02-27 -n 7 -o satellite_relationships.json """ import os @@ -70,24 +70,45 @@ def get_canonical_id(satellite_id): """Get canonical ID for a satellite ID variant""" return SATELLITE_ID_MAPPINGS.get(satellite_id, satellite_id) -def get_previous_day(): - """Get previous day's date in YYYY-MM-DD format""" - yesterday = datetime.now() - timedelta(days=1) - return yesterday.strftime('%Y-%m-%d') +def get_date_range(end_date_str=None, num_days=7): + """ + Get date range for the previous num_days from the end_date. + + Args: + end_date_str: End date string in YYYY-MM-DD format, or None for yesterday + num_days: Number of days to go back + + Returns: + list: List of date strings in YYYY-MM-DD format + """ + # Use yesterday as the end date if not provided + if not end_date_str: + end_date = datetime.now() - timedelta(days=1) + else: + end_date = datetime.strptime(end_date_str, '%Y-%m-%d') + + # Generate list of dates + date_list = [] + for i in range(num_days): + date = end_date - timedelta(days=i) + date_list.append(date.strftime('%Y-%m-%d')) + + return date_list -def run_sat_latency_query(date_str): +def run_sat_latency_query(start_date_str, end_date_str): """ - Run sat_latency_interface command to get data for the specified date. + Run sat_latency_interface command to get data for the specified date range. Args: - date_str: Date string in YYYY-MM-DD format + start_date_str: Start date string in YYYY-MM-DD format + end_date_str: End date string in YYYY-MM-DD format Returns: list: Data returned by sat_latency_interface or None if error """ # Build start and end time strings - start_time = f"{date_str}T00:00:00" - end_time = f"{date_str}T23:59:59" + start_time = f"{start_date_str}T00:00:00" + end_time = f"{end_date_str}T23:59:59" # Build the command base_cmd = "module load miniconda/3.6-base && source activate ~/.mdrexler_conda && sat_latency_interface" @@ -245,27 +266,31 @@ def extract_relationships_from_data(data): return result -def generate_satellite_relationships(date_str=None): +def generate_satellite_relationships(end_date_str=None, num_days=7): """ - Generate satellite relationships JSON by querying data for the specified date. + Generate satellite relationships JSON by querying data for the specified date range. Args: - date_str: Date string in YYYY-MM-DD format, or None for previous day + end_date_str: End date string in YYYY-MM-DD format, or None for yesterday + num_days: Number of days to go back Returns: dict: Structured relationship information """ - # Use previous day if no date provided - if not date_str: - date_str = get_previous_day() + # Get the date range + date_range = get_date_range(end_date_str, num_days) + + # Use the earliest and latest dates for the query + start_date = date_range[-1] # Last item (earliest date) + end_date = date_range[0] # First item (latest date) - logger.info(f"Generating satellite relationships for date: {date_str}") + logger.info(f"Generating satellite relationships for date range: {start_date} to {end_date}") - # Fetch data for the specified date - data = run_sat_latency_query(date_str) + # Fetch data for the specified date range + data = run_sat_latency_query(start_date, end_date) if not data: - logger.error(f"Failed to get data for {date_str}") + logger.error(f"Failed to get data for range {start_date} to {end_date}") return None # Extract relationships from data @@ -275,6 +300,13 @@ def generate_satellite_relationships(date_str=None): logger.error("Failed to extract relationships from data") return None + # Add date range information to the output + result["date_range"] = { + "start_date": start_date, + "end_date": end_date, + "days": num_days + } + return result def save_relationships_json(relationships, output_file): @@ -303,13 +335,14 @@ def save_relationships_json(relationships, output_file): def main(): parser = argparse.ArgumentParser(description='Generate satellite relationships JSON.') - parser.add_argument('-d', '--date', help='Date to query (YYYY-MM-DD). Defaults to previous day') + parser.add_argument('-d', '--date', help='End date to query (YYYY-MM-DD). Defaults to yesterday') + parser.add_argument('-n', '--days', type=int, default=7, help='Number of days to analyze (default: 7)') parser.add_argument('-o', '--output', default='satellite_relationships.json', help='Output JSON file path') args = parser.parse_args() # Generate relationships JSON - result = generate_satellite_relationships(args.date) + result = generate_satellite_relationships(args.date, args.days) if not result: logger.error("Failed to generate relationships JSON")