Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9f6244c

Browse files
committed
added __init__ and filled up dashboards
1 parent 7878099 commit 9f6244c

File tree

2 files changed

+224
-96
lines changed

2 files changed

+224
-96
lines changed

plotly/dashboard_objs/__init__.py

Whitespace-only changes.
Lines changed: 224 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,33 @@
1-
import plotly
2-
from plotly.api.v2.utils import build_url
1+
"""
2+
dashboard_objs
3+
==========
4+
5+
A module which is used to create dashboard objects, manipulate them and then
6+
upload them.
7+
8+
"""
39

10+
import copy
411
import json
512
import requests
13+
import pprint
614
import webbrowser
7-
from IPython import display
15+
16+
import plotly
17+
18+
from plotly import exceptions
19+
from plotly.utils import node_generator
20+
from plotly.api.v2.utils import build_url
821

922
username = plotly.tools.get_credentials_file()['username']
1023
api_key = plotly.tools.get_credentials_file()['api_key']
1124
headers = {'Plotly-Client-Platform': 'nteract'}
1225

1326

14-
# little wrapper around requests.get
15-
def get(*args, **kwargs):
16-
return requests.get(
17-
*args, auth=(username, api_key), headers=headers, **kwargs
18-
)
19-
20-
width = 350
21-
height = 350
22-
dashboard_html = """
23-
<!DOCTYPE HTML>
24-
<html>
25-
<head>
26-
<style>
27-
body {{
28-
margin: 0px;
29-
padding: 0px;
30-
/}}
31-
</style>
32-
</head>
33-
<body>
34-
<canvas id="myCanvas" width="400" height="400"></canvas>
35-
<script>
36-
var canvas = document.getElementById('myCanvas');
37-
var context = canvas.getContext('2d');
38-
<!-- Dashboard -->
39-
context.beginPath();
40-
context.rect(0, 0, {width}, {height});
41-
context.lineWidth = 2;
42-
context.strokeStyle = 'black';
43-
context.stroke();
44-
<!-- Draw some lines in -->
45-
context.beginPath();
46-
context.rect(0, {height}/2, {width}/2, {height}/2);
47-
context.lineWidth = 2;
48-
context.strokeStyle = 'black';
49-
context.stroke();
50-
<!-- Draw the box_ids -->
51-
context.font = '12pt Times New Roman';
52-
context.textAlign = 'center';
53-
context.fillText('0', 50, 50);
54-
</script>
55-
</body>
56-
</html>
57-
""".format(width=350, height=350)
58-
59-
box_html = """
60-
<!-- Draw some lines in -->
61-
context.beginPath();
62-
context.rect(0, {height}/2, {width}/2, {height}/2);
63-
context.lineWidth = 2;
64-
context.strokeStyle = 'black';
65-
context.stroke();
66-
""".format(width=350, height=350)
67-
68-
69-
class FirstEmptyBox(dict):
70-
def __init__(self):
71-
self['type'] = 'box'
72-
self['boxType'] = 'empty'
73-
74-
7527
class EmptyBox(dict):
7628
def __init__(self):
7729
self['type'] = 'box'
7830
self['boxType'] = 'empty'
79-
self['fileId'] = ''
80-
self['shareKey'] = None
81-
self['title'] = ''
8231

8332

8433
class Box(dict):
@@ -101,33 +50,60 @@ def __init__(self, box_1=EmptyBox(), box_2=EmptyBox(), size=400,
10150
self['second'] = box_2
10251

10352

104-
box_ids_to_paths = {}
53+
class Dashboard(dict):
54+
def __init__(self, dashboard_json=None, backgroundColor='#FFFFFF',
55+
boxBackgroundColor='#ffffff', boxBorderColor='#d8d8d8',
56+
boxHeaderBackgroundColor='#f8f8f8', foregroundColor='#333333',
57+
headerBackgroundColor='#2E3A46', headerForegroundColor='#FFFFFF',
58+
links=[], logoUrl='', title='Untitled Dashboard'):
59+
self.box_ids_dict = {}
60+
if not dashboard_json:
61+
self['layout'] = EmptyBox()
62+
self['version'] = 2
63+
self['settings'] = {
64+
'backgroundColor': backgroundColor,
65+
'boxBackgroundColor': boxBackgroundColor,
66+
'boxBorderColor': boxBorderColor,
67+
'boxHeaderBackgroundColor': boxHeaderBackgroundColor,
68+
'foregroundColor': foregroundColor,
69+
'headerBackgroundColor': headerBackgroundColor,
70+
'headerForegroundColor': headerForegroundColor,
71+
'links': links,
72+
'logoUrl': logoUrl,
73+
'title': title
74+
}
75+
# TODO: change name to box_id_to_path
76+
else:
77+
self['layout'] = dashboard_json['layout']
78+
self['version'] = dashboard_json['layout']
79+
self['settings'] = dashboard_json['settings']
10580

81+
all_nodes = []
82+
node_gen = node_generator(dashboard_json['layout'])
10683

107-
class Dashboard(dict):
108-
def __init__(self, backgroundColor='#FFFFFF', boxBackgroundColor='#ffffff',
109-
boxBorderColor='#d8d8d8', boxHeaderBackgroundColor='#f8f8f8',
110-
foregroundColor='#333333', headerBackgroundColor='#2E3A46',
111-
headerForegroundColor='#FFFFFF', links=[], logoUrl='',
112-
title='Untitled Dashboard'):
113-
self['version'] = 2
114-
self['settings'] = {
115-
'backgroundColor': backgroundColor,
116-
'boxBackgroundColor': boxBackgroundColor,
117-
'boxBorderColor': boxBorderColor,
118-
'boxHeaderBackgroundColor': boxHeaderBackgroundColor,
119-
'foregroundColor': foregroundColor,
120-
'headerBackgroundColor': headerBackgroundColor,
121-
'headerForegroundColor': headerForegroundColor,
122-
'links': links,
123-
'logoUrl': logoUrl,
124-
'title': title
125-
}
126-
self['layout'] = FirstEmptyBox()
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
90+
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])
12799

128-
def insert(self, box_or_container, array_of_paths):
100+
def _insert(self, box_or_container, array_of_paths):
101+
"""Performs user-unfriendly box and container manipulations."""
129102
if any(path not in ['first', 'second'] for path in array_of_paths):
130-
return "Invalid path."
103+
raise exceptions.PlotlyError(
104+
"Invalid path. Your 'array_of_paths' list must only contain "
105+
"the strings 'first' and 'second'."
106+
)
131107

132108
if 'first' in self['layout']:
133109
loc_in_dashboard = self['layout']
@@ -142,25 +118,132 @@ def insert(self, box_or_container, array_of_paths):
142118

143119
# update box_ids
144120
if isinstance(box_or_container, Box):
145-
max_id = len(box_ids_to_paths)
146-
box_ids_to_paths[max_id] = array_of_paths
121+
# box -> container
122+
# if replacing a container, remove box_ids for
123+
# the boxes that belong there
124+
for first_or_second in ['first', 'second']:
125+
extended_box_path = copy.deepcopy(array_of_paths)
126+
extended_box_path.append(first_or_second)
127+
for key in self.box_ids_dict.keys():
128+
if self.box_ids_dict[key] == extended_box_path:
129+
self.box_ids_dict.pop(key)
130+
131+
# box -> box
132+
for key in self.box_ids_dict.keys():
133+
if self.box_ids_dict[key] == array_of_paths:
134+
self.box_ids_dict.pop(key)
135+
try:
136+
max_id = max(self.box_ids_dict.keys())
137+
except ValueError:
138+
max_id = 0
139+
self.box_ids_dict[max_id + 1] = array_of_paths
140+
141+
elif isinstance(box_or_container, Container):
142+
# container -> box
143+
for key in self.box_ids_dict.keys():
144+
if self.box_ids_dict[key] == array_of_paths:
145+
self.box_ids_dict.pop(key)
146+
147+
# handles boxes already in container
148+
for first_or_second in ['first', 'second']:
149+
if box_or_container[first_or_second] != EmptyBox():
150+
path_to_box = copy.deepcopy(array_of_paths)
151+
path_to_box.append(first_or_second)
152+
for key in self.box_ids_dict.keys():
153+
if self.box_ids_dict[key] == path_to_box:
154+
self.box_ids_dict.pop(key)
155+
156+
try:
157+
max_id = max(self.box_ids_dict.keys())
158+
except ValueError:
159+
max_id = 0
160+
self.box_ids_dict[max_id + 1] = path_to_box
147161

148162
def _get_box(self, box_id):
163+
"""Returns box from box_id number."""
164+
149165
loc_in_dashboard = self['layout']
150-
for path in box_ids_to_paths[box_id]:
166+
for path in self.box_ids_dict[box_id]:
151167
loc_in_dashboard = loc_in_dashboard[path]
152168
return loc_in_dashboard
153169

170+
def get_preview(self):
171+
"""
172+
Returns JSON and HTML respresentation of the dashboard.
173+
174+
HTML coming soon to a theater near you.
175+
"""
176+
# print JSON figure
177+
pprint.pprint(self)
178+
179+
def insert(self, box, box_id=None, side='above'):
180+
"""
181+
The user-friendly method for inserting boxes into the Dashboard.
182+
183+
box: the box you are inserting into the dashboard.
184+
box_id: pre-existing box you use as a reference point.
185+
"""
186+
# doesn't need box_id or side specified
187+
if 'first' not in self['layout']:
188+
self._insert(Container(), [])
189+
self._insert(box, ['first'])
190+
else:
191+
if box_id is None:
192+
raise exceptions.PlotlyError(
193+
"Make sure the box_id is specfied if there is at least "
194+
"one box in your dashboard."
195+
)
196+
if box_id not in self.box_ids_dict:
197+
raise exceptions.PlotlyError(
198+
"Your box_id must a number which is pointing to a box in "
199+
"your dashboard."
200+
)
201+
202+
if side == 'above':
203+
old_box = self._get_box(box_id)
204+
self._insert(
205+
Container(box, old_box, direction='vertical'),
206+
self.box_ids_dict[box_id]
207+
)
208+
elif side == 'below':
209+
old_box = self._get_box(box_id)
210+
self._insert(
211+
Container(old_box, box, direction='vertical'),
212+
self.box_ids_dict[box_id]
213+
)
214+
elif side == 'left':
215+
old_box = self._get_box(box_id)
216+
self._insert(
217+
Container(box, old_box, direction='horizontal'),
218+
self.box_ids_dict[box_id]
219+
)
220+
elif side == 'right':
221+
old_box = self._get_box(box_id)
222+
self._insert(
223+
Container(old_box, box, direction='horizontal'),
224+
self.box_ids_dict[box_id]
225+
)
154226

155-
def create_dashboard(dashboard_object, filename, world_readable, auto_open=True):
227+
228+
def upload_dashboard(dashboard_object, filename, world_readable,
229+
auto_open=True):
156230
"""
157-
BETA Function for creating a dashboard.
231+
BETA function for uploading dashboards.
232+
233+
Functionality that we may need to consider adding:
234+
- filename needs to be able to support `/` to create or use folders.
235+
This'll require a few API calls.
236+
- this function only works if the filename is unique. Need to call
237+
`update` if this file already exists to overwrite the file.
238+
- world_readable really should be `sharing` and allow `public`, `private`,
239+
or `secret` like in `py.plot`.
240+
- auto_open parameter for opening the result.
158241
"""
159242
res = requests.post(
160243
build_url('dashboards'),
161244
auth=(username, api_key),
162245
headers=headers,
163-
data={
246+
data = {
164247
'content': json.dumps(dashboard_object),
165248
'filename': filename,
166249
'world_readable': world_readable
@@ -172,3 +255,48 @@ def create_dashboard(dashboard_object, filename, world_readable, auto_open=True)
172255
url = res.json()['web_url']
173256
webbrowser.open_new(res.json()['web_url'])
174257
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)

0 commit comments

Comments
 (0)