File: visualization-tools.py

package info (click to toggle)
spectral-cube 0.6.6-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,136 kB
  • sloc: python: 13,236; makefile: 154
file content (146 lines) | stat: -rw-r--r-- 5,262 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import os
import numpy as np
from .utils import ProgressBar

def check_ffmpeg(ffmpeg_cmd):
    returncode = os.system(f'{ffmpeg_cmd} > /dev/null 2&> /dev/null')
    if returncode not in (0, 256):
        raise OSError(f"{ffmpeg_cmd} not found in the executable path."
                      f"  Return code {returncode}")


def make_rgb_movie(cube, prefix, v1, v2, vmin, vmax, ffmpeg_cmd='ffmpeg'):
    """
    Make a velocity movie with red, green, and blue corresponding to
    neighboring velocity channels

    Parameters
    ----------
    cube : SpectralCube
        The cube to visualize
    prefix : str
        A prefix to prepend to the output png and movie.  For example,
        it could be rgb/sourcename_speciesname
    v1 : Quantity
        A value in spectral-axis equivalent units specifying
        the starting velocity / frequency / wavelength
    v2 : Quantity
        A value in spectral-axis equivalent units specifying
        the ending velocity / frequency / wavelength
    vmin : float
        Minimum value to display
    vmax : float
        Maximum value to display
    ffmpeg_cmd : str
        The system command for ffmpeg.  Required to make a movie
    """
    import aplpy

    check_ffmpeg(ffmpeg_cmd)

    # Create the WCS template
    F = aplpy.FITSFigure(cube[0].hdu)
    F.show_grayscale()

    # determine pixel range
    p1 = cube.closest_spectral_channel(v1)
    p2 = cube.closest_spectral_channel(v2)

    for jj, ii in enumerate(ProgressBar(range(p1, p2-1), desc='RGB: ')):
        rgb = np.array([cube[ii+2], cube[ii+1], cube[ii]]).T.swapaxes(0, 1)

        # in case you manually set min/max
        rgb[rgb > vmax] = 1
        rgb[rgb < vmin] = 0

        # this is the unsupported little bit...
        F._ax1.clear()
        F._ax1.imshow((rgb-vmin)/(vmax-vmin), extent=F._extent)

        v1_ = int(np.round(cube.spectral_axis[ii].value))
        v2_ = int(np.round(cube.spectral_axis[ii+2].value))

        # then write out the files
        F.save('{2}_v{0}to{1}.png'.format(v1_, v2_, prefix))
        # make a sorted version for use with ffmpeg
        if os.path.exists('{prefix}{0:04d}.png'.format(jj, prefix=prefix)):
            os.remove('{prefix}{0:04d}.png'.format(jj, prefix=prefix))
        os.link('{2}_v{0}to{1}.png'.format(v1_, v2_, prefix),
                '{prefix}{0:04d}.png'.format(jj, prefix=prefix))

    os.system('{ffmpeg} -r 10 -y -i {prefix}%04d.png -c:v '
              'libx264 -pix_fmt yuv420p -vf '
              '"scale=1024:768" -r 10' # "scale=1024:768,setpts=10*PTS"
              ' {prefix}_RGB_movie.mp4'.format(prefix=prefix,
                                               ffmpeg=ffmpeg_cmd))

def make_multispecies_rgb(cube_r, cube_g, cube_b, prefix, v1, v2, vmin, vmax,
                          ffmpeg_cmd='ffmpeg'):
    """

    Parameters
    ----------
    cube_r, cube_g, cube_b : SpectralCube
        The three cubes to visualize.  They should have identical spatial and
        spectral dimensions.
    prefix : str
        A prefix to prepend to the output png and movie.  For example,
        it could be rgb/sourcename_speciesname
    v1 : Quantity
        A value in spectral-axis equivalent units specifying
        the starting velocity / frequency / wavelength
    v2 : Quantity
        A value in spectral-axis equivalent units specifying
        the ending velocity / frequency / wavelength
    vmin : float
        Minimum value to display (constant for all 3 colors)
    vmax : float
        Maximum value to display (constant for all 3 colors)
    ffmpeg_cmd : str
        The system command for ffmpeg.  Required to make a movie
    """
    import aplpy

    check_ffmpeg(ffmpeg_cmd)

    # Create the WCS template
    F = aplpy.FITSFigure(cube_r[0].hdu)
    F.show_grayscale()

    assert cube_r.shape == cube_b.shape
    assert cube_g.shape == cube_b.shape

    # determine pixel range
    p1 = cube_r.closest_spectral_channel(v1)
    p2 = cube_r.closest_spectral_channel(v2)

    for jj, ii in enumerate(ProgressBar(range(p1, p2+1), desc='RGB multi: ')):
        rgb = np.array([cube_r[ii].value,
                        cube_g[ii].value,
                        cube_b[ii].value
                       ]).T.swapaxes(0, 1)

        # in case you manually set min/max
        rgb[rgb > vmax] = 1
        rgb[rgb < vmin] = 0

        # this is the unsupported little bit...
        F._ax1.clear()
        F._ax1.imshow((rgb-vmin)/(vmax-vmin), extent=F._extent)

        v1_ = int(np.round(cube_r.spectral_axis[ii].value))

        # then write out the files
        F.refresh()
        F.save('{1}_v{0}.png'.format(v1_, prefix))
        # make a sorted version for use with ffmpeg
        if os.path.exists('{prefix}{0:04d}.png'.format(jj, prefix=prefix)):
            os.remove('{prefix}{0:04d}.png'.format(jj, prefix=prefix))
        os.link('{1}_v{0}.png'.format(v1_, prefix),
                '{prefix}{0:04d}.png'.format(jj, prefix=prefix))

    os.system('{ffmpeg} -r 10 -y -i {prefix}%04d.png'
              ' -c:v libx264 -pix_fmt yuv420p -vf '
              '"scale=1024:768" -r 10' # "scale=1024:768,setpts=10*PTS"
              ' {prefix}_RGB_movie.mp4'.format(prefix=prefix,
                                               ffmpeg=ffmpeg_cmd))