//  [python]
def visualize_download_time(allInfos):
    data = {
        'segment': [],
        'download_time': [],
        'config': [],
        'config_linebreak': [],
    }

    for conf, infos in allInfos.items():
        config = fixname(f"{conf.scheduler} - {conf.fec}".upper())
        config_linebreak = fixname(f"{conf.scheduler}\n{conf.fec}".upper())
        for info in infos:
            mean = get_mean(info.segment_download_times)
            stddev = get_mean(info.segment_download_times)

            for i, download_time in enumerate(info.segment_download_times):
                if get_z_score(download_time, mean, stddev) < 1:
                    data['segment'].append(i)
                    data['download_time'].append(download_time)
                    data['config'].append(config)
                    data['config_linebreak'].append(config_linebreak)

    def lineplot():
        plt.figure(figsize=(15,8))
        sns.set(style="ticks", palette="pastel")

        df = pandas.DataFrame.from_dict(data)
        ax = sns.lineplot(data=df, x='segment', y='download_time', hue='config')

        ax.set(xlabel='Segment Number', ylabel='Download Time (s)')
        ax.ticklabel_format(style='plain')
        plt.savefig("vis-dload-time." + FORMAT)

    def boxplot():
        plt.figure(figsize=FIGSIZE.WIDE_M)
        sns.set(style="whitegrid", palette=PALETTE_9)

        df = pandas.DataFrame.from_dict(data)
        ax = sns.boxplot(data=df, x='config_linebreak', y='download_time', showfliers=False)
        sns.despine(offset=10, trim=True)

        ax.set(xlabel='', ylabel='Segment Download Time')
        plt.savefig("vis-dload-dist." + FORMAT)

    def cdf(complementary=False):
        plt.figure(figsize=FIGSIZE.BOX_M)
        sns.set(style="ticks", palette=PALETTE_5)

        data = {}
        configs = list()
        for conf, infos in allInfos.items():
            key = f"{conf.scheduler} - {conf.fec}".upper()
            configs.append(key)

            data[key] = []
            for info in infos:
                data[key] += filter(lambda x: x < 0.4, info.segment_download_times)

            data[key] = z_filter(data[key], 1)

        # fill missing recordings with NaNs
        maxlen = max([len(data[k]) for k in data.keys()])
        for k, v in data.items():
            data[k] = v + [float('nan')] * (maxlen - (len(v)))

        patches = []
        for i, config in enumerate(configs):
            color = sns.color_palette()[i]
            linestyle = "-"

            if "S-IOD" in config:
                color = "orange"
                linestyle = "-"
            elif "IOD" in config:
                color = "goldenrod"
                linestyle = "--"
            elif "S-EDPF" in config:
                color = "royalblue"
                linestyle = "-"
            elif "NONE" in config:
                color = "black"
                linestyle = ":"
            elif "LL" in config:
                color = "black"
                linestyle = "-"

            kwargs = {
                "cumulative": True,
                "color": color,
                "linestyle": linestyle,
            }

            #ax = sns.distplot(data[config], hist=False, kde_kws=kwargs)
            ax = sns.ecdfplot(data[config], complementary=complementary,
                    color=color, linestyle=linestyle)

            patches.append(Line2D([0], [0],
                color=color,
                label=fixname(config),
                linestyle=linestyle,
                lw=2,
            ))

            ax.set(xlabel='Download Time (s)', ylabel='')

        plt.legend(handles=patches)
        if complementary:
            plt.savefig("vis-dload-ccdf." + FORMAT)
        else:
            plt.savefig("vis-dload-cdf." + FORMAT)


    #lineplot()
    boxplot()
    cdf(False)
    cdf(True)