Helper to map a function over a sequence of inputs, sequentially, with progress meter.
    :param client: IPython.parallel.Client instance
    :param task: Function
    :param args: Must be a list of tuples of arguments that the task function will be mapped onto.
                 If the function takes a single argument, it still must be a 1-tuple.
    :param message: String for progress bar
    :param batchsize: Jobs are shipped in batches of this size. Higher numbers mean less network traffic,
                      but longer execution time per job.
    :return: IPython.parallel.AsyncMapResult

def sequential_map(task, args, message, nargs=None):
    """
    Helper to map a function over a sequence of inputs, sequentially, with progress meter.
    :param client: IPython.parallel.Client instance
    :param task: Function
    :param args: Must be a list of tuples of arguments that the task function will be mapped onto.
                 If the function takes a single argument, it still must be a 1-tuple.
    :param message: String for progress bar
    :param batchsize: Jobs are shipped in batches of this size. Higher numbers mean less network traffic,
                      but longer execution time per job.
    :return: IPython.parallel.AsyncMapResult
    """
    njobs = get_njobs(nargs, args)
    show_progress = bool(message)
    if show_progress:
        pbar = setup_progressbar(message, njobs, simple_progress=True)
        pbar.start()
    map_result = []
    for (i, arglist) in enumerate(tupleise(args), start=1):
        map_result.append(task(*arglist))
        if show_progress:
            pbar.update(i)
    if show_progress:
        pbar.finish()
    return map_result