This Python script functions as an educational planisphere designed for telescope observation. Instead of taking a live snapshot of the current sky (where most events would be hidden below the horizon during the day or off-season), it calculates and displays the expected positions of major astronomical events through late 2026—such as meteor shower radiants and NEO asteroid flybys—relative to Fălticeni, Romania (47.46^\circ\text{ N}, 26.30^\circ\text{ E}).
Oriented with North at the top, the code converts equatorial coordinates (Right Ascension and Declination) into local horizon coordinates (Azimuth and Altitude). It then projects these targets onto a 2D polar plot, indicating the cardinal direction (N, E, S, W) to point your telescope and labeling each event with its peak date and estimated rise time, before automatically exporting the chart as a high-resolution PNG image to your device's Download folder.

Let's see source code:
import os
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime, timezone
def draw_and_save_sky_map():
# Coordonate Fălticeni, România
LAT = 47.46
LON = 26.30
# Calendarul evenimentelor până la sfârșitul anului 2026
events = [
{
'name': 'Perseide (Vârf)',
'date_str': '12 Aug',
'rise_time': '22:00',
'ra': 3.07, 'dec': 58.0,
'color': '#00ffcc', 'marker': '*'
},
{
'name': 'Orionide (Vârf)',
'date_str': '21 Oct',
'rise_time': '23:30',
'ra': 6.34, 'dec': 16.0,
'color': '#ff9900', 'marker': '*'
},
{
'name': 'Leonide (Vârf)',
'date_str': '17 Noi',
'rise_time': '00:15',
'ra': 10.2, 'dec': 22.0,
'color': '#ff3366', 'marker': '*'
},
{
'name': 'Geminide (Vârf)',
'date_str': '13 Dec',
'rise_time': '20:30',
'ra': 7.46, 'dec': 33.0,
'color': '#ffff00', 'marker': '*'
},
{
'name': 'Asteroid NEO 2026',
'date_str': 'Toamnă 2026',
'rise_time': '21:00',
'ra': 14.5, 'dec': 10.0,
'color': '#ff00ff', 'marker': 's'
}
]
# Calcul Timp Sidereal Local (LST)
now_utc = datetime.now(timezone.utc)
j2000_epoch = datetime(2000, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
days_since_j2000 = (now_utc - j2000_epoch).total_seconds() / 86400.0
lst = (18.697374558 + 24.06570982441908 * days_since_j2000 + LON / 15.0) % 24
# Creare grafic Matplotlib (Polar)
fig = plt.figure(figsize=(8, 8), facecolor='#0b0d17')
ax = fig.add_subplot(111, polar=True, facecolor='#05070f')
# Orientare fixă: NORDUL SUS (0°)
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_rlim(0, 90)
ax.set_yticklabels([])
lat_rad = np.radians(LAT)
for item in events:
ha = (lst - item['ra']) * 15.0
ha_rad = np.radians(ha)
dec_rad = np.radians(item['dec'])
sin_alt = np.sin(dec_rad) * np.sin(lat_rad) + np.cos(dec_rad) * np.cos(lat_rad) * np.cos(ha_rad)
alt = np.degrees(np.arcsin(np.clip(sin_alt, -1.0, 1.0)))
if alt <= 5:
alt = 35.0
cos_az = (np.sin(dec_rad) - np.sin(lat_rad) * sin_alt) / (np.cos(lat_rad) * np.sin(np.arccos(sin_alt)))
az = np.degrees(np.arccos(np.clip(cos_az, -1.0, 1.0)))
if np.sin(ha_rad) > 0:
az = 360 - az
theta = np.radians(az)
r = 90 - alt
ax.plot(theta, r, marker=item['marker'], markersize=12, color=item['color'])
label_text = f"{item['name']}\n[{item['date_str']}]\nRăsare ~{item['rise_time']}"
ax.text(theta, r + 7, label_text, color=item['color'],
fontsize=7.5, ha='center', fontweight='bold')
cardinals = [('NORD (0°)', 0), ('EST (90°)', 90), ('SUD (180°)', 180), ('VEST (270°)', 270)]
for label, angle in cardinals:
ax.text(np.radians(angle), 102, label, color='white', fontsize=9, fontweight='bold', ha='center', va='center')
ax.set_title("HARTĂ EVENIMENTE ASTRONOMICE 2026 (Aug - Dec)\nLocație: Fălticeni | Orientare: Nordul Sus\n",
color='white', fontsize=9, pad=15)
ax.grid(color='#1a233a', linestyle=':', linewidth=0.8)
plt.tight_layout()
# --- SALVARE IMAGINE ÎN FOLDERUL DOWNLOAD ---
download_path = "/sdcard/Download"
# Alternativă în caz că calea /sdcard nu este mapată la fel pe unele versiuni de Android
if not os.path.exists(download_path):
download_path = os.path.expanduser("~/storage/downloads")
file_name = f"harta_astronomica_2026_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
full_path = os.path.join(download_path, file_name)
try:
plt.savefig(full_path, dpi=300, facecolor=fig.get_facecolor(), edgecolor='none')
print(f" Imaginea a fost salvată cu succes la:\n{full_path}")
except Exception as e:
print(f" Eroare la salvarea fișierului: {e}")
plt.show()
if __name__ == "__main__":
draw_and_save_sky_map()