Der Sloan Digital Sky Survey (#1), auch SDSS abgekürzt, ist eine groß angelegte Himmelsdurchmusterung. Der SDSS ist zur Zeit der Erstellung dieses Beitrags ein noch aktives Projekt, läuft aber schon seit 2000 und hat über 470 Millionen astronomischer Objekte spektroskopisch vermessen. Das Beste daran ist, dass große Teile der Daten öffentlich abrufbar sind und sich so beispielswiese wunderbare Plots erstellen lassen.
Die Sloan Great Wall
Die Sloan Great Wall (#2) ist eine riesige und massive Ansammlung von Galaxien, welche 2003 in den Daten des SDSS gefunden wurde. Mit rund 1,37 Milliarden Lichtjahren Ausdehnung ist es eine der größten bekannten, zusammenhängenden Strukturen im beobachtbaren Universum. Bildliche Darstellungen der Sloan Great Wall (SGW) finden sich z.B. in “J. Richard Gott III et al 2005 ApJ 624 463″ (#3) auf Seite 6 des PDFs oder bei diesem “Astronomy Picture of the Day” (#4).
Zum Glück sind die Daten öffentlich abrufbar und somit gelingt es relativ leicht, solche Strukturen einmal selbst zu plotten!
Zuerst einmal benötigen wir die Daten, die wir auf der offiziellen Seite des SDSS abfragen können. Unter dem Link https://skyserver.sdss.org/dr16/en/tools/search/sql.aspx haben wir die Möglichkeit, direkt SQL Abfragen auf die SDSS Datenbanken zu machen und uns die Ergebnisse in verschiedenen Formaten ausgeben zu lassen.
Für den nachfolgenden Plot der SGW habe ich folgende Abfrage ausgeführt und mir das Ergebnis in eine CSV ausgeben lassen:
SELECT
p.objid, p.ra, p.dec, s.specobjid, s.class, s.subClass, s.z as redshift
FROM PhotoObj AS p
JOIN SpecObj AS s ON s.bestobjid = p.objid
WHERE
p.u BETWEEN 0 AND 20
AND g BETWEEN 0 AND 20
AND s.class = 'GALAXY'
Mit dieser Abfrage lasse ich mir die Objekt-ID (objid), die Daten für Beobachtungswinkel am Himmel – die Rektaszension (ra) und die Deklination (dec) – die Spektrale-ID des Objekts (specobjid), die spektroskopische Klasse (hier: GALAXY), sowie die Rotverschiedbung (z als redshift) ausgeben. Dabei beschränkt sich die Abfrage auf jene Objekte, die Galaxien sind (class=”GALAXY”) und deren Magnitude (Helligkeitswert) in den spektrometrischen Bändern “u” und “g” zwischen 0 und 20 liegen.
Der Grund für diese Einschränkungen ist der, dass öffentliche Abfragen auf 500.000 Objekte beschränkt sind und mit diesen Einschränkungen fast exakt 500.000 Galaxien zurück geliefert werden. Die Abfrage dauert einige Sekunden und liefert wie in diesem Fall ein CSV-File mit gut 48 MB. Diese Datei muss nun im Folgenden weiterverarbeitet werden. Beginnen wir mit dem Einlesen der Datei:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.set()
dateiname = "Skyserver_Radial2_16_2024 10_47_49 PM.csv"
df = pd.read_csv(dateiname, skiprows=1)
df
objid | ra | dec | specobjid | class | subClass | redshift | |
---|---|---|---|---|---|---|---|
0 | 1237655550206804685 | 247.391633 | -0.178874 | 391898682645047296 | GALAXY | STARFORMING | 0.074105 |
1 | 1237662637988381321 | 245.386070 | 8.214101 | 2847408637909952512 | GALAXY | STARFORMING | 0.126080 |
2 | 1237662301916168639 | 255.946999 | 22.856731 | 1900572152269137920 | GALAXY | NaN | 0.138199 |
3 | 1237662268616802943 | 241.290462 | 4.966572 | 2068431844239501312 | GALAXY | STARFORMING | 0.200065 |
4 | 1237648702991368573 | 240.291385 | -1.042677 | 387376666567010304 | GALAXY | STARFORMING | 0.095185 |
… | … | … | … | … | … | … | … |
498311 | 1237653665794031699 | 146.148231 | 2.628170 | 537221140444112896 | GALAXY | NaN | 0.106856 |
498312 | 1237654652028649665 | 129.552814 | 43.792997 | 857956382303873024 | GALAXY | NaN | 0.147038 |
498313 | 1237663782600048766 | 30.383042 | -1.104711 | 453749513597773824 | GALAXY | NaN | 0.044894 |
498314 | 1237664835933896812 | 144.324320 | 29.839972 | 2186559798789564416 | GALAXY | STARFORMING | 0.092128 |
498315 | 1237657770704372048 | 134.525051 | 44.800387 | 1009973766706456576 | GALAXY | STARFORMING | 0.057523 |
498316 rows × 7 columns
Das DataFrame enthält nun insgesamt 498.316 Galaxien aus dem SDSS. Zum Plotten der SGW müssen wir uns klar sein, dass die Rektaszension und die Deklination als Winkelangaben angeben, wohin das Teleskop gezeigt hat. Damit haben wir eine Richtungsinformation, wo eine Galaxie liegt. Was fehlt, ist die Angabe der Entfernung, also die Info wie weit eine Galaxie von uns entfernt ist. Diese Angabe ist über die Rotverschiebung (redshift) zugänglich und je höher der Wert ist, desto weiter weg ist eine Galaxie.
Ein Blick auf die Angaben für die Rektaszension (ra) und die Deklination (dec) enthüllt, dass es sich um Winkelangaben im Grad-Maß (deg) handelt. Um diese mit einem Polarkoordinaten-Plot über matplotlib darzustellen benötigen wir zuerst einmal die Winkelangaben im Bogenmaß (rad). Hierbei gilt für die Umrechnung:
Diese Umrechnung wenden wir auf das DataFrame an und erstellen zwei neue Columns für die Werte im Bogenmaß:
import numpy as np
def convert_rad(x):
return (x * np.pi)/180
df["ra_rad"] = df.ra.map(convert_rad)
df["dec_rad"] = df.dec.map(convert_rad)
df[["objid","ra_rad","dec_rad","redshift"]]
objid | ra_rad | dec_rad | redshift | |
---|---|---|---|---|
0 | 1237655550206804685 | 4.317799 | -0.003122 | 0.074105 |
1 | 1237662637988381321 | 4.282795 | 0.143363 | 0.126080 |
2 | 1237662301916168639 | 4.467118 | 0.398925 | 0.138199 |
3 | 1237662268616802943 | 4.211313 | 0.086683 | 0.200065 |
4 | 1237648702991368573 | 4.193876 | -0.018198 | 0.095185 |
… | … | … | … | … |
498311 | 1237653665794031699 | 2.550768 | 0.045870 | 0.106856 |
498312 | 1237654652028649665 | 2.261123 | 0.764332 | 0.147038 |
498313 | 1237663782600048766 | 0.530284 | -0.019281 | 0.044894 |
498314 | 1237664835933896812 | 2.518935 | 0.520806 | 0.092128 |
498315 | 1237657770704372048 | 2.347905 | 0.781914 | 0.057523 |
498316 rows × 4 columns
Mit diesen Daten kann es schon eigentlich schon ans plotten gehen! Zumindest fast, denn der SDSS deckt recht viel Himmel in RA und DEC ab und wenn man den komplette Datensatz in 2D plottet, dann geht die SGW im Gewimmel der Galaxien unter. Eine kurze Recherche liefert z.B. das Dokument arXiv:1007.4492 (https://arxiv.org/abs/1007.4492) aus dem zu erfahren ist, dass sich viele Cluster in der SGW im Deklinationsbereich von -4° bis 8° befinden. Da ich die Rektaszension nun in Draufsicht plotten möchte, selektiere ich den genannten schmaleren DEC-Bereich zuvor mit einer Query aus dem gesamten DataFrame raus.
Aus diesem selektierten Ausschnitt des DataFrames wird jetzt ein Plot mit einer Polar-Projektion erstellt:
df_gal_wall = df.query("dec < 8 and dec > -4")
fig = plt.figure(figsize=(7,7))
ax = fig.add_subplot(projection='polar')
c = ax.scatter(df_gal_wall.ra_rad, df_gal_wall.redshift, c=df_gal_wall.redshift, s=1, cmap='magma', alpha=0.08)
ax.set_ylim(0,0.10)
ax.set_theta_zero_location("S", offset=-5)
ax.set_rlabel_position(100)
fig.tight_layout()
Zack! Und das war es schon im Wesentlichen. Der Plot kommt den veröffentlichten Plots schon recht nahe. Zwischen redshift 0,06 und 0,08 ist die SGW klar zu erkennen und für solch einen “Quick & Dirty” Ansatz finde ich das Resultat durchaus gelungen. Schon irre, was heute öffentlich an Daten zugänglich ist und mal eben mit dem heimischen PC geplottet werden kann. Der Plot enthält immerhin:
df_gal_wall.info()
<class 'pandas.core.frame.DataFrame'> Index: 101023 entries, 0 to 498313 Data columns (total 9 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 objid 101023 non-null int64 1 ra 101023 non-null float64 2 dec 101023 non-null float64 3 specobjid 101023 non-null uint64 4 class 101023 non-null object 5 subClass 55936 non-null object 6 redshift 101023 non-null float64 7 ra_rad 101023 non-null float64 8 dec_rad 101023 non-null float64 dtypes: float64(5), int64(1), object(2), uint64(1) memory usage: 7.7+ MB
insgesamt über 100.000 Galaxien und lässt sich mit ‘nem handelsüblichen PC in ein paar Sekunden plotten! Auch das ist – neben der SGW an sich – absolut cool.