Skip to content

Commit

Permalink
Merge branch 'master' into dashboard-wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
Kully authored Mar 4, 2017
2 parents 2a3a301 + 4b06dfd commit bb614b3
Show file tree
Hide file tree
Showing 28 changed files with 2,732 additions and 2,630 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## Added
- dashboards can now be created using the API and uploaded to Plotly. Use `import plotly.dashboard_objs` to be create a dashboard a `Dashboard` object. You can learn more about `Dashboard` objects by running `help(plotly.dashboard_objs.Dashboard)` and `help(plotly.plotly.plotly.dashboard_ops)` for uploading and retrieving dashboards from the cloud.


## [2.0.2] - 2017-02-20
### Fixed
- Offline plots created with `plotly.offline.plot` now resize as expected when the window is resized.
Expand Down
4 changes: 2 additions & 2 deletions plotly/figure_factory/_annotated_heatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ def create_annotated_heatmap(z, x=None, y=None, annotation_text=None,
Example 1: Simple annotated heatmap with default configuration
```
import plotly.plotly as py
from plotly.figure_factory create_annotated_heatmap
import plotly.figure_factory as FF
z = [[0.300000, 0.00000, 0.65, 0.300000],
[1, 0.100005, 0.45, 0.4300],
[0.300000, 0.00000, 0.65, 0.300000],
[1, 0.100005, 0.45, 0.00000]]
figure = create_annotated_heatmap(z)
figure = FF.create_annotated_heatmap(z)
py.iplot(figure)
```
"""
Expand Down
8 changes: 4 additions & 4 deletions plotly/figure_factory/_distplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def make_hist(self):
histnorm=self.histnorm,
name=self.group_labels[index],
legendgroup=self.group_labels[index],
marker=dict(color=self.colors[index]),
marker=dict(color=self.colors[index % len(self.colors)]),
autobinx=False,
xbins=dict(start=self.start[index],
end=self.end[index],
Expand Down Expand Up @@ -324,7 +324,7 @@ def make_kde(self):
name=self.group_labels[index],
legendgroup=self.group_labels[index],
showlegend=False if self.show_hist else True,
marker=dict(color=self.colors[index]))
marker=dict(color=self.colors[index % len(self.colors)]))
return curve

def make_normal(self):
Expand Down Expand Up @@ -361,7 +361,7 @@ def make_normal(self):
name=self.group_labels[index],
legendgroup=self.group_labels[index],
showlegend=False if self.show_hist else True,
marker=dict(color=self.colors[index]))
marker=dict(color=self.colors[index % len(self.colors)]))
return curve

def make_rug(self):
Expand All @@ -385,6 +385,6 @@ def make_rug(self):
showlegend=(False if self.show_hist or
self.show_curve else True),
text=self.rug_text[index],
marker=dict(color=self.colors[index],
marker=dict(color=self.colors[index % len(self.colors)],
symbol='line-ns-open'))
return rug
47 changes: 26 additions & 21 deletions plotly/figure_factory/_violin.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ def violinplot(vals, fillcolor='#1f77b4', rugplot=True):


def violin_no_colorscale(data, data_header, group_header, colors,
use_colorscale, group_stats,
height, width, title):
use_colorscale, group_stats, rugplot,
height, width, title):
"""
Refer to FigureFactory.create_violin() for docstring.
Expand Down Expand Up @@ -223,7 +223,8 @@ def violin_no_colorscale(data, data_header, group_header, colors,
if color_index >= len(colors):
color_index = 0
plot_data, plot_xrange = violinplot(vals,
fillcolor=colors[color_index])
fillcolor=colors[color_index],
rugplot=rugplot)
layout = graph_objs.Layout()

for item in plot_data:
Expand All @@ -250,7 +251,7 @@ def violin_no_colorscale(data, data_header, group_header, colors,


def violin_colorscale(data, data_header, group_header, colors, use_colorscale,
group_stats, height, width, title):
group_stats, rugplot, height, width, title):
"""
Refer to FigureFactory.create_violin() for docstring.
Expand Down Expand Up @@ -303,7 +304,8 @@ def violin_colorscale(data, data_header, group_header, colors, use_colorscale,

plot_data, plot_xrange = violinplot(
vals,
fillcolor='rgb{}'.format(intermed_color)
fillcolor='rgb{}'.format(intermed_color),
rugplot=rugplot
)
layout = graph_objs.Layout()

Expand Down Expand Up @@ -343,7 +345,7 @@ def violin_colorscale(data, data_header, group_header, colors, use_colorscale,


def violin_dict(data, data_header, group_header, colors, use_colorscale,
group_stats, height, width, title):
group_stats, rugplot, height, width, title):
"""
Refer to FigureFactory.create_violin() for docstring.
Expand Down Expand Up @@ -375,7 +377,8 @@ def violin_dict(data, data_header, group_header, colors, use_colorscale,

for k, gr in enumerate(group_name):
vals = np.asarray(gb.get_group(gr)[data_header], np.float)
plot_data, plot_xrange = violinplot(vals, fillcolor=colors[gr])
plot_data, plot_xrange = violinplot(vals, fillcolor=colors[gr],
rugplot=rugplot)
layout = graph_objs.Layout()

for item in plot_data:
Expand All @@ -401,18 +404,18 @@ def violin_dict(data, data_header, group_header, colors, use_colorscale,


def create_violin(data, data_header=None, group_header=None, colors=None,
use_colorscale=False, group_stats=None, height=450,
width=600, title='Violin and Rug Plot'):
use_colorscale=False, group_stats=None, rugplot=True,
height=450, width=600, title='Violin and Rug Plot'):
"""
Returns figure for a violin plot
:param (list|array) data: accepts either a list of numerical values,
a list of dictionaries all with identical keys and at least one
column of numeric values, or a pandas dataframe with at least one
column of numbers
column of numbers.
:param (str) data_header: the header of the data column to be used
from an inputted pandas dataframe. Not applicable if 'data' is
a list of numeric values
a list of numeric values.
:param (str) group_header: applicable if grouping data by a variable.
'group_header' must be set to the name of the grouping variable.
:param (str|tuple|list|dict) colors: either a plotly scale name,
Expand All @@ -422,18 +425,19 @@ def create_violin(data, data_header=None, group_header=None, colors=None,
tuple of the form (a, b, c) where a, b and c belong to [0, 1].
If colors is a list, it must contain valid color types as its
members.
:param (bool) use_colorscale: Only applicable if grouping by another
:param (bool) use_colorscale: only applicable if grouping by another
variable. Will implement a colorscale based on the first 2 colors
of param colors. This means colors must be a list with at least 2
colors in it (Plotly colorscales are accepted since they map to a
list of two rgb colors)
list of two rgb colors).
:param (dict) group_stats: a dictioanry where each key is a unique
value from the group_header column in data. Each value must be a
number and will be used to color the violin plots if a colorscale
is being used
:param (float) height: the height of the violin plot
:param (float) width: the width of the violin plot
:param (str) title: the title of the violin plot
is being used.
:param (bool) rugplot: determines if a rugplot is draw on violin plot.
:param (float) height: the height of the violin plot.
:param (float) width: the width of the violin plot.
:param (str) title: the title of the violin plot.
Example 1: Single Violin Plot
```
Expand Down Expand Up @@ -558,7 +562,8 @@ def create_violin(data, data_header=None, group_header=None, colors=None,
data = data[data_header].values.tolist()

# call the plotting functions
plot_data, plot_xrange = violinplot(data, fillcolor=valid_colors[0])
plot_data, plot_xrange = violinplot(data, fillcolor=valid_colors[0],
rugplot=rugplot)

layout = graph_objs.Layout(
title=title,
Expand Down Expand Up @@ -596,13 +601,13 @@ def create_violin(data, data_header=None, group_header=None, colors=None,
# validate colors dict choice below
fig = violin_dict(
data, data_header, group_header, valid_colors,
use_colorscale, group_stats, height, width, title
use_colorscale, group_stats, rugplot, height, width, title
)
return fig
else:
fig = violin_no_colorscale(
data, data_header, group_header, valid_colors,
use_colorscale, group_stats, height, width, title
use_colorscale, group_stats, rugplot, height, width, title
)
return fig
else:
Expand All @@ -622,6 +627,6 @@ def create_violin(data, data_header=None, group_header=None, colors=None,

fig = violin_colorscale(
data, data_header, group_header, valid_colors,
use_colorscale, group_stats, height, width, title
use_colorscale, group_stats, rugplot, height, width, title
)
return fig
28 changes: 16 additions & 12 deletions plotly/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@
'sharing': 'public',
'auto_open': True}}

try:
os.mkdir(TEST_DIR)
os.rmdir(TEST_DIR)
if not os.path.exists(PLOTLY_DIR):
os.mkdir(PLOTLY_DIR)
f = open(TEST_FILE, 'w')
f.write('testing\n')
f.close()
os.remove(TEST_FILE)
_file_permissions = True
except:
_file_permissions = False

def _permissions():
try:
os.mkdir(TEST_DIR)
os.rmdir(TEST_DIR)
if not os.path.exists(PLOTLY_DIR):
os.mkdir(PLOTLY_DIR)
with open(TEST_FILE, 'w') as f:
f.write('testing\n')
os.remove(TEST_FILE)
return True
except:
return False


_file_permissions = _permissions()


def check_file_permissions():
Expand Down
4 changes: 3 additions & 1 deletion plotly/graph_objs/graph_objs.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
from plotly import exceptions, graph_reference
from plotly.graph_objs import graph_objs_tools

_subplot_regex = re.compile(r'(?P<digits>\d+$)')


class PlotlyBase(object):
"""
Expand Down Expand Up @@ -506,7 +508,7 @@ def _get_subplot_attributes(self):

def _get_subplot_key(self, key):
"""Some keys can have appended integers, this handles that."""
match = re.search(r'(?P<digits>\d+$)', key)
match = _subplot_regex.search(key)
if match:
root_key = key[:match.start()]
if (root_key in self._get_subplot_attributes() and
Expand Down
65 changes: 43 additions & 22 deletions plotly/graph_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ def get_attributes_dicts(object_name, parent_object_names=()):
return attributes_dicts


def get_valid_attributes(object_name, parent_object_names=()):
@utils.memoize()
def _get_valid_attributes(object_name, parent_object_names):
attributes = get_attributes_dicts(object_name, parent_object_names)
# These are for documentation and quick lookups. They're just strings.
valid_attributes = set()
Expand All @@ -245,6 +246,11 @@ def get_valid_attributes(object_name, parent_object_names=()):
return valid_attributes


def get_valid_attributes(object_name, parent_object_names=()):
# Enforce that parent_object_names is hashable (a tuple).
return _get_valid_attributes(object_name, tuple(parent_object_names))


def get_deprecated_attributes(object_name, parent_object_names=()):
attributes = get_attributes_dicts(object_name, parent_object_names)
# These are for documentation and quick lookups. They're just strings.
Expand Down Expand Up @@ -340,21 +346,10 @@ def attribute_path_to_object_names(attribute_container_path):
return tuple(object_names)


def get_role(object_name, attribute, value=None, parent_object_names=()):
"""
Values have types associated with them based on graph_reference.
'data' type values are always kept
'style' values are kept if they're sequences (but not strings)
:param (str) object_name: The name of the object containing 'attribute'.
:param (str) attribute: The attribute we want the `role` of.
:param (*) value: If the value is an array, the return can be different.
:param parent_object_names: An iterable of obj names from graph reference.
:returns: (str) This will be 'data', 'style', or 'info'.
"""
if object_name in TRACE_NAMES and attribute == 'type':
@utils.memoize()
def _get_role(object_name, attribute, value_type, parent_object_names=()):
"""Private, more easily memoized version of get_role."""
if attribute == 'type' and object_name in TRACE_NAMES:
return 'info'
attributes_dicts = get_attributes_dicts(object_name, parent_object_names)
matches = []
Expand All @@ -372,12 +367,8 @@ def get_role(object_name, attribute, value=None, parent_object_names=()):
for match in matches:
role = match['role']
array_ok = match.get('arrayOk')
if value is not None and array_ok:
iterable = hasattr(value, '__iter__')
stringy = isinstance(value, six.string_types)
dicty = isinstance(value, dict)
if iterable and not stringy and not dicty:
role = 'data'
if array_ok and value_type == 'array':
role = 'data'
roles.append(role)

# TODO: this is ambiguous until the figure is in place...
Expand All @@ -388,6 +379,36 @@ def get_role(object_name, attribute, value=None, parent_object_names=()):
return role


def get_role(object_name, attribute, value=None, parent_object_names=()):
"""
Values have types associated with them based on graph_reference.
'data' type values are always kept
'style' values are kept if they're sequences (but not strings)
:param (str) object_name: The name of the object containing 'attribute'.
:param (str) attribute: The attribute we want the `role` of.
:param (*) value: If the value is an array, the return can be different.
:param parent_object_names: An iterable of obj names from graph reference.
:returns: (str) This will be 'data', 'style', or 'info'.
"""
if value is None:
value_type = 'none'
elif isinstance(value, dict):
value_type = 'dict'
elif isinstance(value, six.string_types):
value_type = 'string'
elif hasattr(value, '__iter__'):
value_type = 'array'
else:
value_type = 'unknown'

# Enforce that parent_object_names is hashable (a tuple).
return _get_role(object_name, attribute, value_type,
tuple(parent_object_names))


def _is_valid_sub_path(path, parent_paths):
"""
Check if a sub path is valid given an iterable of parent paths.
Expand Down
19 changes: 17 additions & 2 deletions plotly/grid_objs/grid_objs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

from requests.compat import json as _json

from plotly import exceptions, utils
from plotly import exceptions, optional_imports, utils

pd = optional_imports.get_module('pandas')

__all__ = None

Expand Down Expand Up @@ -148,7 +150,20 @@ def __init__(self, columns_or_json, fid=None):
```
"""
# TODO: verify that columns are actually columns
if isinstance(columns_or_json, dict):
if pd and isinstance(columns_or_json, pd.DataFrame):
duplicate_name = utils.get_first_duplicate(columns_or_json.columns)
if duplicate_name:
err = exceptions.NON_UNIQUE_COLUMN_MESSAGE.format(duplicate_name)
raise exceptions.InputError(err)

# create columns from dataframe
all_columns = []
for name in columns_or_json.columns:
all_columns.append(Column(columns_or_json[name].tolist(), name))
self._columns = all_columns
self.id = ''

elif isinstance(columns_or_json, dict):
# check that fid is entered
if fid is None:
raise exceptions.PlotlyError(
Expand Down
Loading

0 comments on commit bb614b3

Please sign in to comment.