{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Doppler Shift Interactive\n", "\n", "This interactive allows you to see how the spectrum of a star is affected by the presense of another object orbiting it, causing the star to move, and therefore for its lines to shift in wavelength." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interactive Figure 1: Doppler Shift versus Radial Velocity\n", "\n", "This first figure show the spectrum of a hydrogen cloud in space versus the labratory spectrum of hydrogen gas. The slider on the right hand side lets you adjust the hydrogen cloud's radial veleocity, that is, its speed directly towards, or away from, us." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Author: Samuel Holen\n", "\n", "# Date Created: 11Jun2018\n", "# Last Modified: 14Oct2018 by Juan Cabanela\n", "#\n", "# Hacked on by Andrew Louwagie Gordon to get absorbtion spectrum plotted." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from IPython.display import display\n", "import numpy as np\n", "import bqplot as bq\n", "import ipywidgets as widgets\n", "import tempNcolor as tc\n", "import number_formatting as e2l\n", "import starlib as star\n", "import traitlets" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Set up all the function to use in this interactive\n", "\n", "# Tracking where the center of each of the lines is in the spectra_arrays, UPDATE if you redefine the \n", "# spectra arrays. - jec 10.13.2018\n", "d_idx = 1\n", "g_idx = 4\n", "b_idx = 7\n", "a_idx = 10\n", "\n", "def New_Lambda(lamda, vel):\n", " # Updates the wavelength of the observed spectra using non-relativistic Doppler Shift Equation\n", " c = 299792458\n", " # Removed the relativistic and replaced with non-relativistic formula. - jec 10.13.2018\n", " #return np.sqrt((1+vel/c)/(1-vel/c))*lamda\n", " return (1+vel/c)*lamda\n", "\n", "def simple_update(change=None):\n", " # updates the display of the observed spectral lines and\n", " # changes their color accordingly. Also changes the \n", " # displayed value of the observed wavelength.\n", " vel = fig1_vel_slider.value\n", " new_H_spectra = New_Lambda(H_spectra_array, vel)\n", " hydrogen_line_moving_simple.x = new_H_spectra\n", " \n", " # Update the shift in wavelength for the source\n", " fig1_dval.value = '{:.3f}'.format(new_H_spectra[d_idx,0] - H_spectra_array[d_idx,0])\n", " fig1_gval.value = '{:.3f}'.format(new_H_spectra[g_idx,0] - H_spectra_array[g_idx,0])\n", " fig1_bval.value = '{:.3f}'.format(new_H_spectra[b_idx,0] - H_spectra_array[b_idx,0])\n", " fig1_aval.value = '{:.3f}'.format(new_H_spectra[a_idx,0] - H_spectra_array[a_idx,0])\n", " \n", " # Indicate the direction the source is moving relative to earth\n", " Vel = e2l.exp2LaTeX(abs(vel/1000),3)[2]\n", " if vel >= 0:\n", " vel_label.value = Vel\n", " direction.value = ' (moving away from us)'\n", " else:\n", " vel_label.value = Vel\n", " direction.value = ' (moving toward us)'\n", "\n", "def simple_reset(b):\n", " # Resets the velocity slider to 0 when the reset button is clicked \n", " # Updated to also reset the labels appropriately. - jec 14oct2018\n", " fig1_vel_slider.value = 0\n", " direction.value = ''\n", " \n", " \n", "def update(change=None):\n", " # updates the display of the observed spectral lines and\n", " # changes their color accordingly. Also changes the \n", " # displayed value of the observed wavelength.\n", " t = 6.84\n", " \n", " # Update position of stars\n", " phi = theta_slider.value*3.6 # Assume theta_slider in % fraction of orbit\n", " phi_step = int(phi)\n", " bsm.phi = phi\n", "\n", " global r,r2\n", " # Velocities to determine shifted wavelengths\n", " if planet_star.value == 'Star':\n", " bsm.mass1 = mass1a\n", " bsm.mass2 = mass2a \n", " r = 1\n", " V1 = vel1[phi_step]\n", " V2 = vel2[phi_step]\n", " # update the display for the velocity of each star\n", " vel1_label.value = '{:.0f}'.format(V1)\n", " vunits1.value = 'km/s'\n", " ax_x.num_ticks = 12\n", " ax_x.tick_format = '.1f'\n", " vel2_label.value = '{:.0f}'.format(V2)\n", " shift = 0.005\n", " # Update the star spectral lines\n", " new_H_spectra = New_Lambda(H_spectra_array,V1*1000)\n", " new_H_spectra2 = New_Lambda(H_spectra_array,V2*1000)\n", " star2.default_size = 60\n", " else:\n", " bsm.mass1 = mass1b\n", " bsm.mass2 = mass2b\n", " r = 0.1\n", " V1 = vel1[phi_step]\n", " V2 = vel2[phi_step]\n", " vel1_label.value = '{:.0f}'.format(V1)\n", " vunits1.value = 'm/s'\n", " ax_x.num_ticks = 4\n", " ax_x.tick_format = '.5f'\n", " vel2_label.value = '{:.0f}'.format(V2)\n", " shift = 5e-7\n", " # Update the star spectral lines\n", " new_H_spectra = New_Lambda(H_spectra_array,V1)\n", " new_H_spectra2 = New_Lambda(H_spectra_array,V2*1000)\n", " star2.default_size = 20\n", " \n", " d1 = r*np.cos(np.pi/180 * phi)\n", " k1 = r*np.sin(np.pi/180 * phi)\n", " star1.x,star1.y = [d1],[k1]\n", " d2 = -r2*np.cos(np.pi/180 * phi)\n", " k2 = -r2*np.sin(np.pi/180 * phi)\n", " star2.x,star2.y = [d2],[k2]\n", " \n", " if picker.value == 'entire spectrum':\n", " hydrogen_line2.x = new_H_spectra\n", " hydrogen_line3.x = new_H_spectra2\n", " elif picker.value == 'violet':\n", " hydrogen_line2.x = [new_H_spectra[1]-shift,new_H_spectra[d_idx],new_H_spectra[d_idx]+shift]\n", " hydrogen_line3.x = [new_H_spectra2[1]-shift,new_H_spectra2[d_idx],new_H_spectra2[d_idx]+shift]\n", " elif picker.value == 'blue':\n", " hydrogen_line2.x = [new_H_spectra[4]-shift,new_H_spectra[g_idx],new_H_spectra[g_idx]+shift]\n", " hydrogen_line3.x = [new_H_spectra2[4]-shift,new_H_spectra2[g_idx],new_H_spectra2[g_idx]+shift]\n", " elif picker.value == 'cyan':\n", " hydrogen_line2.x = [new_H_spectra[7]-shift,new_H_spectra[b_idx],new_H_spectra[b_idx]+shift]\n", " hydrogen_line3.x = [new_H_spectra2[7]-shift,new_H_spectra2[b_idx],new_H_spectra2[b_idx]+shift]\n", " else:\n", " hydrogen_line2.x = [new_H_spectra[10]-shift,new_H_spectra[a_idx],new_H_spectra[a_idx]+shift]\n", " hydrogen_line3.x = [new_H_spectra2[10]-shift,new_H_spectra2[a_idx],new_H_spectra2[a_idx]+shift]\n", "\n", " # Update the shift in wavelength for the large (blue) star\n", " if planet_star.value == 'Star':\n", " dval1.value = '{:.3f}'.format(new_H_spectra[d_idx,0] - H_spectra_array[d_idx,0])\n", " gval1.value = '{:.3f}'.format(new_H_spectra[g_idx,0] - H_spectra_array[g_idx,0])\n", " bval1.value = '{:.3f}'.format(new_H_spectra[b_idx,0] - H_spectra_array[b_idx,0])\n", " aval1.value = '{:.3f}'.format(new_H_spectra[a_idx,0] - H_spectra_array[a_idx,0])\n", " else:\n", " dval1.value = '{:.7f}'.format(new_H_spectra[d_idx,0] - H_spectra_array[d_idx,0])\n", " gval1.value = '{:.7f}'.format(new_H_spectra[g_idx,0] - H_spectra_array[g_idx,0])\n", " bval1.value = '{:.7f}'.format(new_H_spectra[b_idx,0] - H_spectra_array[b_idx,0])\n", " aval1.value = '{:.7f}'.format(new_H_spectra[a_idx,0] - H_spectra_array[a_idx,0])\n", "\n", " # Update the shift in wavelength for the small (red) star\n", " dval2.value = '{:.3f}'.format(new_H_spectra2[d_idx,0] - H_spectra_array[d_idx,0])\n", " gval2.value = '{:.3f}'.format(new_H_spectra2[g_idx,0] - H_spectra_array[g_idx,0])\n", " bval2.value = '{:.3f}'.format(new_H_spectra2[b_idx,0] - H_spectra_array[b_idx,0])\n", " aval2.value = '{:.3f}'.format(new_H_spectra2[a_idx,0] - H_spectra_array[a_idx,0])\n", "\n", " # Indicate the direction each star is moving relative to earth\n", " if V1 >= 0:\n", " direction1.value = 'moving away'\n", " direction2.value = 'moving toward'\n", " else:\n", " direction1.value = 'moving toward'\n", " direction2.value = 'moving away'\n", "\n", "def update_lumen(change=None):\n", " # Update the luminosity of the small orbiting star. This is for the \n", " # simulation going to the limit where the orbiting star is actually a planet.\n", " if planet_star.value == 'Star':\n", " if Lumen.value >= 0.5:\n", " hydrogen_line3.opacities = [Lumen.value-0.5,Lumen.value,Lumen.value-0.5,\n", " Lumen.value-0.5,Lumen.value,Lumen.value-0.5,\n", " Lumen.value-0.5,Lumen.value,Lumen.value-0.5,\n", " Lumen.value-0.5,Lumen.value,Lumen.value-0.5]\n", " else:\n", " hydrogen_line3.opacities = [0.01,Lumen.value,0.01,0.01,Lumen.value,0.01,\n", " 0.01,Lumen.value,0.01,0.01,Lumen.value,0.01]\n", " else:\n", " Lumen.value = 0\n", " hydrogen_line3.opacities = [0]*12\n", "\n", "def update_view(change=None):\n", " global y_sc,ax_y\n", " wave = wavelengths.tolist()\n", " lines_arr = np.array([[410.2,410.2],[410.2,410.2],[410.2,410.2],[434.0,434.0],[434.0,434.0],[434.0,434.0],[486.1,486.1],[486.1,486.1],[486.1,486.1],[656.3,656.3],[656.3,656.3],[656.3,656.3]])\n", " if planet_star.value == 'Star':\n", " adjust = np.array([[-0.005,-0.005],[0,0],[0.005,0.005]])\n", " shift = 0.5\n", " else:\n", " adjust = np.array([[-5e-7,-5e-7],[0,0],[5e-7,5e-7]])\n", " shift = 5e-5\n", " \n", " if picker.value == 'entire spectrum':\n", " x_sc.min = float(min(wavelengths))\n", " x_sc.max = float(max(wavelengths))\n", " ax_x.scale = x_sc\n", " \n", " # Adjust spectra scales\n", " hydrogen_line1.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line2.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line3.scales = {'x': x_sc, 'y': y_sc}\n", " wide_line.scales = {'x': x_sc, 'y': y_sc}\n", " fig.axes = [ax_x,ax_y]\n", " \n", " hydrogen_line1.x = H_spectra_array\n", " hydrogen_line2.x = H_spectra_array\n", " hydrogen_line3.x = H_spectra_array\n", " \n", " wide_line.opacities = [100]*len(wavelengths)\n", "\n", " Lab_label.x=[580,580]\n", " Lab_label.scales={'x': x_sc, 'y': y_sc}\n", "\n", " fig.background_style = {'fill' : 'white'}\n", " elif picker.value == 'violet':\n", " x_sc.min = lines_arr[0,0] - shift\n", " x_sc.max = lines_arr[0,0] + shift\n", " ax_x.scale = x_sc\n", " # Adjust spectra scales\n", " hydrogen_line1.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line2.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line3.scales = {'x': x_sc, 'y': y_sc}\n", " wide_line.scales = {'x': x_sc, 'y': y_sc}\n", " \n", " fig.axes = [ax_x, ax_y]\n", " fig.background_style = {'fill' : colors_array[wave.index(410)]}\n", " \n", " hydrogen_line1.x = lines_arr[0:3] + adjust\n", " hydrogen_line2.x = lines_arr[0:3] + adjust\n", " hydrogen_line3.x = lines_arr[0:3] + adjust\n", " \n", " wide_line.opacities = [0]*len(wavelengths)\n", " \n", " Lab_label.x = [lines_arr[0,0] - shift/2,lines_arr[0,0] - shift/2]\n", " Lab_label.scales={'x': x_sc, 'y': y_sc}\n", " elif picker.value == 'blue':\n", " x_sc.min = lines_arr[3,0] - shift\n", " x_sc.max = lines_arr[3,0] + shift\n", " ax_x.scale = x_sc\n", " # Adjust spectra scales\n", " hydrogen_line1.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line2.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line3.scales = {'x': x_sc, 'y': y_sc}\n", " wide_line.scales = {'x': x_sc, 'y': y_sc}\n", " \n", " fig.axes = [ax_x,ax_y]\n", " fig.background_style = {'fill' : colors_array[wave.index(432)]}\n", " \n", " hydrogen_line1.x = lines_arr[3:6] + adjust\n", " hydrogen_line2.x = lines_arr[3:6] + adjust\n", " hydrogen_line3.x = lines_arr[3:6] + adjust\n", " \n", " wide_line.opacities = [0]*len(wavelengths)\n", " \n", " Lab_label.x = [lines_arr[3,0] - shift/2,lines_arr[3,0] - shift/2]\n", " Lab_label.scales={'x': x_sc, 'y': y_sc}\n", " elif picker.value == 'cyan':\n", " x_sc.min = lines_arr[6,0] - shift\n", " x_sc.max = lines_arr[6,0] + shift\n", " ax_x.scale = x_sc\n", " # Adjust spectra scales\n", " hydrogen_line1.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line2.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line3.scales = {'x': x_sc, 'y': y_sc}\n", " wide_line.scales = {'x': x_sc, 'y': y_sc}\n", " \n", " fig.axes = [ax_x,ax_y]\n", " fig.background_style = {'fill' : colors_array[wave.index(485)]}\n", " \n", " hydrogen_line1.x = lines_arr[6:9] + adjust\n", " hydrogen_line2.x = lines_arr[6:9] + adjust\n", " hydrogen_line3.x = lines_arr[6:9] + adjust\n", " \n", " wide_line.opacities = [0]*len(wavelengths)\n", " \n", " Lab_label.x = [lines_arr[6,0] - shift/2,lines_arr[6,0] - shift/2]\n", " Lab_label.scales={'x': x_sc, 'y': y_sc}\n", "\n", " else:\n", " x_sc.min = lines_arr[9,0] - shift\n", " x_sc.max = lines_arr[9,0] + shift\n", " ax_x.scale = x_sc\n", " \n", " # Adjust spectra scales\n", " hydrogen_line1.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line2.scales = {'x': x_sc, 'y': y_sc}\n", " hydrogen_line3.scales = {'x': x_sc, 'y': y_sc}\n", " wide_line.scales = {'x': x_sc, 'y': y_sc}\n", " \n", " fig.axes = [ax_x,ax_y]\n", " fig.background_style = {'fill' : colors_array[wave.index(656)]}\n", " \n", " hydrogen_line1.x = lines_arr[9:12] + adjust\n", " hydrogen_line2.x = lines_arr[9:12] + adjust\n", " hydrogen_line3.x = lines_arr[9:12] + adjust\n", " \n", " wide_line.opacities = [0]*len(wavelengths)\n", " \n", " Lab_label.x = [lines_arr[9,0] - shift/2,lines_arr[9,0] - shift/2]\n", " Lab_label.scales={'x': x_sc, 'y': y_sc}\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Creates an array of the visible light wavelengths\n", "wavelengths = np.arange(400,700,1)\n", "\n", "# Makes an array to plot vertical lines for each of the spectral lines\n", "H_spectra_list = [[409.2,409.2],[410.2,410.2],[411.2,411.2],[433.0,433.0],[434.0,434.0],[435.0,435.0],[485.1,485.1],[486.1,486.1],[487.1,487.1],[655.3,655.3],[656.3,656.3],[657.3,657.3]]\n", "\n", "#H_spec_list2\n", "H_spectra_array = np.array(H_spectra_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##\n", "## Set up some material for both figures\n", "##\n", "\n", "## Set up some widths here\n", "speed_label_width = '300px'\n", "longspeed_label_width = '400px'\n", "vel_value_width = '60px'\n", "longvel_value_width = '150px'\n", "label_width = '240px'\n", "direction_width = '170px'\n", "longdirection_width = '300px'\n", "line_height='35px'\n", "box_width = '450px'\n", "value_width = '100px'\n", "\n", "# Creates label widgets to display the observed wavelengths of each\n", "# of the 'shifted' spectral lines. (Both Figures 1 and 2)\n", "shift_label1 = widgets.HTML(value='Hδ (410.2 nm):')\n", "shift_label2 = widgets.HTML(value='Hγ (434.0 nm):')\n", "shift_label3 = widgets.HTML(value='Hβ (486.1 nm):')\n", "shift_label4 = widgets.HTML(value='Hα (656.3 nm):')\n", "shift_label1.layout.width = label_width\n", "shift_label2.layout.width = label_width\n", "shift_label3.layout.width = label_width\n", "shift_label4.layout.width = label_width\n", "\n", "shift_label = widgets.HTML(value='Shift: ')\n", "shift_text_width = '50px'\n", "shift_label.layout.width = shift_text_width\n", "\n", "units = widgets.Label(value='nm')\n", "unit_text_width = '30px'\n", "units.layout.width = unit_text_width\n", "\n", "## Create spectral lines display for both figures\n", "# Axes for spectra\n", "# Set the scales\n", "x_sc_fig1 = bq.LinearScale(min=float(min(wavelengths)), max=float(max(wavelengths)))\n", "y_sc_fig1 = bq.LinearScale()\n", "x_sc = bq.LinearScale(min=float(min(wavelengths)), max=float(max(wavelengths)))\n", "y_sc = bq.LinearScale()\n", "\n", "# Define the axes\n", "ax_x_fig1 = bq.Axis(label='Wavelength (nm)', scale=x_sc_fig1, grid_lines='none', num_ticks=12)\n", "ax_y_fig1 = bq.Axis(scale=y_sc_fig1, orientation='vertical', grid_lines='none', num_ticks=0)\n", "ax_x = bq.Axis(label='Wavelength (nm)', scale=x_sc, grid_lines='none', num_ticks=12)\n", "ax_y = bq.Axis(scale=y_sc, orientation='vertical', grid_lines='none', num_ticks=0)\n", "\n", "# Arrays for the spectral lines. one for the stars (0.5 to 1) and one for \n", "# laboratory measurements (0 to 0.5).\n", "height1 = np.array([[0.0,0.5],[0.0,0.5],[0.0,0.5],[0.0,0.5],[0.0,0.5],[0.0,0.5],\n", " [0.0,0.5],[0.0,0.5],[0.0,0.5],[0.0,0.5],[0.0,0.5],[0.0,0.5],[0.0,0.5],[0.0,0.5]])\n", "height2 = np.array([[0.5,1.0],[0.5,1.0],[0.5,1.0],[0.5,1.0],[0.5,1.0],[0.5,1.0],\n", " [0.5,1.0],[0.5,1.0],[0.5,1.0],[0.5,1.0],[0.5,1.0],[0.5,1.0],[0.5,1.0],[0.5,1.0]])\n", "\n", "# This code define the colors to be plotted and \n", "# which wavelengths they are plotted at, uses hexidecimal designation\n", "colors_array = tc.wav2hex(wavelengths)\n", "colors_list = colors_array.tolist()\n", "\n", "# The curve for this figure is created by drawing a bunch of vertical lines that \n", "# go from zero to the blackbody curve, these \n", "# arrays provide the proper pairs of points that define each individual line\n", "x_array = np.array([wavelengths, wavelengths])\n", "fin_x_array = x_array.transpose() # Arrays must be transposed to get pairs of numbers\n", "y_zeros = np.zeros_like(wavelengths)\n", "y_ones = np.ones_like(wavelengths)\n", "y_array = np.array([y_zeros, y_ones])\n", "fin_y_array = y_array.transpose() # Arrays must be transposed to get pairs of numbers\n", "\n", "# Create the spectral lines\n", "# Lab Spectra for Figure 1\n", "hydrogen_line_lab_simple = bq.Lines(x=H_spectra_array, y=height1, scales={'x': x_sc_fig1, 'y': y_sc_fig1}, \n", " colors=['black'] ,opacities=[.3,.8,.3,.3,.8,.3,.3,.8,.3,.3,.8,.3])\n", "# Star for Figure 1\n", "hydrogen_line_moving_simple = bq.Lines(x=H_spectra_array, y=height2, scales={'x': x_sc_fig1, 'y': y_sc_fig1}, \n", " colors=['black'] ,opacities=[.3,.8,.3,.3,.8,.3,.3,.8,.3,.3,.8,.3])\n", "\n", "# Lab Spectra for Figure 2\n", "hydrogen_line1 = bq.Lines(x=H_spectra_array, y=height1, scales={'x': x_sc, 'y': y_sc}, \n", " colors=['black'] ,opacities=[.3,.8,.3,.3,.8,.3,.3,.8,.3,.3,.8,.3])\n", "# Large star (blue) for Figure 2\n", "hydrogen_line2 = bq.Lines(x=H_spectra_array, y=height2, scales={'x': x_sc, 'y': y_sc}, \n", " colors=['black'] ,opacities=[.3,.8,.3,.3,.8,.3,.3,.8,.3,.3,.8,.3])\n", "# Small star (red) for Figure 2\n", "hydrogen_line3 = bq.Lines(x=H_spectra_array, y=height2, scales={'x': x_sc, 'y': y_sc}, \n", " colors=['#303030'] ,opacities=[.3,.8,.3,.3,.8,.3,.3,.8,.3,.3,.8,.3])\n", "\n", "# This is the line command that draws all the lines\n", "fig1_wide_line = bq.Lines(x = fin_x_array, y = fin_y_array, scales={'x': x_sc_fig1, 'y': y_sc_fig1}, colors=colors_list)\n", "wide_line = bq.Lines(x = fin_x_array, y = fin_y_array, scales={'x': x_sc, 'y': y_sc}, colors=colors_list)\n", "\n", "# Labels the lab and source spectra on the figure\n", "fig1_Lab_label = bq.Label(x=[580,580], y=[0.1,0.8], scales={'x': x_sc_fig1, 'y': y_sc_fig1},\n", " text=['Laboratory Spectrum','Source Spectrum'], default_size=15, font_weight='bolder',\n", " colors=['black'], update_on_move=False, align='middle')\n", "Lab_label = bq.Label(x=[580,580], y=[0.1,0.8], scales={'x': x_sc, 'y': y_sc},\n", " text=['Laboratory Spectrum','Source Spectrum'], default_size=15, font_weight='bolder',\n", " colors=['black'], update_on_move=False, align='middle')\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##\n", "## Setup Figure 1\n", "##\n", "\n", "# Slider to adjust velocity (away or towards Earth) of the star in question\n", "fig1_vel_slider = widgets.IntSlider(\n", " value=0,\n", " min=-5e6,\n", " max=5e6,\n", " step=10000,\n", " disabled=False,\n", " continuous_update=True,\n", " orientation='horizontal',\n", " readout=False,\n", " layout=widgets.Layout(width='340px')\n", ")\n", "# Reset button\n", "fig1_reset = widgets.Button(description='Reset')\n", "\n", "# Figure 1 shifts\n", "fig1_dval = widgets.Text(value=str(0.0))\n", "fig1_gval = widgets.Text(value=str(0.0))\n", "fig1_bval = widgets.Text(value=str(0.0))\n", "fig1_aval = widgets.Text(value=str(0.0))\n", "fig1_dval.layout.width = value_width\n", "fig1_gval.layout.width = value_width\n", "fig1_bval.layout.width = value_width\n", "fig1_aval.layout.width = value_width\n", "\n", "# Labels for the velocity slider in Figure 1\n", "speed_label = widgets.HTML(value='Radial Velocity of Source: ')\n", "speed_label.layout.width = longspeed_label_width\n", "\n", "vel_label = widgets.HTML(value='0', positioning='right')\n", "vel_label.layout.width = vel_value_width \n", "vel_label.layout.align_content = 'center'\n", "\n", "vunits = widgets.HTML(value='km/s')\n", "vunits.width = unit_text_width\n", "\n", "direction = widgets.HTML(value='')\n", "direction.layout.width = longdirection_width\n", "\n", "# these boxes contain display commands for the velocity of each star\n", "fig1controls_box = widgets.HBox([speed_label, vel_label, vunits, direction])\n", "fig1controls_box.layout.width = '400px'\n", "\n", "# Define Figure 1\n", "figure1 = bq.Figure(title = 'Hydrogen Cloud Absorbtion Spectrum', axes=[ax_x_fig1, ax_y_fig1], animation = 100,\n", " marks = [fig1_wide_line, hydrogen_line_lab_simple, hydrogen_line_moving_simple, fig1_Lab_label], \n", " padding_y=0, min_aspect_ratio=2.5, max_aspect_ratio=2.5)\n", "figure1.layout.width = '500px'\n", "\n", "# Update the widgets\n", "fig1_vel_slider.observe(simple_update, names=['value'])\n", "fig1_dval.observe(simple_update, names=['value'])\n", "fig1_gval.observe(simple_update, names=['value'])\n", "fig1_bval.observe(simple_update, names=['value'])\n", "fig1_aval.observe(simple_update, names=['value'])\n", "fig1_reset.on_click(simple_reset)\n", "\n", "# These boxes contain the labels for the wavelengths and the shift in wavelength\n", "# text boxes.\n", "fig1_shift_label1_box = widgets.HBox([shift_label1, shift_label, fig1_dval, units])\n", "fig1_shift_label2_box = widgets.HBox([shift_label2, shift_label, fig1_gval, units])\n", "fig1_shift_label3_box = widgets.HBox([shift_label3, shift_label, fig1_bval, units])\n", "fig1_shift_label4_box = widgets.HBox([shift_label4, shift_label, fig1_aval, units])\n", "fig1_shift_label1_box.layout.height=line_height\n", "fig1_shift_label2_box.layout.height=line_height\n", "fig1_shift_label3_box.layout.height=line_height\n", "fig1_shift_label4_box.layout.height=line_height\n", "fig1_shift_label1_box.layout.overflow='visible'\n", "fig1_shift_label2_box.layout.overflow='visible'\n", "fig1_shift_label3_box.layout.overflow='visible'\n", "fig1_shift_label4_box.layout.overflow='visible'\n", "\n", "# Box to contain all of the above boxes\n", "read_box = widgets.VBox([fig1_shift_label1_box, fig1_shift_label2_box, fig1_shift_label3_box, fig1_shift_label4_box])\n", "fig1_right_side_box = widgets.VBox([fig1_vel_slider, fig1controls_box, fig1_reset, read_box])\n", "#fig1_right_side_box.layout.height = '780px'\n", "\n", "# Final box\n", "boxy = widgets.HBox([figure1, fig1_right_side_box])\n", "fig1_right_side_box.layout.width = '500px'\n", "#fig1_right_side_box.layout.height = '300px'\n", "\n", "display(boxy)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interactive Figure 2: Spectrum of a Moving Stellar System\n", "\n", "The following interactive let's you simulate the expected spectrum from \n", "- a binary star system where both stars have visible hydrogen absorption lines and \n", "- an exoplanetary system where both objects have hydrogen in their spectra, but only the star's spectral lines are visible because the exoplanet's spectrum is much too faint to see." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##\n", "## Setup Figure 2\n", "##\n", "\n", "# Slider to adjust velocity (away or towards Earth) of the star in question\n", "\n", "# Each hydrogen spectral line for blue star (central star)\n", "# Note: d-delta,g-gamma,b-beta,a-alpha\n", "dval1 = widgets.Text(value=str(0.0))\n", "gval1 = widgets.Text(value=str(0.0))\n", "bval1 = widgets.Text(value=str(0.0))\n", "aval1 = widgets.Text(value=str(0.0))\n", "# Each hydrogen spectral line for red star (outer star)\n", "dval2 = widgets.Text(value=str(0.0))\n", "gval2 = widgets.Text(value=str(0.0))\n", "bval2 = widgets.Text(value=str(0.0))\n", "aval2 = widgets.Text(value=str(0.0))\n", "\n", "# Label for the velocity slider\n", "speed_label1 = widgets.HTML(value='Radial velocity of Star: ')\n", "speed_label2 = widgets.HTML(value='Radial velocity of Orbiting Object:')\n", "# velocity output for each star\n", "vel1_label = widgets.Text(value='0', positioning='right')\n", "vel2_label = widgets.Text(value='0', positioning='right')\n", "vunits1 = widgets.HTML(value='km/s')\n", "vunits2 = widgets.HTML(value='km/s')\n", "# labels direction each star is moving\n", "direction1 = widgets.HTML(value='')\n", "direction2 = widgets.HTML(value='')\n", "\n", "# Creates a slider to animate the motion of the stars.\n", "theta_slider = widgets.IntSlider(\n", " value=0,\n", " min=0,\n", " max=99,\n", " step=1,\n", " disabled=False,\n", " continuous_update=True,\n", " orientation='horizontal',\n", " readout=True,\n", " readout_format='.0f',\n", " layout=widgets.Layout(width='200px')\n", ")\n", "\n", "# Animate the stars\n", "theta_play = widgets.Play(value = 0, min=theta_slider.min, max=theta_slider.max, \n", " step=1, description=\"Press play\", \n", " disabled=False, _repeat=True, show_repeat=False)\n", "widgets.jslink((theta_play, 'value'), (theta_slider, 'value'))\n", "\n", "# Slider to adjust the 'brightness' (opacity) of the small outer star.\n", "Lumen = widgets.FloatSlider(\n", " value=0,\n", " min=0,\n", " max=1,\n", " step=.01,\n", " disabled=False,\n", " continuous_update=True,\n", " orientation='horizontal',\n", " readout=False,\n", " layout=widgets.Layout(width='340px')\n", ")\n", "lumen_label = widgets.HTML(value='Brightness of Orbiting Object')\n", "star1_label = widgets.HTML(value='Central Star')\n", "star2_label = widgets.HTML(value='Orbiting Object')\n", "line_label = widgets.HTML(value='Line Name (Lab Wavelength)')\n", "\n", "picker = widgets.RadioButtons(value='entire spectrum', options=[('entire spectrum' , 'entire spectrum'),('near 410.2nm' , 'violet'),('near 434.0nm' , 'blue'),('near 486.1nm' , 'cyan'),('near 656.3nm' , 'red')])\n", "picker_label = widgets.HTML(value='Display Range')\n", "\n", "planet_star = widgets.RadioButtons(value='Star', options=['Star','Planet'])\n", "planet_star_label = widgets.HTML(value='Orbiting Object')\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### STAR VELOCITY INFO ###\n", "\n", "mass1a = 5 # solar masses\n", "mass2a = 1 # solar masses\n", "a = 1 # semimajor axis in AU\n", "e = 0.0 # eccentricity\n", "incl = 88 # inclination angle of 88 degrees\n", "\n", "mass1b = 1\n", "mass2b = 1/1000\n", "\n", "# Create a binary star model and radial velocity data in it\n", "bsm = star.BinaryStarModel(mass1a, mass2a, a, e, rv_init=True,incl=incl, N=360)\n", "bsm_b = star.BinaryStarModel(mass1a, mass2a, a, e, incl=0, rv_init=True)\n", "#This created two pandas Dataframes\n", "#bsm.orbit_info\n", "#bsm.radvel_info\n", "\n", "phase = bsm.radvel_info['phase']\n", "vel1 = bsm.radvel_info['v1r']\n", "vel2 = bsm.radvel_info['v2r']\n", "\n", "#binary_view = star.BinaryStarViewer(bsm=bsm, t_idx0=0, view_width=400, view_height=400)\n", "#binary_renderer = binary_view.renderer\n", "\n", "# The BinaryStarModel will automatically update if you change sthe masses or semi-major axis\n", "# but to get the BinaryStarViewer to change automatically for these changes, you need to link\n", "# it using a traitlet link.\n", "#orbit_change_link = traitlets.directional_link((bsm, 'mdl_counter'), (binary_view, 'mdl_counter'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# Define Figure\n", "fig = bq.Figure(title = 'Hydrogen Absorbtion Spectra', axes=[ax_x, ax_y], animation = 100, \n", " marks = [wide_line, hydrogen_line1, hydrogen_line2,hydrogen_line3,Lab_label], \n", " padding_y=0, min_aspect_ratio=2.5, max_aspect_ratio=2.5)\n", "# Size figure\n", "fig.layout.width = '500px'\n", "fig.layout.height = '200px'\n", "fig.layout.overflow = 'hidden'\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Create star animation \n", "# Setup intial conditions for the orbiting stars.\n", "# d1,d2 are x positions and k1,k2 are y positions\n", "phi = theta_slider.value*3.60\n", "r = 1\n", "d1 = r*np.cos(np.pi/180 * phi)\n", "k1 = r*np.sin(np.pi/180 * phi)\n", "r2 = 10\n", "d2 = -r2*np.cos(np.pi/180 * phi)\n", "k2 = -r2*np.sin(np.pi/180 * phi)\n", "\n", "# Axes for stars\n", "# Sets axis scale for x and y to \n", "sc_x = bq.LinearScale(min=-10,max=10)\n", "sc_y = bq.LinearScale(min=-10,max=10)\n", "\n", "# Sets up the axes, grid-lines are set to black so that they blend in with the background.\n", "x_ax = bq.Axis(scale=sc_x, grid_color='white', num_ticks=0)\n", "y_ax = bq.Axis(scale=sc_y, orientation='vertical', grid_color='white', num_ticks=0)\n", "\n", "# Create the stars and the figure to contain them\n", "star1 = bq.Scatter(x=[d1], y=[k1], scales={'x': sc_x, 'y': sc_y}, colors=['blue'],default_size=500)\n", "star2 = bq.Scatter(x=[d2], y=[k2], scales={'x': sc_x, 'y': sc_y}, colors=['red'])\n", "# Gives reference to Earth\n", "to_earth = bq.Lines(x = [[5,10],[10,9],[10,9]], y = [[6,6],[6,7],[6,5]], scales={'x': sc_x, 'y': sc_y}, colors=['yellow'])\n", "earth_label = bq.Label(text=[\"To Earth\"], x=[5], y=[4], colors=['yellow'], scales={'x': sc_x, 'y': sc_y})\n", "fig_star = bq.Figure(title='Stellar System Top-Down View', marks=[star1,star2,to_earth,earth_label], axes=[x_ax, y_ax], \n", " padding_y=0, animation=100, background_style={'fill' : 'black'},\n", " min_aspect_ratio=1, max_aspect_ratio=1)\n", "\n", "fig_star.layout.height = fig.layout.width\n", "fig_star.layout.width = fig.layout.width" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Update the widgets\n", "dval1.observe(update, names=['value'])\n", "gval1.observe(update, names=['value'])\n", "bval1.observe(update, names=['value'])\n", "aval1.observe(update, names=['value'])\n", "\n", "vel1_label.observe(update, names=['value'])\n", "vunits1.observe(update, names=['value'])\n", "direction1.observe(update, names=['value'])\n", "\n", "dval2.observe(update, names=['value'])\n", "gval2.observe(update, names=['value'])\n", "bval2.observe(update, names=['value'])\n", "aval2.observe(update, names=['value'])\n", "\n", "vel2_label.observe(update, names=['value'])\n", "direction2.observe(update, names=['value'])\n", "\n", "theta_slider.observe(update, names=['value'])\n", "Lumen.observe(update_lumen, names=['value'])\n", "\n", "picker.observe(update_view, names=['value'])\n", "picker.observe(update, names=['value'])\n", "planet_star.observe(update, names=['value'])\n", "planet_star.observe(update_view, names=['value'])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "## Display to the screen\n", "\n", "# these boxes contain display commands for the velocity of each star\n", "speed1_label_box = widgets.HBox([speed_label1 ,vel1_label, vunits1, direction1])\n", "speed2_label_box = widgets.HBox([speed_label2, vel2_label, vunits2, direction2])\n", "\n", "# Commands to properly size the velocity boxes\n", "speed_label1.layout.width = speed_label_width \n", "speed_label2.layout.width = speed_label_width \n", "vel1_label.layout.width = vel_value_width \n", "vel2_label.layout.width = vel_value_width \n", "vunits1.layout.width = unit_text_width\n", "vunits2.layout.width = unit_text_width\n", "direction1.layout.width = direction_width\n", "direction2.layout.width = direction_width\n", "speed1_label_box.layout.height=line_height\n", "speed2_label_box.layout.height=line_height\n", "speed1_label_box.layout.overflow='visible'\n", "speed2_label_box.layout.overflow='visible'\n", "\n", "# Set display elements for spectral line Doppler shift data\n", "dval1.layout.width = value_width\n", "gval1.layout.width = value_width\n", "bval1.layout.width = value_width\n", "aval1.layout.width = value_width\n", "dval2.layout.width = value_width\n", "gval2.layout.width = value_width\n", "bval2.layout.width = value_width\n", "aval2.layout.width = value_width\n", "\n", "# These boxes contain the labels for the wavelengths and the shift in wavelength\n", "# text boxes.\n", "shift_label1_box = widgets.HBox([shift_label1, shift_label, dval1, units, dval2, units])\n", "shift_label2_box = widgets.HBox([shift_label2, shift_label, gval1, units, gval2, units])\n", "shift_label3_box = widgets.HBox([shift_label3, shift_label, bval1, units, bval2, units])\n", "shift_label4_box = widgets.HBox([shift_label4, shift_label, aval1, units, aval2, units])\n", "shift_label1_box.layout.height=line_height\n", "shift_label2_box.layout.height=line_height\n", "shift_label3_box.layout.height=line_height\n", "shift_label4_box.layout.height=line_height\n", "shift_label1_box.layout.overflow='visible'\n", "shift_label2_box.layout.overflow='visible'\n", "shift_label3_box.layout.overflow='visible'\n", "shift_label4_box.layout.overflow='visible'\n", "\n", "star_labels = widgets.HBox([line_label, star1_label, star2_label])\n", "line_label_width = '240px' # About labelwidth + shift_text_width\n", "col_label_width = '130px' # About value_width + unit_text_width\n", "line_label.layout.width = line_label_width\n", "star1_label.layout.width = col_label_width\n", "star2_label.layout.width = col_label_width\n", "\n", "# Box to contain all of the above boxes\n", "read_box = widgets.VBox([speed1_label_box, speed2_label_box, star_labels,\n", " shift_label1_box, shift_label2_box, shift_label3_box, shift_label4_box])\n", "read_box.layout.width = box_width\n", "\n", "# box for the star animation control\n", "theta_label = widgets.HTML('Percent of Orbit Done:')\n", "theta_label.layout.width = speed_label_width\n", "phase_angle_box = widgets.HBox([theta_label, theta_slider, theta_play])\n", "phase_angle_box.layout.width = box_width\n", "\n", "# selectors\n", "col_width = '150px'\n", "line_select = widgets.VBox([picker_label, picker])\n", "obj_select = widgets.VBox([planet_star_label, planet_star])\n", "planet_star_label.layout.width = col_width\n", "planet_star.layout.width = col_width\n", "picker_label.layout.width = col_width\n", "picker.layout.width = col_width\n", "select = widgets.HBox([line_select, obj_select])\n", "\n", "# combines the above boxes and brightness controls into one box\n", "right_side_box = widgets.VBox([read_box, phase_angle_box, lumen_label, Lumen, select])\n", "right_side_box.layout.width = box_width\n", "\n", "# box for the figures\n", "fig_box = widgets.VBox([fig, fig_star])\n", "\n", "# Bring it all together\n", "boxy = widgets.HBox([fig_box, right_side_box])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Make sure lumen slider value is reflected in opacities\n", "update_lumen()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display(boxy)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }