def plot_timeline_for_phase(log_directory, job, phase, phase_data):
    min_timestamp = phase_data["min_timestamp"]
    max_timestamp = phase_data["max_timestamp"]

    description = Description(os.path.join(log_directory, job, "description"))
    stage_ordering = description.getStageOrdering(phase)

    duration_lists = {}

    for stage in stage_ordering:
        duration_lists[stage] = []

    for key in phase_data:
        if key in ["min_timestamp", "max_timestamp"]:
            continue

        hostname, stage, worker_id = key

        worker_duration_info = Duration(
            hostname.split('.')[0], stage, worker_id,
            (phase_data[key][0] - min_timestamp) / 1000000.0,
            (phase_data[key][1] - min_timestamp) / 1000000.0)

        duration_lists[stage].append(worker_duration_info)

    def sort_function(x):
        return (x.hostname, x.worker_id, x.start_time, x.stop_time)

    layout = PlotLayout()

    for stage in stage_ordering:
        duration_list = duration_lists[stage]

        duration_list.sort(key=sort_function)

        bars = {}

        # Set up a "padding" bar that will appear to move bars up so that they
        # start when the worker starts
        start_bar = Bar()
        start_bar.linewidth = 0
        start_bar.color = "white"

        for i, duration in enumerate(duration_list):
            if duration.hostname not in bars:
                bars[duration.hostname] = Bar()

            bars[duration.hostname].yValues.append(duration.stop_time -
                                                   duration.start_time)
            start_bar.yValues.append(duration.start_time)

        # Make sure that all bars have the same number of y-axis values,
        # give them x-axis values and set their colors

        start_bar.xValues = range(len(start_bar.yValues))
        start_bar.xTickLabelProperties = {"rotation": 90}

        bar_colors = [
            "red", "blue", "green", "orange", "gray", "pink", "purple", "black"
        ]

        offset = 0

        for i, (hostname, bar) in enumerate(bars.items()):
            # Pad y axis with zeroes so that bars can be laid out next to
            # each other with a StackedBars
            num_y_values = len(bar.yValues)

            bar.yValues = (([0] * offset) + bar.yValues +
                           ([0] * (len(duration_list) -
                                   (num_y_values + offset))))

            # Put the label for this hostname roughly in the middle of its bar
            # cluster
            start_bar.xTickLabels.append(hostname)
            # Subtracting 0.5 to account for half the width of the bar
            start_bar.xTickLabelPoints.append(offset + (num_y_values / 2.0) -
                                              0.5)

            offset += num_y_values

            bar.xValues = range(len(bar.yValues))
            bar.color = bar_colors[i % len(bar_colors)]
            bar.label = hostname

        stacked_bars = StackedBars()
        stacked_bars.add(start_bar)

        for hostname in sorted(bars.keys()):
            stacked_bars.add(bars[hostname])

        plot = Plot()
        plot.setYLimits(0,
                        ((max_timestamp - min_timestamp) / 1000000.0) * 1.05)
        plot.setXLabel("Worker")
        plot.setYLabel("Time (s)")
        plot.setTitle(stage)

        plot.add(stacked_bars)
        layout.addPlot(plot)

    return layout
def plot_timeline_for_phase(log_directory, job, phase, phase_data):
    min_timestamp = phase_data["min_timestamp"]
    max_timestamp = phase_data["max_timestamp"]

    description = Description(os.path.join(log_directory, job, "description"))
    stage_ordering = description.getStageOrdering(phase)

    duration_lists = {}

    for stage in stage_ordering:
        duration_lists[stage] = []

    for key in phase_data:
        if key in ["min_timestamp", "max_timestamp"]:
            continue

        hostname, stage, worker_id = key

        worker_duration_info = Duration(
            hostname.split('.')[0], stage, worker_id,
            (phase_data[key][0] - min_timestamp) / 1000000.0,
            (phase_data[key][1] - min_timestamp) / 1000000.0)

        duration_lists[stage].append(worker_duration_info)

    def sort_function(x):
        return (x.hostname, x.worker_id, x.start_time, x.stop_time)

    layout = PlotLayout()

    for stage in stage_ordering:
        duration_list = duration_lists[stage]

        duration_list.sort(key=sort_function)

        bars = {}

        # Set up a "padding" bar that will appear to move bars up so that they
        # start when the worker starts
        start_bar = Bar()
        start_bar.linewidth = 0
        start_bar.color = "white"

        for i, duration in enumerate(duration_list):
            if duration.hostname not in bars:
                bars[duration.hostname] = Bar()

            bars[duration.hostname].yValues.append(
                duration.stop_time - duration.start_time)
            start_bar.yValues.append(duration.start_time)

        # Make sure that all bars have the same number of y-axis values,
        # give them x-axis values and set their colors

        start_bar.xValues = range(len(start_bar.yValues))
        start_bar.xTickLabelProperties = {
            "rotation" : 90
            }

        bar_colors = ["red", "blue", "green", "orange", "gray", "pink",
                      "purple", "black"]

        offset = 0

        for i, (hostname, bar) in enumerate(bars.items()):
            # Pad y axis with zeroes so that bars can be laid out next to
            # each other with a StackedBars
            num_y_values = len(bar.yValues)

            bar.yValues = (([0] * offset) + bar.yValues +
                           ([0] *
                            (len(duration_list) - (num_y_values + offset))))

            # Put the label for this hostname roughly in the middle of its bar
            # cluster
            start_bar.xTickLabels.append(hostname)
            # Subtracting 0.5 to account for half the width of the bar
            start_bar.xTickLabelPoints.append(offset + (num_y_values / 2.0)
                                              - 0.5)

            offset += num_y_values

            bar.xValues = range(len(bar.yValues))
            bar.color = bar_colors[i % len(bar_colors)]
            bar.label = hostname

        stacked_bars = StackedBars()
        stacked_bars.add(start_bar)

        for hostname in sorted(bars.keys()):
            stacked_bars.add(bars[hostname])

        plot = Plot()
        plot.setYLimits(0, ((max_timestamp - min_timestamp) / 1000000.0) * 1.05)
        plot.setXLabel("Worker")
        plot.setYLabel("Time (s)")
        plot.setTitle(stage)

        plot.add(stacked_bars)
        layout.addPlot(plot)

    return layout