|
2 | 2 | "cells": [ |
3 | 3 | { |
4 | 4 | "cell_type": "markdown", |
5 | | - "id": "refined-night", |
6 | 5 | "metadata": {}, |
7 | 6 | "source": [ |
8 | 7 | "# Extracting and Plotting Position-Velocity Diagrams\n", |
|
11 | 10 | "Adam Ginsburg, Eric Koch\n", |
12 | 11 | "\n", |
13 | 12 | "## Learning Goals\n", |
14 | | - "* Extract a position-velocity diagram from a cube using both pixel and sky coordinates using [pvextractor](https://pvextractor.readthedocs.io/en/latest/)\n", |
| 13 | + "* Extract a position-velocity diagram from a spectral cube using both pixel and sky coordinates using [pvextractor](https://pvextractor.readthedocs.io/en/latest/)\n", |
15 | 14 | "* Display the position-velocity diagram with appropriately labeled coordinates\n", |
16 | 15 | "* Display the extraction path on the plots\n", |
17 | 16 | "\n", |
18 | 17 | "## Keywords\n", |
19 | | - "cube, pv-diagram\n", |
| 18 | + "pv-diagram, spectral cube, pvextractor, radio astronomy, coordinates\n", |
20 | 19 | "\n", |
21 | 20 | "## Summary\n", |
22 | | - "In this tutorial, we will extract position-velocity (PV) diagrams from a cube and plot them.\n", |
| 21 | + "In this tutorial, we will extract position-velocity (PV) diagrams from a spectral cube and plot them.\n", |
23 | 22 | "\n", |
24 | 23 | "Position-velocity diagrams are often used in radio astronomy for analysis of rotating objects, like protostellar disks and galaxies, to measure rotation curves and determine the contained mass. They are also used in studies of atomic and molecular clouds to show where overlapping emission may point at interactions between distinct clouds. Both radio and optical position-velocity diagrams are used to study outflows, jets, and winds; in the optical, two-dimensional spectra obtained from long-slit spectrographs naturally produce the equivalent of a position-velocity diagram." |
25 | 24 | ] |
26 | 25 | }, |
27 | 26 | { |
28 | 27 | "cell_type": "markdown", |
29 | | - "id": "hungarian-ticket", |
30 | 28 | "metadata": {}, |
31 | 29 | "source": [ |
32 | 30 | "### Header material\n", |
|
37 | 35 | { |
38 | 36 | "cell_type": "code", |
39 | 37 | "execution_count": null, |
40 | | - "id": "according-administration", |
41 | 38 | "metadata": {}, |
42 | 39 | "outputs": [], |
43 | 40 | "source": [ |
|
57 | 54 | }, |
58 | 55 | { |
59 | 56 | "cell_type": "markdown", |
60 | | - "id": "meaning-musician", |
61 | 57 | "metadata": {}, |
62 | 58 | "source": [ |
63 | 59 | "Retrieve and open a cube from astropy-data:" |
|
66 | 62 | { |
67 | 63 | "cell_type": "code", |
68 | 64 | "execution_count": null, |
69 | | - "id": "separated-division", |
70 | 65 | "metadata": {}, |
71 | 66 | "outputs": [], |
72 | 67 | "source": [ |
|
76 | 71 | }, |
77 | 72 | { |
78 | 73 | "cell_type": "markdown", |
79 | | - "id": "international-entry", |
80 | 74 | "metadata": {}, |
81 | 75 | "source": [ |
82 | | - "Show single channel to find where to draw the path.\n", |
83 | | - "We use pixel units so it's easier to define the path from the pixel coords in the matplotlib viewer." |
| 76 | + "We show a single channel from the cube to visualize the data spatially.\n", |
| 77 | + "We use pixel units to start; we'll show celestial coordinates later" |
84 | 78 | ] |
85 | 79 | }, |
86 | 80 | { |
87 | 81 | "cell_type": "code", |
88 | 82 | "execution_count": null, |
89 | | - "id": "expired-judgment", |
90 | 83 | "metadata": {}, |
91 | 84 | "outputs": [], |
92 | 85 | "source": [ |
|
95 | 88 | }, |
96 | 89 | { |
97 | 90 | "cell_type": "markdown", |
98 | | - "id": "arranged-burke", |
99 | 91 | "metadata": {}, |
100 | 92 | "source": [ |
101 | 93 | "# PV Extraction from Pixel Coordinates\n", |
|
108 | 100 | { |
109 | 101 | "cell_type": "code", |
110 | 102 | "execution_count": null, |
111 | | - "id": "according-conference", |
112 | 103 | "metadata": {}, |
113 | 104 | "outputs": [], |
114 | 105 | "source": [ |
|
117 | 108 | }, |
118 | 109 | { |
119 | 110 | "cell_type": "markdown", |
120 | | - "id": "demonstrated-makeup", |
121 | 111 | "metadata": {}, |
122 | 112 | "source": [ |
123 | 113 | "Then we can overplot it on our figure, now with WCS shown. The plotting uses [WCSAxes](https://docs.astropy.org/en/stable/visualization/wcsaxes/index.html)" |
|
126 | 116 | { |
127 | 117 | "cell_type": "code", |
128 | 118 | "execution_count": null, |
129 | | - "id": "empty-variance", |
130 | 119 | "metadata": {}, |
131 | 120 | "outputs": [], |
132 | 121 | "source": [ |
|
137 | 126 | }, |
138 | 127 | { |
139 | 128 | "cell_type": "markdown", |
140 | | - "id": "peripheral-secretariat", |
141 | 129 | "metadata": {}, |
142 | 130 | "source": [ |
143 | 131 | "`spacing` gives the separation between these points in pixels; we finely sampled by picking one-pixel spacing." |
144 | 132 | ] |
145 | 133 | }, |
146 | 134 | { |
147 | 135 | "cell_type": "markdown", |
148 | | - "id": "latest-hartford", |
149 | 136 | "metadata": {}, |
150 | 137 | "source": [ |
151 | 138 | "We can then extract the pv diagram, specifying the same spacing." |
|
154 | 141 | { |
155 | 142 | "cell_type": "code", |
156 | 143 | "execution_count": null, |
157 | | - "id": "abstract-environment", |
158 | 144 | "metadata": {}, |
159 | 145 | "outputs": [], |
160 | 146 | "source": [ |
|
164 | 150 | }, |
165 | 151 | { |
166 | 152 | "cell_type": "markdown", |
167 | | - "id": "dynamic-oliver", |
168 | 153 | "metadata": {}, |
169 | 154 | "source": [ |
170 | 155 | "and plot it. `pvdiagram` is a `PrimaryHDU` object, so we need to grab the data separately from the header and convert the header to a WCS object:" |
|
173 | 158 | { |
174 | 159 | "cell_type": "code", |
175 | 160 | "execution_count": null, |
176 | | - "id": "chief-belgium", |
177 | 161 | "metadata": {}, |
178 | 162 | "outputs": [], |
179 | 163 | "source": [ |
|
188 | 172 | }, |
189 | 173 | { |
190 | 174 | "cell_type": "markdown", |
191 | | - "id": "willing-signal", |
192 | 175 | "metadata": {}, |
193 | 176 | "source": [ |
194 | 177 | "Changing units to the more commonly used km/s and more readable arcminutes can be done with [wcsaxes tools](https://docs.astropy.org/en/stable/visualization/wcsaxes/controlling_axes.html):" |
|
197 | 180 | { |
198 | 181 | "cell_type": "code", |
199 | 182 | "execution_count": null, |
200 | | - "id": "conservative-prevention", |
201 | 183 | "metadata": {}, |
202 | 184 | "outputs": [], |
203 | 185 | "source": [ |
|
219 | 201 | }, |
220 | 202 | { |
221 | 203 | "cell_type": "markdown", |
222 | | - "id": "acceptable-spokesman", |
223 | 204 | "metadata": {}, |
224 | 205 | "source": [ |
225 | 206 | "We can put all this together:" |
|
228 | 209 | { |
229 | 210 | "cell_type": "code", |
230 | 211 | "execution_count": null, |
231 | | - "id": "immediate-hurricane", |
232 | 212 | "metadata": {}, |
233 | 213 | "outputs": [], |
234 | 214 | "source": [ |
|
241 | 221 | { |
242 | 222 | "cell_type": "code", |
243 | 223 | "execution_count": null, |
244 | | - "id": "bottom-nashville", |
245 | 224 | "metadata": {}, |
246 | 225 | "outputs": [], |
247 | 226 | "source": [ |
|
266 | 245 | }, |
267 | 246 | { |
268 | 247 | "cell_type": "markdown", |
269 | | - "id": "cheap-greek", |
270 | 248 | "metadata": {}, |
271 | 249 | "source": [ |
272 | 250 | "# PV Extraction from Sky Coordinates" |
273 | 251 | ] |
274 | 252 | }, |
275 | 253 | { |
276 | 254 | "cell_type": "markdown", |
277 | | - "id": "awful-tournament", |
278 | 255 | "metadata": {}, |
279 | 256 | "source": [ |
280 | 257 | "We can also make paths using celestial coordinates by passing coordinates defined in an`~astropy.coordinates.SkyCoord` object to `~pvextractor.Path`." |
|
283 | 260 | { |
284 | 261 | "cell_type": "code", |
285 | 262 | "execution_count": null, |
286 | | - "id": "northern-event", |
287 | 263 | "metadata": {}, |
288 | 264 | "outputs": [], |
289 | 265 | "source": [ |
|
293 | 269 | { |
294 | 270 | "cell_type": "code", |
295 | 271 | "execution_count": null, |
296 | | - "id": "descending-charles", |
297 | 272 | "metadata": {}, |
298 | 273 | "outputs": [], |
299 | 274 | "source": [ |
|
302 | 277 | }, |
303 | 278 | { |
304 | 279 | "cell_type": "markdown", |
305 | | - "id": "printable-sierra", |
306 | 280 | "metadata": {}, |
307 | 281 | "source": [ |
308 | 282 | "We can plot again; the coordinates will be automatically determined" |
|
311 | 285 | { |
312 | 286 | "cell_type": "code", |
313 | 287 | "execution_count": null, |
314 | | - "id": "obvious-switzerland", |
315 | 288 | "metadata": {}, |
316 | 289 | "outputs": [], |
317 | 290 | "source": [ |
|
323 | 296 | { |
324 | 297 | "cell_type": "code", |
325 | 298 | "execution_count": null, |
326 | | - "id": "phantom-juice", |
327 | 299 | "metadata": {}, |
328 | 300 | "outputs": [], |
329 | 301 | "source": [ |
|
334 | 306 | { |
335 | 307 | "cell_type": "code", |
336 | 308 | "execution_count": null, |
337 | | - "id": "ignored-utility", |
338 | 309 | "metadata": {}, |
339 | 310 | "outputs": [], |
340 | 311 | "source": [ |
|
359 | 330 | }, |
360 | 331 | { |
361 | 332 | "cell_type": "markdown", |
362 | | - "id": "solved-commander", |
363 | 333 | "metadata": {}, |
364 | 334 | "source": [ |
365 | 335 | "We can also change the aspect ratio of the PV diagram:" |
|
368 | 338 | { |
369 | 339 | "cell_type": "code", |
370 | 340 | "execution_count": null, |
371 | | - "id": "roman-surprise", |
372 | 341 | "metadata": {}, |
373 | 342 | "outputs": [], |
374 | 343 | "source": [ |
|
394 | 363 | }, |
395 | 364 | { |
396 | 365 | "cell_type": "markdown", |
397 | | - "id": "applicable-theta", |
398 | 366 | "metadata": {}, |
399 | 367 | "source": [ |
400 | 368 | "## PV Extraction with Spatial Averaging" |
401 | 369 | ] |
402 | 370 | }, |
403 | 371 | { |
404 | 372 | "cell_type": "markdown", |
405 | | - "id": "unauthorized-emphasis", |
406 | 373 | "metadata": {}, |
407 | 374 | "source": [ |
408 | 375 | "`~pvextractor.Path` allows you to specify a `width` to average over, which specifies a spatial range around the path to average over:" |
|
411 | 378 | { |
412 | 379 | "cell_type": "code", |
413 | 380 | "execution_count": null, |
414 | | - "id": "operational-mexico", |
415 | 381 | "metadata": {}, |
416 | 382 | "outputs": [], |
417 | 383 | "source": [ |
|
421 | 387 | { |
422 | 388 | "cell_type": "code", |
423 | 389 | "execution_count": null, |
424 | | - "id": "pressed-opportunity", |
425 | 390 | "metadata": {}, |
426 | 391 | "outputs": [], |
427 | 392 | "source": [ |
|
430 | 395 | }, |
431 | 396 | { |
432 | 397 | "cell_type": "markdown", |
433 | | - "id": "confidential-event", |
434 | 398 | "metadata": {}, |
435 | 399 | "source": [ |
436 | 400 | "We can plot this path as a set of patches to show where we averaged. The default spacing is 1 pixel,so we plot 1-pixel chunks." |
|
439 | 403 | { |
440 | 404 | "cell_type": "code", |
441 | 405 | "execution_count": null, |
442 | | - "id": "optical-attendance", |
443 | 406 | "metadata": {}, |
444 | 407 | "outputs": [], |
445 | 408 | "source": [ |
|
471 | 434 | }, |
472 | 435 | { |
473 | 436 | "cell_type": "markdown", |
474 | | - "id": "killing-customer", |
475 | 437 | "metadata": {}, |
476 | 438 | "source": [ |
477 | 439 | "We can also have more widely spaced chunks.\n", |
|
482 | 444 | { |
483 | 445 | "cell_type": "code", |
484 | 446 | "execution_count": null, |
485 | | - "id": "selected-virgin", |
486 | 447 | "metadata": {}, |
487 | 448 | "outputs": [], |
488 | 449 | "source": [ |
|
514 | 475 | }, |
515 | 476 | { |
516 | 477 | "cell_type": "markdown", |
517 | | - "id": "disabled-constraint", |
518 | 478 | "metadata": {}, |
519 | 479 | "source": [ |
520 | 480 | "## Saving\n", |
|
525 | 485 | { |
526 | 486 | "cell_type": "code", |
527 | 487 | "execution_count": null, |
528 | | - "id": "nearby-daughter", |
529 | 488 | "metadata": {}, |
530 | 489 | "outputs": [], |
531 | 490 | "source": [ |
|
535 | 494 | ], |
536 | 495 | "metadata": { |
537 | 496 | "kernelspec": { |
538 | | - "display_name": "python", |
| 497 | + "display_name": "Python 3", |
539 | 498 | "language": "python", |
540 | 499 | "name": "python3" |
541 | 500 | }, |
|
549 | 508 | "name": "python", |
550 | 509 | "nbconvert_exporter": "python", |
551 | 510 | "pygments_lexer": "ipython3", |
552 | | - "version": "3.9.7" |
| 511 | + "version": "3.7.3" |
553 | 512 | } |
554 | 513 | }, |
555 | 514 | "nbformat": 4, |
|
0 commit comments