[Python] need help Replicating Stellarium-Style Constellation Maps with Python (Skyfield +...

Discussão em 'Python' iniciado por Stack, Setembro 1, 2025.

  1. Stack

    Stack Membro Participativo

    I’m trying to plot constellations with Python using Gaia star data, but the constellation lines don’t look like they do in Stellarium. I’ve tried plotting in both Alt/Az and RA/Dec, even used a Mollweide projection for an atlas view. I also adjusted the star datasets with Hipparcos coordinates. Still, sometimes the lines look stretched or distorted instead of the clean Stellarium patterns.i have shared my current constellation plotting code

    now i am using i=embedded constellation data in the code itself

    t# ------------------- CONSTELLATION LINE DATA -------------------
    def get_constellation_lines():
    """Return accurate constellation line data with verified coordinates"""
    # Using verified star coordinates from Hipparcos catalog
    constellation_lines = {
    'UMa': [ # Ursa Major - Big Dipper (verified coordinates)
    # The classic Big Dipper pattern
    [(165.460, 61.751), (154.275, 55.960), (143.550, 54.925), (127.566, 57.033)], # Handle: Alkaid->Mizar->Alioth->Megrez
    [(127.566, 57.033), (116.166, 53.695), (124.500, 49.313), (133.793, 47.779), (127.566, 57.033)] # Bowl: Megrez->Dubhe->Merak->Phecda->back to Megrez
    ],
    'Vir': [ # Virgo - Simple Y pattern
    # Main Y-shape with Spica as the base
    [(201.298, -11.161), (213.915, 19.182)], # Spica to Zavijava
    [(213.915, 19.182), (190.415, -1.449)], # Zavijava to Porrima
    [(213.915, 19.182), (177.673, 1.765)] # Zavijava to Vindemiatrix
    ],
    'Cyg': [ # Cygnus - Northern Cross (verified)
    # Main cross pattern
    [(310.358, 45.280), (292.175, 27.959)], # Deneb to Sadr (vertical)
    [(305.557, 40.257), (297.696, 8.868)], # Delta Cyg to Gienah (horizontal)
    [(292.175, 27.959), (289.276, 31.733)] # Sadr to Albireo (head)
    ],
    'Leo': [ # Leo - The Lion with sickle
    # The backwards question mark (sickle)
    [(152.093, 11.967), (154.993, 14.572)], # Regulus to Algieba
    [(154.993, 14.572), (147.737, 20.524)], # Algieba to Adhafera
    [(147.737, 20.524), (143.385, 26.007)], # Adhafera to Ras Elased Australis
    [(143.385, 26.007), (133.208, 19.841)], # To Ras Elased Borealis
    # Body triangle
    [(152.093, 11.967), (177.265, 14.572), (165.417, 2.317)] # Regulus to Denebola to Zosma
    ],
    'Cas': [ # Cassiopeia - W shape (verified)
    [(14.1771, 56.5373), (28.5989, 63.6700), (15.1804, 60.2353), (2.2930, 59.1500), (354.8370, 56.5428)]
    ],
    'Ori': [ # Orion - The Hunter (verified belt stars)
    # Belt stars
    [(85.1896, -1.9424), (84.0533, -1.2017), (83.0016, -0.2990)], # Alnitak->Alnilam->Mintaka
    # Shoulders to belt
    [(88.7929, 7.4069), (85.1896, -1.9424)], # Betelgeuse to Alnitak
    [(81.2829, 6.9496), (83.0016, -0.2990)], # Bellatrix to Mintaka
    # Sword
    [(84.0533, -1.2017), (83.8582, -5.3691)], # Alnilam to sword
    # Legs
    [(85.1896, -1.9424), (82.0617, -9.6695)], # Alnitak to Saiph
    [(83.0016, -0.2990), (78.6345, -8.2016)] # Mintaka to Rigel
    ],
    'Lyr': [ # Lyra - Small pattern around Vega
    [(279.235, 38.784), (284.736, 32.690), (287.441, 33.363), (281.413, 39.145), (279.235, 38.784)]
    ],
    'Aql': [ # Aquila - Eagle pattern
    [(297.696, 8.868), (292.175, 27.959), (295.024, -0.318)] # Altair and wings
    ]
    }
    return constellation_lines

    def calculate_star_position(ra, dec, observer, t):
    """Calculate alt/az for a star given RA/Dec"""
    star = Star(ra=Angle(degrees=ra), dec=Angle(degrees=dec))
    app = observer.at(t).observe(star).apparent()
    alt, az, dist = app.altaz()
    return alt.degrees, az.degreesype here



    **plotting logic **

    constellation_lines = get_constellation_lines()
    constellation_count = 0
    constellation_names = {
    'UMa': 'Ursa Major\n(Big Dipper)',
    'Ori': 'Orion\n(The Hunter)',
    'Cas': 'Cassiopeia\n(The Queen)',
    'Vir': 'Virgo\n(The Virgin)',
    'Leo': 'Leo\n(The Lion)',
    'Cyg': 'Cygnus\n(The Swan)',
    'Lyr': 'Lyra\n(The Harp)',
    'Aql': 'Aquila\n(The Eagle)'
    }

    constellation_centers = {} # Store centers for name placement

    print(f"[INFO] Drawing constellation lines...")

    for const_name, line_segments in constellation_lines.items():
    all_positions = []
    any_lines_drawn = False

    print(f"[DEBUG] Processing {const_name} with {len(line_segments)} segments")

    for segment_idx, segment in enumerate(line_segments):
    # Calculate positions for this line segment
    segment_positions = []

    print(f"[DEBUG] Segment {segment_idx}: {len(segment)} stars")

    for ra, dec in segment:
    alt, az = calculate_star_position(ra, dec, observer, t)
    segment_positions.append((alt, az))
    all_positions.append((alt, az))
    print(f"[DEBUG] Star at RA={ra:.2f}, Dec={dec:.2f} -> Alt={alt:.1f}°, Az={az:.1f}°")

    # Check if any stars in this segment are above horizon
    visible_stars = [(alt, az) for alt, az in segment_positions if alt > 0]

    if len(visible_stars) < 2:
    print(f"[DEBUG] Skipping segment - only {len(visible_stars)} stars above horizon")
    continue

    # Draw lines connecting consecutive stars in this segment
    for i in range(len(segment_positions) - 1):
    alt1, az1 = segment_positions
    alt2, az2 = segment_positions[i + 1]

    # Only draw if both stars are above horizon
    if alt1 > 0 and alt2 > 0:
    # Enhanced colors and styles for different constellations
    if const_name == 'Vir':
    color, width, alpha = "gold", 4.0, 0.95
    elif const_name == 'Ori':
    color, width, alpha = "lightcoral", 3.5, 0.9
    elif const_name in ['UMa', 'Cas']:
    color, width, alpha = "cyan", 3.0, 0.9
    elif const_name in ['Leo', 'Cyg']:
    color, width, alpha = "lightgreen", 2.8, 0.85
    else:
    color, width, alpha = "lightblue", 2.5, 0.8

    ax.plot([np.radians(az1), np.radians(az2)], [90-alt1, 90-alt2],
    color=color, linewidth=width, alpha=alpha, zorder=5,
    solid_capstyle='round')
    any_lines_drawn = True
    print(f"[DEBUG] Drew line from ({alt1:.1f}°, {az1:.1f}°) to ({alt2:.1f}°, {az2:.1f}°)")

    # Draw constellation stars (prominent markers)
    for alt, az in segment_positions:
    if alt > 0: # Above horizon
    if const_name == 'Vir':
    ax.scatter(np.radians(az), 90-alt, s=45,
    facecolors="gold", edgecolors="orange",
    linewidth=2, alpha=0.95, zorder=6)
    elif const_name == 'Ori':
    ax.scatter(np.radians(az), 90-alt, s=40,
    facecolors="lightcoral", edgecolors="red",
    linewidth=1.5, alpha=0.9, zorder=6)
    elif const_name in ['UMa', 'Cas']:
    ax.scatter(np.radians(az), 90-alt, s=35,
    facecolors="cyan", edgecolors="blue",
    linewidth=1.5, alpha=0.9, zorder=6)
    else:
    ax.scatter(np.radians(az), 90-alt, s=30,
    facecolors="lightgreen", edgecolors="white",
    linewidth=1, alpha=0.85, zorder=6)

    # Calculate constellation center for name placement
    if all_positions:
    visible_positions = [pos for pos in all_positions if pos[0] > 0]
    if visible_positions and any_lines_drawn:
    center_alt = np.mean([pos[0] for pos in visible_positions])
    center_az = np.mean([pos[1] for pos in visible_positions])
    constellation_centers[const_name] = (center_alt, center_az)
    constellation_count += 1
    print(f"[DEBUG] {const_name} center: Alt={center_alt:.1f}°, Az={center_az:.1f}°")


    enter image description here this is the result i am getting

    How can I make the constellation lines match the way they appear in Stellarium? Are there specific transformations or datasets that would help? Any guidance would be really appreciated! enter image description here this is how i want it to look like

    Continue reading...

Compartilhe esta Página