+
+ def _generate_trending_traces(
+ ttype: str,
+ name: str,
+ df: pd.DataFrame,
+ color: str,
+ norm_factor: float
+ ) -> list:
+ """Generate the trending traces for the trending graph.
+
+ :param ttype: Test type (MRR, NDR, PDR).
+ :param name: The test name to be displayed as the graph title.
+ :param df: Data frame with test data.
+ :param color: The color of the trace (samples and trend line).
+ :param norm_factor: The factor used for normalization of the results to
+ CPU frequency set to Constants.NORM_FREQUENCY.
+ :type ttype: str
+ :type name: str
+ :type df: pandas.DataFrame
+ :type color: str
+ :type norm_factor: float
+ :returns: Traces (samples, trending line, anomalies)
+ :rtype: list
+ """
+
+ df = df.dropna(subset=[C.VALUE[ttype], ])
+ if df.empty:
+ return list(), list()
+
+ x_axis = df["start_time"].tolist()
+ if ttype == "latency":
+ y_data = [(v / norm_factor) for v in df[C.VALUE[ttype]].tolist()]
+ else:
+ y_data = [(v * norm_factor) for v in df[C.VALUE[ttype]].tolist()]
+ units = df[C.UNIT[ttype]].unique().tolist()
+
+ anomalies, trend_avg, trend_stdev = classify_anomalies(
+ {k: v for k, v in zip(x_axis, y_data)}
+ )
+
+ hover = list()
+ customdata = list()
+ customdata_samples = list()
+ for idx, (_, row) in enumerate(df.iterrows()):
+ d_type = "trex" if row["dut_type"] == "none" else row["dut_type"]
+ hover_itm = (
+ f"date: {row['start_time'].strftime('%Y-%m-%d %H:%M:%S')}<br>"
+ f"<prop> [{row[C.UNIT[ttype]]}]: {y_data[idx]:,.0f}<br>"
+ f"<stdev>"
+ f"<additional-info>"
+ f"{d_type}-ref: {row['dut_version']}<br>"
+ f"csit-ref: {row['job']}/{row['build']}<br>"
+ f"hosts: {', '.join(row['hosts'])}"
+ )
+ if ttype == "mrr":
+ stdev = (
+ f"stdev [{row['result_receive_rate_rate_unit']}]: "
+ f"{row['result_receive_rate_rate_stdev']:,.0f}<br>"
+ )
+ else:
+ stdev = str()
+ if ttype in ("hoststack-cps", "hoststack-rps"):
+ add_info = (
+ f"bandwidth [{row[C.UNIT['hoststack-bps']]}]: "
+ f"{row[C.VALUE['hoststack-bps']]:,.0f}<br>"
+ f"latency [{row[C.UNIT['hoststack-lat']]}]: "
+ f"{row[C.VALUE['hoststack-lat']]:,.0f}<br>"
+ )
+ else:
+ add_info = str()
+ hover_itm = hover_itm.replace(
+ "<prop>", "latency" if ttype == "latency" else "average"
+ ).replace("<stdev>", stdev).replace("<additional-info>", add_info)
+ hover.append(hover_itm)
+ if ttype == "latency":
+ customdata_samples.append(get_hdrh_latencies(row, name))
+ customdata.append({"name": name})
+ else:
+ customdata_samples.append(
+ {"name": name, "show_telemetry": True}
+ )
+ customdata.append({"name": name})
+
+ hover_trend = list()
+ for avg, stdev, (_, row) in zip(trend_avg, trend_stdev, df.iterrows()):
+ d_type = "trex" if row["dut_type"] == "none" else row["dut_type"]
+ hover_itm = (
+ f"date: {row['start_time'].strftime('%Y-%m-%d %H:%M:%S')}<br>"
+ f"trend [{row[C.UNIT[ttype]]}]: {avg:,.0f}<br>"
+ f"stdev [{row[C.UNIT[ttype]]}]: {stdev:,.0f}<br>"
+ f"{d_type}-ref: {row['dut_version']}<br>"
+ f"csit-ref: {row['job']}/{row['build']}<br>"
+ f"hosts: {', '.join(row['hosts'])}"
+ )
+ if ttype == "latency":
+ hover_itm = hover_itm.replace("[pps]", "[us]")
+ hover_trend.append(hover_itm)
+
+ traces = [
+ go.Scatter( # Samples
+ x=x_axis,
+ y=y_data,
+ name=name,
+ mode="markers",
+ marker={
+ "size": 5,
+ "color": color,
+ "symbol": "circle",
+ },
+ text=hover,
+ hoverinfo="text+name",
+ showlegend=True,
+ legendgroup=name,
+ customdata=customdata_samples
+ ),
+ go.Scatter( # Trend line
+ x=x_axis,
+ y=trend_avg,
+ name=name,
+ mode="lines",
+ line={
+ "shape": "linear",
+ "width": 1,
+ "color": color,
+ },
+ text=hover_trend,
+ hoverinfo="text+name",
+ showlegend=False,
+ legendgroup=name,
+ customdata=customdata
+ )
+ ]
+
+ if anomalies:
+ anomaly_x = list()
+ anomaly_y = list()
+ anomaly_color = list()
+ hover = list()
+ for idx, anomaly in enumerate(anomalies):
+ if anomaly in ("regression", "progression"):
+ anomaly_x.append(x_axis[idx])
+ anomaly_y.append(trend_avg[idx])
+ anomaly_color.append(C.ANOMALY_COLOR[anomaly])
+ hover_itm = (
+ f"date: {x_axis[idx].strftime('%Y-%m-%d %H:%M:%S')}<br>"
+ f"trend [pps]: {trend_avg[idx]:,.0f}<br>"
+ f"classification: {anomaly}"
+ )
+ if ttype == "latency":
+ hover_itm = hover_itm.replace("[pps]", "[us]")
+ hover.append(hover_itm)
+ anomaly_color.extend([0.0, 0.5, 1.0])
+ traces.append(
+ go.Scatter(
+ x=anomaly_x,
+ y=anomaly_y,
+ mode="markers",
+ text=hover,
+ hoverinfo="text+name",
+ showlegend=False,
+ legendgroup=name,
+ name=name,
+ customdata=customdata,
+ marker={
+ "size": 15,
+ "symbol": "circle-open",
+ "color": anomaly_color,
+ "colorscale": C.COLORSCALE_LAT \
+ if ttype == "latency" else C.COLORSCALE_TPUT,
+ "showscale": True,
+ "line": {
+ "width": 2
+ },
+ "colorbar": {
+ "y": 0.5,
+ "len": 0.8,
+ "title": "Circles Marking Data Classification",
+ "titleside": "right",
+ "tickmode": "array",
+ "tickvals": [0.167, 0.500, 0.833],
+ "ticktext": C.TICK_TEXT_LAT \
+ if ttype == "latency" else C.TICK_TEXT_TPUT,
+ "ticks": "",
+ "ticklen": 0,
+ "tickangle": -90,
+ "thickness": 10
+ }
+ }
+ )
+ )
+
+ return traces, units
+
+