1
|
|
"""
|
2
|
|
Visualization using the plotly library.
|
3
|
|
"""
|
4
|
|
|
5
|
|
# Plotly is an optional library
|
6
|
8
|
from importlib.util import find_spec
|
7
|
8
|
from typing import Any, Dict, List
|
8
|
|
|
9
|
|
|
10
|
8
|
def _isnotebook():
|
11
|
|
"""
|
12
|
|
Checks if we are inside a jupyter notebook or not.
|
13
|
|
"""
|
14
|
8
|
try:
|
15
|
8
|
shell = get_ipython().__class__.__name__
|
16
|
0
|
if shell in ["ZMQInteractiveShell", "google.colab._shell"]:
|
17
|
0
|
return True
|
18
|
0
|
elif shell == "TerminalInteractiveShell":
|
19
|
0
|
return False
|
20
|
|
else:
|
21
|
0
|
return False
|
22
|
8
|
except NameError:
|
23
|
8
|
return False
|
24
|
|
|
25
|
|
|
26
|
8
|
spec = find_spec("plotly")
|
27
|
8
|
if spec is None:
|
28
|
0
|
_plotly_found = False
|
29
|
|
else:
|
30
|
8
|
_plotly_found = True
|
31
|
8
|
del spec, find_spec
|
32
|
|
|
33
|
|
|
34
|
8
|
def check_plotly():
|
35
|
|
"""
|
36
|
|
Checks if plotly is found and auto inits the offline notebook
|
37
|
|
"""
|
38
|
8
|
if _plotly_found is False:
|
39
|
0
|
raise ModuleNotFoundError(
|
40
|
|
"Plotly is required for this function. Please 'conda install plotly' or 'pip isntall plotly'."
|
41
|
|
)
|
42
|
|
|
43
|
8
|
if _isnotebook():
|
44
|
0
|
import plotly
|
45
|
|
|
46
|
0
|
plotly.offline.init_notebook_mode(connected=True)
|
47
|
|
|
48
|
|
|
49
|
8
|
def _configure_return(figure, filename, return_figure):
|
50
|
8
|
import plotly
|
51
|
|
|
52
|
8
|
if return_figure is None:
|
53
|
8
|
return_figure = not _isnotebook()
|
54
|
|
|
55
|
8
|
if return_figure:
|
56
|
8
|
return figure
|
57
|
|
else:
|
58
|
0
|
return plotly.offline.iplot(figure, filename=filename)
|
59
|
|
|
60
|
|
|
61
|
8
|
def custom_plot(data: Any, layout: Any, return_figure=True) -> "plotly.Figure":
|
62
|
|
"""A custom plotly plot where the data and layout are pre-specified
|
63
|
|
|
64
|
|
Parameters
|
65
|
|
----------
|
66
|
|
data : Any
|
67
|
|
Plotly data block
|
68
|
|
layout : Any
|
69
|
|
Plotly layout block
|
70
|
|
return_figure : bool, optional
|
71
|
|
Returns the raw plotly figure or not
|
72
|
|
"""
|
73
|
|
|
74
|
0
|
check_plotly()
|
75
|
0
|
import plotly.graph_objs as go
|
76
|
|
|
77
|
0
|
figure = go.Figure(data=data, layout=layout)
|
78
|
|
|
79
|
0
|
return _configure_return(figure, "qcportal-bar", return_figure)
|
80
|
|
|
81
|
|
|
82
|
8
|
def bar_plot(traces: "List[Series]", title=None, ylabel=None, return_figure=True) -> "plotly.Figure":
|
83
|
|
"""Renders a plotly bar plot
|
84
|
|
|
85
|
|
Parameters
|
86
|
|
----------
|
87
|
|
traces : List[Series]
|
88
|
|
A list of bar plots to show, if more than one series the resulting graph will be grouped.
|
89
|
|
title : None, optional
|
90
|
|
The title of the graph
|
91
|
|
ylabel : None, optional
|
92
|
|
The y axis label
|
93
|
|
return_figure : bool, optional
|
94
|
|
Returns the raw plotly figure or not
|
95
|
|
|
96
|
|
Returns
|
97
|
|
-------
|
98
|
|
plotly.Figure
|
99
|
|
The requested bar plot.
|
100
|
|
"""
|
101
|
|
|
102
|
8
|
check_plotly()
|
103
|
8
|
import plotly.graph_objs as go
|
104
|
|
|
105
|
8
|
data = [go.Bar(x=trace.index, y=trace, name=trace.name) for trace in traces]
|
106
|
|
|
107
|
8
|
layout = {}
|
108
|
8
|
if title:
|
109
|
8
|
layout["title"] = title
|
110
|
8
|
if ylabel:
|
111
|
8
|
layout["yaxis"] = {"title": ylabel}
|
112
|
8
|
layout = go.Layout(layout)
|
113
|
8
|
figure = go.Figure(data=data, layout=layout)
|
114
|
|
|
115
|
8
|
return _configure_return(figure, "qcportal-bar", return_figure)
|
116
|
|
|
117
|
|
|
118
|
8
|
def violin_plot(
|
119
|
|
traces: "DataFrame", negative: "DataFrame" = None, title=None, points=False, ylabel=None, return_figure=True
|
120
|
|
) -> "plotly.Figure":
|
121
|
|
"""Renders a plotly violin plot
|
122
|
|
|
123
|
|
Parameters
|
124
|
|
----------
|
125
|
|
traces : DataFrame
|
126
|
|
Pandas DataFrame of points to plot, will create a violin plot of each column.
|
127
|
|
negative : DataFrame, optional
|
128
|
|
A comparison violin plot, these columns will present the right hand side.
|
129
|
|
title : None, optional
|
130
|
|
The title of the graph
|
131
|
|
points : None, optional
|
132
|
|
Show points or not, this option is not available for comparison violin plots.
|
133
|
|
ylabel : None, optional
|
134
|
|
The y axis label
|
135
|
|
return_figure : bool, optional
|
136
|
|
Returns the raw plotly figure or not
|
137
|
|
|
138
|
|
Returns
|
139
|
|
-------
|
140
|
|
plotly.Figure
|
141
|
|
The requested violin plot.
|
142
|
|
"""
|
143
|
8
|
check_plotly()
|
144
|
8
|
import plotly.graph_objs as go
|
145
|
|
|
146
|
8
|
data = []
|
147
|
8
|
if negative is not None:
|
148
|
|
|
149
|
8
|
for trace, side in zip([traces, negative], ["positive", "negative"]):
|
150
|
8
|
p = {"name": trace.name, "type": "violin", "box": {"visible": True}}
|
151
|
8
|
p["y"] = trace.stack()
|
152
|
8
|
p["x"] = trace.stack().reset_index().level_1
|
153
|
8
|
p["side"] = side
|
154
|
|
|
155
|
8
|
data.append(p)
|
156
|
|
else:
|
157
|
8
|
for name, series in traces.items():
|
158
|
8
|
p = {"name": name, "type": "violin", "box": {"visible": True}}
|
159
|
8
|
p["y"] = series
|
160
|
|
|
161
|
8
|
data.append(p)
|
162
|
|
|
163
|
8
|
layout = go.Layout({"title": title, "yaxis": {"title": ylabel}})
|
164
|
8
|
figure = go.Figure(data=data, layout=layout)
|
165
|
|
|
166
|
8
|
return _configure_return(figure, "qcportal-violin", return_figure)
|
167
|
|
|
168
|
|
|
169
|
8
|
def scatter_plot(
|
170
|
|
traces: List[Dict[str, Any]],
|
171
|
|
mode="lines+markers",
|
172
|
|
title=None,
|
173
|
|
ylabel=None,
|
174
|
|
xlabel=None,
|
175
|
|
xline=True,
|
176
|
|
yline=True,
|
177
|
|
custom_layout=None,
|
178
|
|
return_figure=True,
|
179
|
|
) -> "plotly.Figure":
|
180
|
|
"""Renders a plotly scatter plot
|
181
|
|
|
182
|
|
Parameters
|
183
|
|
----------
|
184
|
|
traces : List[Dict[str, Any]]
|
185
|
|
A List of traces to plot, require x and y values
|
186
|
|
mode : str, optional
|
187
|
|
The mode of lines, will not override mode in the traces dictionary
|
188
|
|
title : None, optional
|
189
|
|
The title of the graph
|
190
|
|
ylabel : None, optional
|
191
|
|
The y axis label
|
192
|
|
xlabel : None, optional
|
193
|
|
The x axis label
|
194
|
|
xline : bool, optional
|
195
|
|
Show the x-zeroline
|
196
|
|
yline : bool, optional
|
197
|
|
Show the y-zeroline
|
198
|
|
custom_layout : None, optional
|
199
|
|
Overrides all other layout options
|
200
|
|
return_figure : bool, optional
|
201
|
|
Returns the raw plotly figure or not
|
202
|
|
|
203
|
|
Returns
|
204
|
|
-------
|
205
|
|
plotly.Figure
|
206
|
|
The requested scatter plot.
|
207
|
|
|
208
|
|
"""
|
209
|
1
|
check_plotly()
|
210
|
1
|
import plotly.graph_objs as go
|
211
|
|
|
212
|
1
|
data = []
|
213
|
1
|
for trace in traces:
|
214
|
1
|
data.append(go.Scatter(**trace))
|
215
|
|
|
216
|
1
|
if custom_layout is None:
|
217
|
0
|
layout = go.Layout(
|
218
|
|
{
|
219
|
|
"title": title,
|
220
|
|
"yaxis": {"title": ylabel, "zeroline": yline},
|
221
|
|
"xaxis": {"title": xlabel, "zeroline": xline},
|
222
|
|
}
|
223
|
|
)
|
224
|
|
else:
|
225
|
1
|
layout = go.Layout(**custom_layout)
|
226
|
1
|
figure = go.Figure(data=data, layout=layout)
|
227
|
|
|
228
|
1
|
return _configure_return(figure, "qcportal-violin", return_figure)
|