-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Animations/Frames in Python API #584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
cb4552c
b4c3953
54c1386
d19c6ca
efa390e
eb57218
5482b53
b2b8451
a156503
d173cbb
d17a222
49bdc97
4fbdc99
dbb386f
bd2132b
26c3714
0c7bb1c
4acc146
c195e78
6f12ba8
253228f
405e71d
c1727d8
fca8fed
587dfa5
495b015
dd20177
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -163,7 +163,7 @@ def init_notebook_mode(connected=False): | |
def _plot_html(figure_or_data, config, validate, default_width, | ||
default_height, global_requirejs): | ||
# force no validation if frames is in the call | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
# TODO - add validation for frames in call - # | ||
# TODO - add validation for frames in call - #605 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed now 👍 |
||
if 'frames' in figure_or_data: | ||
figure = tools.return_figure_from_figure_or_data( | ||
figure_or_data, False | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,5 @@ | |
meta_ops, | ||
file_ops, | ||
get_config, | ||
bad_create_animations, | ||
get_uid_by_col_name | ||
get_grid | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ | |
from plotly.session import (sign_in, update_session_plot_options, | ||
get_session_plot_options, get_session_credentials, | ||
get_session_config) | ||
from plotly.grid_objs import grid_objs | ||
|
||
|
||
__all__ = None | ||
|
||
|
@@ -384,6 +385,7 @@ def get_figure(file_owner_or_url, file_id=None, raw=False): | |
raise exceptions.PlotlyError( | ||
"The 'file_id' argument must be a non-negative number." | ||
) | ||
|
||
response = requests.get(plotly_rest_url + resource, | ||
headers=headers, | ||
verify=get_config()['plotly_ssl_verification']) | ||
|
@@ -1452,160 +1454,44 @@ def _send_to_plotly(figure, **plot_options): | |
return r | ||
|
||
|
||
def bad_create_animations(fig, kwargs, payload): | ||
def get_grid(grid_url, raw=False): | ||
""" | ||
Makes a post to GRIDS and PLOTS if frames is in the figure. | ||
Returns a JSON figure representation for the specified grid. | ||
|
||
|
||
This function bypasses the current '/clientresp' route of making a POST | ||
request to return back a url. Instead, the V2 REST API is used if frames | ||
is part of the figure's keys. Currently, 'error', 'message' and 'warning' | ||
are hard codded to the empty string. | ||
""" | ||
url_v2_plot = "https://api.plot.ly/v2/plots" | ||
url_v2_grid = "https://api.plot.ly/v2/grids" | ||
auth = HTTPBasicAuth(str(payload['un']), str(payload['key'])) | ||
headers = {'Plotly-Client-Platform': 'python'} | ||
|
||
# add layout if not in fig | ||
if 'layout' not in fig: | ||
fig['layout'] = {} | ||
|
||
# make a copy of fig | ||
fig_with_uids = copy.deepcopy(fig) | ||
|
||
# make grid | ||
cols_dict = {} | ||
frames_cols_dict = {} | ||
counter = 0 | ||
trace_num = 0 | ||
for trace in fig['data']: | ||
for var in ['x', 'y']: | ||
if 'name' in trace: | ||
cols_dict["{name}, {x_or_y}".format(name=trace['name'], | ||
x_or_y=var)] = { | ||
"data": list(trace[var]), "order": counter | ||
} | ||
else: | ||
cols_dict["Trace {num}, {x_or_y}".format(num=trace_num, | ||
x_or_y=var)] = { | ||
"data": list(trace[var]), "order": counter | ||
} | ||
counter += 1 | ||
trace_num += 1 | ||
|
||
# add frames data to grid | ||
for j in range(len(fig['frames'])): | ||
for var in ['x', 'y']: | ||
if 'name' in fig['frames'][j]['data']: | ||
cols_dict["{name}, {x_or_y}".format( | ||
name=fig['frames'][j]['data'][0]['name'], x_or_y=var | ||
)] = { | ||
"data": list(fig['frames'][j]['data'][0][var]), | ||
"order": counter | ||
} | ||
else: | ||
cols_dict["Trace {num}, {x_or_y}".format( | ||
num=trace_num, x_or_y=var | ||
)] = { | ||
"data": list(fig['frames'][j]['data'][0][var]), | ||
"order": counter | ||
} | ||
counter += 1 | ||
trace_num += 1 | ||
|
||
grid_info = { | ||
"data": {"cols": cols_dict}, | ||
"world_readable": True | ||
} | ||
|
||
r = requests.post(url_v2_grid, auth=auth, | ||
headers=headers, json=grid_info) | ||
r_dict = json.loads(r.text) | ||
|
||
# make plot | ||
fid = r_dict['file']['fid'] | ||
cols_index = 0 | ||
for trace in fig_with_uids['data']: | ||
if 'x' in trace: | ||
del trace['x'] | ||
if 'y' in trace: | ||
del trace['y'] | ||
|
||
trace["xsrc"] = "{fid}:{idlocal}".format( | ||
fid=fid, idlocal=r_dict['file']['cols'][cols_index]['uid'] | ||
) | ||
trace["ysrc"] = "{fid}:{idlocal}".format( | ||
fid=fid, idlocal=r_dict['file']['cols'][cols_index + 1]['uid'] | ||
) | ||
cols_index += 2 | ||
|
||
# replace data in frames by grid ids | ||
for j in range(len(fig['frames'])): | ||
if 'x' in fig_with_uids['frames'][j]['data'][0]: | ||
del fig_with_uids['frames'][j]['data'][0]['x'] | ||
if 'y' in fig_with_uids['frames'][j]['data'][0]: | ||
del fig_with_uids['frames'][j]['data'][0]['y'] | ||
|
||
fig_with_uids['frames'][j]['data'][0]["xsrc"] = "{fid}:{idlocal}".format( | ||
fid=fid, idlocal=r_dict['file']['cols'][cols_index]['uid'] | ||
) | ||
fig_with_uids['frames'][j]['data'][0]["ysrc"] = "{fid}:{idlocal}".format( | ||
fid=fid, idlocal=r_dict['file']['cols'][cols_index + 1]['uid'] | ||
) | ||
cols_index += 2 | ||
|
||
plots_info = { | ||
"figure": fig_with_uids, | ||
"world_readable": json.loads(kwargs)['world_readable'] | ||
} | ||
|
||
r = requests.post(url_v2_plot, auth=auth, | ||
headers=headers, json=plots_info) | ||
|
||
r_json = json.loads(r.text) | ||
|
||
r_dict = { | ||
'error': '', | ||
'filename': json.loads(kwargs)['filename'], | ||
'message': '', | ||
'url': r_json['file']['web_url'], | ||
'warning': '' | ||
} | ||
|
||
return r_dict | ||
|
||
|
||
def get_uid_by_col_name(grid_url, col_name): | ||
""" | ||
Search for a column of a grid by name and return the uid of the column. | ||
:param (bool) raw: if False, will output a Grid instance of the JSON grid | ||
being retrieved. If True, raw JSON will be returned. | ||
""" | ||
credentials = get_credentials() | ||
validate_credentials(credentials) | ||
auth = HTTPBasicAuth(credentials['username'], credentials['api_key']) | ||
headers = {'Plotly-Client-Platform': 'python'} | ||
username, api_key = credentials['username'], credentials['api_key'] | ||
headers = {'plotly-username': username, | ||
'plotly-apikey': api_key, | ||
'plotly-version': version.__version__, | ||
'plotly-platform': 'python'} | ||
upload_url = _api_v2.api_url('grids') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did the |
||
|
||
tilda_index = grid_url.find('~') | ||
fid_in_url = grid_url[tilda_index + 1: -1].replace('/', ':') | ||
get_url = upload_url + '/' + fid_in_url | ||
|
||
r = requests.get(get_url, auth=auth, headers=headers) | ||
r_text = json.loads(r.text) | ||
|
||
col_uid = '' | ||
for col in r_text['cols']: | ||
if col_name == col['name']: | ||
col_uid = col['uid'] | ||
break | ||
|
||
all_col_names = ([r_text['cols'][j]['name'] for j in | ||
range(len(r_text['cols']))]) | ||
if col_uid == '': | ||
raise exceptions.PlotlyError( | ||
'The col_name does not match with any column name in your grid. ' | ||
'The column names in your grid are {}'.format(all_col_names)) | ||
if grid_url[-1] == '/': | ||
fid_in_url = grid_url[tilda_index + 1: -1].replace('/', ':') | ||
else: | ||
fid_in_url = grid_url[tilda_index + 1: len(grid_url)] | ||
fid_in_url = fid_in_url.replace('/', ':') | ||
get_url = upload_url + '/' + fid_in_url + '/content' | ||
|
||
|
||
r = requests.get(get_url, headers=headers) | ||
json_res = json.loads(r.text) | ||
if raw is False: | ||
# create a new grid | ||
new_grid = grid_objs.Grid( | ||
|
||
[grid_objs.Column(json_res['cols'][column]['data'], column) | ||
for column in json_res['cols']] | ||
|
||
) | ||
# fill in uids | ||
for column in new_grid: | ||
column.id = json_res['cols'][column.name]['uid'] | ||
return new_grid | ||
else: | ||
return col_uid | ||
return json_res | ||
|
||
|
||
def _open_url(url): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this raise if it can't find a uid? Is there a case where we would want to accept the empty string if a column uid cannot be found?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it should. It's possible for the column_reference to be the empty string
''
if a grid hasn't been uploaded yet, for instance.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
grids are instantiated with
id
s so I don't think that's a risk here. For now, I think it's fine to have it just return theid
of that column, whatever it happens to be.