Skip to content

Commit 6f6b2c1

Browse files
committed
migrating all network code out of dashboards_objs.py
1 parent 2b00ed2 commit 6f6b2c1

File tree

4 files changed

+132
-68
lines changed

4 files changed

+132
-68
lines changed

plotly/api/v2/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from __future__ import absolute_import
22

3-
from plotly.api.v2 import (files, folders, grids, images, plot_schema, plots,
4-
users)
3+
from plotly.api.v2 import (dashboards, files, folders, grids, images, plot_schema,
4+
plots, users)

plotly/dashboard_objs/dashboard_objs.py

Lines changed: 31 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def __init__(self, dashboard_json=None, backgroundColor='#FFFFFF',
5656
boxHeaderBackgroundColor='#f8f8f8', foregroundColor='#333333',
5757
headerBackgroundColor='#2E3A46', headerForegroundColor='#FFFFFF',
5858
links=[], logoUrl='', title='Untitled Dashboard'):
59+
# TODO: change name to box_id_to_path
5960
self.box_ids_dict = {}
6061
if not dashboard_json:
6162
self['layout'] = EmptyBox()
@@ -72,30 +73,33 @@ def __init__(self, dashboard_json=None, backgroundColor='#FFFFFF',
7273
'logoUrl': logoUrl,
7374
'title': title
7475
}
75-
# TODO: change name to box_id_to_path
7676
else:
7777
self['layout'] = dashboard_json['layout']
78-
self['version'] = dashboard_json['layout']
78+
self['version'] = dashboard_json['version']
7979
self['settings'] = dashboard_json['settings']
8080

81-
all_nodes = []
82-
node_gen = node_generator(dashboard_json['layout'])
81+
self._assign_boxes_to_ids()
8382

84-
finished_iteration = False
85-
while not finished_iteration:
86-
try:
87-
all_nodes.append(node_gen.next())
88-
except StopIteration:
89-
finished_iteration = True
83+
def _assign_boxes_to_ids(self):
84+
self.box_ids_dict = {}
85+
all_nodes = []
86+
node_gen = node_generator(self['layout'])
9087

91-
for node in all_nodes:
92-
if (node[1] != () and node[0]['type'] == 'box' and
93-
node[0]['boxType'] != 'empty'):
94-
try:
95-
max_id = max(self.box_ids_dict.keys())
96-
except ValueError:
97-
max_id = 0
98-
self.box_ids_dict[max_id + 1] = list(node[1])
88+
finished_iteration = False
89+
while not finished_iteration:
90+
try:
91+
all_nodes.append(node_gen.next())
92+
except StopIteration:
93+
finished_iteration = True
94+
95+
for node in all_nodes:
96+
if (node[1] != () and node[0]['type'] == 'box'
97+
and node[0]['boxType'] != 'empty'):
98+
try:
99+
max_id = max(self.box_ids_dict.keys())
100+
except ValueError:
101+
max_id = 0
102+
self.box_ids_dict[max_id + 1] = list(node[1])
99103

100104
def _insert(self, box_or_container, array_of_paths):
101105
"""Performs user-unfriendly box and container manipulations."""
@@ -195,10 +199,10 @@ def insert(self, box, box_id=None, side='above'):
195199
)
196200
if box_id not in self.box_ids_dict:
197201
raise exceptions.PlotlyError(
198-
"Your box_id must a number which is pointing to a box in "
199-
"your dashboard."
202+
"Your box_id must a number in your dashboard. To view a "
203+
"representation of your dashboard run 'get_preview()'."
200204
)
201-
205+
#self._assign_boxes_to_ids()
202206
if side == 'above':
203207
old_box = self._get_box(box_id)
204208
self._insert(
@@ -223,6 +227,12 @@ def insert(self, box, box_id=None, side='above'):
223227
Container(old_box, box, direction='horizontal'),
224228
self.box_ids_dict[box_id]
225229
)
230+
else:
231+
raise exceptions.PlotlyError(
232+
"If there is at least one box in your dashboard, you "
233+
"must specify a valid side value. You must choose from "
234+
"'above', 'below', 'left', and 'right'."
235+
)
226236

227237

228238
def upload_dashboard(dashboard_object, filename, world_readable,
@@ -255,48 +265,3 @@ def upload_dashboard(dashboard_object, filename, world_readable,
255265
url = res.json()['web_url']
256266
webbrowser.open_new(res.json()['web_url'])
257267
return url
258-
259-
260-
# little wrapper around requests.get
261-
def get(*args, **kwargs):
262-
return requests.get(
263-
*args, auth=(username, api_key), headers=headers, **kwargs
264-
)
265-
266-
267-
def _get_all_dashboards():
268-
"""Grab a list of all users' dashboards."""
269-
dashboards = []
270-
res = get(build_url('dashboards')).json()
271-
272-
for dashboard in res['results']:
273-
if not dashboard['deleted']:
274-
dashboards.append(dashboard)
275-
while res['next']:
276-
res = get(res['next']).json()
277-
278-
for dashboard in res['results']:
279-
if not dashboard['deleted']:
280-
dashboards.append(dashboard)
281-
return dashboards
282-
283-
284-
def _get_dashboard_json(dashboard_name):
285-
dashboards = _get_all_dashboards()
286-
for index, dboard in enumerate(dashboards):
287-
if dboard['filename'] == dashboard_name:
288-
break
289-
290-
dashboard = get(dashboards[index]['api_urls']['dashboards']).json()
291-
dashboard_json = json.loads(dashboard['content'])
292-
return dashboard_json
293-
294-
295-
def get_dashboard_names():
296-
dashboards = _get_all_dashboards()
297-
return [str(dboard['filename']) for dboard in dashboards]
298-
299-
300-
def get_dashboard(dashboard_name):
301-
dashboard_json = _get_dashboard_json(dashboard_name)
302-
return Dashboard(dashboard_json)

plotly/plotly/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
file_ops,
2424
get_config,
2525
get_grid,
26+
_get_all_dashboards,
27+
_get_dashboard_json,
28+
get_dashboard,
29+
get_dashboard_names,
30+
dashboard_ops,
2631
create_animations,
2732
icreate_animations
2833
)

plotly/plotly/plotly.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
from __future__ import absolute_import
1818

1919
import copy
20+
import json
2021
import os
2122
import warnings
23+
import webbrowser
2224

2325
import six
2426
import six.moves
@@ -28,6 +30,7 @@
2830
from plotly.api import v1, v2
2931
from plotly.plotly import chunked_requests
3032
from plotly.grid_objs import Grid, Column
33+
from plotly.dashboard_objs import dashboard_objs as dashboard
3134

3235
# This is imported like this for backwards compat. Careful if changing.
3336
from plotly.config import get_config, get_credentials
@@ -1342,6 +1345,97 @@ def get_grid(grid_url, raw=False):
13421345
return Grid(parsed_content, fid)
13431346

13441347

1348+
def _get_all_dashboards():
1349+
"""Grab a list of all users' dashboards."""
1350+
dashboards = []
1351+
res = v2.dashboards.list().json()
1352+
1353+
for dashboard in res['results']:
1354+
if not dashboard['deleted']:
1355+
dashboards.append(dashboard)
1356+
while res['next']:
1357+
res = v2.utils.request('get', res['next']).json()
1358+
1359+
for dashboard in res['results']:
1360+
if not dashboard['deleted']:
1361+
dashboards.append(dashboard)
1362+
return dashboards
1363+
1364+
1365+
def _get_dashboard_json(dashboard_name):
1366+
dashboards = _get_all_dashboards()
1367+
for index, dboard in enumerate(dashboards):
1368+
if dboard['filename'] == dashboard_name:
1369+
break
1370+
1371+
dashboard = v2.utils.request('get', dashboards[index]['api_urls']['dashboards']).json()
1372+
dashboard_json = json.loads(dashboard['content'])
1373+
return dashboard_json
1374+
1375+
1376+
def get_dashboard(dashboard_name):
1377+
"""
1378+
Some BETA pass of getting a dashboard from Plotly.
1379+
1380+
May need to put in dashboard_ops.
1381+
"""
1382+
dashboard_json = _get_dashboard_json(dashboard_name)
1383+
return dashboard.Dashboard(dashboard_json)
1384+
1385+
1386+
def get_dashboard_names():
1387+
dashboards = _get_all_dashboards()
1388+
return [str(dboard['filename']) for dboard in dashboards]
1389+
1390+
1391+
class dashboard_ops:
1392+
"""
1393+
Interface to Plotly's Dashboards API.
1394+
Plotly Dashboards are JSON blobs. They are made up by a bunch of
1395+
containers which contain either empty boxes or boxes with file urls.
1396+
"""
1397+
@classmethod
1398+
def upload(cls, dashboard, filename,
1399+
sharing='public', auto_open=True):
1400+
"""
1401+
BETA function for uploading dashboards to Plotly.
1402+
1403+
Functionality that we may need to consider adding:
1404+
- filename needs to be able to support `/` to create or use folders.
1405+
This'll require a few API calls.
1406+
- this function only works if the filename is unique. Need to call
1407+
`update` if this file already exists to overwrite the file.
1408+
- world_readable really should be `sharing` and allow `public`,
1409+
`private`, or `secret` like in `py.plot`.
1410+
- auto_open parameter for opening the result.
1411+
"""
1412+
if sharing == 'public':
1413+
world_readable = True
1414+
elif sharing == 'private':
1415+
world_readable = False
1416+
elif sharing == 'secret':
1417+
world_readable = False
1418+
1419+
data = {
1420+
'content': json.dumps(dashboard),
1421+
'filename': filename,
1422+
'world_readable': world_readable
1423+
}
1424+
1425+
res = v2.dashboards.create(data)
1426+
res.raise_for_status()
1427+
1428+
url = res.json()['web_url']
1429+
1430+
if auto_open:
1431+
webbrowser.open_new(res.json()['web_url'])
1432+
1433+
if sharing == 'secret':
1434+
url = add_share_key_to_url(url)
1435+
1436+
return url
1437+
1438+
13451439
def create_animations(figure, filename=None, sharing='public', auto_open=True):
13461440
"""
13471441
BETA function that creates plots with animations via `frames`.

0 commit comments

Comments
 (0)