Completed
Push — master ( 77a482...bbe50c )
by Chris
01:42
created

vegalite()   B

Complexity

Conditions 6

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
dl 0
loc 35
rs 7.5384
c 0
b 0
f 0
1
"""A separate Flask app that serves fake endpoints for demo purposes."""
2
3
# -*- coding: utf-8 -*-
4
5
import csv
6
import json
7
import locale
8
import os
9
from datetime import timedelta as td
10
from datetime import datetime as dt
11
from random import randrange as rr
12
from random import choice, random
13
import time
14
15
from flask import (
16
    Flask,
17
    abort,
18
    request,
19
    jsonify,
20
    render_template,
21
)
22
from flask_cors import CORS
23
from flask_cors import cross_origin
24
25
app = Flask('endpoints_test')
26
CORS(app)
27
app.config['SECRET_KEY'] = 'NOTSECURELOL'
28
app.debug = True
29
30
STRESS_MAX_POINTS = 300
31
32
locale.setlocale(locale.LC_ALL, '')
33
34
cwd = os.getcwd()
35
36
37
def recursive_d3_data(current=0, max_iters=12, data=None):
38
    """Generate d3js data for stress testing.
39
    Format is suitable in treemap, circlepack and dendrogram testing.
40
    """
41
    if current >= max_iters:
42
        return data
43
    if data is None:
44
        data = dict(name='foo', size=rr(10, 10000), children=[])
45
    data = dict(name='foo', size=rr(10, 10000),
46
                children=[data, data])
47
    return recursive_d3_data(
48
        current=current + 1,
49
        max_iters=max_iters,
50
        data=data)
51
52
53
def dates_list(max_dates=10):
54
    """Generate a timeseries dates list."""
55
    now = dt.now()
56
    return [str(now + td(days=i * 10))[0:10] for i in range(max_dates)]
57
58
59
def rr_list(max_range=10):
60
    """Generate a list of random integers."""
61
    return [rr(0, 100) for i in range(max_range)]
62
63
64
@cross_origin()
65
@app.route('/combination')
66
def combination():
67
    """Fake endpoint."""
68
    data = {
69
        'columns': [
70
            ['data1', 30, 20, 50, 40, 60, 50],
71
            ['data2', 200, 130, 90, 240, 130, 220],
72
            ['data3', 300, 200, 160, 400, 250, 250],
73
            ['data4', 200, 130, 90, 240, 130, 220],
74
            ['data5', 130, 120, 150, 140, 160, 150],
75
            ['data6', 90, 70, 20, 50, 60, 120],
76
        ],
77
        'type': 'bar',
78
        'types': {
79
            'data3': 'spline',
80
            'data4': 'line',
81
            'data6': 'area',
82
        },
83
        'groups': [
84
            ['data1', 'data2'],
85
        ]
86
    }
87
    return jsonify(dict(data=data))
88
89
90
@cross_origin()
91
@app.route('/stacked-bar')
92
def stackedbar():
93
    """Fake endpoint."""
94
    return jsonify({
95
        'data': {
96
            'columns': [
97
                ['data1', -30, 200, 200, 400, -150, 250],
98
                ['data2', 130, 100, -100, 200, -150, 50],
99
                ['data3', -230, 200, 200, -300, 250, 250]
100
            ],
101
            'type': 'bar',
102
            'groups': [
103
                ['data1', 'data2']
104
            ]
105
        },
106
        'grid': {
107
            'y': {
108
                'lines': [{'value': 0}]
109
            }
110
        }
111
    })
112
113
114
@cross_origin()
115
@app.route('/wordcloud')
116
def wordcloud():
117
    """Fake endpoint."""
118
    words = [
119
        'awesome', 'rad', 'neato', 'the', 'flask', 'jsondash', 'graphs',
120
        'charts', 'd3', 'js', 'dashboards', 'c3',
121
    ]
122
    sizes = range(len(words))
123
    return jsonify([
124
        {'text': word, 'size': sizes[i] * 12} for i, word in enumerate(words)
125
    ])
126
127
128
@cross_origin()
129
@app.route('/vegalite')
130
def vegalite():
131
    """Fake endpoint.
132
133
    Reads data from a local vega spec, and if there is a
134
    remote url specified, (assuming it exists here), open and load it as well.
135
136
    This returns all required json as a single endpoint.
137
    """
138
    chart_type = request.args.get('type', 'bar')
139
    filename = '{}/examples/vegalite/{}.json'.format(cwd, chart_type)
140
    try:
141
        with open(filename, 'r') as chartjson:
142
            chartjson = chartjson.read()
143
            data = json.loads(chartjson)
144
            if data.get('data', {}).get('url') is not None:
145
                datapath = '{}/examples/vegalite/{}'.format(
146
                    cwd, data['data']['url']
147
                )
148
                with open(datapath, 'r') as datafile:
149
                    if datapath.endswith('.json'):
150
                        raw_data = datafile.read()
151
                        raw_data = json.loads(raw_data)
152
                    # TODO: adding csv support for example.
153
                    data.update(data=dict(
154
                        name='some data',
155
                        values=raw_data,
156
                    ))
157
                    return jsonify(data)
158
            else:
159
                return chartjson
160
    except IOError:
161
        pass
162
    return jsonify({})
163
164
165
@cross_origin()
166
@app.route('/plotly')
167
def plotly():
168
    """Fake endpoint."""
169
    chart_type = request.args.get('chart', 'line')
170
    filename = '{}/examples/plotly/{}.json'.format(cwd, chart_type)
171
    with open(filename, 'r') as chartjson:
172
        return chartjson.read()
173
    return jsonify({})
174
175
176
@cross_origin
177
@app.route('/plotly-dynamic')
178
def plotly_dynamic():
179
    """Fake endpoint."""
180
    filename = '{}/examples/plotly/bar_line_dynamic.json'.format(cwd)
181
    with open(filename, 'r') as chartjson:
182
        return chartjson.read()
183
    return jsonify({})
184
185
186
@cross_origin()
187
@app.route('/timeline')
188
def timeline():
189
    """Fake endpoint."""
190
    with open('{}/examples/timeline3.json'.format(cwd), 'r') as timelinejson:
191
        return timelinejson.read()
192
    return jsonify({})
193
194
195
@app.route('/dtable', methods=['GET'])
196
def dtable():
197
    """Fake endpoint."""
198
    if 'stress' in request.args:
199
        return jsonify([
200
            dict(
201
                foo=rr(1, 1000),
202
                bar=rr(1, 1000),
203
                baz=rr(1, 1000),
204
                quux=rr(1, 1000)) for _ in range(STRESS_MAX_POINTS)
205
        ])
206
    fname = 'dtable-override' if 'override' in request.args else 'dtable'
207
    with open('{}/examples/{}.json'.format(os.getcwd(), fname), 'r') as djson:
208
        return djson.read()
209
    return jsonify({})
210
211
212
@cross_origin()
213
@app.route('/timeseries')
214
def timeseries():
215
    """Fake endpoint."""
216
    return jsonify({
217
        "dates": dates_list(),
218
        "line1": rr_list(max_range=10),
219
        "line2": rr_list(max_range=10),
220
        "line3": rr_list(max_range=10),
221
    })
222
223
224
@cross_origin()
225
@app.route('/custom')
226
def custompage():
227
    """Fake endpoint."""
228
    kwargs = dict(number=rr(1, 1000))
229
    return render_template('examples/custom.html', **kwargs)
230
231
232
@cross_origin()
233
@app.route('/gauge')
234
def gauge():
235
    """Fake endpoint."""
236
    return jsonify({'data': rr(1, 100)})
237
238
239
@cross_origin()
240
@app.route('/area-custom')
241
def area_custom():
242
    """Fake endpoint."""
243
    return jsonify({
244
        "data": {
245
            "columns": [
246
                ["data1", 300, 350, 300, 0, 0, 0],
247
                ["data2", 130, 100, 140, 200, 150, 50]
248
            ],
249
            "types": {
250
                "data1": "area",
251
                "data2": "area-spline"
252
            }
253
        }
254
    })
255
256
257
@cross_origin()
258
@app.route('/scatter')
259
def scatter():
260
    """Fake endpoint."""
261
    if 'override' in request.args:
262
        with open('{}/examples/overrides.json'.format(cwd), 'r') as jsonfile:
263
            return jsonfile.read()
264
    return jsonify({
265
        "bar1": [1, 2, 30, 12, 100],
266
        "bar2": rr_list(max_range=40),
267
        "bar3": rr_list(max_range=40),
268
        "bar4": [-10, 1, 5, 4, 10, 20],
269
    })
270
271
272
@cross_origin()
273
@app.route('/pie')
274
def pie():
275
    """Fake endpoint."""
276
    letters = list('abcde')
277
    if 'stress' in request.args:
278
        letters = range(STRESS_MAX_POINTS)
279
    return jsonify({'data {}'.format(name): rr(1, 100) for name in letters})
280
281
282
@cross_origin()
283
@app.route('/custom-inputs')
284
def custom_inputs():
285
    """Fake endpoint."""
286
    _range = int(request.args.get('range', 5))
287
    entries = int(request.args.get('entries', 3))
288
    starting = int(request.args.get('starting_num', 0))
289
    prefix = request.args.get('prefix', 'item')
290
    if 'override' in request.args:
291
        show_axes = request.args.get('show_axes', False)
292
        show_axes = show_axes == 'on'
293
        data = dict(
294
            data=dict(
295
                columns=[
296
                    ['{} {}'.format(prefix, i)] + rr_list(max_range=entries)
297
                    for i in range(starting, _range)
298
                ],
299
            )
300
        )
301
        if show_axes:
302
            data.update(axis=dict(
303
                x=dict(label='This is the X axis'),
304
                y=dict(label='This is the Y axis')))
305
        return jsonify(data)
306
    return jsonify({
307
        i: rr_list(max_range=_range) for i in range(starting, entries)
308
    })
309
310
311
@cross_origin()
312
@app.route('/bar')
313
def barchart():
314
    """Fake endpoint."""
315
    if 'stress' in request.args:
316
        return jsonify({
317
            'bar-{}'.format(k): rr_list(max_range=STRESS_MAX_POINTS)
318
            for k in range(STRESS_MAX_POINTS)
319
        })
320
    return jsonify({
321
        "bar1": [1, 2, 30, 12, 100],
322
        "bar2": rr_list(max_range=5),
323
        "bar3": rr_list(max_range=5),
324
    })
325
326
327
@cross_origin()
328
@app.route('/line')
329
def linechart():
330
    """Fake endpoint."""
331
    if 'stress' in request.args:
332
        return jsonify({
333
            'bar-{}'.format(k): rr_list(max_range=STRESS_MAX_POINTS)
334
            for k in range(STRESS_MAX_POINTS)
335
        })
336
    return jsonify({
337
        "line1": [1, 4, 3, 10, 12, 14, 18, 10],
338
        "line2": [1, 2, 10, 20, 30, 6, 10, 12, 18, 2],
339
        "line3": rr_list(),
340
    })
341
342
343
@cross_origin()
344
@app.route('/singlenum')
345
def singlenum():
346
    """Fake endpoint."""
347
    _min, _max = 10, 10000
348
    if 'sales' in request.args:
349
        val = locale.currency(float(rr(_min, _max)), grouping=True)
350
    else:
351
        val = rr(_min, _max)
352
    if 'negative' in request.args:
353
        val = '-{}'.format(val)
354
    return jsonify(val)
355
356
357
@cross_origin()
358
@app.route('/deadend')
359
def test_die():
360
    """Fake endpoint that ends in a random 50x error."""
361
    # Simulate slow connection
362
    time.sleep(random())
363
    abort(choice([500, 501, 502, 503, 504]))
364
365
366
@cross_origin()
367
@app.route('/venn')
368
def test_venn():
369
    """Fake endpoint."""
370
    data = [
371
        {'sets': ['A'], 'size': rr(10, 100)},
372
        {'sets': ['B'], 'size': rr(10, 100)},
373
        {'sets': ['C'], 'size': rr(10, 100)},
374
        {'sets': ['A', 'B'], 'size': rr(10, 100)},
375
        {'sets': ['A', 'B', 'C'], 'size': rr(10, 100)},
376
    ]
377
    return jsonify(data)
378
379
380
@cross_origin()
381
@app.route('/sparklines', methods=['GET'])
382
def sparklines():
383
    """Fake endpoint."""
384
    if any([
385
        'pie' in request.args,
386
        'discrete' in request.args,
387
    ]):
388
        return jsonify([rr(1, 100) for _ in range(10)])
389
    return jsonify([[i, rr(i, 100)] for i in range(10)])
390
391
392
@cross_origin()
393
@app.route('/circlepack', methods=['GET'])
394
def circlepack():
395
    """Fake endpoint."""
396
    if 'stress' in request.args:
397
        # Build a very large dataset
398
        return jsonify(recursive_d3_data())
399
    with open('{}/examples/flare.json'.format(cwd), 'r') as djson:
400
        return djson.read()
401
    return jsonify({})
402
403
404
@cross_origin()
405
@app.route('/treemap', methods=['GET'])
406
def treemap():
407
    """Fake endpoint."""
408
    if 'stress' in request.args:
409
        # Build a very large dataset
410
        return jsonify(recursive_d3_data())
411
    with open('{}/examples/flare.json'.format(cwd), 'r') as djson:
412
        return djson.read()
413
    return jsonify({})
414
415
416
@cross_origin()
417
@app.route('/map', methods=['GET'])
418
def datamap():
419
    """Fake endpoint."""
420
    return render_template('examples/map.html')
421
422
423
@cross_origin()
424
@app.route('/dendrogram', methods=['GET'])
425
def dendro():
426
    """Fake endpoint."""
427
    if 'stress' in request.args:
428
        # Build a very large dataset
429
        return jsonify(recursive_d3_data())
430
    filename = 'flare-simple' if 'simple' in request.args else 'flare'
431
    with open('{}/examples/{}.json'.format(cwd, filename), 'r') as djson:
432
        return djson.read()
433
    return jsonify({})
434
435
436
@cross_origin()
437
@app.route('/voronoi', methods=['GET'])
438
def voronoi():
439
    """Fake endpoint."""
440
    w, h = request.args.get('width', 800), request.args.get('height', 800)
441
    max_points = int(request.args.get('points', 100))
442
    if 'stress' in request.args:
443
        max_points = 500
444
    return jsonify([[rr(1, h), rr(1, w)] for _ in range(max_points)])
445
446
447
@cross_origin()
448
@app.route('/digraph', methods=['GET'])
449
def graphdata():
450
    """Fake endpoint."""
451
    if 'filetree' in request.args:
452
        with open('{}/examples/filetree_digraph.dot'.format(cwd), 'r') as dot:
453
            return jsonify(dict(graph=dot.read()))
454
    if 'simple' in request.args:
455
        graphdata = """
456
        digraph {
457
            a -> b;
458
            a -> c;
459
            b -> c;
460
            b -> a;
461
            b -> b;
462
        }
463
        """
464
        return jsonify(dict(graph=graphdata))
465
    nodes = list('abcdefghijkl')
466
    node_data = '\n'.join([
467
        '{0} -> {1};'.format(choice(nodes), choice(nodes))
468
        for _ in range(10)
469
    ])
470
    graphdata = """digraph {lb} {nodes} {rb}""".format(
471
        lb='{', rb='}', nodes=node_data)
472
    return jsonify(dict(
473
        graph=graphdata,
474
    ))
475
476
477
if __name__ == '__main__':
478
    PORT = int(os.getenv('PORT', 5004))
479
    HOST = os.getenv('HOST', '0.0.0.0')
480
    app.run(debug=True, host=HOST, port=PORT)
481