Ejemplo n.º 1
0
def generate_error_layout(year_id, constructor_id):
    """
    Generates an error layout in the event that the given constructor never competed in the given year.
    :param year_id: Year
    :param constructor_id: Driver ID
    :return: Div layout
    """
    logging.info("Generating error layout")
    constructor_name = get_constructor_name(constructor_id, include_flag=False)
    constructor_results = results[results["constructorId"] == constructor_id]
    years_for_that_constructor = sorted(races.loc[constructor_results["raceId"].values.tolist(), "year"].unique())
    year_races = races[races["year"] == year_id]
    constructors_for_that_year = results[results["raceId"].isin(year_races.index.values)]["constructorId"].unique()

    # Generate the text
    text = f"Unfortunately, {constructor_name} never competed in the {year_id} season. Here are some other options:<br>"
    text += f"The following constructors competed in the {year_id} season..."
    text += "<ul>"
    for cid in constructors_for_that_year:
        text += f"<li>{get_constructor_name(cid)}</li>"
    text += "</ul>"
    text += f"{constructor_name} has competed in the following years..."
    text += "<ul>"
    for year in years_for_that_constructor:
        text += f"<li>{year}</li>"
    text += "</ul><br>"

    layout = Div(text=text)
    return layout
Ejemplo n.º 2
0
def generate_wcc_plot(year_races, year_constructor_standings, year_results, constructor_id, consider_window=2):
    """
    Generates a plot of WCC progression, focusing on the 5 constructors around the constructor
    :param year_races: Year races
    :param year_constructor_standings: Year cosntructor standings
    :param year_results: Year results
    :param constructor_id: Constructor ID
    :param consider_window: Window to consider (e.g. if set to 2, will focus on 5 constructors)
    :return: WCC plot layout
    """
    # Get the driver's final position
    final_rid = year_races[year_races["round"] == year_races["round"].max()].index.values[0]
    final_standings = year_constructor_standings[year_constructor_standings["raceId"] == final_rid]
    final_standings = final_standings.set_index("constructorId")
    if constructor_id in final_standings.index:
        constructor_final_standing = final_standings.loc[constructor_id, "position"]
        if isinstance(constructor_final_standing, Series):
            constructor_final_standing = constructor_final_standing.values[0]
        if constructor_final_standing > consider_window:
            min_position = constructor_final_standing - consider_window
            max_position = constructor_final_standing + consider_window
        else:
            min_position = 1
            max_position = 2 * consider_window + 1
        considering_cids = final_standings[(final_standings["position"] >= min_position) &
                                           (final_standings["position"] <= max_position)].index.unique().tolist()
        all_cids = set(final_standings.index)
        muted_cids = all_cids - set(considering_cids)
        return year.generate_wcc_plot(year_constructor_standings, year_results, highlight_cid=constructor_id,
                                      muted_cids=muted_cids)
    constructor_name = get_constructor_name(constructor_id, include_flag=False)
    return Div(text=f"Unfortunately, we have encountered an error or {constructor_name} was never officially "
                    f"classified in this season.")
Ejemplo n.º 3
0
def generate_error_layout(year_id, circuit_id, constructor_id):
    """
    Generates error layout in the event that the given constructor didn't compete at the given circuit in the given
    year
    :param year_id: Year
    :param circuit_id: Circuit ID
    :param constructor_id: Constructor ID
    :return: Error layout
    """
    logging.info("Generating error layout")
    constructor_name = get_constructor_name(constructor_id)
    circuit_name = get_circuit_name(circuit_id)
    constructor_results = results[results["constructorId"] == constructor_id]
    rids_constructor_competed_in = constructor_results["raceId"].values.tolist(
    )
    constructor_races = races.loc[rids_constructor_competed_in]
    cids_constructor_competed_at = constructor_races["circuitId"].unique(
    ).tolist()

    # Generate the text
    text = f"Unfortunately, {constructor_name} did not compete in a race at {circuit_name} in {year_id}. The constructor " \
           f"competed at the following tracks in the following years:<br>"
    text += "<ul>"
    for circuit_id in cids_constructor_competed_at:
        years = constructor_races[constructor_races["circuitId"] ==
                                  circuit_id]["year"].unique().tolist()
        years_str = rounds_to_str(years)
        text += f"<li>{get_circuit_name(circuit_id)} ({years_str})</li>"
    text += "</ul><br>"
    layout = Div(text=text)
    return layout
def generate_error_layout(year_id, circuit_id, driver_id, constructor_id):
    logging.info("Generating error layout")
    driver_name = get_driver_name(driver_id)
    circuit_name = get_circuit_name(circuit_id)
    constructor_name = get_constructor_name(constructor_id)

    year_races = races[races["year"] == year_id]
    year_results = results[results["raceId"].isin(year_races.index)]
    constructors_this_driver = year_results[year_results["driverId"] == driver_id]["constructorId"].unique()
    circuit_years = sorted(races[races["circuitId"] == circuit_id]["year"].unique(), reverse=True)

    text = f"Unfortunately, {driver_name} did not compete at {circuit_name} in {year_id} for {constructor_name}.<br>"

    text += f"{driver_name} drove for the following constructors in {year_id}:<br>"
    text += "<ul>"
    for cid in constructors_this_driver:
        text += f"<li>{get_constructor_name(cid)}</li>"
    text += "</ul><br>"
    text += f"The following races happened in {year_id}:<br>"
    text += "<ul>"
    for rid in year_races.index.values:
        text += f"<li>{get_race_name(rid)}</li>"
    text += "</ul><br>"
    text += f"{circuit_name} hosted a Grand Prix in the following years:<br>"
    text += "<ul>"
    for year_id in circuit_years:
        text += f"<li>{year_id}</li>"
    text += "</ul><br>"
    layout = Div(text=text)
    return layout
Ejemplo n.º 5
0
def generate_error_layout(circuit_id, constructor_id):
    """
    Generates an error layout in the event that the given constructor never competed at the given circuit.
    :param circuit_id: Circuit ID
    :param constructor_id: Constructor ID
    :return: Div layout
    """
    logging.info("Generating error layout")
    circuit_name = get_circuit_name(circuit_id, include_flag=False)
    constructor_name = get_constructor_name(constructor_id, include_flag=False)
    circuit_rids = races[races["circuitId"] == circuit_id].index.values
    constructors_at_that_circuit = results[results["raceId"].isin(
        circuit_rids)]["constructorId"].unique()
    rids_for_this_constructor = results[results["constructorId"] ==
                                        constructor_id]["raceId"]
    circuits_for_this_constructor = races[races.index.isin(
        rids_for_this_constructor)]["circuitId"].unique()

    # Generate the text
    text = f"Unfortunately, {constructor_name} never competed at {circuit_name}. Here are some other options:<br>"
    text += f"{constructor_name} competed at the following circuits..."
    text += "<ul>"
    for cid in circuits_for_this_constructor:
        text += f"<li>{get_circuit_name(cid)}</li>"
    text += "</ul>"
    text += f"The {circuit_name} hosted the following constructors..."
    text += "<ul>"
    for cid in constructors_at_that_circuit:
        text += f"<li>{get_constructor_name(cid)}</li>"
    text += "</ul><br>"

    layout = Div(text=text)
    return layout
Ejemplo n.º 6
0
def generate_winners_table(circuit_years, circuit_results, circuit_races):
    """
    Table of drivers who've won the most at this circuit
    :return:
    """
    driver_scores = defaultdict(lambda: [0, []])
    constructor_scores = defaultdict(lambda: [0, []])
    for year in circuit_years:
        race = circuit_races[circuit_races["year"] == year]
        rid = race.index.values[0]
        results = circuit_results[circuit_results["raceId"] == rid]
        win = results[results["position"] == 1]
        if win.shape[0] > 0:
            win = win.iloc[0]
        else:
            continue
        driver_winner_name = get_driver_name(win["driverId"])
        driver_scores[driver_winner_name][0] += 1
        driver_scores[driver_winner_name][1].append(year)
        constructor_winner_name = get_constructor_name(win["constructorId"])
        constructor_scores[constructor_winner_name][0] += 1
        constructor_scores[constructor_winner_name][1].append(year)
    driver_scores = pd.DataFrame.from_dict(driver_scores, orient="index", columns=["wins", "years"])
    constructor_scores = pd.DataFrame.from_dict(constructor_scores, orient="index", columns=["wins", "years"])
    driver_scores.index.name = "name"
    constructor_scores.index.name = "name"
    driver_scores = driver_scores.sort_values(by="wins", ascending=False)
    constructor_scores = constructor_scores.sort_values(by="wins", ascending=False)
    driver_scores["years"] = driver_scores["years"].apply(rounds_to_str)
    constructor_scores["years"] = constructor_scores["years"].apply(rounds_to_str)

    winners_columns = [
        TableColumn(field="wins", title="Num. Wins", width=50),
        TableColumn(field="name", title="Name", width=200),
        TableColumn(field="years", title="Years Won", width=200),
    ]

    # Driver table
    title_div = Div(text=u"<h2><b>Who has won the most at this circuit \u2014 Drivers?</b></h2>")
    source = ColumnDataSource(data=driver_scores)
    driver_winners_table = DataTable(source=source, columns=winners_columns, index_position=None, min_height=530)
    driver_winners_layout = column([title_div, row([driver_winners_table], sizing_mode="stretch_width")])

    # Constructor table
    title_div = Div(text=u"<h2><b>Who has won the most at this circuit \u2014 Constructors?</b></h2>")
    source = ColumnDataSource(data=constructor_scores)
    constructor_winners_table = DataTable(source=source, columns=winners_columns, index_position=None, min_height=530)
    constructor_winners_layout = column([title_div, row([constructor_winners_table], sizing_mode="stretch_width")])

    return row([driver_winners_layout, vdivider(), constructor_winners_layout], sizing_mode="stretch_width")
Ejemplo n.º 7
0
def generate_error_layout(year_id, driver_id, constructor_id):
    """
    Generates an error layout in the event that the given driver didn't compete for the given constructor in the given
    year.
    :param year_id: Year
    :param driver_id: Driver ID
    :param constructor_id: Constructor ID
    :return: Div layout
    """
    logging.info("Generating error layout")
    driver_name = get_driver_name(driver_id)
    constructor_name = get_constructor_name(constructor_id)
    year_races = races[races["year"] == year_id]
    year_results = results[results["raceId"].isin(year_races.index.values)]
    driver_results = year_results[year_results["driverId"] == driver_id]
    constructor_results = year_results[year_results["constructorId"] ==
                                       constructor_id]

    # Generate the text
    text = f"Unfortunately, {driver_name} did not compete for {constructor_name} in {year_id}.<br>"

    text += f"{driver_name} competed for the following constructors this year:<br>"
    text += "<ul>"
    for cid in driver_results["constructorId"].unique():
        text += f"<li>{get_constructor_name(cid)}</li>"
    text += "</ul><br>"
    if constructor_results.shape[0] == 0:
        text += f"{constructor_name} did not compete this season.<br>"
    else:
        text += f"{constructor_name} had the following drivers this year:<br>"
        text += "<ul>"
        for did in constructor_results["driverId"].unique():
            text += f"<li>{get_driver_name(did)}</li>"
        text += "</ul><br>"
    text += f"The following constructors participated in the {year_id} season:<br>"
    text += "<ul>"
    for cid in year_results["constructorId"].unique():
        text += f"<li>{get_constructor_name(cid)}</li>"
    text += "</ul><br>"
    text += f"The following drivers participated in the {year_id} season:<br>"
    text += "<ul>"
    for did in year_results["driverId"].unique():
        text += f"<li>{get_driver_name(did)}</li>"
    text += "</ul><br>"
    layout = Div(text=text)
    return layout
Ejemplo n.º 8
0
def generate_error_layout(circuit_id, driver_id, constructor_id):
    """
    Generates error layout in the case where the given constructor with the given driver hasn't competed at the given
    circuit.
    :param circuit_id: Circuit ID
    :param driver_id: Driver ID
    :param constructor_id: Constructor ID
    :return: Error layout
    """
    logging.info("Generating error layout")
    circuit_name = get_circuit_name(circuit_id)
    driver_name = get_driver_name(driver_id)
    constructor_name = get_constructor_name(constructor_id)
    circuit_rids = races[races["circuitId"] == circuit_id].index.values
    circuit_results = results[results["raceId"].isin(circuit_rids)]
    # Constructors at this circuit
    constructors_at_circuit = circuit_results["constructorId"].unique()
    # Constructors of this driver at this circuit
    driver_constructors = circuit_results[circuit_results["driverId"] == driver_id]["constructorId"].unique()
    # Drivers for this constructor
    constructor_drivers = circuit_results[circuit_results["constructorId"] == constructor_id]["driverId"].unique()

    # Generate the text
    text = f"Unfortunately, {driver_name} never competed at {circuit_name} with {constructor_name}. " \
           f"Here are some other options:<br>"
    text += f"The following constructors competed at {circuit_name}..."
    text += "<ul>"
    for cid in constructors_at_circuit:
        text += f"<li>{get_constructor_name(cid)}</li>"
    text += "</ul><br>"
    text += f"{driver_name} raced at {circuit_name} while competing with the following constructors..."
    text += "<ul>"
    for cid in driver_constructors:
        text += f"<li>{get_constructor_name(cid)}</li>"
    text += "</ul><br>"
    text += f"{constructor_name} had the following drivers while competing at {circuit_name}..."
    text += "<ul>"
    for did in constructor_drivers:
        text += f"<li>{get_driver_name(did)}</li>"
    text += "</ul><br>"

    layout = Div(text=text)

    return layout
Ejemplo n.º 9
0
def generate_stats_layout(positions_source, comparison_source,
                          constructor_results, year_id, driver_id):
    """
    Year summary div, including:
    - WDC place
    - Highest race finish
    - Number of races
    - Points
    - Points per race
    - Number of wins and where were they
    - Number of podiums and where were they
    - Teammates
    - Constructors
    - Mean gap to teammate in positions
    - Mean grid position
    - Mean finish position
    :param positions_source: Positions source
    :param comparison_source: Comparison source (from teammate comparison line plot)
    :param constructor_results: Constructor results (from results.csv)
    :param year_id: Year
    :param driver_id: Driver ID
    :return: Stats layout
    """
    logging.info("Generating year driver stats layout")
    if positions_source.shape[0] == 0:
        return Div(text="")
    wdc_final_standing = positions_source["wdc_final_standing"].mode()
    if wdc_final_standing.shape[0] > 0:
        wdc_final_standing_str = int_to_ordinal(wdc_final_standing.values[0])
    else:
        wdc_final_standing_str = ""
    highest_race_finish_idx = positions_source["finish_position_int"].idxmin()
    if np.isnan(highest_race_finish_idx):
        highest_race_finish_str = ""
    else:
        highest_race_finish = positions_source.loc[highest_race_finish_idx,
                                                   "finish_position_int"]
        round_name = positions_source.loc[highest_race_finish_idx, "roundName"]
        highest_race_finish_str = int_to_ordinal(
            highest_race_finish) + " at " + round_name
        highest_race_finish_str = highest_race_finish_str.strip()
    num_races = positions_source.shape[0]
    num_races_str = str(num_races)
    points = positions_source["points"].max()
    if np.isnan(points):
        points_str = ""
    elif points <= 0:
        points_str = str(points) + " (0 pts/race)"
    else:
        points_str = str(points) + " (" + str(round(points / num_races,
                                                    1)) + " pts/race)"
    wins_slice = positions_source[positions_source["finish_position_int"] == 1]
    num_wins = wins_slice.shape[0]
    if num_wins == 0:
        wins_str = str(num_wins)
    else:
        wins_str = str(num_wins) + " (" + ", ".join(
            wins_slice["roundName"]) + ")"
        if len(wins_str) > 95:
            split = wins_str.split(" ")
            split.insert(int(len(split) / 2), "<br>    " + "".ljust(20))
            wins_str = " ".join(split)
    podiums_slice = positions_source[
        positions_source["finish_position_int"] <= 3]
    num_podiums = podiums_slice.shape[0]
    if num_podiums == 0:
        podiums_str = str(num_podiums)
    else:
        podiums_str = str(num_podiums) + " (" + ", ".join(
            podiums_slice["roundName"]) + ")"
        if len(podiums_str) > 95:
            split = podiums_str.split(" ")
            split.insert(int(len(split) / 2), "<br>    " + "".ljust(20))
            podiums_str = " ".join(split)
    teammate_dids = set(constructor_results["driverId"].unique()) - {driver_id}
    teammate_names = []
    for did in teammate_dids:
        teammate_names.append(get_driver_name(did, include_flag=False))
    teammate_str = ", ".join(teammate_names)
    constructor_cids = set(constructor_results["constructorId"].unique())
    constructor_names = []
    for cid in constructor_cids:
        constructor_names.append(get_constructor_name(cid, include_flag=True))
    constructors_str = ", ".join(constructor_names)
    mean_grid_pos = positions_source["grid"].replace("", np.nan).mean()
    if np.isnan(mean_grid_pos):
        mean_grid_pos_str = ""
    else:
        mean_grid_pos_str = str(round(mean_grid_pos, 1))
    mean_finish_pos = positions_source["finish_position_int"].mean()
    if np.isnan(mean_finish_pos):
        mean_finish_pos_str = ""
    else:
        mean_finish_pos_str = str(round(mean_finish_pos, 1))
    mean_teammate_gap_pos = (comparison_source["driver_fp"] -
                             comparison_source["teammate_fp"]).mean()
    if np.isnan(mean_teammate_gap_pos):
        mean_teammate_gap_pos_str = ""
    else:
        mean_teammate_gap_pos_str = str(abs(round(mean_teammate_gap_pos, 1))) + " places " + \
                                    ("better" if mean_teammate_gap_pos < 0 else "worse") + " than teammate"

    # Construct the HTML
    header_template = """
    <h2 style="text-align: left;"><b>{}</b></h2>
    """
    template = """
    <pre><b>{}</b> {}<br></pre>
    """

    driver_name = get_driver_name(driver_id, include_flag=False)
    driver_stats = header_template.format(
        f"{driver_name}'s Stats for the {year_id} Season")
    driver_stats += template.format("WDC Final Pos.: ".ljust(20),
                                    wdc_final_standing_str)
    driver_stats += template.format("Num. Races: ".ljust(20), num_races_str)
    if num_wins == 0:
        driver_stats += template.format("Best Finish Pos.: ".ljust(20),
                                        highest_race_finish_str)
    driver_stats += template.format("Wins: ".ljust(20), wins_str)
    driver_stats += template.format("Podiums: ".ljust(20), podiums_str)
    driver_stats += template.format("Points: ".ljust(20), points_str)
    driver_stats += template.format("Constructor(s): ".ljust(20),
                                    constructors_str)
    driver_stats += template.format("Teammate(s): ".ljust(20), teammate_str)
    driver_stats += template.format("Avg. Grid Pos.: ".ljust(20),
                                    mean_grid_pos_str)
    driver_stats += template.format("Avg. Finish Pos.: ".ljust(20),
                                    mean_finish_pos_str)
    driver_stats += template.format("Avg. Gap to T.M.: ".ljust(20),
                                    mean_teammate_gap_pos_str)

    return Div(text=driver_stats)
Ejemplo n.º 10
0
def generate_stats_layout(ycd_results,
                          ycd_pit_stop_data,
                          ycd_fastest_lap_data,
                          year_driver_standings,
                          race_results,
                          quali_source,
                          race_id,
                          circuit_id,
                          driver_id,
                          download_image=True):
    """
    Stats div including:
    - Location
    - Date
    - Weather
    - Rating
    - Constructor
    - Qualifying position and time
    - Laps
    - Fastest lap time along with rank
    - Average lap time
    - Basic teammate info (i.e. teammate finish in 5th with an average lap time of 1:15.125)
    - Finish position
    - Finish time
    - Points scored
    - Num pit stops
    - WDC impact (WDC place before, WDC after)
    :param ycd_results: YCD results
    :param ycd_pit_stop_data: YCD pit stop data
    :param ycd_fastest_lap_data: YCD fastest lap data
    :param year_driver_standings: YCD driver standings
    :param race_results: Race results
    :param quali_source: Quali source
    :param race_id: Race ID
    :param circuit_id: Circuit ID
    :param driver_id: Driver ID
    :param download_image: Whether to actually download the image
    :return: Stats layout
    """
    logging.info("Generating race stats layout")
    # Track image
    if download_image:
        image_url = str(circuits.loc[circuit_id, "imgUrl"])
        image_view = plot_image_url(image_url)
        disclaimer = Div(
            text="The image is of the current configuration of the track.")
        image_view = column([image_view, disclaimer],
                            sizing_mode="stretch_both")
    else:
        image_view = Div()

    # Race info
    race = races.loc[race_id]
    round_num = race["round"]
    circuit = circuits.loc[circuit_id]
    date = race["datetime"].split(" ")
    if len(date) > 0:
        date_str = date[0]
    else:
        date_str = race["datetime"]
    location_str = circuit["location"] + ", " + circuit["country"]
    circuit_str = circuit["name"] + " (" + location_str + ")"
    weather = race["weather"]
    if weather is None or weather == "":
        weather_str = ""
    else:
        weather_str = str(weather).title()
    sc = race["SCLaps"]
    if np.isnan(sc):
        sc_str = ""
    else:
        sc_str = str(int(sc)) + " laps under safety car"
    rating = race["rating"]
    if np.isnan(rating):
        rating_str = ""
    else:
        rating_str = str(round(rating, 1)) + " / 10"
    ycd_driver_standings = year_driver_standings[
        (year_driver_standings["raceId"] == race_id)
        & (year_driver_standings["driverId"] == driver_id)]
    ycd_driver_standings_prev = year_driver_standings[
        (year_driver_standings["raceId"] == race_id - 1)
        & (year_driver_standings["driverId"] == driver_id)]
    if round_num == 1 and ycd_driver_standings.shape[0] > 0:
        wdc_impact_str = int_to_ordinal(
            ycd_driver_standings["positionText"].values[0])
    elif round_num > 1 and ycd_driver_standings.shape[
            0] > 0 and ycd_driver_standings_prev.shape[0] > 0:
        wdc_impact_str = "from " + int_to_ordinal(ycd_driver_standings_prev["position"].values[0]) + " to " + \
                         int_to_ordinal(ycd_driver_standings["position"].values[0])
    else:
        wdc_impact_str = ""
    if ycd_pit_stop_data.shape[0] > 0:
        num_pit_stops_str = str(ycd_pit_stop_data.shape[0])
    else:
        num_pit_stops_str = ""
    if ycd_results.shape[0] > 0:
        ycd_results_row = ycd_results.iloc[0]
        constructor_id = ycd_results_row["constructorId"]
        constructor_str = get_constructor_name(constructor_id)
        grid_str = int_to_ordinal(ycd_results_row["grid"]).strip()
        fp_str, _ = result_to_str(ycd_results_row["positionOrder"],
                                  ycd_results_row["statusId"])
        fp_str = fp_str.strip()
        laps_str = str(ycd_results_row["laps"])
        runtime_str = millis_to_str(ycd_results_row["milliseconds"]).strip()
        points = ycd_results_row["points"]
        if abs(int(points) - points) < 0.01:
            points = int(points)
        points_str = str(points)
        teammates = set(
            race_results[race_results["constructorId"] ==
                         constructor_id]["driverId"].values) - {driver_id}
        teammate_strs = []
        for teammate_did in teammates:
            teammate_result = race_results[race_results["driverId"] ==
                                           teammate_did]
            if teammate_result.shape[0] > 0:
                tm_result_row = teammate_result.iloc[0]
                tm_name = get_driver_name(teammate_did)
                tm_fp_str, _ = result_to_str(tm_result_row["positionOrder"],
                                             tm_result_row["statusId"])
                tm_time_str = millis_to_str(tm_result_row["milliseconds"])
                if "ret" in tm_fp_str.lower():
                    teammate_strs.append(tm_name + " " + tm_fp_str)
                else:
                    teammate_strs.append(tm_name + " finished " +
                                         tm_fp_str.strip() + " (" +
                                         tm_time_str.strip() + ")")
        teammate_str = ", ".join(teammate_strs)
    else:
        constructor_str = ""
        grid_str = ""
        fp_str = ""
        laps_str = ""
        runtime_str = ""
        points_str = ""
        teammate_str = ""
    ycd_quali_source = quali_source[quali_source["driver_id"] == driver_id]
    if ycd_quali_source.shape[0] > 0:
        ycd_quali_row = ycd_quali_source.iloc[0]
        quali_pos = ycd_quali_row["quali_position"]
        quali_pos_str = int_to_ordinal(quali_pos).strip()
        quali_time_str = ""
        if "q1" in ycd_quali_source.columns and ycd_quali_row["q1"] != "~":
            quali_time_str = ycd_quali_row["q1"]
        if "q2" in ycd_quali_source.columns and ycd_quali_row["q2"] != "~":
            quali_time_str = ycd_quali_row["q2"]
        if "q3" in ycd_quali_source.columns and ycd_quali_row["q3"] != "~":
            quali_time_str = ycd_quali_row["q3"]
        quali_time_str = quali_time_str.strip()
    else:
        quali_pos_str = ""
        quali_time_str = ""
    if ycd_fastest_lap_data.shape[0] > 0:
        ycd_fastest_lap_data_row = ycd_fastest_lap_data.iloc[0]
        if np.isnan(ycd_fastest_lap_data_row["fastest_lap_time_millis"]):
            fastest_lap_str = ""
        else:
            fastest_lap_str = ycd_fastest_lap_data_row["fastest_lap_time_str"] + " (" + \
                              int_to_ordinal(ycd_fastest_lap_data_row["rank"]).strip() + " fastest this race)"
        avg_lap_time_str = millis_to_str(
            ycd_fastest_lap_data_row["avg_lap_time_millis"])
    else:
        fastest_lap_str = ""
        avg_lap_time_str = ""

    header_template = """
    <h2 style="text-align: center;"><b>{}</b></h2>
    """

    template = """
    <pre><b>{}</b> {}<br></pre>
    """

    race_name = get_race_name(race_id, include_year=True)
    driver_name = get_driver_name(driver_id)
    ycd_stats = header_template.format(driver_name + " at the " + race_name)

    ycd_stats += template.format("Circuit Name: ".ljust(22), circuit_str)
    ycd_stats += template.format("Date: ".ljust(22), date_str)
    if weather_str != "" and weather_str.lower() != "nan":
        ycd_stats += template.format("Weather: ".ljust(22), weather_str)
    if not np.isnan(rating):
        ycd_stats += template.format("Rating: ".ljust(22), rating_str)
    if not np.isnan(sc):
        ycd_stats += template.format("Safety Car Laps: ".ljust(22), sc_str)
    if wdc_impact_str != "":
        if round_num == 1:
            ycd_stats += template.format("WDC Position: ".ljust(22),
                                         wdc_impact_str)
        else:
            ycd_stats += template.format("WDC Impact: ".ljust(22),
                                         wdc_impact_str)
    if ycd_pit_stop_data.shape[0] > 0:
        ycd_stats += template.format("Num Pit Stops: ".ljust(22),
                                     num_pit_stops_str)
    if quali_pos_str != "":
        ycd_stats += template.format("Qualifying Position: ".ljust(22),
                                     quali_pos_str)
    if quali_time_str != "":
        ycd_stats += template.format("Qualifying Time: ".ljust(22),
                                     quali_time_str)
    if ycd_results.shape[0] > 0:
        ycd_stats += template.format("Constructor: ".ljust(22),
                                     constructor_str)
        ycd_stats += template.format("Grid Position: ".ljust(22), grid_str)
        ycd_stats += template.format("Finish Position: ".ljust(22), fp_str)
        ycd_stats += template.format("Num Laps: ".ljust(22), laps_str)
        ycd_stats += template.format("Race Time: ".ljust(22), runtime_str)
        ycd_stats += template.format("Points Earned: ".ljust(22), points_str)
        ycd_stats += template.format("Teammate(s): ".ljust(22), teammate_str)
    if ycd_fastest_lap_data.shape[0] > 0:
        if fastest_lap_str != "":
            ycd_stats += template.format("Fastest Lap Time: ".ljust(22),
                                         fastest_lap_str)
        ycd_stats += template.format("Avg. Lap Time: ".ljust(22),
                                     avg_lap_time_str)

    divider = vdivider()
    return row([image_view, divider, Div(text=ycd_stats)],
               sizing_mode="stretch_both")
Ejemplo n.º 11
0
def mark_teammate_team_changes(yd_results,
                               positions_source,
                               driver_id,
                               fig,
                               x_offset=0.03):
    """
    Marks team and teammate changes
    :param yd_results: YD results
    :param positions_source: Positions source
    :param driver_id: Driver ID
    :param fig: Figure to mark
    :param x_offset: Offset for drawing text labels
    :return: None
    """
    if yd_results.shape[0] > 0:
        prev_constructor = -1
        prev_teammate_did = -1
        color_gen = ColorDashGenerator()
        label_kwargs = dict(render_mode="canvas",
                            text_color="white",
                            text_font_size="10pt",
                            angle=math.pi / 4)

        def draw_mark(location, line_color, text, up=True):
            line = Span(line_color=line_color,
                        location=location,
                        dimension="height",
                        line_alpha=0.4,
                        line_width=3.2)
            fig.add_layout(line)
            label = Label(x=location + x_offset,
                          y=18 if up else 16,
                          text=text,
                          **label_kwargs)
            fig.add_layout(label)

        for race_id in yd_results["raceId"]:
            cid = yd_results[yd_results["raceId"] == race_id]["constructorId"]
            x = positions_source[positions_source["race_id"] == race_id]["x"]
            if x.shape[0] > 0:
                x = x.values[0]
            else:
                continue
            if cid.shape[0] > 0:
                cid = cid.values[0]
                constructor_race_results = results[
                    (results["raceId"] == race_id)
                    & (results["constructorId"] == cid)]
                dids = constructor_race_results["driverId"].unique().tolist()
                if driver_id in dids:
                    dids.remove(driver_id)
                if len(dids) > 0:
                    teammate_did = dids[0]
                    if teammate_did != prev_teammate_did:
                        draw_mark(
                            x, "white",
                            get_driver_name(teammate_did,
                                            include_flag=False,
                                            just_last=True))
                        prev_teammate_did = teammate_did
            # Team changes
            race_results = yd_results[yd_results["raceId"] == race_id]
            if race_results.shape[0] > 0:
                curr_constructor = race_results["constructorId"].values[0]
                if curr_constructor != prev_constructor:  # Mark the constructor change
                    color, _ = color_gen.get_color_dash(None, curr_constructor)
                    draw_mark(x,
                              color,
                              get_constructor_name(curr_constructor,
                                                   include_flag=False),
                              up=False)
                    prev_constructor = curr_constructor
Ejemplo n.º 12
0
def generate_results_table(yd_results, yd_fastest_lap_data, year_results,
                           year_fastest_lap_data, driver_id):
    """
    Table of results at each race, including quali position, finish position (or reason for DNF), time, gap to leader,
    fastest lap time and gap to fastest lap (of all drivers), average lap time and gap to fastest average lap time
    (of all drivers)
    :param yd_results: YD results
    :param yd_fastest_lap_data: YD fastest lap data
    :param year_results: Year results
    :param year_fastest_lap_data: Year fastest lap data
    :param driver_id: Driver ID
    :return: Results table
    """
    logging.info("Generating results table")
    source = pd.DataFrame(columns=[
        "race_name", "constructor_name", "quali_pos_str", "finish_pos_str",
        "time_str", "fastest_lap_time_str", "avg_lap_time_str"
    ])
    for idx, results_row in yd_results.iterrows():
        rid = results_row["raceId"]
        race_results = year_results[year_results["raceId"] == rid]
        race_fastest_lap_data = year_fastest_lap_data[
            year_fastest_lap_data["raceId"] == rid]
        race_driver_fastest_lap_data = yd_fastest_lap_data[
            yd_fastest_lap_data["raceId"] == rid]
        race_name = get_race_name(rid)
        constructor_name = get_constructor_name(results_row["constructorId"])
        quali_pos_str = int_to_ordinal(results_row["grid"])
        finish_pos = str(results_row["positionOrder"])
        status_id = results_row["statusId"]
        finish_pos_str, finish_pos = result_to_str(finish_pos, status_id)
        classification = get_status_classification(status_id)
        time = results_row["milliseconds"]
        winner = race_results[race_results["positionOrder"] == 1]
        if winner.shape[0] > 0 and winner["driverId"].values[0] != driver_id \
                and not np.isnan(time) and not np.isnan(results_row["position"]):
            time_gap = millis_to_str(time - winner["milliseconds"].values[0])
            time_str = millis_to_str(time) + " (+" + time_gap + ")"
            if status_id != 1 and classification == "finished":
                time_str = millis_to_str(
                    time) + " (+" + time_gap + ", " + status.loc[
                        status_id, "status"] + ")"
        elif finish_pos == 1:
            time_str = millis_to_str(time)
        else:
            time_str = "~"
        if race_driver_fastest_lap_data.shape[0] > 0:
            fastest_lap_time = race_driver_fastest_lap_data[
                "fastest_lap_time_millis"].values[0]
            fastest_lap_time_str = millis_to_str(fastest_lap_time)
            if race_driver_fastest_lap_data["rank"].values[0] == " 1":
                fastest_lap_time_str = fastest_lap_time_str + " (Fastest)"
            else:
                fastest_time = race_fastest_lap_data[
                    race_fastest_lap_data["rank"] ==
                    " 1"]["fastest_lap_time_millis"]
                if fastest_time.shape[0] > 0 and not np.isnan(
                        fastest_lap_time):
                    fastest_time = fastest_time.values[0]
                    fastest_gap = millis_to_str(fastest_lap_time -
                                                fastest_time)
                    fastest_lap_time_str = millis_to_str(
                        fastest_lap_time) + " (+" + fastest_gap + ")"
            if fastest_lap_time_str == "":
                fastest_lap_time_str = "~"
            fastest_avg_idx = race_fastest_lap_data[
                "avg_lap_time_millis"].idxmin()
            avg_lap_time = race_driver_fastest_lap_data[
                "avg_lap_time_millis"].values[0]
            if np.isnan(avg_lap_time):
                avg_lap_time_str = "~"
            elif race_fastest_lap_data.loc[
                    fastest_avg_idx,
                    "driver_id"] == driver_id or np.isnan(avg_lap_time):
                avg_lap_time_str = millis_to_str(
                    avg_lap_time) + " (Fastest Avg.)"
            else:
                fastest_avg_time = race_fastest_lap_data.loc[
                    fastest_avg_idx, "avg_lap_time_millis"]
                avg_gap = millis_to_str(avg_lap_time - fastest_avg_time)
                avg_lap_time_str = millis_to_str(
                    avg_lap_time) + " (+" + avg_gap + ")"
        else:
            fastest_lap_time_str = "~"
            avg_lap_time_str = "~"
        source = source.append(
            {
                "race_name": race_name,
                "constructor_name": constructor_name,
                "quali_pos_str": quali_pos_str,
                "finish_pos_str": finish_pos_str,
                "time_str": time_str,
                "fastest_lap_time_str": fastest_lap_time_str,
                "avg_lap_time_str": avg_lap_time_str
            },
            ignore_index=True)

    results_columns = [
        TableColumn(field="race_name", title="Race Name", width=100),
        TableColumn(field="constructor_name", title="Constructor", width=100),
        TableColumn(field="quali_pos_str", title="Grid Pos.", width=75),
        TableColumn(field="finish_pos_str", title="Finish Pos.", width=75),
        TableColumn(field="time_str", title="Time", width=100),
        TableColumn(field="fastest_lap_time_str",
                    title="Fastest Lap Time",
                    width=75),
        TableColumn(field="avg_lap_time_str", title="Avg. Lap Time", width=75),
    ]
    results_table = DataTable(source=ColumnDataSource(data=source),
                              columns=results_columns,
                              index_position=None,
                              height=27 * yd_results.shape[0])
    title = Div(
        text=
        f"<h2><b>Results for each race</b></h2><br><i>The fastest lap time and average lap time gaps "
        f"shown are calculated based on the gap to the fastest of all drivers and fastest average of "
        f"all drivers in that race respectively.</i>")
    return column(
        [title, row([results_table], sizing_mode="stretch_width")],
        sizing_mode="stretch_width")
def get_layout(year_id=-1, circuit_id=-1, driver_id=-1, constructor_id=-1, download_image=True, **kwargs):
    logging.info(f"Generating layout for mode YEARCIRCUITDRIVERCONSTRUCTOR in yearcircuitdriverconstructor, "
                 f"year_id={year_id}, circuit_id={circuit_id}, driver_id={driver_id}, constructor_id={constructor_id}")
    year_races = races[races["year"] == year_id]
    race = year_races[year_races["circuitId"] == circuit_id]
    if race.shape[0] == 0:
        return generate_error_layout(year_id, circuit_id, driver_id, constructor_id)
    rid = race.index.values[0]
    race_results = results[results["raceId"] == rid]
    ycdc_results = race_results[(race_results["driverId"] == driver_id) &
                                (race_results["constructorId"] == constructor_id)]
    if ycdc_results.shape[0] == 0:
        return generate_error_layout(year_id, circuit_id, driver_id, constructor_id)

    race_laps = lap_times[lap_times["raceId"] == rid]
    ycdc_laps = race_laps[race_laps["driverId"] == driver_id]
    ycdc_pit_stop_data = pit_stop_data[(pit_stop_data["raceId"] == rid) & (pit_stop_data["driverId"] == driver_id)]
    race_quali = quali[quali["raceId"] == rid]
    ycdc_fastest_lap_data = fastest_lap_data[(fastest_lap_data["raceId"] == rid) &
                                             (fastest_lap_data["driver_id"] == driver_id)]
    year_driver_standings = driver_standings[driver_standings["raceId"].isin(year_races.index.values)]

    disclaimer_sc, sc_starts, sc_ends = detect_safety_car(race_laps, race)
    disclaimer_sc = PlotItem(disclaimer_sc, [], "", listed=False)
    disclaimer_overtakes, overtake_data = detect_overtakes(ycdc_laps, race_laps)
    disclaimer_overtakes = PlotItem(disclaimer_overtakes, [], "", listed=False)

    gap_plot, cached_driver_map = generate_gap_plot(race_laps, race_results, driver_id, sc_starts=sc_starts,
                                                    sc_ends=sc_ends, overtake_data=overtake_data,
                                                    ycdc_pit_stop_data=ycdc_pit_stop_data)
    gap_plot = PlotItem(gap_plot, [], COMMON_PLOT_DESCRIPTIONS["generate_gap_plot"])

    position_plot = PlotItem(generate_position_plot, [race_laps, race_results, cached_driver_map, driver_id],
                             COMMON_PLOT_DESCRIPTIONS["generate_position_plot"],
                             kwargs=dict(sc_starts=sc_starts, sc_ends=sc_ends, ycdc_pit_stop_data=ycdc_pit_stop_data))

    lap_time_plot = PlotItem(generate_lap_time_plot, [race_laps, race_results, cached_driver_map, driver_id],
                             COMMON_PLOT_DESCRIPTIONS["generate_times_plot"],
                             kwargs=dict(sc_starts=sc_starts, sc_ends=sc_ends, overtake_data=overtake_data))

    quali_table, quali_source = generate_quali_table(race_quali, race_results, driver_id)
    description = u"Qualifying Table \u2014 table showing the results from qualifying at this race"
    quali_table = PlotItem(quali_table, [], description)

    description = u"Various statistics on this driver at this race"
    stats_layout = PlotItem(generate_stats_layout, [ycdc_results, ycdc_pit_stop_data, ycdc_fastest_lap_data,
                                                    year_driver_standings, race_results, quali_source, rid, circuit_id,
                                                    driver_id], description,
                            kwargs=dict(download_image=download_image))

    driver_name = get_driver_name(driver_id)
    race_name = get_race_name(rid, include_year=True)
    constructor_name = get_constructor_name(constructor_id)
    header = generate_div_item(f"<h2><b>What did {driver_name}'s {race_name} with {constructor_name} "
                               f"look like?</b></h2><br><i>"
                               f"Yellow dashed vertical lines show the start of a safety car period, orange vertical "
                               f"lines show the end*. "
                               f"<br>The white line marks the fastest lap of the race."
                               f"<br>Green lines show overtakes and red lines show being overtaken**."
                               f"<br>Pink lines show pit stops along with how long was spent in the pits.</i>")

    middle_spacer = generate_spacer_item()
    group = generate_plot_list_selector([
        [header],
        [gap_plot], [middle_spacer],
        [position_plot], [middle_spacer],
        [lap_time_plot], [middle_spacer],
        [disclaimer_sc],
        [disclaimer_overtakes],
        [quali_table],
        [stats_layout]
    ])

    logging.info("Finished generating layout for mode YEARCIRCUITDRIVERCONSTRUCTOR")

    return group
Ejemplo n.º 14
0
def generate_results_table(yc_results, yc_fastest_lap_data, year_results, year_fastest_lap_data, year_only=False,
                           height=None, include_driver_name=True, include_constructor_name=False):
    """
    Generates a table of results at each race, including quali position, finish position (or reason for DNF), time, gap
    to leader, fastest lap time and gap to fastest lap (of all drivers), average lap time and gap to fastest average lap
    time (of all drivers).
    :param yc_results: YC results
    :param yc_fastest_lap_data: YC fastest lap data
    :param year_results: Year results
    :param year_fastest_lap_data: Year fastest lap data
    :param year_only: Whether to set the race name row to just the year
    :param height: Plot height
    :param include_driver_name: If True, will include a driver name column
    :param include_constructor_name: If True, will include a constructor name column
    :return: Table layout, source
    """
    # TODO this might be able to be refactored with yeardriver or year, but it is kind of unique
    logging.info("Generating results table")
    source = pd.DataFrame(columns=["race_name", "driver_name", "driver_id ", "race_id", "year", "constructor_name",
                                   "quali_pos_str",
                                   "finish_pos_str",
                                   "time_str",
                                   "fastest_lap_time_str",
                                   "avg_lap_time_str"])
    for idx, results_row in yc_results.sort_values(by=["raceId", "driverId"]).iterrows():
        rid = results_row["raceId"]
        driver_id = results_row["driverId"]
        constructor_id = results_row["constructorId"]
        driver_name = get_driver_name(driver_id)
        constructor_name = get_constructor_name(constructor_id)
        race_results = year_results[year_results["raceId"] == rid]
        race_fastest_lap_data = year_fastest_lap_data[year_fastest_lap_data["raceId"] == rid]
        race_driver_fastest_lap_data = yc_fastest_lap_data[(yc_fastest_lap_data["raceId"] == rid) &
                                                           (yc_fastest_lap_data["driver_id"] == driver_id)]
        race_name = get_race_name(rid)
        grid = results_row["grid"]
        if grid == -1:
            quali_pos_str = "DNQ"
        else:
            quali_pos_str = int_to_ordinal(grid)
        status_id = results_row["statusId"]
        finish_pos_str, finish_pos = result_to_str(results_row["positionOrder"], status_id)
        time = results_row["milliseconds"]
        winner = race_results[race_results["positionOrder"] == 1]
        if winner.shape[0] > 0 and winner["driverId"].values[0] != driver_id \
                and not np.isnan(time) and not np.isnan(results_row["position"]):
            time_gap = millis_to_str(time - winner["milliseconds"].values[0])
            time_str = millis_to_str(time) + " (+" + time_gap + ")"
            if status_id != 1 and get_status_classification(status_id) == "finished":
                time_str = millis_to_str(time) + " (+" + time_gap + ", " + status.loc[status_id, "status"] + ")"
        elif finish_pos == 1:
            time_str = millis_to_str(time)
        else:
            time_str = "Not Set"
        if race_driver_fastest_lap_data.shape[0] > 0:
            fastest_lap_time = race_driver_fastest_lap_data["fastest_lap_time_millis"].values[0]
            fastest_lap_time_str = millis_to_str(fastest_lap_time)
            if race_driver_fastest_lap_data["rank"].values[0] == " 1":
                fastest_lap_time_str = fastest_lap_time_str + " (Fastest)"
            else:
                fastest_time = race_fastest_lap_data[race_fastest_lap_data["rank"] == " 1"]["fastest_lap_time_millis"]
                if fastest_time.shape[0] > 0 and not np.isnan(fastest_lap_time):
                    fastest_time = fastest_time.values[0]
                    fastest_gap = millis_to_str(fastest_lap_time - fastest_time)
                    fastest_lap_time_str = millis_to_str(fastest_lap_time) + " (+" + fastest_gap + ")"
            if fastest_lap_time_str == "":
                fastest_lap_time_str = "Not Set"
            fastest_avg_idx = race_fastest_lap_data["avg_lap_time_millis"].idxmin()
            avg_lap_time = race_driver_fastest_lap_data["avg_lap_time_millis"].values[0]
            if np.isnan(avg_lap_time):
                avg_lap_time_str = "Not Set"
            elif race_fastest_lap_data.loc[fastest_avg_idx, "driver_id"] == driver_id or np.isnan(avg_lap_time):
                avg_lap_time_str = millis_to_str(avg_lap_time) + " (Fastest Avg.)"
            else:
                fastest_avg_time = race_fastest_lap_data.loc[fastest_avg_idx, "avg_lap_time_millis"]
                avg_gap = millis_to_str(avg_lap_time - fastest_avg_time)
                avg_lap_time_str = millis_to_str(avg_lap_time) + " (+" + avg_gap + ")"
        else:
            fastest_lap_time_str = "Not Set"
            avg_lap_time_str = "Not Set"
        source = source.append({
            "race_name": race_name,
            "race_id": rid,
            "driver_name": driver_name,
            "driver_id": driver_id,
            "constructor_name": constructor_name,
            "year": races.loc[rid, "year"],
            "quali_pos_str": quali_pos_str,
            "finish_pos_str": finish_pos_str,
            "time_str": time_str,
            "fastest_lap_time_str": fastest_lap_time_str,
            "avg_lap_time_str": avg_lap_time_str
        }, ignore_index=True)

    source = source.sort_values(by="year", ascending=False)

    results_columns = [
        TableColumn(field="quali_pos_str", title="Grid Pos.", width=75),
        TableColumn(field="finish_pos_str", title="Finish Pos.", width=75),
        TableColumn(field="time_str", title="Time", width=100),
        TableColumn(field="fastest_lap_time_str", title="Fastest Lap Time", width=75),
        TableColumn(field="avg_lap_time_str", title="Avg. Lap Time", width=75),
    ]
    if include_driver_name:
        results_columns.insert(0, TableColumn(field="driver_name", title="Driver Name", width=100))
    if include_constructor_name:
        results_columns.insert(0, TableColumn(field="constructor_name", title="Constructor Name", width=100))
    if year_only:
        results_columns.insert(0, TableColumn(field="year", title="Year", width=50))
    else:
        results_columns.insert(0, TableColumn(field="race_name", title="Race Name", width=100))
    results_table = DataTable(source=ColumnDataSource(data=source), columns=results_columns, index_position=None,
                              height=28 * yc_results.shape[0] if height is None else height)
    title = Div(text=f"<h2><b>Results for each race</b></h2><br><i>The fastest lap time and average lap time gaps "
                     f"shown are calculated based on the gap to the fastest of all drivers and fastest average of "
                     f"all drivers in that race respectively.</i>")
    return column([title, row([results_table], sizing_mode="stretch_width")], sizing_mode="stretch_width"), source
Ejemplo n.º 15
0
def get_layout(year_id=-1,
               circuit_id=-1,
               constructor_id=-1,
               download_image=True,
               **kwargs):
    # Generate slices
    year_races = races[races["year"] == year_id]
    race = year_races[year_races["circuitId"] == circuit_id]
    if race.shape[0] == 0:
        return generate_error_layout(year_id=year_id,
                                     circuit_id=circuit_id,
                                     constructor_id=constructor_id)
    rid = race.index.values[0]
    race_results = results[results["raceId"] == rid]
    ycc_results = race_results[race_results["constructorId"] == constructor_id]

    logging.info(
        f"Generating layout for mode YEARCIRCUITCONSTRUCTOR in yearcircuitconstructor, year_id={year_id}, "
        f"circuit_id={circuit_id}, constructor_id={constructor_id}")

    if ycc_results.shape[0] == 0:
        return generate_error_layout(year_id=year_id,
                                     circuit_id=circuit_id,
                                     constructor_id=constructor_id)

    # Generate more slices
    driver_ids = ycc_results["driverId"].unique()
    ycc_pit_stop_data = pit_stop_data[(pit_stop_data["raceId"] == rid) & (
        pit_stop_data["driverId"].isin(driver_ids))]
    race_laps = lap_times[lap_times["raceId"] == rid]
    race_quali = quali[quali["raceId"] == rid]
    ycc_fastest_lap_data = fastest_lap_data[
        (fastest_lap_data["raceId"] == rid)
        & (fastest_lap_data["driver_id"].isin(driver_ids))]
    year_driver_standings = driver_standings[driver_standings["raceId"].isin(
        year_races.index.values)]
    year_constructor_standings = constructor_standings[
        constructor_standings["raceId"].isin(year_races.index.values)]

    disclaimer_sc, sc_starts, sc_ends = detect_safety_car(race_laps, race)
    disclaimer_sc = PlotItem(disclaimer_sc, [], "", listed=False)

    gap_plot, cached_driver_map = generate_gap_plot(
        race_laps,
        race_results,
        driver_ids,
        constructor_id,
        sc_starts=sc_starts,
        sc_ends=sc_ends,
        ycc_pit_stop_data=ycc_pit_stop_data)
    gap_plot = PlotItem(gap_plot, [],
                        COMMON_PLOT_DESCRIPTIONS["generate_gap_plot"])

    position_plot = PlotItem(
        generate_position_plot, [
            race_laps, race_results, cached_driver_map, driver_ids,
            constructor_id
        ],
        COMMON_PLOT_DESCRIPTIONS["generate_position_plot"],
        kwargs=dict(sc_starts=sc_starts,
                    sc_ends=sc_ends,
                    ycc_pit_stop_data=ycc_pit_stop_data))

    lap_time_plot = PlotItem(generate_lap_time_plot, [
        race_laps, race_results, cached_driver_map, driver_ids, constructor_id
    ],
                             COMMON_PLOT_DESCRIPTIONS["generate_times_plot"],
                             kwargs=dict(sc_starts=sc_starts, sc_ends=sc_ends))

    quali_table, quali_source = generate_quali_table(race_quali, race_results,
                                                     driver_ids)
    quali_table = PlotItem(quali_table, [], "add descr. " * 5)

    stats_layout = PlotItem(generate_stats_layout, [
        ycc_results, ycc_pit_stop_data, ycc_fastest_lap_data,
        year_driver_standings, year_constructor_standings, quali_source, rid,
        circuit_id, constructor_id, driver_ids
    ],
                            "add descr. " * 5,
                            kwargs=dict(download_image=download_image))

    constructor_name = get_constructor_name(constructor_id)
    race_name = get_race_name(rid, include_year=True)
    header = generate_div_item(
        f"<h2><b>What did {constructor_name}'s {race_name} look like?"
        f"</b></h2><br><i>Yellow dashed vertical lines show the start of a safety car period, "
        f"orange vertical lines show the end.*"
        f"<br>The white line marks the fastest lap of the race."
        f"<br>Pink lines show pit stops along with how long was spent in the pits."
    )

    middle_spacer = generate_spacer_item()
    group = generate_plot_list_selector([[header], [gap_plot], [middle_spacer],
                                         [position_plot], [middle_spacer],
                                         [lap_time_plot], [middle_spacer],
                                         [disclaimer_sc], [quali_table],
                                         [stats_layout]])

    logging.info("Finished generating layout for mode YEARCIRCUITCONSTRUCTOR")

    return group
Ejemplo n.º 16
0
def get_layout(year_id=-1, constructor_id=-1, **kwargs):
    if year_id < 1958:
        return Div(text="The constructor's championship did not exist this year! It started in 1958.")
    year_races = races[races["year"] == year_id]
    year_results = results[results["raceId"].isin(year_races.index)]
    yc_results = year_results[year_results["constructorId"] == constructor_id]

    # Detect if it is a valid combo
    if yc_results.shape[0] == 0:
        return generate_error_layout(year_id, constructor_id)

    # Generate more slices
    year_constructor_standings = constructor_standings[constructor_standings["raceId"].isin(year_races.index)]
    year_constructor_standings = year_constructor_standings.sort_values(by="raceId")
    yc_constructor_standings = year_constructor_standings[year_constructor_standings["constructorId"] == constructor_id]
    year_fastest_lap_data = fastest_lap_data[fastest_lap_data["raceId"].isin(year_races.index)]
    yc_fastest_lap_data_idxs = []
    yc_driver_standings_idxs = []
    for idx, results_row in yc_results.iterrows():
        rid = results_row["raceId"]
        did = results_row["driverId"]
        fl_slice = year_fastest_lap_data[(year_fastest_lap_data["raceId"] == rid) &
                                         (year_fastest_lap_data["driver_id"] == did)]
        yc_fastest_lap_data_idxs.extend(fl_slice.index.values.tolist())
        driver_standings_slice = driver_standings[(driver_standings["raceId"] == rid) &
                                                  (driver_standings["driverId"] == did)]
        yc_driver_standings_idxs.extend(driver_standings_slice.index.values.tolist())
    yc_fastest_lap_data = fastest_lap_data.loc[yc_fastest_lap_data_idxs]
    yc_driver_standings = driver_standings.loc[yc_driver_standings_idxs]
    yc_races = year_races[year_races.index.isin(yc_results["raceId"])]

    logging.info(f"Generating layout for mode YEARCONSTRUCTOR in yearconstructor, year_id={year_id}, "
                 f"constructor_id={constructor_id}")

    wcc_plot = PlotItem(generate_wcc_plot, [year_races, year_constructor_standings, year_results, constructor_id],
                        COMMON_PLOT_DESCRIPTIONS["generate_wcc_plot"])

    positions_plot, positions_source = generate_positions_plot(yc_constructor_standings, yc_results,
                                                               yc_fastest_lap_data, year_id, constructor_id)
    positions_plot = PlotItem(positions_plot, [], COMMON_PLOT_DESCRIPTIONS["generate_positions_plot"])

    spvfp_scatter = PlotItem(generate_spvfp_scatter, [yc_results, yc_races, yc_driver_standings],
                             COMMON_PLOT_DESCRIPTIONS["generate_spvfp_scatter"])

    mltr_fp_scatter = PlotItem(generate_mltr_fp_scatter, [yc_results, yc_races, yc_driver_standings],
                               COMMON_PLOT_DESCRIPTIONS["generate_mltr_fp_scatter"])

    win_plot = PlotItem(generate_win_plot, [positions_source, constructor_id],
                        COMMON_PLOT_DESCRIPTIONS["generate_win_plot"])

    finishing_position_bar_plot = PlotItem(generate_finishing_position_bar_plot, [yc_results],
                                           COMMON_PLOT_DESCRIPTIONS["generate_finishing_position_bar_plot"])

    description = u"Driver Performance Table \u2014 table showing the performance of every driver that competed for " \
                  u"this constructor for this season, including number of races, podiums, wins, podiums, etc."
    driver_performance_layout = PlotItem(generate_driver_performance_table, [yc_races, yc_results], description)

    description = u"Results Table \u2014 table showing this constructor's results at every race this season"
    results_table = PlotItem(generate_results_table, [yc_results, yc_fastest_lap_data, year_results,
                                                      year_fastest_lap_data], description)

    teammate_comparison_line_plot, comparison_source = generate_teammate_comparison_line_plot(yc_results, year_races,
                                                                                              yc_driver_standings,
                                                                                              year_id)
    teammate_comparison_line_plot = PlotItem(teammate_comparison_line_plot, [],
                                             COMMON_PLOT_DESCRIPTIONS["generate_teammate_comparison_line_plot"])

    description = u"Various statistics on this constructor during this year"
    stats_layout = PlotItem(generate_stats_layout, [positions_source, yc_results, comparison_source, year_id,
                                                    constructor_id], description)

    constructor_name = get_constructor_name(constructor_id)
    header = generate_div_item(f"<h2><b>What did {constructor_name}'s {year_id} season look like?</b></h2>")

    logging.info("Finished generating layout for mode YEARCONSTRUCTOR")

    middle_spacer = generate_spacer_item()
    group = generate_plot_list_selector([
        [header],
        [wcc_plot], [middle_spacer],
        [positions_plot], [middle_spacer],
        [win_plot], [middle_spacer],
        [finishing_position_bar_plot], [middle_spacer],
        [spvfp_scatter, mltr_fp_scatter], [middle_spacer],
        [teammate_comparison_line_plot], [middle_spacer],
        [driver_performance_layout],
        [stats_layout],
        [results_table]
    ])

    return group
Ejemplo n.º 17
0
def generate_stats_layout(circuit_id, circuit_years, circuit_fastest_lap_data, circuit_results, circuit_races,
                          download_image=True):
    """
    Generates a layout of the circuit image along with some basic stats on the track
    :param circuit_id: Circuit ID
    :param circuit_years: Circuit years
    :param circuit_fastest_lap_data: Circuit fastest lap data
    :param circuit_results: Circuit results
    :param circuit_races: Circuit races
    :param download_image: Whether to download the image
    :return: Race stats layout
    """
    logging.info("Generating circuit stats layout")

    circuit_row = circuits.loc[circuit_id]

    # Track image
    if download_image:
        image_url = str(circuit_row["imgUrl"])
        image_view = plot_image_url(image_url)
        disclaimer = Div(text="The image is of the current configuration of the track.")
        image_view = column([image_view, disclaimer], sizing_mode="stretch_both")
    else:
        image_view = Div()

    # Circuit stats
    header_template = """
    <h2 style="text-align: center;"><b>{}</b></h2>
    """

    template = """
    <pre><b>{}</b> {}<br></pre>
    """

    circuit_stats = header_template.format("Circuit Stats")

    location = circuit_row["location"] + ", " + circuit_row["country"]
    circuit_stats += template.format("Location: ".ljust(22), location)

    years_races = rounds_to_str(circuit_years)
    if len(years_races) > 50:
        years_races = years_races[:50] + "<br>" + "".ljust(22) + years_races[50:]
    circuit_stats += template.format("Years Raced: ".ljust(22), years_races)

    num_races = circuit_races.shape[0]
    circuit_stats += template.format("Races Held: ".ljust(22), str(num_races))

    avg_rating = circuit_row["avgRating"]
    if not np.isnan(avg_rating):
        circuit_stats += template.format("Avg. Fan Rating: ".ljust(22), round(avg_rating, 1))

    # Fastest race lap
    if circuit_fastest_lap_data["fastest_lap_time_millis"].shape[0] > 0 and \
            circuit_fastest_lap_data["fastest_lap_time_millis"].isna().sum() < \
            circuit_fastest_lap_data["fastest_lap_time_millis"].shape[0]:
        minidx = circuit_fastest_lap_data["fastest_lap_time_millis"].idxmin()
        fastest = circuit_fastest_lap_data.loc[minidx]
        did = fastest["driver_id"]
        rid = fastest["raceId"]
        year = str(circuit_races.loc[rid, "year"])
        cid = circuit_results[(circuit_results["raceId"] == rid) &
                              (circuit_results["driverId"] == did)]["constructorId"].values[0]
        constructor = get_constructor_name(cid, include_flag=False)
        fastest = fastest["fastest_lap_time_str"] + " (" + get_driver_name(did) + ", " + constructor + ", " + year + ")"
        circuit_stats += template.format("Fastest Race Lap: ".ljust(22), fastest)

    # DNF pct
    if circuit_results.shape[0] > 0:
        classifications = circuit_results["statusId"].apply(get_status_classification)
        dnfs = classifications[(classifications == "mechanical") | (classifications == "crash")].shape[0]
        finishes = classifications[classifications == "finished"].shape[0]
        dnf_pct = dnfs / (dnfs + finishes)
        dnf_pct_str = f"{round(100 * dnf_pct, 1)}% of cars DNF'd"
        circuit_stats += template.format("DNF Percent: ".ljust(22), dnf_pct_str)

    # Weather and SC Laps
    weather = circuit_races["weather"].value_counts()
    if weather.shape[0] > 0:
        dry = weather["dry"] if "dry" in weather.index else 0
        varied = weather["varied"] if "varied" in weather.index else 0
        wet = weather["wet"] if "wet" in weather.index else 0
        circuit_stats += "<i>Note, we only have safety car and weather data from 2007 to 2017</i>"
        circuit_stats += template.format("Dry Races: ".ljust(22), str(dry) + " (" +
                                         str(round(100 * dry / num_races, 1)) + "% of races)")
        circuit_stats += template.format("Varied Races: ".ljust(22), str(varied) + " (" +
                                         str(round(100 * varied / num_races, 1)) + "% of races)")
        circuit_stats += template.format("Wet Races: ".ljust(22), str(wet) + " (" +
                                         str(round(100 * wet / num_races, 1)) + "% of races)")

    sc_laps = circuit_races["SCLaps"].mean()
    if not np.isnan(sc_laps):
        circuit_stats += template.format("Avg. Safety Car Laps: ".ljust(22), round(sc_laps, 1))

    stats_div = Div(text=circuit_stats)

    divider = vdivider()

    return row([image_view, divider, stats_div], sizing_mode="stretch_width")
Ejemplo n.º 18
0
def generate_stats_layout(positions_source, yc_results, comparison_source, year_id, constructor_id):
    """
    Year summary div, including WCC place, highest race finish, number of races, points, points per race, number of
    wins, number of podiums, and everything else in constructor.generate_stats_layout and
    yeardriver.generate_stats_layout
    - WCC place
    - Highest race finish
    - Number of races
    - Points
    - Points per race
    - Number of wins and where were they
    - Number of podiums and where were they
    - Teammates
    - Constructors
    - Mean gap to teammate in positions
    - Mean grid position
    - Mean finish position
    - DNF info
    :param positions_source: Positions source
    :param yc_results: YC results
    :param comparison_source: Comparison source
    :param year_id: Year ID
    :param constructor_id: Constructor ID
    :return: Stats layout
    """
    logging.info("Generating year constructor stats layout")
    if positions_source.shape[0] == 0:
        return Div(text="")
    wcc_final_standing = positions_source["wcc_final_standing"].mode()
    if wcc_final_standing.shape[0] > 0:
        wcc_final_standing_str = int_to_ordinal(wcc_final_standing.values[0])
    else:
        wcc_final_standing_str = ""
    highest_race_finish_idx = yc_results["positionOrder"].idxmin()
    if np.isnan(highest_race_finish_idx):
        highest_race_finish_str = ""
    else:
        highest_race_finish = yc_results.loc[highest_race_finish_idx, "positionOrder"]
        round_name = get_race_name(yc_results.loc[highest_race_finish_idx, "raceId"])
        highest_race_finish_str = int_to_ordinal(highest_race_finish) + " at " + round_name
    num_races = positions_source["race_id"].unique().shape[0]
    num_races_str = str(num_races)
    points = positions_source["points"].max()
    if np.isnan(points):
        points_str = ""
    elif points <= 0:
        points_str = str(points) + " (0 pts/race)"
    else:
        points_str = str(points) + " (" + str(round(points / num_races, 1)) + " pts/race)"
    wins_slice = yc_results[yc_results["positionOrder"] == 1]
    num_wins = wins_slice.shape[0]
    if num_wins == 0:
        wins_str = str(num_wins)
    else:
        wins_str = str(num_wins) + " (" + ", ".join(wins_slice["raceId"].apply(get_race_name)) + ")"
        if len(wins_str) > 120:
            split = wins_str.split(" ")
            split.insert(int(len(split) / 2), "<br>    " + "".ljust(20))
            wins_str = " ".join(split)
    podiums_slice = yc_results[yc_results["positionOrder"] <= 3]
    num_podiums = podiums_slice.shape[0]
    if num_podiums == 0:
        podiums_str = str(num_podiums)
    else:
        race_names = ", ".join([get_race_name(rid) for rid in podiums_slice["raceId"].unique()])
        podiums_str = str(num_podiums) + " (" + race_names + ")"
        if len(podiums_str) > 120:
            split = podiums_str.split(" ")
            split.insert(int(len(split) / 2), "<br>    " + "".ljust(20))
            podiums_str = " ".join(split)
    driver_dids = yc_results["driverId"].unique()
    driver_names = []
    for did in driver_dids:
        driver_names.append(get_driver_name(did))
    driver_names = ", ".join(driver_names)
    mean_grid_pos = yc_results["grid"].replace("", np.nan).mean()
    if np.isnan(mean_grid_pos):
        mean_grid_pos_str = ""
    else:
        mean_grid_pos_str = str(round(mean_grid_pos, 1))
    mean_finish_pos = yc_results["positionOrder"].mean()
    if np.isnan(mean_finish_pos):
        mean_finish_pos_str = ""
    else:
        mean_finish_pos_str = str(round(mean_finish_pos, 1))
    classifications = yc_results["statusId"].apply(get_status_classification)
    num_mechanical_dnfs = classifications[classifications == "mechanical"].shape[0]
    num_crash_dnfs = classifications[classifications == "crash"].shape[0]
    if num_races > 0:
        num_mechanical_dnfs_str = str(num_mechanical_dnfs) + " (" + \
                                  str(round(100 * num_mechanical_dnfs / num_races, 1)) + "%)"
        num_crash_dnfs_str = str(num_crash_dnfs) + " (" + str(round(100 * num_crash_dnfs / num_races, 1)) + "%)"
    else:
        num_mechanical_dnfs_str = ""
        num_crash_dnfs_str = ""
    mean_teammate_gap_pos = (comparison_source["driver1_fp"] - comparison_source["driver2_fp"]).mean()
    if np.isnan(mean_teammate_gap_pos):
        mean_teammate_gap_pos_str = ""
    else:
        mean_teammate_gap_pos_str = "Driver {} finished {} places better than driver {} on average"
        mean_teammate_gap_pos_str = mean_teammate_gap_pos_str.format("1" if mean_teammate_gap_pos < 0 else "2",
                                                                     str(abs(round(mean_teammate_gap_pos, 1))),
                                                                     "2" if mean_teammate_gap_pos < 0 else "1")

    # Construct the HTML
    header_template = """
    <h2 style="text-align: left;"><b>{}</b></h2>
    """
    template = """
    <pre><b>{}</b> {}<br></pre>
    """

    constructor_name = get_constructor_name(constructor_id, include_flag=False)
    constructor_stats = header_template.format(f"{constructor_name}'s Stats for the {year_id} Season")
    constructor_stats += template.format("WCC Final Pos.: ".ljust(20), wcc_final_standing_str)
    constructor_stats += template.format("Num. Races: ".ljust(20), num_races_str)
    if num_wins == 0:
        constructor_stats += template.format("Best Finish Pos.: ".ljust(20), highest_race_finish_str)
    constructor_stats += template.format("Wins: ".ljust(20), wins_str)
    constructor_stats += template.format("Podiums: ".ljust(20), podiums_str)
    constructor_stats += template.format("Points: ".ljust(20), points_str)
    constructor_stats += template.format("Drivers(s): ".ljust(20), driver_names)
    constructor_stats += template.format("Avg. Grid Pos.: ".ljust(20), mean_grid_pos_str)
    constructor_stats += template.format("Avg. Finish Pos.: ".ljust(20), mean_finish_pos_str)
    constructor_stats += template.format("Mechanical DNFs: ".ljust(20), num_mechanical_dnfs_str)
    constructor_stats += template.format("Crash DNFs: ".ljust(20), num_crash_dnfs_str)
    constructor_stats += template.format("Avg. Driver Gap: ".ljust(20), mean_teammate_gap_pos_str)

    return Div(text=constructor_stats)
Ejemplo n.º 19
0
def generate_lap_time_plot(cd_lap_times,
                           cd_rids,
                           circuit_id,
                           driver_id,
                           constructor_id=None):
    """
    Plot lap time distribution of the driver at this circuit along with the lap time distribution of all drivers at this
    circuit during the time period to show how fast and consistent he is.
    :param cd_lap_times: Circuit driver lap times
    :param cd_rids: Circuit driver race IDs
    :param circuit_id: Circuit ID
    :param driver_id: Driver ID, can be set to None if using constructor mode
    :param constructor_id: Constructor ID, set to None if not using constructor mode
    :return: Lap time plot layout
    """
    logging.info("Generating lap time distribution plot")
    # Collect data on everyone during these years
    all_times = lap_times[lap_times["raceId"].isin(cd_rids)]
    millis_range_min = all_times["milliseconds"].mean(
    ) - 1 * all_times["milliseconds"].std()
    millis_range_max = all_times["milliseconds"].mean(
    ) + 2 * all_times["milliseconds"].std()

    cd_lap_times = cd_lap_times[
        (cd_lap_times["milliseconds"] > millis_range_min)
        & (cd_lap_times["milliseconds"] < millis_range_max)]
    if cd_lap_times.shape[0] == 0:
        return Div(
            text=
            "Unfortunately, we do not yet have lap time data on this driver at this circuit."
        )
    all_times = all_times[(all_times["milliseconds"] > millis_range_min)
                          & (all_times["milliseconds"] < millis_range_max)]

    cd_hist, cd_edges = np.histogram(cd_lap_times["milliseconds"], bins=50)
    all_hist, all_edges = np.histogram(all_times["milliseconds"], bins=50)
    cd_hist = cd_hist / cd_lap_times.shape[0]
    all_hist = all_hist / all_times.shape[0]

    all_pdf_source = pd.DataFrame(columns=["x", "pdf"])
    cd_pdf_source = pd.DataFrame(columns=["x", "pdf"])
    for i in range(0, all_edges.shape[0] - 1):
        x = 0.5 * (all_edges[i] + all_edges[i + 1])
        pdf = all_hist[i]
        all_pdf_source = all_pdf_source.append({
            "x": x,
            "pdf": pdf
        },
                                               ignore_index=True)
    for i in range(0, cd_edges.shape[0] - 1):
        x = 0.5 * (cd_edges[i] + cd_edges[i + 1])
        pdf = cd_hist[i]
        cd_pdf_source = cd_pdf_source.append({
            "x": x,
            "pdf": pdf
        },
                                             ignore_index=True)
    all_pdf_source["lap_time_str"] = all_pdf_source["x"].apply(millis_to_str)
    cd_pdf_source["lap_time_str"] = all_pdf_source["x"].apply(millis_to_str)
    all_pdf_source["pct_str"] = all_pdf_source["pdf"].apply(
        lambda pdf: str(round(100 * pdf, 1)) + "%")
    cd_pdf_source["pct_str"] = cd_pdf_source["pdf"].apply(
        lambda pdf: str(round(100 * pdf, 1)) + "%")

    if constructor_id:
        name = get_constructor_name(constructor_id, include_flag=False)
    else:
        name = get_driver_name(driver_id, include_flag=False, just_last=True)
    circuit_name = get_circuit_name(circuit_id, include_flag=False)
    title = u"Lap Time Distribution \u2014 " + name + "'s lap times at " + circuit_name + \
            " vs the rest of the field during their years"
    max_y = 0.02 + max(cd_pdf_source["pdf"].max(), all_pdf_source["pdf"].max())
    min_x = all_edges[0] - 500
    max_x = all_edges[-1] + 500
    time_dist = figure(title=title,
                       y_axis_label="% Occurrence",
                       x_axis_label="Lap Time",
                       y_range=Range1d(0, max_y, bounds=(0, max_y)),
                       x_range=Range1d(min_x, max_x,
                                       bounds=(min_x, max_x + 3)),
                       tools="pan,box_zoom,wheel_zoom,reset,save")
    subtitle = "Only lap times within 2 standard deviations of the mean are shown, means marked with horizontal line"
    time_dist.add_layout(Title(text=subtitle, text_font_style="italic"),
                         "above")
    time_dist.xaxis.formatter = DatetimeTickFormatter(**DATETIME_TICK_KWARGS)
    time_dist.yaxis.formatter = NumeralTickFormatter(format="0.0%")

    cd_quad = time_dist.quad(top=cd_hist,
                             bottom=0,
                             left=cd_edges[:-1],
                             right=cd_edges[1:],
                             fill_color="orange",
                             line_alpha=0,
                             alpha=0.1,
                             muted_alpha=0)

    line_kwargs = dict(x="x",
                       y="pdf",
                       line_alpha=0.9,
                       line_width=2,
                       muted_line_alpha=0.05)
    cd_pdf_line = time_dist.line(source=cd_pdf_source,
                                 color="orange",
                                 **line_kwargs)
    all_pdf_line = time_dist.line(source=all_pdf_source,
                                  color="white",
                                  **line_kwargs)

    # Mark means
    line_kwargs = dict(y=[-100, 100],
                       line_alpha=0.9,
                       line_width=2,
                       muted_alpha=0.05)
    all_mean = all_times["milliseconds"].mean()
    cd_mean = cd_lap_times["milliseconds"].mean()
    cd_mean_line = time_dist.line(x=[cd_mean] * 2,
                                  line_color="orange",
                                  **line_kwargs)
    all_mean_line = time_dist.line(x=[all_mean] * 2,
                                   line_color="white",
                                   **line_kwargs)

    # Legend
    legend = [
        LegendItem(label=f"{name}'s Dist.",
                   renderers=[cd_pdf_line, cd_quad, cd_mean_line]),
        LegendItem(label="All Drivers Dist.",
                   renderers=[all_pdf_line, all_mean_line])
    ]

    legend = Legend(items=legend,
                    location="top_right",
                    glyph_height=15,
                    spacing=2,
                    inactive_fill_color="gray")
    time_dist.add_layout(legend, "right")
    time_dist.legend.click_policy = "mute"
    time_dist.legend.label_text_font_size = "12pt"

    # Hover tooltip
    time_dist.add_tools(
        HoverTool(show_arrow=False,
                  renderers=[all_pdf_line, cd_pdf_line],
                  tooltips=[("Lap Time", "@lap_time_str"),
                            ("Percent of Laps", "@pct_str")]))

    # Crosshair tooltip
    time_dist.add_tools(CrosshairTool(line_color="white", line_alpha=0.6))

    return time_dist
Ejemplo n.º 20
0
    generate_driver_performance_table)
driver_performance_layout, driver_performance_source = generate_driver_performance_layout(
    constructor_races, constructor_results)

# Constructor stats div
generate_constructor_stats_layout = time_decorator(generate_stats_layout)
constructor_stats = generate_constructor_stats_layout(
    constructor_years, constructor_races, driver_performance_source,
    constructor_results, constructor_constructor_standings, constructor_id)

n = constructors.index.unique().shape[0]
i = 1

for constructor_id in constructors.index.unique():
    try:
        name = get_constructor_name(constructor_id, include_flag=False)
        print(f"Testing constructor ID {constructor_id}, {name}, {i} / {n}")
        i += 1
        start = time.time()
        get_layout(constructor_id=constructor_id)
        end = time.time()
        elapsed = 1000 * (end - start)
        print(f"Completed in  {elapsed} milliseconds")
        times["cid"].append(constructor_id)
        times["time"].append(elapsed)
    except Exception as e:
        print(f"Encountered exception: {e}")
        track = traceback.format_exc()
        print("The traceback is:")
        print(track)
        error_ids.append(constructor_id)
Ejemplo n.º 21
0
def get_layout(year_id=-1,
               driver_id=-1,
               constructor_id=-1,
               download_image=True,
               **kwargs):
    # Generate slices
    year_races = races[races["year"] == year_id]
    year_rids = sorted(year_races.index.values)
    year_results = results[results["raceId"].isin(year_rids)]
    ydc_results = year_results[(year_results["driverId"] == driver_id) & (
        year_results["constructorId"] == constructor_id)].sort_values(
            by="raceId")

    logging.info(
        f"Generating layout for mode YEARDRIVERCONSTRUCTOR in yeardriverconstructor, year_id={year_id}, "
        f"driver_id={driver_id}, constructor_id={constructor_id}")

    # Check if valid
    if ydc_results.shape[0] == 0:
        return generate_error_layout(year_id, driver_id, constructor_id)

    # Generate more slices
    yd_races = year_races.loc[ydc_results["raceId"].values]
    year_driver_standings = driver_standings[driver_standings["raceId"].isin(
        year_rids)]
    yd_driver_standings = year_driver_standings[
        year_driver_standings["driverId"] == driver_id]
    year_constructor_standings = constructor_standings[
        constructor_standings["raceId"].isin(year_rids)]
    year_constructor_standings = year_constructor_standings.sort_values(
        by="raceId")
    year_fastest_lap_data = fastest_lap_data[fastest_lap_data["raceId"].isin(
        year_rids)]
    yd_fastest_lap_data = year_fastest_lap_data[
        year_fastest_lap_data["driver_id"] == driver_id]
    constructor_results = year_results[year_results["constructorId"] ==
                                       constructor_id]

    wdc_plot = PlotItem(
        generate_wdc_plot,
        [year_races, year_driver_standings, year_results, driver_id],
        COMMON_PLOT_DESCRIPTIONS["generate_wdc_plot"])

    wcc_plot = PlotItem(
        generate_wcc_plot,
        [year_races, year_constructor_standings, year_results, constructor_id],
        COMMON_PLOT_DESCRIPTIONS["generate_wcc_plot"])

    positions_plot, positions_source = generate_positions_plot(
        ydc_results, yd_driver_standings, yd_fastest_lap_data, driver_id,
        year_id)
    positions_plot = PlotItem(
        positions_plot, [],
        COMMON_PLOT_DESCRIPTIONS["generate_positions_plot"])

    spvfp_scatter = PlotItem(
        generate_spvfp_scatter, [ydc_results, yd_races, yd_driver_standings],
        COMMON_PLOT_DESCRIPTIONS["generate_spvfp_scatter"])

    mltr_fp_scatter = PlotItem(
        generate_mltr_fp_scatter, [ydc_results, yd_races, yd_driver_standings],
        COMMON_PLOT_DESCRIPTIONS["generate_mltr_fp_scatter"])

    win_plot = PlotItem(generate_win_plot, [positions_source, driver_id],
                        COMMON_PLOT_DESCRIPTIONS["generate_win_plot"])

    position_dist = PlotItem(
        generate_finishing_position_bar_plot, [ydc_results],
        COMMON_PLOT_DESCRIPTIONS["generate_finishing_position_bar_plot"])

    teammatefp_fp_scatter = PlotItem(
        generate_teammatefp_fp_scatter,
        [positions_source, constructor_results, driver_id],
        COMMON_PLOT_DESCRIPTIONS["generate_teammatefp_fp_scatter"])

    teammate_diff_plot = PlotItem(
        generate_teammate_diff_comparison_scatter,
        [positions_source, constructor_results, driver_id],
        COMMON_PLOT_DESCRIPTIONS["generate_teammate_diff_comparison_scatter"])

    teammate_comparison_line_plot, comparison_source = generate_teammate_comparison_line_plot(
        positions_source, constructor_results, driver_id)
    teammate_comparison_line_plot = PlotItem(
        teammate_comparison_line_plot, [],
        COMMON_PLOT_DESCRIPTIONS["generate_teammate_comparison_line_plot"])

    description = u"Results Table \u2014 table of results for every race this driver competed at this year with " \
                  u"this constructor"
    results_table = PlotItem(generate_results_table, [
        ydc_results, yd_fastest_lap_data, year_results, year_fastest_lap_data,
        driver_id
    ], description)

    description = u"Various statistics on this driver at this constructor during this year"
    stats_layout = PlotItem(generate_stats_layout, [
        positions_source, comparison_source, constructor_results, year_id,
        driver_id
    ], description)

    if download_image:
        image_url = str(drivers.loc[driver_id, "imgUrl"])
        image_view = plot_image_url(image_url)
    else:
        image_view = Div()
    image_view = PlotItem(image_view, [], "", listed=False)

    driver_name = get_driver_name(driver_id)
    constructor_name = get_constructor_name(constructor_id)
    header = generate_div_item(
        f"<h2><b>What did {driver_name}'s {year_id} season with "
        f"{constructor_name} look like?</b></h2>")

    middle_spacer = generate_spacer_item()
    group = generate_plot_list_selector(
        [[header], [wdc_plot], [middle_spacer], [wcc_plot], [middle_spacer],
         [positions_plot], [middle_spacer], [win_plot], [middle_spacer],
         [spvfp_scatter, mltr_fp_scatter], [middle_spacer], [position_dist],
         [middle_spacer], [teammatefp_fp_scatter, teammate_diff_plot],
         [middle_spacer], [teammate_comparison_line_plot], [results_table],
         [image_view, generate_vdivider_item(), stats_layout]])

    logging.info("Finished generating layout for mode YEARDRIVERCONSTRUCTOR")

    return group
Ejemplo n.º 22
0
def generate_stats_layout(cd_years,
                          cd_races,
                          cd_results,
                          cd_fastest_lap_data,
                          positions_source,
                          circuit_id,
                          driver_id,
                          constructor_id=None):
    """
    Stats div including:
    - Years
    - Num. races
    - Num. wins
    - Num. podiums
    - Best results
    - Average start position
    - Average finish position
    - Average lap time
    - Fastest lap time
    - Num mechanical DNFs and mechanical DNF rate
    - Num crash DNFs and crash DNF rate
    :param cd_years: CD years
    :param cd_races: CD races
    :param cd_results: CD results
    :param cd_fastest_lap_data: CD fastest lap data
    :param positions_source: Positions source
    :param driver_id: Driver ID
    :param circuit_id: Circuit ID
    :param constructor_id: If set to anything but None, will do constructor mode
    :return: Stats div layout
    """
    logging.info("Generating stats div")
    num_races = cd_results.shape[0]
    if num_races == 0:
        return Div()
    win_results = cd_results[cd_results["positionOrder"] == 1]
    num_wins = win_results.shape[0]
    if num_wins > 0:
        rids = win_results["raceId"]
        years = sorted(cd_races.loc[rids.values,
                                    "year"].astype(str).values.tolist(),
                       reverse=True)
        num_wins = str(num_wins) + " (" + ", ".join(years) + ")"
    else:
        num_wins = str(num_wins)
    podium_results = cd_results[cd_results["positionOrder"] <= 3]
    num_podiums = podium_results.shape[0]
    if num_podiums > 0:
        rids = podium_results["raceId"]
        years = list(set(cd_races.loc[rids.values, "year"].values.tolist()))
        years = rounds_to_str(years)
        num_podiums_str = str(num_podiums) + " (" + years + ")"
        if len(num_podiums_str) > 120:
            split = num_podiums_str.split(" ")
            split.insert(int(len(split) / 2), "<br>      " + "".ljust(20))
            num_podiums_str = " ".join(split)
    else:
        num_podiums_str = str(num_podiums)
    best_result = None
    if num_wins == 0:
        idxmin = cd_results["positionOrder"].idxmin()
        if not np.isnan(idxmin):
            rid = cd_results.loc[idxmin, "raceId"]
            year = cd_races.loc[rid, "year"]
            best_result = int_to_ordinal(
                int(cd_results.loc[idxmin, "positionOrder"])) + f" ({year})"
    mean_sp = round(cd_results["grid"].mean(), 1)
    mean_fp = round(cd_results["positionOrder"].mean(), 1)

    avg_lap_time = cd_fastest_lap_data["avg_lap_time_millis"].mean()
    fastest_lap_time = cd_fastest_lap_data["fastest_lap_time_millis"].min()

    classifications = cd_results["statusId"].apply(get_status_classification)
    num_mechanical_dnfs = classifications[classifications ==
                                          "mechanical"].shape[0]
    num_crash_dnfs = classifications[classifications == "crash"].shape[0]
    num_finishes = classifications[classifications == "finished"].shape[0]
    mechanical_dnfs_str = str(num_mechanical_dnfs)
    crash_dnfs_str = str(num_crash_dnfs)
    finishes_str = str(num_finishes)
    if num_races > 0:
        mechanical_dnfs_str += " (" + str(
            round(100 * num_mechanical_dnfs / num_races, 1)) + "%)"
        crash_dnfs_str += " (" + str(round(100 * num_crash_dnfs / num_races,
                                           1)) + "%)"
        finishes_str += " (" + str(round(100 * num_finishes / num_races,
                                         1)) + "%)"

    if positions_source.shape[0] > 0:
        avg_finish_pos_overall = positions_source["avg_finish_pos"].mean()
        avg_finish_pos_here = positions_source["finish_position_int"].mean()
        diff = avg_finish_pos_here - avg_finish_pos_overall
        avg_finish_pos_overall = round(avg_finish_pos_overall, 1)
        avg_finish_pos_here = round(avg_finish_pos_here, 1)
        w = "higher" if diff < 0 else "lower"
        finish_pos_diff_str = f"Finished on average {round(abs(diff), 1)} place(s) {w} than average " \
                              f"(pos. {avg_finish_pos_here} here vs pos. {avg_finish_pos_overall} average overall)"
    else:
        finish_pos_diff_str = ""

    header_template = """
    <h2 style="text-align: center;"><b>{}</b></h2>
    """

    template = """
    <pre><b>{}</b> {}<br></pre>
    """

    if constructor_id:
        name = get_constructor_name(constructor_id, include_flag=False)
    else:
        name = get_driver_name(driver_id, include_flag=False, just_last=True)
    cd_stats = header_template.format(
        f"{name} at {get_circuit_name(circuit_id, include_flag=False)} Stats")
    cd_stats += template.format("Years: ".ljust(22), rounds_to_str(cd_years))
    cd_stats += template.format("Num Races: ".ljust(22), str(num_races))
    cd_stats += template.format("Num Wins: ".ljust(22), str(num_wins))
    cd_stats += template.format("Num Podiums: ".ljust(22),
                                str(num_podiums_str))
    if best_result:
        cd_stats += template.format("Best Result: ".ljust(22),
                                    str(best_result))
    cd_stats += template.format("Avg. Start Pos.: ".ljust(22), mean_sp)
    cd_stats += template.format("Avg. Finish Pos.: ".ljust(22), mean_fp)

    if not np.isnan(avg_lap_time):
        cd_stats += template.format("Avg. Lap Time: ".ljust(22),
                                    millis_to_str(avg_lap_time))
        cd_stats += template.format("Fastest Lap Time: ".ljust(22),
                                    millis_to_str(fastest_lap_time))
    cd_stats += template.format("Num. Mechanical DNFs: ".ljust(22),
                                mechanical_dnfs_str)
    cd_stats += template.format("Num. Crash DNFs: ".ljust(22), crash_dnfs_str)
    cd_stats += template.format("Num Finishes".ljust(22), finishes_str)
    if positions_source.shape[0] > 0:
        cd_stats += template.format("Compared to Average: ".ljust(22),
                                    finish_pos_diff_str)

    return Div(text=cd_stats)
Ejemplo n.º 23
0
def get_layout(circuit_id=-1,
               constructor_id=-1,
               download_image=True,
               **kwargs):
    # Grab some useful slices
    circuit_rids = races[races["circuitId"] == circuit_id].index.values
    constructor_results = results[results["constructorId"] == constructor_id]
    cc_results = constructor_results[constructor_results["raceId"].isin(
        circuit_rids)]
    cc_rids = cc_results["raceId"]
    cc_races = races[races.index.isin(cc_rids)]

    logging.info(
        f"Generating layout for mode CIRCUITCONSTRUCTOR in circuitconstructor, circuit_id={circuit_id}, "
        f"constructor_id={constructor_id}")

    # Detect invalid combos
    if cc_races.shape[0] == 0:
        return generate_error_layout(circuit_id, constructor_id)

    # Generate some more slices
    circuit_results = results[results["raceId"].isin(circuit_rids)]
    circuit_fastest_lap_data = fastest_lap_data[
        fastest_lap_data["raceId"].isin(circuit_rids)]
    cc_years = cc_races["year"].unique()
    cc_years.sort()
    cc_fastest_lap_data_idxs = []
    cc_lap_time_idxs = []
    cc_driver_standings_idxs = []
    for idx, results_row in cc_results.iterrows():
        rid = results_row["raceId"]
        did = results_row["driverId"]
        fl_slice = circuit_fastest_lap_data[
            circuit_fastest_lap_data["driver_id"] == did]
        cc_fastest_lap_data_idxs.extend(fl_slice.index.values.tolist())
        lt_slice = lap_times[(lap_times["raceId"] == rid)
                             & (lap_times["driverId"] == did)]
        cc_lap_time_idxs.extend(lt_slice.index.values.tolist())
        driver_standings_slice = driver_standings[
            (driver_standings["raceId"] == rid)
            & (driver_standings["driverId"] == did)]
        cc_driver_standings_idxs.extend(
            driver_standings_slice.index.values.tolist())
    cc_fastest_lap_data = circuit_fastest_lap_data.loc[
        cc_fastest_lap_data_idxs]
    cc_lap_times = lap_times.loc[cc_lap_time_idxs]
    cc_driver_standings = driver_standings.loc[cc_driver_standings_idxs]
    constructor_constructor_standings = constructor_standings[
        constructor_standings["constructorId"] == constructor_id]

    positions_plot, positions_source = generate_positions_plot(
        cc_years, cc_fastest_lap_data, constructor_results,
        constructor_constructor_standings, cc_races, constructor_id)
    positions_plot = PlotItem(
        positions_plot, [],
        COMMON_PLOT_DESCRIPTIONS["generate_positions_plot"])

    win_plot = PlotItem(generate_win_plot, [positions_source, constructor_id],
                        COMMON_PLOT_DESCRIPTIONS["generate_win_plot"])

    lap_time_distribution_plot = PlotItem(
        generate_lap_time_plot,
        [cc_lap_times, cc_rids, circuit_id, constructor_id],
        COMMON_PLOT_DESCRIPTIONS["generate_times_plot"])

    finish_position_bar_plot = PlotItem(
        generate_finishing_position_bar_plot, [cc_results],
        COMMON_PLOT_DESCRIPTIONS["generate_finishing_position_bar_plot"])

    spvfp_scatter = PlotItem(
        generate_spvfp_scatter, [cc_results, cc_races, cc_driver_standings],
        COMMON_PLOT_DESCRIPTIONS["generate_spvfp_scatter"])

    mltr_fp_scatter = PlotItem(
        generate_mltr_fp_scatter, [cc_results, cc_races, cc_driver_standings],
        COMMON_PLOT_DESCRIPTIONS["generate_mltr_fp_scatter"])

    description = u"Various statistics on this constructor at this circuit"
    stats_div = PlotItem(generate_stats_layout, [
        cc_years, cc_races, cc_results, cc_fastest_lap_data, positions_source,
        circuit_id, constructor_id
    ], description)

    description = u"Results Table \u2014 table showing this constructor's results at every race this circuit"
    results_table = PlotItem(generate_results_table, [
        cc_results, cc_fastest_lap_data, circuit_results,
        circuit_fastest_lap_data
    ], description)

    if download_image:
        # Track image
        circuit_row = circuits.loc[circuit_id]
        image_url = str(circuit_row["imgUrl"])
        image_view = plot_image_url(image_url)
        disclaimer = Div(
            text="The image is of the current configuration of the track.")
        image_view = column([image_view, disclaimer],
                            sizing_mode="stretch_both")
    else:
        image_view = Div()
    image_view = PlotItem(image_view, [], "", listed=False)

    circuit_name = get_circuit_name(circuit_id)
    constructor_name = get_constructor_name(constructor_id)
    header = generate_div_item(
        f"<h2><b>What did/does {constructor_name}'s performance at "
        f"{circuit_name} look like?</b></h2><br>")

    middle_spacer = generate_spacer_item()
    group = generate_plot_list_selector([[header], [positions_plot],
                                         [middle_spacer], [win_plot],
                                         [middle_spacer],
                                         [lap_time_distribution_plot],
                                         [middle_spacer],
                                         [finish_position_bar_plot],
                                         [middle_spacer],
                                         [spvfp_scatter, mltr_fp_scatter],
                                         [middle_spacer], [image_view],
                                         [stats_div], [results_table]])

    logging.info("Finished generating layout for mode CIRCUITCONSTRUCTOR")

    return group
Ejemplo n.º 24
0
def generate_circuit_results_table(circuit_years, circuit_races, circuit_results, circuit_qualifying,
                                   circuit_fastest_lap_data):
    """
    Show results for every race at that circuit, including polesetting and time, winner and time, 2nd and 3rd, and
    fastest lap if that data is available
    :param circuit_years: Circuit years
    :param circuit_races: Circuit races
    :param circuit_results: Circuit results
    :param circuit_qualifying: Circuit qualifying
    :param circuit_fastest_lap_data: Circuit fastest lap data
    :return: Table layout
    """
    logging.info("Generating circuit results table")
    source = pd.DataFrame(columns=["year", "laps", "pole", "fastest_lap", "p1", "p2", "p3"])
    for year in circuit_years:
        race = circuit_races[circuit_races["year"] == year]
        rid = race.index.values[0]
        results = circuit_results[circuit_results["raceId"] == rid]

        # Qualifying
        if results.shape[0] == 0:
            continue
        pole_row = results[results["grid"] == 1].iloc[0]
        pole_did = pole_row["driverId"]
        pole_name = get_driver_name(pole_did)
        quali = circuit_qualifying[(circuit_qualifying["raceId"] == rid) & (circuit_qualifying["driverId"] == pole_did)]
        quali = quali
        pole_time = ""
        if quali.shape[0] > 0:
            quali = quali.iloc[0]
            if not np.isnan(quali["q1"]):
                pole_time = millis_to_str(quali["q1"])
            if not np.isnan(quali["q2"]):
                pole_time = millis_to_str(quali["q2"])
            if not np.isnan(quali["q3"]):
                pole_time = millis_to_str(quali["q3"])
            pole_str = pole_name + " (" + pole_time + ")"
        else:
            pole_str = pole_name

        # Fastest lap
        fastest = circuit_fastest_lap_data[circuit_fastest_lap_data["raceId"] == rid]
        fastest = fastest[fastest["rank"] == " 1"]
        if fastest.shape[0] > 0:
            fastest = fastest.iloc[0]
            fastest_name = get_driver_name(fastest["driver_id"])
            fastest_time = fastest["fastest_lap_time_str"]
            fastest_str = fastest_name + " (" + fastest_time + ")"
        else:
            fastest_str = ""

        # Winner and num laps
        win = results[results["position"] == 1].iloc[0]
        winner_name = get_driver_name(win["driverId"])
        winner_time = millis_to_str(win["milliseconds"])
        winner_constructor = get_constructor_name(win["constructorId"])
        num_laps = win["laps"]

        # P2 and P3
        p2_name = results[results["position"] == 2]["driverId"]
        p3_name = results[results["position"] == 3]["driverId"]

        if p2_name.shape[0] > 0:
            p2_name = get_driver_name(p2_name.values[0])
        else:
            p2_name = ""
        if p3_name.shape[0] > 0:
            p3_name = get_driver_name(p3_name.values[0])
        else:
            p3_name = ""

        source = source.append({
            "year": year,
            "laps": num_laps,
            "pole": pole_str,
            "fastest_lap": fastest_str,
            "p1": winner_name + " (" + winner_time + "), " + winner_constructor,
            "p2": p2_name,
            "p3": p3_name
        }, ignore_index=True)

    title_div = Div(text="<h2><b>Circuit Results</b></h2>")

    source = source.sort_values(by="year", ascending=False)
    column_source = ColumnDataSource(data=source)
    results_columns = [
        TableColumn(field="year", title="Year", width=50),
        TableColumn(field="laps", title="Laps", width=50),
        TableColumn(field="pole", title="Pole Position", width=200),
        TableColumn(field="p1", title="First", width=300),
        TableColumn(field="p2", title="Second", width=150),
        TableColumn(field="p3", title="Third", width=150),
    ]
    if source["fastest_lap"].isna().sum() + source[source["fastest_lap"].str.match("")].shape[0] < source.shape[0]:
        results_columns.insert(3, TableColumn(field="fastest_lap", title="Fastest Lap", width=200))
    fast_table = DataTable(source=column_source, columns=results_columns, index_position=None, min_height=530)
    fast_row = row([fast_table], sizing_mode="stretch_width")

    return column([title_div, fast_row], sizing_mode="stretch_width")
Ejemplo n.º 25
0
def generate_circuits_table():
    """
    Generates a table with information on every circuit.
    :return: Circuits table layout
    """
    source = pd.DataFrame(columns=[
        "circuit_name", "location", "num_races", "years", "top_driver",
        "top_constructor"
    ])
    for cid, circuit_row in circuits.iterrows():
        circuit_name = get_circuit_name(cid)
        location = circuit_row["location"] + ", " + circuit_row["country"]
        circuit_races = races[races["circuitId"] == cid]
        num_races = circuit_races.shape[0]
        years = circuit_races["year"].unique()
        years.sort()
        years = rounds_to_str(years)
        circuit_winners = results[(results["raceId"].isin(circuit_races.index))
                                  & (results["position"] == 1)]
        driver_winners = circuit_winners["driverId"].value_counts()
        top_num_wins = driver_winners.iloc[0]
        top_driver_winners = []
        for did, num_wins in driver_winners.iteritems():
            if num_wins == top_num_wins:
                top_driver_winners.append(
                    get_driver_name(did) + " (" + str(num_wins) + " wins)")
            else:
                break
        top_driver_winners = ", ".join(top_driver_winners)

        constructor_winners = circuit_winners["constructorId"].value_counts()
        top_num_wins = constructor_winners.iloc[0]
        top_constructor_winners = []
        for constructor_id, num_wins in constructor_winners.iteritems():
            if num_wins == top_num_wins:
                top_constructor_winners.append(
                    get_constructor_name(constructor_id) + " (" +
                    str(num_wins) + " wins)")
            else:
                break
        top_constructor_winners = ", ".join(top_constructor_winners)

        source = source.append(
            {
                "circuit_name": circuit_name,
                "location": location,
                "num_races": num_races,
                "years": years,
                "top_driver": top_driver_winners,
                "top_constructor": top_constructor_winners
            },
            ignore_index=True)
    source = source.sort_values(by="num_races", ascending=False)

    circuits_columns = [
        TableColumn(field="circuit_name", title="Circuit Name", width=150),
        TableColumn(field="location", title="Location", width=100),
        TableColumn(field="num_races", title="Num. Races", width=50),
        TableColumn(field="years", title="Years", width=130),
        TableColumn(field="top_driver",
                    title="Top Winner(s) (Driver)",
                    width=275),
        TableColumn(field="top_constructor",
                    title="Top Winner(s) (Constructor)",
                    width=200),
    ]

    circuits_table = DataTable(source=ColumnDataSource(data=source),
                               columns=circuits_columns,
                               index_position=None)

    title = Div(text="<h2><b>All Circuits</b></h2>")

    return column([title, circuits_table], sizing_mode="stretch_width")