PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); $loggedIn = isset($_SESSION['user_id']); $pageTitle = 'T CrB Lichtkurve'; $headerIntroPre = 'Variabler Stern'; $headerIntroTitle = 'T CrB Lichtkurve'; $headerIntroSub = 'AAVSO-WebObs-Daten mit waehlbaren Filtern in einem gemeinsamen Plotly-Diagramm.'; $errors = []; function h(?string $value): string { return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); } $filterRows = $pdo->query(" SELECT `filter_code`, COUNT(*) AS `entry_count` FROM `aavso_tcrb_observations` WHERE `filter_code` IS NOT NULL AND `filter_code` <> '' GROUP BY `filter_code` ORDER BY `filter_code` ASC ")->fetchAll(); $availableFilters = []; foreach ($filterRows as $filterRow) { $filterCode = trim((string) ($filterRow['filter_code'] ?? '')); if ($filterCode === '') { continue; } $availableFilters[] = [ 'code' => $filterCode, 'count' => (int) ($filterRow['entry_count'] ?? 0), ]; } $selectedFilters = array_values(array_unique(array_filter(array_map( static fn ($value): string => trim((string) $value), is_array($_GET['filters'] ?? null) ? $_GET['filters'] : [] ), static fn (string $value): bool => $value !== ''))); if (empty($selectedFilters)) { $selectedFilters = in_array('V', array_column($availableFilters, 'code'), true) ? ['V'] : array_column($availableFilters, 'code'); } $selectedFilters = array_values(array_intersect($selectedFilters, array_column($availableFilters, 'code'))); if (empty($availableFilters)) { $errors[] = 'In der Tabelle aavso_tcrb_observations sind noch keine T-CrB-Daten vorhanden.'; } $observations = []; $summary = [ 'count' => 0, 'min_utc' => null, 'max_utc' => null, 'min_mag' => null, 'max_mag' => null, ]; if (empty($errors) && !empty($selectedFilters)) { $placeholders = implode(',', array_fill(0, count($selectedFilters), '?')); $stmt = $pdo->prepare(" SELECT `observed_at_utc`, `jd`, `magnitude`, `magnitude_error`, `filter_code`, `observer_code`, `notes_raw` FROM `aavso_tcrb_observations` WHERE `filter_code` IN ({$placeholders}) ORDER BY `observed_at_utc` ASC, `jd` ASC "); $stmt->execute($selectedFilters); $rows = $stmt->fetchAll(); foreach ($rows as $row) { $observedAtUtc = (string) ($row['observed_at_utc'] ?? ''); $magnitude = isset($row['magnitude']) ? (float) $row['magnitude'] : null; if ($observedAtUtc === '' || $magnitude === null) { continue; } $observations[] = [ 'observed_at_utc' => $observedAtUtc, 'jd' => isset($row['jd']) ? (float) $row['jd'] : null, 'magnitude' => $magnitude, 'magnitude_error' => $row['magnitude_error'] !== null ? (float) $row['magnitude_error'] : null, 'filter_code' => (string) ($row['filter_code'] ?? ''), 'observer_code' => (string) ($row['observer_code'] ?? ''), 'notes_raw' => (string) ($row['notes_raw'] ?? ''), ]; $summary['count']++; $summary['min_utc'] = $summary['min_utc'] === null || $observedAtUtc < $summary['min_utc'] ? $observedAtUtc : $summary['min_utc']; $summary['max_utc'] = $summary['max_utc'] === null || $observedAtUtc > $summary['max_utc'] ? $observedAtUtc : $summary['max_utc']; $summary['min_mag'] = $summary['min_mag'] === null || $magnitude < $summary['min_mag'] ? $magnitude : $summary['min_mag']; $summary['max_mag'] = $summary['max_mag'] === null || $magnitude > $summary['max_mag'] ? $magnitude : $summary['max_mag']; } } if (empty($errors) && empty($observations)) { $errors[] = 'Fuer die ausgewaehlten Filter wurden keine Daten gefunden.'; } $filterPalette = [ 'U' => '#4c6ef5', 'B' => '#1c7ed6', 'V' => '#2b8a3e', 'R' => '#c92a2a', 'I' => '#862e9c', 'CV' => '#495057', 'TG' => '#0b7285', 'TB' => '#364fc7', 'TR' => '#d9480f', ]; $chartDatasets = []; foreach ($selectedFilters as $selectedFilter) { $chartDatasets[$selectedFilter] = [ 'filter' => $selectedFilter, 'color' => $filterPalette[$selectedFilter] ?? sprintf('#%06X', crc32($selectedFilter) & 0xFFFFFF), 'points' => [], ]; } foreach ($observations as $observation) { $filterCode = $observation['filter_code']; if (!isset($chartDatasets[$filterCode])) { continue; } $chartDatasets[$filterCode]['points'][] = $observation; } $chartDatasets = array_values(array_filter($chartDatasets, static fn (array $dataset): bool => !empty($dataset['points']))); $plotlyTraces = []; foreach ($chartDatasets as $dataset) { $xValues = []; $yValues = []; $errorValues = []; $customData = []; $hasErrors = false; foreach ($dataset['points'] as $point) { $xValues[] = (string) $point['observed_at_utc']; $yValues[] = (float) $point['magnitude']; $errorValue = $point['magnitude_error'] !== null ? (float) $point['magnitude_error'] : 0.0; $errorValues[] = $errorValue; if ($errorValue > 0) { $hasErrors = true; } $customData[] = [ $point['jd'], $point['observer_code'] !== '' ? $point['observer_code'] : '—', $point['magnitude_error'] !== null ? number_format((float) $point['magnitude_error'], 3, '.', '') : '—', ]; } $plotlyTraces[] = [ 'type' => 'scatter', 'mode' => 'lines+markers', 'name' => $dataset['filter'], 'x' => $xValues, 'y' => $yValues, 'line' => [ 'color' => $dataset['color'], 'width' => 2, ], 'marker' => [ 'color' => $dataset['color'], 'size' => 7, 'line' => [ 'color' => '#0f172a', 'width' => 1, ], ], 'error_y' => [ 'type' => 'data', 'array' => $errorValues, 'visible' => $hasErrors, 'thickness' => 1.1, 'width' => 3, 'color' => $dataset['color'], ], 'customdata' => $customData, 'hovertemplate' => 'Filter %{fullData.name}
' . 'Magnitude %{y:.3f}
' . 'Fehler %{customdata[2]}
' . 'UTC %{x}
' . 'JD %{customdata[0]}
' . 'Observer %{customdata[1]}', ]; } $meanSourcePoints = []; foreach ($chartDatasets as $dataset) { foreach ($dataset['points'] as $point) { $meanSourcePoints[] = $point; } } usort($meanSourcePoints, static function (array $a, array $b): int { return strcmp((string) $a['observed_at_utc'], (string) $b['observed_at_utc']); }); if (count($meanSourcePoints) >= 3) { $windowSize = min(11, count($meanSourcePoints)); if ($windowSize % 2 === 0) { $windowSize--; } $halfWindow = intdiv($windowSize, 2); $meanX = []; $meanY = []; $meanCustomData = []; foreach ($meanSourcePoints as $index => $point) { $start = max(0, $index - $halfWindow); $end = min(count($meanSourcePoints) - 1, $index + $halfWindow); $sum = 0.0; $count = 0; for ($i = $start; $i <= $end; $i++) { $sum += (float) $meanSourcePoints[$i]['magnitude']; $count++; } if ($count === 0) { continue; } $meanValue = $sum / $count; $meanX[] = (string) $point['observed_at_utc']; $meanY[] = $meanValue; $meanCustomData[] = [$count]; } if (!empty($meanX)) { $plotlyTraces[] = [ 'type' => 'scatter', 'mode' => 'lines', 'name' => 'Mittelkurve', 'x' => $meanX, 'y' => $meanY, 'line' => [ 'color' => '#f4d35e', 'width' => 3, 'dash' => 'solid', 'shape' => 'spline', 'smoothing' => 0.7, ], 'customdata' => $meanCustomData, 'hovertemplate' => 'Mittelkurve
' . 'Magnitude %{y:.3f}
' . 'UTC %{x}
' . 'Fenster %{customdata[0]} Punkte', ]; } } $plotlyPayload = [ 'traces' => $plotlyTraces, 'summary' => $summary, ]; ?>

Filter

Lichtkurve

Messpunkte
Erster UTC-Zeitpunkt
Letzter UTC-Zeitpunkt
bis Magnitudenbereich
Noch keine darstellbaren Daten vorhanden.