# Buggy code
def calc_stats_cat(
    srs: dd.Series,
) -> Tuple[Dict[str, str], Dict[str, str], Dict[str, str], Dict[str, str]]:
    """
    Calculate stats from a categorical column
    Parameters
    ----------
    srs
        a categorical column
    Returns
    -------
    Dict[str, str]
        Dictionary that contains Overview
    """
    # overview stats
    size = len(srs)  # include nan
    count = srs.count()  # exclude nan
    uniq_count = srs.nunique()
    overview_dict = {
        "Distinct Count": uniq_count,
        "Unique (%)": uniq_count / count,
        "Missing": size - count,
        "Missing (%)": 1 - (count / size),
        "Memory Size": srs.memory_usage(),
    }
    srs = srs.astype("str")
    # length stats
    length = srs.str.len()
    length_dict = {
        "mean": length.mean(),
        "median": length.median(),
        "minimum": length.min(),
        "maximum": length.max(),
    }
    # quantile stats
    max_lbl_len = 13
    quantile_dict = {}
    for label, centile in zip(
        (
            "Minimum",
            "5-th Percentile",
            "Q1",
            "Median",
            "Q3",
            "95-th Percentile",
            "Maximum",
        ),
        (0, 0.05, 0.25, 0.5, 0.75, 0.95, 1),
    ):
        if round(len(srs) * centile) == 0:
            element = srs[round(len(srs) * centile)]
            if len(element) > max_lbl_len:
                quantile_dict[label] = element[0 : max_lbl_len - 2] + "..."
            else:
                quantile_dict[label] = element
        else:
            element = srs[round(len(srs) * centile) - 1]
            if len(element) > max_lbl_len:
                quantile_dict[label] = element[0 : max_lbl_len - 2] + "..."
            else:
                quantile_dict[label] = element

    # letter stats
    letter_dict = {
        "count": srs.str.count(r"[a-zA-Z]").sum(),
        "Lowercase Letter": srs.str.count(r"[a-z]").sum(),
        "Space Separator": srs.str.count(r"[ ]").sum(),
        "Uppercase Letter": srs.str.count(r"[A-Z]").sum(),
        "Dash Punctuation": srs.str.count(r"[-]").sum(),
        "Decimal Number": srs.str.count(r"[0-9]").sum(),
    }
    return (
        {k: _format_values(k, v) for k, v in overview_dict.items()},
        {k: _format_values(k, v) for k, v in length_dict.items()},
        quantile_dict,
        {k: _format_values(k, v) for k, v in letter_dict.items()},
    )


# Traceback (ValueError)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-43-f8a3846cc211> in <module>
1 df = pd.DataFrame({"A": ["01-02", "01-02"]})
----> 2 plot(df, "A", top_words=2)

~/dataprep/dataprep/eda/basic/__init__.py in plot(df, x, y, z, bins, ngroups, largest, nsubgroups, timeunit, agg, sample_size, value_range, yscale, tile_size, dtype, top_words, stopword, lemmatize, stem)
163         stem=stem,
164     )
--> 165     figure = render(intermediate, yscale=yscale, tile_size=tile_size)
166
167     return Report(figure)

~/dataprep/dataprep/eda/basic/render.py in render(itmdt, yscale, tile_size, plot_width_sml, plot_height_sml, plot_width_lrg, plot_height_lrg, plot_width_wide)
1684         visual_elem = render_basic(itmdt, yscale, plot_width_sml, plot_height_sml)
1685     elif itmdt.visual_type == "categorical_column":
-> 1686         visual_elem = render_cat(itmdt, yscale, plot_width_lrg, plot_height_lrg)
1687     elif itmdt.visual_type == "numerical_column":
1688         visual_elem = render_num(itmdt, yscale, plot_width_lrg, plot_height_lrg)

~/dataprep/dataprep/eda/basic/render.py in render_cat(itmdt, yscale, plot_width, plot_height)
1393     tabs.append(pie_viz(df, itmdt["col"], miss_pct, plot_width, plot_height))
1394     freq_tuple = itmdt["word_cloud"]
-> 1395     word_cloud = wordcloud_viz(freq_tuple, plot_width, plot_height)
1396     tabs.append(Panel(child=row(word_cloud), title="word cloud"))
1397     wordfreq = wordfreq_viz(freq_tuple, plot_width, plot_height, True)

~/dataprep/dataprep/eda/basic/render.py in wordcloud_viz(freq_tuple, plot_width, plot_height)
228     )
229     top_freq = freq_tuple[1]
--> 230     wordcloud.generate_from_frequencies(dict(top_freq))
231     wcimg = wordcloud.to_array().astype(np.uint8)
232     alpha = np.full([*wcimg.shape[:2], 1], 255, dtype=np.uint8)

~/dataprep/.venv/lib/python3.8/site-packages/wordcloud/wordcloud.py in generate_from_frequencies(self, frequencies, max_font_size)
401         frequencies = sorted(frequencies.items(), key=itemgetter(1), reverse=True)
402         if len(frequencies) <= 0:
--> 403             raise ValueError("We need at least 1 word to plot a word cloud, "
404                              "got %d." % len(frequencies))
405         frequencies = frequencies[:self.max_words]

ValueError: We need at least 1 word to plot a word cloud, got 0.

# Fixed code
def calc_stats_cat(
    srs: dd.Series,
) -> Tuple[Dict[str, str], Dict[str, str], Dict[str, str], Dict[str, str]]:
    """
    Calculate stats from a categorical column
    Parameters
    ----------
    srs
        a categorical column
    Returns
    -------
    Dict[str, str]
        Dictionary that contains Overview
    """
    # overview stats
    size = len(srs)  # include nan
    count = srs.count()  # exclude nan
    uniq_count = srs.nunique()
    overview_dict = {
        "Distinct Count": uniq_count,
        "Unique (%)": uniq_count / count,
        "Missing": size - count,
        "Missing (%)": 1 - (count / size),
        "Memory Size": srs.memory_usage(),
    }
    srs = srs.astype("str")
    # quantile stats
    max_lbl_len = 25
    quantile_dict = {}
    for label, centile in zip(
        (
            "1st Row",
            "25% Row",
            "50% Row",
            "75% Row",
            "Last Row",
        ),
        (0, 0.25, 0.5, 0.75, 1),
    ):
        if round(len(srs) * centile) == 0:
            element = srs[round(len(srs) * centile)]
            if len(element) > max_lbl_len:
                quantile_dict[label] = element[0 : max_lbl_len - 2] + "..."
            else:
                quantile_dict[label] = element
        else:
            element = srs[round(len(srs) * centile) - 1]
            if len(element) > max_lbl_len:
                quantile_dict[label] = element[0 : max_lbl_len - 2] + "..."
            else:
                quantile_dict[label] = element

    srs = srs.dropna()
    # length stats
    length = srs.str.len()
    length_dict = {
        "Mean": length.mean(),
        "Standard Deviation": length.std(),
        "Median": length.median(),
        "Minimum": length.min(),
        "Maximum": length.max(),
    }
    # letter stats
    letter_dict = {
        "Count": srs.str.count(r"[a-zA-Z]").sum(),
        "Lowercase Letter": srs.str.count(r"[a-z]").sum(),
        "Space Separator": srs.str.count(r"[ ]").sum(),
        "Uppercase Letter": srs.str.count(r"[A-Z]").sum(),
        "Dash Punctuation": srs.str.count(r"[-]").sum(),
        "Decimal Number": srs.str.count(r"[0-9]").sum(),
    }
    return (
        {k: _format_values(k, v) for k, v in overview_dict.items()},
        {k: _format_values(k, v) for k, v in length_dict.items()},
        quantile_dict,
        {k: _format_values(k, v) for k, v in letter_dict.items()},
    )