mirror of
https://github.com/AllenDowney/AstronomicalData.git
synced 2025-12-27 21:23:03 -08:00
1551 lines
88 KiB
HTML
1551 lines
88 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Photometry — Astronomical Data in Python</title>
|
||
|
||
<link rel="stylesheet" href="_static/css/index.d431a4ee1c1efae0e38bdfebc22debff.css">
|
||
|
||
|
||
<link rel="stylesheet"
|
||
href="_static/vendor/fontawesome/5.13.0/css/all.min.css">
|
||
<link rel="preload" as="font" type="font/woff2" crossorigin
|
||
href="_static/vendor/fontawesome/5.13.0/webfonts/fa-solid-900.woff2">
|
||
<link rel="preload" as="font" type="font/woff2" crossorigin
|
||
href="_static/vendor/fontawesome/5.13.0/webfonts/fa-brands-400.woff2">
|
||
|
||
|
||
|
||
<link rel="stylesheet"
|
||
href="_static/vendor/open-sans_all/1.44.1/index.css">
|
||
<link rel="stylesheet"
|
||
href="_static/vendor/lato_latin-ext/1.44.1/index.css">
|
||
|
||
|
||
<link rel="stylesheet" href="_static/sphinx-book-theme.bfb7730f9caf2ec0b46a44615585038c.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||
<link rel="stylesheet" type="text/css" href="_static/togglebutton.css" />
|
||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||
<link rel="stylesheet" type="text/css" href="_static/mystnb.css" />
|
||
<link rel="stylesheet" type="text/css" href="_static/sphinx-thebe.css" />
|
||
<link rel="stylesheet" type="text/css" href="_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css" />
|
||
<link rel="stylesheet" type="text/css" href="_static/panels-variables.06eb56fa6e07937060861dad626602ad.css" />
|
||
|
||
<link rel="preload" as="script" href="_static/js/index.30270b6e4c972e43c488.js">
|
||
|
||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||
<script src="_static/jquery.js"></script>
|
||
<script src="_static/underscore.js"></script>
|
||
<script src="_static/doctools.js"></script>
|
||
<script src="_static/language_data.js"></script>
|
||
<script src="_static/togglebutton.js"></script>
|
||
<script src="_static/clipboard.min.js"></script>
|
||
<script src="_static/copybutton.js"></script>
|
||
<script >var togglebuttonSelector = '.toggle, .admonition.dropdown, .tag_hide_input div.cell_input, .tag_hide-input div.cell_input, .tag_hide_output div.cell_output, .tag_hide-output div.cell_output, .tag_hide_cell.cell, .tag_hide-cell.cell';</script>
|
||
<script src="_static/sphinx-book-theme.be0a4a0c39cd630af62a2fcf693f3f06.js"></script>
|
||
<script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"inlineMath": [["\\(", "\\)"]], "displayMath": [["\\[", "\\]"]], "processRefs": false, "processEnvironments": false}})</script>
|
||
<script async="async" src="https://unpkg.com/thebelab@latest/lib/index.js"></script>
|
||
<script >
|
||
const thebe_selector = ".thebe"
|
||
const thebe_selector_input = "pre"
|
||
const thebe_selector_output = ".output"
|
||
</script>
|
||
<script async="async" src="_static/sphinx-thebe.js"></script>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
<link rel="next" title="Visualization" href="07_plot.html" />
|
||
<link rel="prev" title="Joining Tables" href="05_join.html" />
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta name="docsearch:language" content="en" />
|
||
|
||
|
||
|
||
</head>
|
||
<body data-spy="scroll" data-target="#bd-toc-nav" data-offset="80">
|
||
|
||
|
||
<div class="container-xl">
|
||
<div class="row">
|
||
|
||
<div class="col-12 col-md-3 bd-sidebar site-navigation show" id="site-navigation">
|
||
|
||
<div class="navbar-brand-box">
|
||
<a class="navbar-brand text-wrap" href="index.html">
|
||
|
||
|
||
<h1 class="site-logo" id="site-title">Astronomical Data in Python</h1>
|
||
|
||
</a>
|
||
</div>
|
||
|
||
<form class="bd-search d-flex align-items-center" action="search.html" method="get">
|
||
<i class="icon fas fa-search"></i>
|
||
<input type="search" class="form-control" name="q" id="search-input" placeholder="Search this book..." aria-label="Search this book..." autocomplete="off" >
|
||
</form>
|
||
|
||
<nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
|
||
<ul class="nav sidenav_l1">
|
||
<li class="toctree-l1">
|
||
<a class="reference internal" href="README.html">
|
||
Astronomical Data in Python
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
<ul class="current nav sidenav_l1">
|
||
<li class="toctree-l1">
|
||
<a class="reference internal" href="01_query.html">
|
||
1. Queries
|
||
</a>
|
||
</li>
|
||
<li class="toctree-l1">
|
||
<a class="reference internal" href="02_coords.html">
|
||
2. Coordinates and Units
|
||
</a>
|
||
</li>
|
||
<li class="toctree-l1">
|
||
<a class="reference internal" href="03_motion.html">
|
||
3. Proper Motion
|
||
</a>
|
||
</li>
|
||
<li class="toctree-l1">
|
||
<a class="reference internal" href="04_select.html">
|
||
4. Transformation and Selection
|
||
</a>
|
||
</li>
|
||
<li class="toctree-l1">
|
||
<a class="reference internal" href="05_join.html">
|
||
Joining Tables
|
||
</a>
|
||
</li>
|
||
<li class="toctree-l1 current active">
|
||
<a class="current reference internal" href="#">
|
||
Photometry
|
||
</a>
|
||
</li>
|
||
<li class="toctree-l1">
|
||
<a class="reference internal" href="07_plot.html">
|
||
Visualization
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
|
||
</nav>
|
||
|
||
<!-- To handle the deprecated key -->
|
||
|
||
<div class="navbar_extra_footer">
|
||
Powered by <a href="https://jupyterbook.org">Jupyter Book</a>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<main class="col py-md-3 pl-md-4 bd-content overflow-auto" role="main">
|
||
|
||
<div class="row topbar fixed-top container-xl">
|
||
<div class="col-12 col-md-3 bd-topbar-whitespace site-navigation show">
|
||
</div>
|
||
<div class="col pl-2 topbar-main">
|
||
|
||
<button id="navbar-toggler" class="navbar-toggler ml-0" type="button" data-toggle="collapse"
|
||
data-toggle="tooltip" data-placement="bottom" data-target=".site-navigation" aria-controls="navbar-menu"
|
||
aria-expanded="true" aria-label="Toggle navigation" aria-controls="site-navigation"
|
||
title="Toggle navigation" data-toggle="tooltip" data-placement="left">
|
||
<i class="fas fa-bars"></i>
|
||
<i class="fas fa-arrow-left"></i>
|
||
<i class="fas fa-arrow-up"></i>
|
||
</button>
|
||
|
||
<div class="dropdown-buttons-trigger">
|
||
<button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn" aria-label="Download this page"><i
|
||
class="fas fa-download"></i></button>
|
||
|
||
|
||
<div class="dropdown-buttons">
|
||
<!-- ipynb file if we had a myst markdown file -->
|
||
|
||
<!-- Download raw file -->
|
||
<a class="dropdown-buttons" href="_sources/06_photo.ipynb"><button type="button"
|
||
class="btn btn-secondary topbarbtn" title="Download source file" data-toggle="tooltip"
|
||
data-placement="left">.ipynb</button></a>
|
||
<!-- Download PDF via print -->
|
||
<button type="button" id="download-print" class="btn btn-secondary topbarbtn" title="Print to PDF"
|
||
onClick="window.print()" data-toggle="tooltip" data-placement="left">.pdf</button>
|
||
</div>
|
||
|
||
</div>
|
||
<!-- Source interaction buttons -->
|
||
|
||
<div class="dropdown-buttons-trigger">
|
||
<button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn"
|
||
aria-label="Connect with source repository"><i class="fab fa-github"></i></button>
|
||
<div class="dropdown-buttons sourcebuttons">
|
||
<a class="repository-button"
|
||
href="https://github.com/AllenDowney/AstronomicalData"><button type="button" class="btn btn-secondary topbarbtn"
|
||
data-toggle="tooltip" data-placement="left" title="Source repository"><i
|
||
class="fab fa-github"></i>repository</button></a>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- Full screen (wrap in <a> to have style consistency -->
|
||
<a class="full-screen-button"><button type="button" class="btn btn-secondary topbarbtn" data-toggle="tooltip"
|
||
data-placement="bottom" onclick="toggleFullScreen()" title="Fullscreen mode"><i
|
||
class="fas fa-expand"></i></button></a>
|
||
|
||
<!-- Launch buttons -->
|
||
|
||
<div class="dropdown-buttons-trigger">
|
||
<button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn"
|
||
aria-label="Launch interactive content"><i class="fas fa-rocket"></i></button>
|
||
<div class="dropdown-buttons">
|
||
|
||
<a class="binder-button" href="https://mybinder.org/v2/gh/AllenDowney/AstronomicalData/master?urlpath=tree/06_photo.ipynb"><button type="button"
|
||
class="btn btn-secondary topbarbtn" title="Launch Binder" data-toggle="tooltip"
|
||
data-placement="left"><img class="binder-button-logo"
|
||
src="_static/images/logo_binder.svg"
|
||
alt="Interact on binder">Binder</button></a>
|
||
|
||
|
||
|
||
<a class="colab-button" href="https://colab.research.google.com/github/AllenDowney/AstronomicalData/blob/master/06_photo.ipynb"><button type="button" class="btn btn-secondary topbarbtn"
|
||
title="Launch Colab" data-toggle="tooltip" data-placement="left"><img class="colab-button-logo"
|
||
src="_static/images/logo_colab.png"
|
||
alt="Interact on Colab">Colab</button></a>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- Table of contents -->
|
||
<div class="d-none d-md-block col-md-2 bd-toc show">
|
||
|
||
<div class="tocsection onthispage pt-5 pb-3">
|
||
<i class="fas fa-list"></i> Contents
|
||
</div>
|
||
<nav id="bd-toc-nav">
|
||
<ul class="nav section-nav flex-column">
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#outline">
|
||
Outline
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#reload-the-data">
|
||
Reload the data
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#plotting-photometry-data">
|
||
Plotting photometry data
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#isochrone">
|
||
Isochrone
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#making-a-polygon">
|
||
Making a polygon
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#which-points-are-in-the-polygon">
|
||
Which points are in the polygon?
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#save-the-polygon">
|
||
Save the polygon
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#reloading-the-data">
|
||
Reloading the data
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#merging-photometry-data">
|
||
Merging photometry data
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#selecting-based-on-photometry">
|
||
Selecting based on photometry
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#write-the-data">
|
||
Write the data
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#summary">
|
||
Summary
|
||
</a>
|
||
</li>
|
||
<li class="toc-h2 nav-item toc-entry">
|
||
<a class="reference internal nav-link" href="#best-practices">
|
||
Best practices
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
|
||
</nav>
|
||
|
||
</div>
|
||
</div>
|
||
<div id="main-content" class="row">
|
||
<div class="col-12 col-md-9 pl-md-3 pr-md-0">
|
||
|
||
<div>
|
||
|
||
<div class="section" id="photometry">
|
||
<h1>Photometry<a class="headerlink" href="#photometry" title="Permalink to this headline">¶</a></h1>
|
||
<p>This is the sixth in a series of notebooks related to astronomy data.</p>
|
||
<p>As a continuing example, we will replicate part of the analysis in a recent paper, “<a class="reference external" href="https://arxiv.org/abs/1805.00425">Off the beaten path: Gaia reveals GD-1 stars outside of the main stream</a>” by Adrian M. Price-Whelan and Ana Bonaca.</p>
|
||
<p>In the previous lesson we downloaded photometry data from Pan-STARRS, which is available from the same server we’ve been using to get Gaia data.</p>
|
||
<p>The next step in the analysis is to select candidate stars based on the photometry data.<br />
|
||
The following figure from the paper is a color-magnitude diagram showing the stars we previously selected based on proper motion:</p>
|
||
<a class="reference internal image-reference" href="https://github.com/datacarpentry/astronomy-python/raw/gh-pages/fig/gd1-3.png"><img alt="https://github.com/datacarpentry/astronomy-python/raw/gh-pages/fig/gd1-3.png" src="https://github.com/datacarpentry/astronomy-python/raw/gh-pages/fig/gd1-3.png" style="width: 300px;" /></a>
|
||
<p>In red is a theoretical isochrone, showing where we expect the stars in GD-1 to fall based on the metallicity and age of their original globular cluster.</p>
|
||
<p>By selecting stars in the shaded area, we can further distinguish the main sequence of GD-1 from mostly younger background stars.</p>
|
||
<div class="section" id="outline">
|
||
<h2>Outline<a class="headerlink" href="#outline" title="Permalink to this headline">¶</a></h2>
|
||
<p>Here are the steps in this notebook:</p>
|
||
<ol class="simple">
|
||
<li><p>We’ll reload the data from the previous notebook and make a color-magnitude diagram.</p></li>
|
||
<li><p>We’ll use an isochrone computed by MIST to specify a polygonal region in the color-magnitude diagram and select the stars inside it.</p></li>
|
||
<li><p>Then we’ll merge the photometry data with the list of candidate stars, storing the result in a Pandas <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code>.</p></li>
|
||
</ol>
|
||
<p>After completing this lesson, you should be able to</p>
|
||
<ul class="simple">
|
||
<li><p>Use Matplotlib to specify a <code class="docutils literal notranslate"><span class="pre">Polygon</span></code> and determine which points fall inside it.</p></li>
|
||
<li><p>Use Pandas to merge data from multiple <code class="docutils literal notranslate"><span class="pre">DataFrames</span></code>, much like a database <code class="docutils literal notranslate"><span class="pre">JOIN</span></code> operation.</p></li>
|
||
</ul>
|
||
</div>
|
||
<div class="section" id="reload-the-data">
|
||
<h2>Reload the data<a class="headerlink" href="#reload-the-data" title="Permalink to this headline">¶</a></h2>
|
||
<p>The following cell downloads the photometry data we created in the previous notebook.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="kn">from</span> <span class="nn">wget</span> <span class="kn">import</span> <span class="n">download</span>
|
||
|
||
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'gd1_photo.fits'</span>
|
||
<span class="n">filepath</span> <span class="o">=</span> <span class="s1">'https://github.com/AllenDowney/AstronomicalData/raw/main/data/'</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">download</span><span class="p">(</span><span class="n">filepath</span><span class="o">+</span><span class="n">filename</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we can read the data back into an Astropy <code class="docutils literal notranslate"><span class="pre">Table</span></code>.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">astropy.table</span> <span class="kn">import</span> <span class="n">Table</span>
|
||
|
||
<span class="n">photo_table</span> <span class="o">=</span> <span class="n">Table</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="plotting-photometry-data">
|
||
<h2>Plotting photometry data<a class="headerlink" href="#plotting-photometry-data" title="Permalink to this headline">¶</a></h2>
|
||
<p>Now that we have photometry data from Pan-STARRS, we can replicate the <a class="reference external" href="https://en.wikipedia.org/wiki/Galaxy_color%E2%80%93magnitude_diagram">color-magnitude diagram</a> from the original paper:</p>
|
||
<a class="reference internal image-reference" href="https://github.com/datacarpentry/astronomy-python/raw/gh-pages/fig/gd1-3.png"><img alt="https://github.com/datacarpentry/astronomy-python/raw/gh-pages/fig/gd1-3.png" src="https://github.com/datacarpentry/astronomy-python/raw/gh-pages/fig/gd1-3.png" style="width: 300px;" /></a>
|
||
<p>The y-axis shows the apparent magnitude of each source with the <a class="reference external" href="https://en.wikipedia.org/wiki/Photometric_system">g filter</a>.</p>
|
||
<p>The x-axis shows the difference in apparent magnitude between the g and i filters, which indicates color.</p>
|
||
<p>Stars with lower values of (g-i) are brighter in g-band than in i-band, compared to other stars, which means they are bluer.</p>
|
||
<p>Stars in the lower-left quadrant of this diagram are less bright than the others, and have lower metallicity, which means they are <a class="reference external" href="http://spiff.rit.edu/classes/ladder/lectures/ordinary_stars/ordinary.html">likely to be older</a>.</p>
|
||
<p>Since we expect the stars in GD-1 to be older than the background stars, the stars in the lower-left are more likely to be in GD-1.</p>
|
||
<p>The following function takes a table containing photometry data and draws a color-magnitude diagram.
|
||
The input can be an Astropy <code class="docutils literal notranslate"><span class="pre">Table</span></code> or Pandas <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code>, as long as it has columns named <code class="docutils literal notranslate"><span class="pre">g_mean_psf_mag</span></code> and <code class="docutils literal notranslate"><span class="pre">i_mean_psf_mag</span></code>.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
|
||
|
||
<span class="k">def</span> <span class="nf">plot_cmd</span><span class="p">(</span><span class="n">table</span><span class="p">):</span>
|
||
<span class="sd">"""Plot a color magnitude diagram.</span>
|
||
<span class="sd"> </span>
|
||
<span class="sd"> table: Table or DataFrame with photometry data</span>
|
||
<span class="sd"> """</span>
|
||
<span class="n">y</span> <span class="o">=</span> <span class="n">table</span><span class="p">[</span><span class="s1">'g_mean_psf_mag'</span><span class="p">]</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="n">table</span><span class="p">[</span><span class="s1">'g_mean_psf_mag'</span><span class="p">]</span> <span class="o">-</span> <span class="n">table</span><span class="p">[</span><span class="s1">'i_mean_psf_mag'</span><span class="p">]</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s1">'ko'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">xlim</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">])</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">ylim</span><span class="p">([</span><span class="mi">14</span><span class="p">,</span> <span class="mi">22</span><span class="p">])</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">gca</span><span class="p">()</span><span class="o">.</span><span class="n">invert_yaxis</span><span class="p">()</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'$Magnitude (g)$'</span><span class="p">)</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">'$Color (g-i)$'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">plot_cmd</span></code> uses a new function, <code class="docutils literal notranslate"><span class="pre">invert_yaxis</span></code>, to invert the <code class="docutils literal notranslate"><span class="pre">y</span></code> axis, which is conventional when plotting magnitudes, since lower magnitude indicates higher brightness.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">invert_yaxis</span></code> is a little different from the other functions we’ve used. You can’t call it like this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">plt</span><span class="o">.</span><span class="n">invert_yaxis</span><span class="p">()</span> <span class="c1"># doesn't work</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>You have to call it like this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">plt</span><span class="o">.</span><span class="n">gca</span><span class="p">()</span><span class="o">.</span><span class="n">invert_yaxis</span><span class="p">()</span> <span class="c1"># works</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">gca</span></code> stands for “get current axis”. It returns an object that represents the axes of the current figure, and that object provides <code class="docutils literal notranslate"><span class="pre">invert_yaxis</span></code>.</p>
|
||
<p><strong>In case anyone asks:</strong> The most likely reason for this inconsistency in the interface is that <code class="docutils literal notranslate"><span class="pre">invert_yaxis</span></code> is a lesser-used function, so it’s not made available at the top level of the interface.</p>
|
||
<p>Here’s what the results look like.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">plot_cmd</span><span class="p">(</span><span class="n">photo_table</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<img alt="_images/06_photo_14_0.png" src="_images/06_photo_14_0.png" />
|
||
</div>
|
||
</div>
|
||
<p>Our figure does not look exactly like the one in the paper because we are working with a smaller region of the sky, so we don’t have as many stars. But we can see an overdense region in the lower left that contains stars with the photometry we expect for GD-1.</p>
|
||
<p>In the next section we’ll use an isochrone to specify a polygon that contains this overdense regioin.</p>
|
||
</div>
|
||
<div class="section" id="isochrone">
|
||
<h2>Isochrone<a class="headerlink" href="#isochrone" title="Permalink to this headline">¶</a></h2>
|
||
<p>Based on our best estimates for the ages of the stars in GD-1 and their metallicity, we can compute a <a class="reference external" href="https://en.wikipedia.org/wiki/Stellar_isochrone">stellar isochrone</a> that predicts the relationship between their magnitude and color.</p>
|
||
<p>In fact, we can use <a class="reference external" href="http://waps.cfa.harvard.edu/MIST/">MESA Isochrones & Stellar Tracks</a> (MIST) to compute it for us.</p>
|
||
<p>Using the <a class="reference external" href="http://waps.cfa.harvard.edu/MIST/interp_isos.html">MIST Version 1.2 web interface</a>, we computed an isochrone with the following parameters:</p>
|
||
<ul class="simple">
|
||
<li><p>Rotation initial v/v_crit = 0.4</p></li>
|
||
<li><p>Single age, linear scale = 12e9</p></li>
|
||
<li><p>Composition [Fe/H] = -1.35</p></li>
|
||
<li><p>Synthetic Photometry, PanStarrs</p></li>
|
||
<li><p>Extinction av = 0</p></li>
|
||
</ul>
|
||
<p>The following cell downloads the results:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="kn">from</span> <span class="nn">wget</span> <span class="kn">import</span> <span class="n">download</span>
|
||
|
||
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'MIST_iso_5fd2532653c27.iso.cmd'</span>
|
||
<span class="n">filepath</span> <span class="o">=</span> <span class="s1">'https://github.com/AllenDowney/AstronomicalData/raw/main/data/'</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">download</span><span class="p">(</span><span class="n">filepath</span><span class="o">+</span><span class="n">filename</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>To read this file we’ll download a Python module <a class="reference external" href="https://github.com/jieunchoi/MIST_codes">from this repository</a>.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="kn">from</span> <span class="nn">wget</span> <span class="kn">import</span> <span class="n">download</span>
|
||
|
||
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'read_mist_models.py'</span>
|
||
<span class="n">filepath</span> <span class="o">=</span> <span class="s1">'https://github.com/jieunchoi/MIST_codes/raw/master/scripts/'</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">download</span><span class="p">(</span><span class="n">filepath</span><span class="o">+</span><span class="n">filename</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we can read the file:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">read_mist_models</span>
|
||
|
||
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'MIST_iso_5fd2532653c27.iso.cmd'</span>
|
||
<span class="n">iso</span> <span class="o">=</span> <span class="n">read_mist_models</span><span class="o">.</span><span class="n">ISOCMD</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>Reading in: MIST_iso_5fd2532653c27.iso.cmd
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>The result is an <code class="docutils literal notranslate"><span class="pre">ISOCMD</span></code> object.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="nb">type</span><span class="p">(</span><span class="n">iso</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>read_mist_models.ISOCMD
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>It contains a list of arrays, one for each isochrone.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="nb">type</span><span class="p">(</span><span class="n">iso</span><span class="o">.</span><span class="n">isocmds</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>list
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>We only got one isochrone.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="nb">len</span><span class="p">(</span><span class="n">iso</span><span class="o">.</span><span class="n">isocmds</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>1
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>So we can select it like this:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">iso_array</span> <span class="o">=</span> <span class="n">iso</span><span class="o">.</span><span class="n">isocmds</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>It’s a NumPy array:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="nb">type</span><span class="p">(</span><span class="n">iso_array</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>numpy.ndarray
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>But it’s an unusual NumPy array, because it contains names for the columns.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">iso_array</span><span class="o">.</span><span class="n">dtype</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>dtype([('EEP', '<i4'), ('isochrone_age_yr', '<f8'), ('initial_mass', '<f8'), ('star_mass', '<f8'), ('log_Teff', '<f8'), ('log_g', '<f8'), ('log_L', '<f8'), ('[Fe/H]_init', '<f8'), ('[Fe/H]', '<f8'), ('PS_g', '<f8'), ('PS_r', '<f8'), ('PS_i', '<f8'), ('PS_z', '<f8'), ('PS_y', '<f8'), ('PS_w', '<f8'), ('PS_open', '<f8'), ('phase', '<f8')])
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Which means we can select columns using the bracket operator:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">iso_array</span><span class="p">[</span><span class="s1">'phase'</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>array([0., 0., 0., ..., 6., 6., 6.])
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>We can use <code class="docutils literal notranslate"><span class="pre">phase</span></code> to select the part of the isochrone for stars in the main sequence and red giant phases.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">phase_mask</span> <span class="o">=</span> <span class="p">(</span><span class="n">iso_array</span><span class="p">[</span><span class="s1">'phase'</span><span class="p">]</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&</span> <span class="p">(</span><span class="n">iso_array</span><span class="p">[</span><span class="s1">'phase'</span><span class="p">]</span> <span class="o"><</span> <span class="mi">3</span><span class="p">)</span>
|
||
<span class="n">phase_mask</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>354
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">main_sequence</span> <span class="o">=</span> <span class="n">iso_array</span><span class="p">[</span><span class="n">phase_mask</span><span class="p">]</span>
|
||
<span class="nb">len</span><span class="p">(</span><span class="n">main_sequence</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>354
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>The other two columns we’ll use are <code class="docutils literal notranslate"><span class="pre">PS_g</span></code> and <code class="docutils literal notranslate"><span class="pre">PS_i</span></code>, which contain simulated photometry data for stars with the given age and metallicity, based on a model of the Pan-STARRS sensors.</p>
|
||
<p>We’ll use these columns to superimpose the isochrone on the color-magnitude diagram, but first we have to use a <a class="reference external" href="https://en.wikipedia.org/wiki/Distance_modulus">distance modulus</a> to scale the isochrone based on the estimated distance of GD-1.</p>
|
||
<p>We can use the <code class="docutils literal notranslate"><span class="pre">Distance</span></code> object from Astropy to compute the distance modulus.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">astropy.coordinates</span> <span class="k">as</span> <span class="nn">coord</span>
|
||
<span class="kn">import</span> <span class="nn">astropy.units</span> <span class="k">as</span> <span class="nn">u</span>
|
||
|
||
<span class="n">distance</span> <span class="o">=</span> <span class="mf">7.8</span> <span class="o">*</span> <span class="n">u</span><span class="o">.</span><span class="n">kpc</span>
|
||
<span class="n">distmod</span> <span class="o">=</span> <span class="n">coord</span><span class="o">.</span><span class="n">Distance</span><span class="p">(</span><span class="n">distance</span><span class="p">)</span><span class="o">.</span><span class="n">distmod</span><span class="o">.</span><span class="n">value</span>
|
||
<span class="n">distmod</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>14.4604730134524
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we can compute the scaled magnitude and color of the isochrone.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">mag_g</span> <span class="o">=</span> <span class="n">main_sequence</span><span class="p">[</span><span class="s1">'PS_g'</span><span class="p">]</span> <span class="o">+</span> <span class="n">distmod</span>
|
||
<span class="n">color_g_i</span> <span class="o">=</span> <span class="n">main_sequence</span><span class="p">[</span><span class="s1">'PS_g'</span><span class="p">]</span> <span class="o">-</span> <span class="n">main_sequence</span><span class="p">[</span><span class="s1">'PS_i'</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we can plot it on the color-magnitude diagram like this.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">plot_cmd</span><span class="p">(</span><span class="n">photo_table</span><span class="p">)</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">color_g_i</span><span class="p">,</span> <span class="n">mag_g</span><span class="p">);</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<img alt="_images/06_photo_44_0.png" src="_images/06_photo_44_0.png" />
|
||
</div>
|
||
</div>
|
||
<p>The theoretical isochrone passes through the overdense region where we expect to find stars in GD-1.</p>
|
||
<p>Let’s save this result so we can reload it later without repeating the steps in this section.</p>
|
||
<p>So we can save the data in an HDF5 file, we’ll put it in a Pandas <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code> first:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
|
||
|
||
<span class="n">iso_df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">()</span>
|
||
<span class="n">iso_df</span><span class="p">[</span><span class="s1">'mag_g'</span><span class="p">]</span> <span class="o">=</span> <span class="n">mag_g</span>
|
||
<span class="n">iso_df</span><span class="p">[</span><span class="s1">'color_g_i'</span><span class="p">]</span> <span class="o">=</span> <span class="n">color_g_i</span>
|
||
|
||
<span class="n">iso_df</span><span class="o">.</span><span class="n">head</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_html"><div>
|
||
<style scoped>
|
||
.dataframe tbody tr th:only-of-type {
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.dataframe tbody tr th {
|
||
vertical-align: top;
|
||
}
|
||
|
||
.dataframe thead th {
|
||
text-align: right;
|
||
}
|
||
</style>
|
||
<table border="1" class="dataframe">
|
||
<thead>
|
||
<tr style="text-align: right;">
|
||
<th></th>
|
||
<th>mag_g</th>
|
||
<th>color_g_i</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<th>0</th>
|
||
<td>28.294743</td>
|
||
<td>2.195021</td>
|
||
</tr>
|
||
<tr>
|
||
<th>1</th>
|
||
<td>28.189718</td>
|
||
<td>2.166076</td>
|
||
</tr>
|
||
<tr>
|
||
<th>2</th>
|
||
<td>28.051761</td>
|
||
<td>2.129312</td>
|
||
</tr>
|
||
<tr>
|
||
<th>3</th>
|
||
<td>27.916194</td>
|
||
<td>2.093721</td>
|
||
</tr>
|
||
<tr>
|
||
<th>4</th>
|
||
<td>27.780024</td>
|
||
<td>2.058585</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div></div></div>
|
||
</div>
|
||
<p>And then save it.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">filename</span> <span class="o">=</span> <span class="s1">'gd1_isochrone.hdf5'</span>
|
||
|
||
<span class="n">iso_df</span><span class="o">.</span><span class="n">to_hdf</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'iso_df'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="making-a-polygon">
|
||
<h2>Making a polygon<a class="headerlink" href="#making-a-polygon" title="Permalink to this headline">¶</a></h2>
|
||
<p>The following cell downloads the isochrone we made in the previous section, if necessary.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="kn">from</span> <span class="nn">wget</span> <span class="kn">import</span> <span class="n">download</span>
|
||
|
||
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'gd1_isochrone.hdf5'</span>
|
||
<span class="n">filepath</span> <span class="o">=</span> <span class="s1">'https://github.com/AllenDowney/AstronomicalData/raw/main/data/'</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">download</span><span class="p">(</span><span class="n">filepath</span><span class="o">+</span><span class="n">filename</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we can read it back in.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">iso_df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_hdf</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'iso_df'</span><span class="p">)</span>
|
||
<span class="n">iso_df</span><span class="o">.</span><span class="n">head</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_html"><div>
|
||
<style scoped>
|
||
.dataframe tbody tr th:only-of-type {
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.dataframe tbody tr th {
|
||
vertical-align: top;
|
||
}
|
||
|
||
.dataframe thead th {
|
||
text-align: right;
|
||
}
|
||
</style>
|
||
<table border="1" class="dataframe">
|
||
<thead>
|
||
<tr style="text-align: right;">
|
||
<th></th>
|
||
<th>mag_g</th>
|
||
<th>color_g_i</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<th>0</th>
|
||
<td>28.294743</td>
|
||
<td>2.195021</td>
|
||
</tr>
|
||
<tr>
|
||
<th>1</th>
|
||
<td>28.189718</td>
|
||
<td>2.166076</td>
|
||
</tr>
|
||
<tr>
|
||
<th>2</th>
|
||
<td>28.051761</td>
|
||
<td>2.129312</td>
|
||
</tr>
|
||
<tr>
|
||
<th>3</th>
|
||
<td>27.916194</td>
|
||
<td>2.093721</td>
|
||
</tr>
|
||
<tr>
|
||
<th>4</th>
|
||
<td>27.780024</td>
|
||
<td>2.058585</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div></div></div>
|
||
</div>
|
||
<p>Here’s what the isochrone looks like on the color-magnitude diagram.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">plot_cmd</span><span class="p">(</span><span class="n">photo_table</span><span class="p">)</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">iso_df</span><span class="p">[</span><span class="s1">'color_g_i'</span><span class="p">],</span> <span class="n">iso_df</span><span class="p">[</span><span class="s1">'mag_g'</span><span class="p">]);</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<img alt="_images/06_photo_54_0.png" src="_images/06_photo_54_0.png" />
|
||
</div>
|
||
</div>
|
||
<p>In the bottom half of the figure, the isochrone passes through the overdense region where the stars are likely to belong to GD-1.</p>
|
||
<p>In the top half, the isochrone passes through other regions where the stars have higher magnitude and metallicity than we expect for stars in GD-1.</p>
|
||
<p>So we’ll select the part of the isochrone that lies in the overdense region.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">g_mask</span></code> is a Boolean Series that is <code class="docutils literal notranslate"><span class="pre">True</span></code> where <code class="docutils literal notranslate"><span class="pre">g</span></code> is between 18.0 and 21.5.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g</span> <span class="o">=</span> <span class="n">iso_df</span><span class="p">[</span><span class="s1">'mag_g'</span><span class="p">]</span>
|
||
|
||
<span class="n">g_mask</span> <span class="o">=</span> <span class="p">(</span><span class="n">g</span> <span class="o">></span> <span class="mf">18.0</span><span class="p">)</span> <span class="o">&</span> <span class="p">(</span><span class="n">g</span> <span class="o"><</span> <span class="mf">21.5</span><span class="p">)</span>
|
||
<span class="n">g_mask</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>117
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>We can use it to select the corresponding rows in <code class="docutils literal notranslate"><span class="pre">iso_df</span></code>:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">iso_masked</span> <span class="o">=</span> <span class="n">iso_df</span><span class="p">[</span><span class="n">g_mask</span><span class="p">]</span>
|
||
<span class="n">iso_masked</span><span class="o">.</span><span class="n">head</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_html"><div>
|
||
<style scoped>
|
||
.dataframe tbody tr th:only-of-type {
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.dataframe tbody tr th {
|
||
vertical-align: top;
|
||
}
|
||
|
||
.dataframe thead th {
|
||
text-align: right;
|
||
}
|
||
</style>
|
||
<table border="1" class="dataframe">
|
||
<thead>
|
||
<tr style="text-align: right;">
|
||
<th></th>
|
||
<th>mag_g</th>
|
||
<th>color_g_i</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<th>94</th>
|
||
<td>21.411746</td>
|
||
<td>0.692171</td>
|
||
</tr>
|
||
<tr>
|
||
<th>95</th>
|
||
<td>21.322466</td>
|
||
<td>0.670238</td>
|
||
</tr>
|
||
<tr>
|
||
<th>96</th>
|
||
<td>21.233380</td>
|
||
<td>0.648449</td>
|
||
</tr>
|
||
<tr>
|
||
<th>97</th>
|
||
<td>21.144427</td>
|
||
<td>0.626924</td>
|
||
</tr>
|
||
<tr>
|
||
<th>98</th>
|
||
<td>21.054549</td>
|
||
<td>0.605461</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div></div></div>
|
||
</div>
|
||
<p>Now, to select the stars in the overdense region, we have to define a polygon that includes stars near the isochrone.</p>
|
||
<p>The original paper uses the following formulas to define the left and right boundaries.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g</span> <span class="o">=</span> <span class="n">iso_masked</span><span class="p">[</span><span class="s1">'mag_g'</span><span class="p">]</span>
|
||
<span class="n">left_color</span> <span class="o">=</span> <span class="n">iso_masked</span><span class="p">[</span><span class="s1">'color_g_i'</span><span class="p">]</span> <span class="o">-</span> <span class="mf">0.4</span> <span class="o">*</span> <span class="p">(</span><span class="n">g</span><span class="o">/</span><span class="mi">28</span><span class="p">)</span><span class="o">**</span><span class="mi">5</span>
|
||
<span class="n">right_color</span> <span class="o">=</span> <span class="n">iso_masked</span><span class="p">[</span><span class="s1">'color_g_i'</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.8</span> <span class="o">*</span> <span class="p">(</span><span class="n">g</span><span class="o">/</span><span class="mi">28</span><span class="p">)</span><span class="o">**</span><span class="mi">5</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>The intention is to define a polygon that gets wider as <code class="docutils literal notranslate"><span class="pre">g</span></code> increases, to reflect increasing uncertainty.</p>
|
||
<p>But we can do about as well with a simpler formula:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g</span> <span class="o">=</span> <span class="n">iso_masked</span><span class="p">[</span><span class="s1">'mag_g'</span><span class="p">]</span>
|
||
<span class="n">left_color</span> <span class="o">=</span> <span class="n">iso_masked</span><span class="p">[</span><span class="s1">'color_g_i'</span><span class="p">]</span> <span class="o">-</span> <span class="mf">0.06</span>
|
||
<span class="n">right_color</span> <span class="o">=</span> <span class="n">iso_masked</span><span class="p">[</span><span class="s1">'color_g_i'</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.12</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Here’s what these boundaries look like:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">plot_cmd</span><span class="p">(</span><span class="n">photo_table</span><span class="p">)</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">left_color</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'left color'</span><span class="p">)</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">right_color</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'right color'</span><span class="p">)</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">();</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<img alt="_images/06_photo_64_0.png" src="_images/06_photo_64_0.png" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="which-points-are-in-the-polygon">
|
||
<h2>Which points are in the polygon?<a class="headerlink" href="#which-points-are-in-the-polygon" title="Permalink to this headline">¶</a></h2>
|
||
<p>Matplotlib provides a <code class="docutils literal notranslate"><span class="pre">Polygon</span></code> object that we can use to check which points fall in the polygon we just constructed.</p>
|
||
<p>To make a <code class="docutils literal notranslate"><span class="pre">Polygon</span></code>, we need to assemble <code class="docutils literal notranslate"><span class="pre">g</span></code>, <code class="docutils literal notranslate"><span class="pre">left_color</span></code>, and <code class="docutils literal notranslate"><span class="pre">right_color</span></code> into a loop, so the points in <code class="docutils literal notranslate"><span class="pre">left_color</span></code> are connected to the points of <code class="docutils literal notranslate"><span class="pre">right_color</span></code> in reverse order.</p>
|
||
<p>We’ll use the following function, which takes two arrays and joins them front-to-back:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
|
||
|
||
<span class="k">def</span> <span class="nf">front_to_back</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="n">second</span><span class="p">):</span>
|
||
<span class="sd">"""Join two arrays front to back."""</span>
|
||
<span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="n">second</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">front_to_back</span></code> uses a “slice index” to reverse the elements of <code class="docutils literal notranslate"><span class="pre">second</span></code>.</p>
|
||
<p>As explained in the <a class="reference external" href="https://numpy.org/doc/stable/reference/arrays.indexing.html">NumPy documentation</a>, a slice index has three parts separated by colons:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">start</span></code>: The index of the element where the slice starts.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">stop</span></code>: The index of the element where the slice ends.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">step</span></code>: The step size between elements.</p></li>
|
||
</ul>
|
||
<p>In this example, <code class="docutils literal notranslate"><span class="pre">start</span></code> and <code class="docutils literal notranslate"><span class="pre">stop</span></code> are omitted, which means all elements are selected.</p>
|
||
<p>And <code class="docutils literal notranslate"><span class="pre">step</span></code> is <code class="docutils literal notranslate"><span class="pre">-1</span></code>, which means the elements are in reverse order.</p>
|
||
<p>We can use <code class="docutils literal notranslate"><span class="pre">front_to_back</span></code> to make a loop that includes the elements of <code class="docutils literal notranslate"><span class="pre">left_color</span></code> and <code class="docutils literal notranslate"><span class="pre">right_color</span></code>:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">color_loop</span> <span class="o">=</span> <span class="n">front_to_back</span><span class="p">(</span><span class="n">left_color</span><span class="p">,</span> <span class="n">right_color</span><span class="p">)</span>
|
||
<span class="n">color_loop</span><span class="o">.</span><span class="n">shape</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>(234,)
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>And a corresponding loop with the elements of <code class="docutils literal notranslate"><span class="pre">g</span></code> in forward and reverse order.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">mag_loop</span> <span class="o">=</span> <span class="n">front_to_back</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">g</span><span class="p">)</span>
|
||
<span class="n">mag_loop</span><span class="o">.</span><span class="n">shape</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>(234,)
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Here’s what the loop looks like.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">plot_cmd</span><span class="p">(</span><span class="n">photo_table</span><span class="p">)</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">color_loop</span><span class="p">,</span> <span class="n">mag_loop</span><span class="p">);</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<img alt="_images/06_photo_72_0.png" src="_images/06_photo_72_0.png" />
|
||
</div>
|
||
</div>
|
||
<p>To make a <code class="docutils literal notranslate"><span class="pre">Polygon</span></code>, it will be convenient to put <code class="docutils literal notranslate"><span class="pre">color_loop</span></code> and <code class="docutils literal notranslate"><span class="pre">mag_loop</span></code> into a <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code>:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">loop_df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">()</span>
|
||
<span class="n">loop_df</span><span class="p">[</span><span class="s1">'color_loop'</span><span class="p">]</span> <span class="o">=</span> <span class="n">color_loop</span>
|
||
<span class="n">loop_df</span><span class="p">[</span><span class="s1">'mag_loop'</span><span class="p">]</span> <span class="o">=</span> <span class="n">mag_loop</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we can pass <code class="docutils literal notranslate"><span class="pre">loop_df</span></code> to <code class="docutils literal notranslate"><span class="pre">Polygon</span></code>:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">matplotlib.patches</span> <span class="kn">import</span> <span class="n">Polygon</span>
|
||
|
||
<span class="n">polygon</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span><span class="n">loop_df</span><span class="p">)</span>
|
||
<span class="n">polygon</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span><matplotlib.patches.Polygon at 0x7fe98cd29400>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>The result is a <code class="docutils literal notranslate"><span class="pre">Polygon</span></code> object , which provides <code class="docutils literal notranslate"><span class="pre">contains_points</span></code>, which figures out which points are inside the polygon.</p>
|
||
<p>To test it, we’ll create a list with two points, one inside the polygon and one outside.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">points</span> <span class="o">=</span> <span class="p">[(</span><span class="mf">0.4</span><span class="p">,</span> <span class="mi">20</span><span class="p">),</span>
|
||
<span class="p">(</span><span class="mf">0.4</span><span class="p">,</span> <span class="mi">16</span><span class="p">)]</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we can make sure <code class="docutils literal notranslate"><span class="pre">contains_points</span></code> does what we expect.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">inside</span> <span class="o">=</span> <span class="n">polygon</span><span class="o">.</span><span class="n">contains_points</span><span class="p">(</span><span class="n">points</span><span class="p">)</span>
|
||
<span class="n">inside</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>array([ True, False])
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>The result is an array of Boolean values.</p>
|
||
<p>We are almost ready to select stars whose photometry data falls in this polygon. But first we need to do some data cleaning.</p>
|
||
</div>
|
||
<div class="section" id="save-the-polygon">
|
||
<h2>Save the polygon<a class="headerlink" href="#save-the-polygon" title="Permalink to this headline">¶</a></h2>
|
||
<p><a class="reference external" href="https://en.wikipedia.org/wiki/Reproducibility#Reproducible_research">Reproducibile research</a> is “the idea that … the full computational environment used to produce the results in the paper such as the code, data, etc. can be used to reproduce the results and create new work based on the research.”</p>
|
||
<p>This Jupyter notebook is an example of reproducible research because it contains all of the code needed to reproduce the results, including the database queries that download the data and and analysis.</p>
|
||
<p>In this lesson we used an isochrone to derive a polygon, which we used to select stars based on photometry.
|
||
So it is important to record the polygon as part of the data analysis pipeline.</p>
|
||
<p>Here’s how we can save it in an HDF file.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">filename</span> <span class="o">=</span> <span class="s1">'gd1_polygon.hdf5'</span>
|
||
<span class="n">loop_df</span><span class="o">.</span><span class="n">to_hdf</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'loop_df'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="reloading-the-data">
|
||
<h2>Reloading the data<a class="headerlink" href="#reloading-the-data" title="Permalink to this headline">¶</a></h2>
|
||
<p>Now we need to combine the photometry data with the list of candidate stars we identified in a previous notebook. The following cell downloads it:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="kn">from</span> <span class="nn">wget</span> <span class="kn">import</span> <span class="n">download</span>
|
||
|
||
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'gd1_candidates.hdf5'</span>
|
||
<span class="n">filepath</span> <span class="o">=</span> <span class="s1">'https://github.com/AllenDowney/AstronomicalData/raw/main/data/'</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">download</span><span class="p">(</span><span class="n">filepath</span><span class="o">+</span><span class="n">filename</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
|
||
|
||
<span class="n">candidate_df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_hdf</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'candidate_df'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">candidate_df</span></code> is the Pandas DataFrame that contains the results from Lesson 4, which selects stars likely to be in GD-1 based on proper motion. It also includes position and proper motion transformed to the ICRS frame.</p>
|
||
</div>
|
||
<div class="section" id="merging-photometry-data">
|
||
<h2>Merging photometry data<a class="headerlink" href="#merging-photometry-data" title="Permalink to this headline">¶</a></h2>
|
||
<p>Before we select stars based on photometry data, we have to solve two problems:</p>
|
||
<ol class="simple">
|
||
<li><p>We only have Pan-STARRS data for some stars in <code class="docutils literal notranslate"><span class="pre">candidate_df</span></code>.</p></li>
|
||
<li><p>Even for the stars where we have Pan-STARRS data in <code class="docutils literal notranslate"><span class="pre">photo_table</span></code>, some photometry data is missing.</p></li>
|
||
</ol>
|
||
<p>We will solve these problems in two step:</p>
|
||
<ol class="simple">
|
||
<li><p>We’ll merge the data from <code class="docutils literal notranslate"><span class="pre">candidate_df</span></code> and <code class="docutils literal notranslate"><span class="pre">photo_table</span></code> into a single Pandas <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code>.</p></li>
|
||
<li><p>We’ll use Pandas functions to deal with missing data.</p></li>
|
||
</ol>
|
||
<p><code class="docutils literal notranslate"><span class="pre">candidate_df</span></code> is already a <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code>, but <code class="docutils literal notranslate"><span class="pre">results</span></code> is an Astropy <code class="docutils literal notranslate"><span class="pre">Table</span></code>. Let’s convert it to Pandas:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">photo_df</span> <span class="o">=</span> <span class="n">photo_table</span><span class="o">.</span><span class="n">to_pandas</span><span class="p">()</span>
|
||
|
||
<span class="k">for</span> <span class="n">colname</span> <span class="ow">in</span> <span class="n">photo_df</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">colname</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>source_id
|
||
g_mean_psf_mag
|
||
i_mean_psf_mag
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we want to combine <code class="docutils literal notranslate"><span class="pre">candidate_df</span></code> and <code class="docutils literal notranslate"><span class="pre">photo_df</span></code> into a single table, using <code class="docutils literal notranslate"><span class="pre">source_id</span></code> to match up the rows.</p>
|
||
<p>You might recognize this task; it’s the same as the JOIN operation in ADQL/SQL.</p>
|
||
<p>Pandas provides a function called <code class="docutils literal notranslate"><span class="pre">merge</span></code> that does what we want. Here’s how we use it.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">merged</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">candidate_df</span><span class="p">,</span>
|
||
<span class="n">photo_df</span><span class="p">,</span>
|
||
<span class="n">on</span><span class="o">=</span><span class="s1">'source_id'</span><span class="p">)</span>
|
||
<span class="n">merged</span><span class="o">.</span><span class="n">head</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_html"><div>
|
||
<style scoped>
|
||
.dataframe tbody tr th:only-of-type {
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.dataframe tbody tr th {
|
||
vertical-align: top;
|
||
}
|
||
|
||
.dataframe thead th {
|
||
text-align: right;
|
||
}
|
||
</style>
|
||
<table border="1" class="dataframe">
|
||
<thead>
|
||
<tr style="text-align: right;">
|
||
<th></th>
|
||
<th>source_id</th>
|
||
<th>ra</th>
|
||
<th>dec</th>
|
||
<th>pmra</th>
|
||
<th>pmdec</th>
|
||
<th>parallax</th>
|
||
<th>radial_velocity</th>
|
||
<th>phi1</th>
|
||
<th>phi2</th>
|
||
<th>pm_phi1</th>
|
||
<th>pm_phi2</th>
|
||
<th>g_mean_psf_mag</th>
|
||
<th>i_mean_psf_mag</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<th>0</th>
|
||
<td>635860218726658176</td>
|
||
<td>138.518707</td>
|
||
<td>19.092339</td>
|
||
<td>-5.941679</td>
|
||
<td>-11.346409</td>
|
||
<td>0.307456</td>
|
||
<td>NaN</td>
|
||
<td>-59.247330</td>
|
||
<td>-2.016078</td>
|
||
<td>-7.527126</td>
|
||
<td>1.748779</td>
|
||
<td>17.8978</td>
|
||
<td>17.517401</td>
|
||
</tr>
|
||
<tr>
|
||
<th>1</th>
|
||
<td>635674126383965568</td>
|
||
<td>138.842874</td>
|
||
<td>19.031798</td>
|
||
<td>-3.897001</td>
|
||
<td>-12.702780</td>
|
||
<td>0.779463</td>
|
||
<td>NaN</td>
|
||
<td>-59.133391</td>
|
||
<td>-2.306901</td>
|
||
<td>-7.560608</td>
|
||
<td>-0.741800</td>
|
||
<td>19.2873</td>
|
||
<td>17.678101</td>
|
||
</tr>
|
||
<tr>
|
||
<th>2</th>
|
||
<td>635535454774983040</td>
|
||
<td>137.837752</td>
|
||
<td>18.864007</td>
|
||
<td>-4.335041</td>
|
||
<td>-14.492309</td>
|
||
<td>0.314514</td>
|
||
<td>NaN</td>
|
||
<td>-59.785300</td>
|
||
<td>-1.594569</td>
|
||
<td>-9.357536</td>
|
||
<td>-1.218492</td>
|
||
<td>16.9238</td>
|
||
<td>16.478100</td>
|
||
</tr>
|
||
<tr>
|
||
<th>3</th>
|
||
<td>635497276810313600</td>
|
||
<td>138.044516</td>
|
||
<td>19.009471</td>
|
||
<td>-7.172931</td>
|
||
<td>-12.291499</td>
|
||
<td>0.425404</td>
|
||
<td>NaN</td>
|
||
<td>-59.557744</td>
|
||
<td>-1.682147</td>
|
||
<td>-9.000831</td>
|
||
<td>2.334407</td>
|
||
<td>19.9242</td>
|
||
<td>18.334000</td>
|
||
</tr>
|
||
<tr>
|
||
<th>4</th>
|
||
<td>635614168640132864</td>
|
||
<td>139.592197</td>
|
||
<td>18.807956</td>
|
||
<td>-3.309603</td>
|
||
<td>-13.708905</td>
|
||
<td>0.583382</td>
|
||
<td>NaN</td>
|
||
<td>-58.938113</td>
|
||
<td>-3.024192</td>
|
||
<td>-8.062762</td>
|
||
<td>-1.869082</td>
|
||
<td>16.1516</td>
|
||
<td>14.666300</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div></div></div>
|
||
</div>
|
||
<p>The first argument is the “left” table, the second argument is the “right” table, and the keyword argument <code class="docutils literal notranslate"><span class="pre">on='source_id'</span></code> specifies a column to use to match up the rows.</p>
|
||
<p>The result is a <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code> that contains the same number of rows as <code class="docutils literal notranslate"><span class="pre">photo_df</span></code>.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="nb">len</span><span class="p">(</span><span class="n">candidate_df</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">photo_df</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">merged</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>(7346, 3724, 3724)
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>And it contains all columns from both tables.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">colname</span> <span class="ow">in</span> <span class="n">merged</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">colname</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>source_id
|
||
ra
|
||
dec
|
||
pmra
|
||
pmdec
|
||
parallax
|
||
radial_velocity
|
||
phi1
|
||
phi2
|
||
pm_phi1
|
||
pm_phi2
|
||
g_mean_psf_mag
|
||
i_mean_psf_mag
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><strong>Detail</strong> You might notice that Pandas also provides a function called <code class="docutils literal notranslate"><span class="pre">join</span></code>; it does almost the same thing, but the interface is slightly different. We think <code class="docutils literal notranslate"><span class="pre">merge</span></code> is a little easier to use, so that’s what we chose. It’s also more consistent with JOIN in SQL, so if you learn how to use <code class="docutils literal notranslate"><span class="pre">pd.merge</span></code>, you are also learning how to use SQL JOIN.</p>
|
||
<p>Also, someone might ask why we have to use Pandas to do this join; why didn’t we do it in ADQL. The answer is that we could have done that, but since we already have the data we need, we should probably do the computation locally rather than make another round trip to the Gaia server.</p>
|
||
</div>
|
||
<div class="section" id="selecting-based-on-photometry">
|
||
<h2>Selecting based on photometry<a class="headerlink" href="#selecting-based-on-photometry" title="Permalink to this headline">¶</a></h2>
|
||
<p>Now let’s see how many of these points are inside the polygon we chose.</p>
|
||
<p>We’ll put color and magnitude data from <code class="docutils literal notranslate"><span class="pre">merged</span></code> into a new <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code>:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">points</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">()</span>
|
||
|
||
<span class="n">points</span><span class="p">[</span><span class="s1">'color'</span><span class="p">]</span> <span class="o">=</span> <span class="n">merged</span><span class="p">[</span><span class="s1">'g_mean_psf_mag'</span><span class="p">]</span> <span class="o">-</span> <span class="n">merged</span><span class="p">[</span><span class="s1">'i_mean_psf_mag'</span><span class="p">]</span>
|
||
<span class="n">points</span><span class="p">[</span><span class="s1">'mag'</span><span class="p">]</span> <span class="o">=</span> <span class="n">merged</span><span class="p">[</span><span class="s1">'g_mean_psf_mag'</span><span class="p">]</span>
|
||
|
||
<span class="n">points</span><span class="o">.</span><span class="n">head</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_html"><div>
|
||
<style scoped>
|
||
.dataframe tbody tr th:only-of-type {
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.dataframe tbody tr th {
|
||
vertical-align: top;
|
||
}
|
||
|
||
.dataframe thead th {
|
||
text-align: right;
|
||
}
|
||
</style>
|
||
<table border="1" class="dataframe">
|
||
<thead>
|
||
<tr style="text-align: right;">
|
||
<th></th>
|
||
<th>color</th>
|
||
<th>mag</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<th>0</th>
|
||
<td>0.3804</td>
|
||
<td>17.8978</td>
|
||
</tr>
|
||
<tr>
|
||
<th>1</th>
|
||
<td>1.6092</td>
|
||
<td>19.2873</td>
|
||
</tr>
|
||
<tr>
|
||
<th>2</th>
|
||
<td>0.4457</td>
|
||
<td>16.9238</td>
|
||
</tr>
|
||
<tr>
|
||
<th>3</th>
|
||
<td>1.5902</td>
|
||
<td>19.9242</td>
|
||
</tr>
|
||
<tr>
|
||
<th>4</th>
|
||
<td>1.4853</td>
|
||
<td>16.1516</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div></div></div>
|
||
</div>
|
||
<p>Which we can pass to <code class="docutils literal notranslate"><span class="pre">contains_points</span></code>:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">inside</span> <span class="o">=</span> <span class="n">polygon</span><span class="o">.</span><span class="n">contains_points</span><span class="p">(</span><span class="n">points</span><span class="p">)</span>
|
||
<span class="n">inside</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>array([False, False, False, ..., False, False, False])
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>The result is a Boolean array. We can use <code class="docutils literal notranslate"><span class="pre">sum</span></code> to see how many stars fall in the polygon.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">inside</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>454
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Now we can use <code class="docutils literal notranslate"><span class="pre">inside</span></code> as a mask to select stars that fall inside the polygon.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">selected2</span> <span class="o">=</span> <span class="n">merged</span><span class="p">[</span><span class="n">inside</span><span class="p">]</span>
|
||
<span class="n">points2</span> <span class="o">=</span> <span class="n">points</span><span class="p">[</span><span class="n">inside</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Let’s make a color-magnitude plot one more time, highlighting the selected stars with green markers.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">plot_cmd</span><span class="p">(</span><span class="n">photo_table</span><span class="p">)</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">color_g_i</span><span class="p">,</span> <span class="n">mag_g</span><span class="p">)</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">color_loop</span><span class="p">,</span> <span class="n">mag_loop</span><span class="p">)</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">points2</span><span class="p">[</span><span class="s1">'color'</span><span class="p">],</span> <span class="n">points2</span><span class="p">[</span><span class="s1">'mag'</span><span class="p">],</span> <span class="s1">'g.'</span><span class="p">);</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<img alt="_images/06_photo_106_0.png" src="_images/06_photo_106_0.png" />
|
||
</div>
|
||
</div>
|
||
<p>It looks like the selected stars are, in fact, inside the polygon, which means they have photometry data consistent with GD-1.</p>
|
||
<p>Finally, we can plot the coordinates of the selected stars:</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mf">2.5</span><span class="p">))</span>
|
||
|
||
<span class="n">x</span> <span class="o">=</span> <span class="n">selected2</span><span class="p">[</span><span class="s1">'phi1'</span><span class="p">]</span>
|
||
<span class="n">y</span> <span class="o">=</span> <span class="n">selected2</span><span class="p">[</span><span class="s1">'phi2'</span><span class="p">]</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s1">'ko'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.9</span><span class="p">)</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">'ra (degree GD1)'</span><span class="p">)</span>
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'dec (degree GD1)'</span><span class="p">)</span>
|
||
|
||
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s1">'equal'</span><span class="p">);</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<img alt="_images/06_photo_108_0.png" src="_images/06_photo_108_0.png" />
|
||
</div>
|
||
</div>
|
||
<p>This example includes two new Matplotlib commands:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">figure</span></code> creates the figure. In previous examples, we didn’t have to use this function; the figure was created automatically. But when we call it explicitly, we can provide arguments like <code class="docutils literal notranslate"><span class="pre">figsize</span></code>, which sets the size of the figure.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">axis</span></code> with the parameter <code class="docutils literal notranslate"><span class="pre">equal</span></code> sets up the axes so a unit is the same size along the <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> axes.</p></li>
|
||
</ul>
|
||
<p>In an example like this, where <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> represent coordinates in space, equal axes ensures that the distance between points is represented accurately.</p>
|
||
</div>
|
||
<div class="section" id="write-the-data">
|
||
<h2>Write the data<a class="headerlink" href="#write-the-data" title="Permalink to this headline">¶</a></h2>
|
||
<p>Finally, let’s write the merged DataFrame to a file.</p>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">filename</span> <span class="o">=</span> <span class="s1">'gd1_merged.hdf5'</span>
|
||
|
||
<span class="n">merged</span><span class="o">.</span><span class="n">to_hdf</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'merged'</span><span class="p">)</span>
|
||
<span class="n">selected2</span><span class="o">.</span><span class="n">to_hdf</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'selected2'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="cell docutils container">
|
||
<div class="cell_input docutils container">
|
||
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="o">!</span>ls -lh gd1_merged.hdf5
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="cell_output docutils container">
|
||
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>-rw-rw-r-- 1 downey downey 1.1M Dec 29 11:51 gd1_merged.hdf5
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>If you are using Windows, <code class="docutils literal notranslate"><span class="pre">ls</span></code> might not work; in that case, try:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>!dir gd1_merged.hdf5
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="summary">
|
||
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||
<p>In this lesson, we worked with three datasets:</p>
|
||
<ul class="simple">
|
||
<li><p>The list of candidate stars from Gaia,</p></li>
|
||
<li><p>The photometry data from Pan-STARRS, and</p></li>
|
||
<li><p>An isochrone computed by MIST.</p></li>
|
||
</ul>
|
||
<p>We drew a color-magnitude diagram and used it to identify stars we think are likely to be in GD-1.</p>
|
||
<p>We used the isochrone to define a polygon that includes those stars.</p>
|
||
<p>Then we used a Pandas <code class="docutils literal notranslate"><span class="pre">merge</span></code> operation to combine Gaia and Pan-STARRS data into a single <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code>.</p>
|
||
<p>Plotting the results, we have a clear picture of GD-1, similar to Figure 1 in the original paper.</p>
|
||
</div>
|
||
<div class="section" id="best-practices">
|
||
<h2>Best practices<a class="headerlink" href="#best-practices" title="Permalink to this headline">¶</a></h2>
|
||
<ul class="simple">
|
||
<li><p>Matplotlib provides operations for working with points, polygons, and other geometric entities, so it’s not just for making figures.</p></li>
|
||
<li><p>If you want to perform something like a database <code class="docutils literal notranslate"><span class="pre">JOIN</span></code> operation with data that is in a Pandas <code class="docutils literal notranslate"><span class="pre">DataFrame</span></code>, you can use the <code class="docutils literal notranslate"><span class="pre">join</span></code> or <code class="docutils literal notranslate"><span class="pre">merge</span></code> function. In many cases, <code class="docutils literal notranslate"><span class="pre">merge</span></code> is easier to use because the arguments are more like SQL.</p></li>
|
||
<li><p>Use Matplotlib options to control the size and aspect ratio of figures to make them easier to interpret. In this example, we scaled the axes so the size of a degree is equal along both axes.</p></li>
|
||
<li><p>Be sure to record every element of the data analysis pipeline that would be needed to replicate the results.</p></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="text/x-thebe-config">
|
||
{
|
||
requestKernel: true,
|
||
binderOptions: {
|
||
repo: "binder-examples/jupyter-stacks-datascience",
|
||
ref: "master",
|
||
},
|
||
codeMirrorConfig: {
|
||
theme: "abcdef",
|
||
mode: "python"
|
||
},
|
||
kernelOptions: {
|
||
kernelName: "python3",
|
||
path: "./."
|
||
},
|
||
predefinedOutput: true
|
||
}
|
||
</script>
|
||
<script>kernelName = 'python3'</script>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class='prev-next-bottom'>
|
||
|
||
<a class='left-prev' id="prev-link" href="05_join.html" title="previous page">Joining Tables</a>
|
||
<a class='right-next' id="next-link" href="07_plot.html" title="next page">Visualization</a>
|
||
|
||
</div>
|
||
<footer class="footer mt-5 mt-md-0">
|
||
<div class="container">
|
||
<p>
|
||
|
||
By Allen B. Downey<br/>
|
||
|
||
© Copyright 2020.<br/>
|
||
</p>
|
||
</div>
|
||
</footer>
|
||
</main>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<script src="_static/js/index.30270b6e4c972e43c488.js"></script>
|
||
|
||
|
||
|
||
</body>
|
||
</html> |