# Buggy code
def missing_spectrum(df: dd.DataFrame, bins: int, ncols: int) -> Intermediate:
    """
    Calculate a missing spectrum for each column
    """
    # pylint: disable=too-many-locals
    num_bins = min(bins, len(df) - 1)

    df = df.iloc[:, :ncols]
    cols = df.columns[:ncols]
    ncols = len(cols)
    nrows = len(df)
    chunk_size = len(df) // num_bins
    data = df.isnull().to_dask_array()
    data.compute_chunk_sizes()
    data = data.rechunk((chunk_size, None))

    (notnull_counts,) = dd.compute(data.sum(axis=0) / data.shape[0])
    missing_percent = {col: notnull_counts[idx] for idx, col in enumerate(cols)}

    missing_percs = data.map_blocks(missing_perc_blockwise, dtype=float).compute()
    locs0 = np.arange(len(missing_percs)) * chunk_size
    locs1 = np.minimum(locs0 + chunk_size, nrows)
    locs_middle = locs0 + chunk_size / 2

    df = pd.DataFrame(
        {
            "column": np.repeat(cols.values, len(missing_percs)),
            "location": np.tile(locs_middle, ncols),
            "missing_rate": missing_percs.T.ravel(),
            "loc_start": np.tile(locs0, ncols),
            "loc_end": np.tile(locs1, ncols),
        }
    )
    return Intermediate(
        data=df,
        missing_percent=missing_percent,
        visual_type="missing_spectrum",
    )


# Traceback (IndexError)
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-50-47c276e219b8> in <module>
----> 1 plot_missing(X)

~\miniconda3\lib\site-packages\dataprep\eda\missing\__init__.py in plot_missing(df, x, y, bins, ncols, ndist_sample, dtype)
63         df, x, y, dtype=dtype, bins=bins, ncols=ncols, ndist_sample=ndist_sample
64     )
---> 65     fig = render_missing(itmdt)
66     return Report(fig)

~\miniconda3\lib\site-packages\dataprep\eda\missing\render.py in render_missing(itmdt, plot_width, plot_height, palette)
61     elif itmdt.visual_type == "missing_spectrum_heatmap":
62         return render_missing_heatmap(
---> 63             itmdt, plot_width, plot_height, palette or BIPALETTE
64         )
65

~\miniconda3\lib\site-packages\dataprep\eda\missing\render.py in render_missing_heatmap(itmdt, plot_width, plot_height, palette)
287     pan_spectrum = Panel(child=fig_spectrum, title="Spectrum")
288     tabs.append(pan_spectrum)
--> 289     fig_heatmap = render_heatmaps_tab(itmdt, plot_width, plot_height, palette)
290     pan_heatmap = Panel(child=fig_heatmap, title="Heatmap")
291     tabs.append(pan_heatmap)

~\miniconda3\lib\site-packages\dataprep\eda\missing\render.py in render_heatmaps_tab(itmdt, plot_width, plot_height, palette)
307         np.triu(np.ones(df.shape)).astype(np.bool)  # pylint: disable=no-member
308     ).T
--> 309     df = df.unstack().reset_index(name="correlation")
310     df = df.rename(columns={"level_0": "x", "level_1": "y"})
311     df = df[df["x"] != df["y"]]

~\miniconda3\lib\site-packages\pandas\core\frame.py in unstack(self, level, fill_value)
6384         from pandas.core.reshape.reshape import unstack
6385
-> 6386         return unstack(self, level, fill_value)
6387
6388     _shared_docs[

~\miniconda3\lib\site-packages\pandas\core\reshape\reshape.py in unstack(obj, level, fill_value)
408             return _unstack_frame(obj, level, fill_value=fill_value)
409         else:
--> 410             return obj.T.stack(dropna=False)
411     else:
412         if is_extension_array_dtype(obj.dtype):

~\miniconda3\lib\site-packages\pandas\core\frame.py in stack(self, level, dropna)
6249             return stack_multiple(self, level, dropna=dropna)
6250         else:
-> 6251             return stack(self, level, dropna=dropna)
6252
6253     def explode(self, column: Union[str, Tuple]) -> "DataFrame":

~\miniconda3\lib\site-packages\pandas\core\reshape\reshape.py in stack(frame, level, dropna)
541         # we concatenate instead.
542         dtypes = list(frame.dtypes.values)
--> 543         dtype = dtypes[0]
544
545         if is_extension_array_dtype(dtype):

IndexError: list index out of range

# Fixed code
def missing_spectrum(
    df: dd.DataFrame, bins: int, ncols: int
) -> Tuple[dd.DataFrame, dd.DataFrame]:
    """
    Calculate a missing spectrum for each column
    """
    # pylint: disable=too-many-locals
    num_bins = min(bins, len(df) - 1)

    df = df.iloc[:, :ncols]
    cols = df.columns[:ncols]
    ncols = len(cols)
    nrows = len(df)
    chunk_size = len(df) // num_bins
    data = df.isnull().to_dask_array()
    data.compute_chunk_sizes()
    data = data.rechunk((chunk_size, None))

    notnull_counts = data.sum(axis=0) / data.shape[0]
    total_missing_percs = {col: notnull_counts[idx] for idx, col in enumerate(cols)}

    spectrum_missing_percs = data.map_blocks(
        missing_perc_blockwise, chunks=(1, data.shape[1]), dtype=float
    )
    nsegments = len(spectrum_missing_percs)

    locs0 = da.arange(nsegments) * chunk_size
    locs1 = da.minimum(locs0 + chunk_size, nrows)
    locs_middle = locs0 + chunk_size / 2

    df = dd.from_dask_array(
        da.repeat(da.from_array(cols.values, (1,)), nsegments),
        columns=["column"],
    )

    df = df.assign(
        location=da.tile(locs_middle, ncols),
        missing_rate=spectrum_missing_percs.T.ravel(),
        loc_start=da.tile(locs0, ncols),
        loc_end=da.tile(locs1, ncols),
    )

    return df, total_missing_percs