.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/plot_elevation.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_plot_elevation.py: Plot Elevation map of objects over a single night ================================================= Given an observer location, a date, and a list of objects, plot the maximum elevation that each object gets to over the course of the night, and when it happens. .. GENERATED FROM PYTHON SOURCE LINES 8-21 .. code-block:: Python from zoneinfo import ZoneInfo from datetime import datetime, timedelta import matplotlib.pyplot as plt import matplotlib.dates as mdates import numpy as np from labellines import labelLines import kete .. GENERATED FROM PYTHON SOURCE LINES 22-24 Inputs: ------- .. GENERATED FROM PYTHON SOURCE LINES 24-36 .. code-block:: Python timezone = ZoneInfo("America/Los_Angeles") object_names = ["Vesta", "10p", "Pallas", 734] start_time = datetime(2025, 2, 11, 12, tzinfo=timezone) # Observers position, on the surface of the earth: site = "Palomar Mountain" # Elevation minimum label cutoff = 20 .. GENERATED FROM PYTHON SOURCE LINES 37-39 Calculating elevations over one night ------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 39-108 .. code-block:: Python jd_start = kete.Time.from_iso(start_time.isoformat()).jd jd_end = jd_start + 1 # Fetch orbital elements from horizons states = [ kete.HorizonsProperties.fetch(str(name), update_name=True).state for name in object_names ] states = kete.propagate_n_body(states, jd_start) # step through time in 1 minute increments step_time = 1 / (24 * 60) steps = np.arange(0, 1, step_time) elevation = [] night_len = [] sun_elevation = [] moon_elevation = [] for subrange in steps: # for each time step, calculate the elevation and sun elevation jd_step = jd_start + subrange approx_state = kete.propagate_two_body(states, jd_step) sun2obs = kete.spice.mpc_code_to_ecliptic(site, jd_step).pos earth2obs = kete.spice.mpc_code_to_ecliptic(site, jd_step, center="399").pos sun_elevation.append(90 - earth2obs.angle_between(-sun2obs)) moon = kete.spice.get_state("Moon", jd_step) obs2obj = kete.Vector(moon.pos - sun2obs) moon_elevation.append(90 - earth2obs.angle_between(obs2obj)) cur_elev = [] for state in approx_state: obs2obj = kete.Vector(state.pos - sun2obs) cur_elev.append(90 - earth2obs.angle_between(obs2obj)) elevation.append(cur_elev) elevation = np.array(elevation) sun_elevation = np.array(sun_elevation) # Keep only data points where the sun is below the horizon # starting with sunset sunset_idx = np.argmax(sun_elevation < 0) elevation = elevation[sunset_idx:] steps = steps[sunset_idx:] sun_elevation = sun_elevation[sunset_idx:] moon_elevation = moon_elevation[sunset_idx:] # repeat for sunrise sunrise_idx = np.argmax(sun_elevation > 0) elevation = elevation[:sunrise_idx] steps = steps[:sunrise_idx] sun_elevation = sun_elevation[:sunrise_idx] moon_elevation = moon_elevation[:sunrise_idx] # Now sort the objects by earliest maximum elevation sort_idx = np.argsort(np.argmax(np.array(elevation).T, axis=1))[::-1] elevation = elevation[:, sort_idx] object_names = np.array(object_names)[sort_idx] dates_utc = [kete.Time(t + jd_start).to_datetime() for t in steps] dates = [t.astimezone(timezone) for t in dates_utc] moon_frac = kete.spice.moon_illumination_frac(jd_start) # Find the time closest to midnight midnight = dates[np.argmax([d.hour + d.minute for d in dates])] .. GENERATED FROM PYTHON SOURCE LINES 109-112 First Plot: ----------- This shows the elevation of all objects as the night progresses. .. GENERATED FROM PYTHON SOURCE LINES 112-188 .. code-block:: Python plt.figure(dpi=150, figsize=(8, 4)) ys = np.arange(0, 91, 10) plt.yticks(ys, ys) plt.ylim(0, 90) # plot each of the elevation lines for elev, name in zip(elevation.T, object_names): plt.plot(dates, elev, label=name) # Add labels at the top of the elevation lines lines = plt.gca().get_lines() max_elev = [] for idx, line in zip(np.argmax(np.array(elevation).T, axis=1), lines): max_elev.append(line._x[idx]) labelLines(lines, xvals=max_elev, zorder=2.5) line = plt.plot( dates, moon_elevation, label=f"Moon ({moon_frac:0.0%})", ls="--", c="k", lw=1 )[0] labelLines([line], xvals=line._x[np.argmax(moon_elevation)], zorder=2.45, fontsize=8) plt.axvline(midnight, c="k", zorder=2) plt.xlabel( "Local Time - " + start_time.strftime("%Y-%m-%d") + " to " + (start_time + timedelta(days=1)).strftime("%Y-%m-%d") ) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%H:%M", tz=timezone)) plt.gca().xaxis.set_major_locator(mdates.HourLocator(byhour=range(24))) plt.gca().xaxis.set_minor_locator(mdates.MinuteLocator(byminute=range(0, 24 * 15, 15))) plt.ylabel("Elevation") night = np.array(dates)[sun_elevation < 0] civil_night = np.array(dates)[sun_elevation < -6] nautical_night = np.array(dates)[sun_elevation < -12] astro_night = np.array(dates)[sun_elevation < -18] for dark in [night, civil_night, nautical_night, astro_night]: plt.fill_between( dark, -90, 90, where=dark, color="blue", alpha=0.07, transform=plt.gca().get_xaxis_transform(), zorder=3, ) plt.grid() ax = plt.twiny() for elev, name in zip(elevation.T, object_names): plt.plot(dates, elev, c="None") ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M", tz="UTC")) ax.xaxis.set_major_locator(mdates.HourLocator(byhour=range(24))) ax.xaxis.set_minor_locator(mdates.MinuteLocator(byminute=range(0, 24 * 15, 15))) plt.xlabel("Time (UTC)") ymin, ymax = plt.gca().get_ylim() ax2 = plt.twinx() ax2.set_ylim(ymin, ymax) elev_ticks = np.arange(10, 91, 10) airmass = [f"{x:0.3g}" for x in kete.conversion.compute_airmass(90 - elev_ticks)] ax2.set_yticks(elev_ticks, airmass) plt.ylabel("Airmass") plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_elevation_001.png :alt: plot elevation :srcset: /auto_examples/images/sphx_glr_plot_elevation_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 189-192 Second Plot: ------------ Same data as above, but plotted as a heatmap, sorted by earliest maximum elevation. .. GENERATED FROM PYTHON SOURCE LINES 192-245 .. code-block:: Python elevation[elevation < 0] = np.nan plt.figure(dpi=150, figsize=(8, 3 + len(object_names) * 0.2)) plt.xlabel( "Local Time - " + start_time.strftime("%Y-%m-%d") + " to " + (start_time + timedelta(days=1)).strftime("%Y-%m-%d") ) plt.yticks(range(len(object_names)), object_names) plt.xlim(np.min(night), np.max(night)) plt.axvline(midnight, c="k", alpha=0.8, zorder=-1) plt.pcolormesh(dates, range(len(object_names)), np.clip(elevation.T, 0, 100)) x_cut = np.argmax(elevation > cutoff, axis=0) for idx, idy in enumerate(x_cut): idy2 = np.argmax(elevation[(idy + 1) :, idx] < cutoff) + idy plt.plot( [dates[idy], dates[idy]], [idx - 0.5, idx + 0.5], c="white", ls="--", lw=0.75 ) plt.plot( [dates[idy2], dates[idy2]], [idx - 0.5, idx + 0.5], c="white", ls="--", lw=0.75 ) for idx, idy in enumerate(np.argmax(np.nan_to_num(elevation), axis=0)): plt.plot(dates[idy], idx, ".", c="white", ms=3) plt.text( dates[idy], idx - 0.17, rf" {elevation[idy, idx]:0.1f}", fontsize=8, color="white", ) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%H:%M", tz=timezone)) plt.gca().xaxis.set_major_locator(mdates.HourLocator(byhour=range(24))) plt.gca().xaxis.set_minor_locator(mdates.MinuteLocator(byminute=range(0, 24 * 15, 15))) cb = plt.colorbar(location="bottom", pad=0.25, fraction=0.05, label="Elevation (Deg)") cb.ax.plot([cutoff, cutoff], [0, 1], c="w", ls="--", lw=0.75) plt.grid(axis="x", lw=0.25) ax = plt.twiny() ax.pcolormesh(dates, range(len(object_names)), np.clip(elevation.T, 0, 100), alpha=0) ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M", tz="UTC")) ax.xaxis.set_major_locator(mdates.HourLocator(byhour=range(24))) ax.xaxis.set_minor_locator(mdates.MinuteLocator(byminute=range(0, 24 * 15, 15))) plt.xlabel("Time (UTC)") plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_elevation_002.png :alt: plot elevation :srcset: /auto_examples/images/sphx_glr_plot_elevation_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.879 seconds) .. _sphx_glr_download_auto_examples_plot_elevation.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_elevation.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_elevation.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_elevation.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_