-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuplot_lib.py
More file actions
222 lines (200 loc) · 7.66 KB
/
uplot_lib.py
File metadata and controls
222 lines (200 loc) · 7.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
from IPython.display import IFrame, HTML
import json
from jinja2 import Template
# def uplot_data(data=[], options='{}', html=False):
def uplot_data(data=[], labels=[], html=False, **kwargs):
""" Wrapper to use javascript library uplot in jupyter
Keyword arguments:
data: List of data to be plotted, the format is [x, y1, y2, ...]
x, y1, y2, etc are all lists of values. They all need to be
the same length. If there are no values of y for an x value,
None can be used as the y-value for that x-value
labels: List of Labels for each y-list in data.
html: instead of returning rendered HTML, return string of html to be
renedered
**kwargs: Extra arguments to be passed to the uplot library
e.g. title='Title', size=10, etc.
Javascript library source code
https://github.com/leeoniya/uPlot
"""
h = '''
<link rel="stylesheet" href="https://leeoniya.github.io/uPlot/dist/uPlot.min.css">
<script src="https://leeoniya.github.io/uPlot/dist/uPlot.iife.js"></script>
<div id="plot"></div>
<script>
data = {{data}}
options = {{options}};
if (typeof options.scatter == 'undefined') {
options.scatter = false
}
if (options.scatter) {
for (i=1; i<data.length; i++) {
options['series'][i]["paths"] = u => null;
}
}
u2 = new uPlot(options, data, document.getElementById("plot"))
</script>
'''
options = build_uplot_options(len(data)-1, labels, **kwargs)
h2 = Template(h).render(data=json.dumps(data), options=options)
h2 = h2.replace('"', "'")
# print(h2)
iframe = '''<iframe srcdoc="{source}" src=""
width={w} height="{h}" frameborder="0" sandbox="allow-scripts">
</iframe>'''
if html:
return h2
else:
# return HTML(h2)
return HTML(iframe.format(source=h2, w=800, h=400))
def build_uplot_options(num_yseries, labels=[], **kwargs):
# If plot shows up but no points, the number of lables/series may mismatch
# the number y-series values
colors = ["lavender",
"thistle",
"plum",
"violet",
"orchid",
"fuchsia",
"magenta",
"mediumorchid",
"mediumpurple",
"blueviolet",
"darkviolet",
"darkorchid",
"darkmagenta",
"purple",
"indigo"
]
colors.reverse()
options_dict = {'title': '',
'width': 750,
'height': 300,
'scales': {'x': {'time': False}, 'y': {'auto': True}},
'series': [{'label': 'x'}]}
for key in kwargs.keys():
if key in options_dict.keys():
options_dict[key] = kwargs[key]
if 'scatter' in kwargs.keys():
options_dict['scatter'] = kwargs['scatter']
if 'size' in kwargs.keys():
size = kwargs['size']
else:
size = 2
# Check that length of labels matches length in data
# build options
if (len(labels)<(num_yseries)):
extra = [f'y_{i}' for i in range(num_yseries-len(labels))]
labels += extra
else:
labels = labels[:num_yseries]
if len(labels):
y_series = [{'label': labels[i],
'stroke': colors[i],
'points': {'space': 0, 'size': size}}
for i in range(len(labels))]
# print(y_series)
options_dict['series'] += y_series
return json.dumps(options_dict)
def uplot_scatter(data, labels=[], html=False, **kwargs):
""" Wrapper to use javascript library uplot in jupyter to make a
scatterplot
Keyword arguments:
data: List of data to be plotted, the format is [x, y1, y2, ...]
x, y1, y2, etc are all lists of values. They all need to be
the same length. If there are no values of y for an x value,
None can be used as the y-value for that x-value
labels: List of Labels for each y-list in data.
html: instead of returning rendered HTML, return string of html to be
renedered
**kwargs: Extra arguments to be passed to the uplot library
e.g. title='Title', size=10, etc.
Javascript library source code
https://github.com/leeoniya/uPlot
"""
return uplot_data(data, labels, html=html, scatter=True, **kwargs)
def uplot_multixy(data=[], labels=[], html=False, **kwargs):
""" Wrapper to use javascript library uplot in jupyter to make a
scatterplot with multiple x and y values
Keyword arguments:
data: List of data to be plotted, the format is [x1, y1, x2, y2, ...]
x1, y1, y2, etc are all lists of numbers. The x_n and y_n
need to be the same length. But, the different sets of x and
y values do not need to be the same. The wrapper merges all
of the x values into one large x list.
labels: List of Labels for each y-list in data.
html: instead of returning rendered HTML, return string of html to be
renedered
**kwargs: Extra arguments to be passed to the uplot library
e.g. title='Title', size=10, etc.
Javascript library source code
https://github.com/leeoniya/uPlot
"""
h = '''
<link rel="stylesheet" href="https://leeoniya.github.io/uPlot/dist/uPlot.min.css">
<script src="https://leeoniya.github.io/uPlot/dist/uPlot.iife.js"></script>
<div id="plot"></div>
<script>
function build_data(d) {
data = [d[0], d[1]]
if (d.length>2) {
i=2
while(i<d.length) {
data = merge(data, [d[i], d[i+1]])
i += 2
}
}
return data
}
function sorted(input, argsort) {
let sorted = new Array(argsort.length)
for(let i=0; i<argsort.length; i++) {
sorted[i] = input[argsort[i]]
}
return sorted
}
function merge(a,b) {
// build t, but don't sort yet
t = a[0]
t = t.concat(b[0])
//
argsort = t.map((item,idx)=>[item,idx]).sort((a,b)=>(a[0]-b[0])).map(item=>item[1])
// console.log('argsort',argsort)
t = sorted(t, argsort)
data = [t]
// console.log('a.length', a.length);
for (let i=1; i<a.length; i++) {
let y1 = [...a[i]] // shallow copy
y1.length += b[0].length;
let s = sorted(y1, argsort)
data.push(s)
// console.log('push s', i, s)
}
y2 = new Array(a[0].length)
y2 = y2.concat(b[1])
s = sorted(y2, argsort)
data.push(s)
return data
}
data_in = {{data}}
data = build_data(data_in)
// console.log(data)
options = {{options}};
for (i=1; i<data.length; i++) {
options['series'][i]["paths"] = u => null;
}
u2 = new uPlot(options, data, document.getElementById("plot"))
</script>
'''
options = build_uplot_options(len(data)>>1, labels, **kwargs)
h2 = Template(h).render(data=data, options=options)
h2 = h2.replace('"', "'")
# print(h2)
iframe = '''<iframe srcdoc="{source}" src=""
width={w} height="{h}" frameborder="0" sandbox="allow-scripts">
</iframe>'''
if html:
return h2
else:
# return HTML(h2)
return HTML(iframe.format(source=h2, w=800, h=400))