UTI: Add Download for iterative data.
[csit.git] / resources / tools / dash / app / pal / stats / graphs.py
1 # Copyright (c) 2022 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """
15 """
16
17 import plotly.graph_objects as go
18 import pandas as pd
19
20 from datetime import datetime, timedelta
21
22 def select_data(data: pd.DataFrame, itm:str, start: datetime,
23         end: datetime) -> pd.DataFrame:
24     """Select the data for graphs from the provided data frame.
25
26     :param data: Data frame with data for graphs.
27     :param itm: Item (in this case job name) which data will be selected from
28         the input data frame.
29     :param start: The date (and time) when the selected data starts.
30     :param end: The date (and time) when the selected data ends.
31     :type data: pandas.DataFrame
32     :type itm: str
33     :type start: datetime.datetime
34     :type end: datetime.datetime
35     :returns: A data frame with selected data.
36     :rtype: pandas.DataFrame
37     """
38
39     df = data.loc[
40         (data["job"] == itm) &
41         (data["start_time"] >= start) & (data["start_time"] <= end)
42     ].sort_values(by="start_time", ignore_index=True)
43     df = df.dropna(subset=["duration", ])
44
45     return df
46
47
48 def graph_statistics(df: pd.DataFrame, job:str, layout: dict,
49         start: datetime=datetime.utcnow()-timedelta(days=180),
50         end: datetime=datetime.utcnow()) -> tuple:
51     """Generate graphs:
52     1. Passed / failed tests,
53     2. Job durations
54     with additional information shown in hover.
55
56     :param df: Data frame with input data.
57     :param job: The name of job which data will be presented in the graphs.
58     :param layout: Layout of plot.ly graph.
59     :param start: The date (and time) when the selected data starts.
60     :param end: The date (and time) when the selected data ends.
61     :type df: pandas.DataFrame
62     :type job: str
63     :type layout: dict
64     :type start: datetime.datetime
65     :type end: datetime.datetime
66     :returns: Tuple with two generated graphs (pased/failed tests and job
67         duration).
68     :rtype: tuple(plotly.graph_objects.Figure, plotly.graph_objects.Figure)
69     """
70
71     data = select_data(df, job, start, end)
72     if data.empty:
73         return None, None
74
75     hover = list()
76     for _, row in data.iterrows():
77         d_type = "trex" if row["dut_type"] == "none" else row["dut_type"]
78         hover_itm = (
79             f"date: {row['start_time'].strftime('%Y-%m-%d %H:%M:%S')}<br>"
80             f"duration: "
81             f"{(int(row['duration']) // 3600):02d}:"
82             f"{((int(row['duration']) % 3600) // 60):02d}<br>"
83             f"passed: {row['passed']}<br>"
84             f"failed: {row['failed']}<br>"
85             f"{d_type}-ref: {row['dut_version']}<br>"
86             f"csit-ref: {row['job']}/{row['build']}<br>"
87             f"hosts: {', '.join(row['hosts'])}"
88         )
89         hover.append(hover_itm)
90
91     # Job durations:
92     fig_duration = go.Figure(
93         data=go.Scatter(
94             x=data["start_time"],
95             y=data["duration"],
96             name=u"Duration",
97             text=hover,
98             hoverinfo=u"text"
99         )
100     )
101
102     tickvals = [0, ]
103     step = max(data["duration"]) / 5
104     for i in range(5):
105         tickvals.append(int(step * (i + 1)))
106     layout_duration = layout.get("plot-stats-duration", dict())
107     if layout_duration:
108         layout_duration["yaxis"]["tickvals"] = tickvals
109         layout_duration["yaxis"]["ticktext"] = [
110             f"{(val // 3600):02d}:{((val % 3600) // 60):02d}" \
111                 for val in tickvals
112         ]
113         fig_duration.update_layout(layout_duration)
114
115     # Passed / failed:
116     fig_passed = go.Figure(
117         data=[
118             go.Bar(
119                 x=data["start_time"],
120                 y=data["passed"],
121                 name=u"Passed",
122                 hovertext=hover,
123                 hoverinfo=u"text"
124             ),
125             go.Bar(
126                 x=data["start_time"],
127                 y=data["failed"],
128                 name=u"Failed",
129                 hovertext=hover,
130                 hoverinfo=u"text"
131             )
132         ]
133     )
134     layout_pf = layout.get("plot-stats-passed", dict())
135     if layout_pf:
136         fig_passed.update_layout(layout_pf)
137
138     return fig_passed, fig_duration