Skip to content

Commit c65886b

Browse files
committed
add sparkline file
1 parent 590330b commit c65886b

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

plotly/figure_factory/_sparkline.py

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
from __future__ import absolute_import
2+
3+
from plotly import exceptions, optional_imports
4+
from plotly.figure_factory import utils
5+
6+
import plotly
7+
import plotly.graph_objs as go
8+
9+
import numpy as np
10+
pd = optional_imports.get_module('pandas')
11+
12+
VALID_CHART_TYPES = ['name', 'bullet', 'line', 'avg', 'bar']
13+
14+
15+
def create_sparkline(df, chart_types=('name', 'bullet', 'line', 'avg', 'bar'),
16+
colors=('rgb(181,221,232)', 'rgb(62,151,169)'),
17+
column_width=None, show_titles=True, left_aligned=False,
18+
scatter_options=None, **layout_options):
19+
"""
20+
Returns figure for sparkline.
21+
22+
:param (pd.DataFrame | list | tuple) df: either a list/tuple of
23+
dictionaries or a pandas DataFrame.
24+
:param (list|tuple) chart_types: a sequence of any combination of valid
25+
chart types. The valid chart types are 'name', 'bullet', 'line', 'avg'
26+
and 'bar'
27+
:param (list|tuple) colors: a sequence of exactly 2 colors which are used
28+
to color the charts. Set the first color to your ___ color and the
29+
second color as your ___
30+
Default = ('rgb(181,221,232)', 'rgb(62,151,169)')
31+
:param (list) column_width: Specify a list that contains numbers where
32+
the amount of numbers in the list is equal to `chart_types`. Call
33+
`help(plotly.tools.make_subplots)` for more info on this subplot param
34+
:param (bool) show_titles: determines if title of chart type is displayed
35+
above their respective column
36+
:param (bool) left_aligned: determines if text cells are left-algined or
37+
right-aligned
38+
:param (dict) scatter_options: describes attributes for the scatter point
39+
in each bullet chart such as name and marker size. Call
40+
help(plotly.graph_objs.Scatter) for more information on valid params.
41+
:param layout_options: describes attributes for the layout of the figure
42+
such as title, height and width. Call help(plotly.graph_objs.Layout)
43+
for more information on valid params
44+
"""
45+
# validate dataframe
46+
if not pd:
47+
raise exceptions.ImportError(
48+
"'pandas' must be installed for this figure factory."
49+
)
50+
51+
elif not isinstance(df, pd.DataFrame):
52+
raise exceptions.PlotlyError(
53+
'df must be a pandas DataFrame'
54+
)
55+
56+
# validate list/tuple of colors
57+
if not utils.is_sequence(colors):
58+
raise exceptions.PlotlyError(
59+
'colors must be a list/tuple'
60+
)
61+
62+
if len(colors) < 2:
63+
raise exceptions.PlotlyError(
64+
'colors must be a list/tuple with 2 colors inside'
65+
)
66+
plotly.colors.validate_colors(colors)
67+
68+
num_of_chart_types = len(chart_types)
69+
# narrow columns that are 'name' or 'avg'
70+
narrow_cols = ['name', 'avg']
71+
narrow_idxs = []
72+
for i, chart in enumerate(chart_types):
73+
if chart in narrow_cols:
74+
narrow_idxs.append(i)
75+
76+
if not column_width:
77+
column_width = [3.0] * num_of_chart_types
78+
for idx in narrow_idxs:
79+
column_width[idx] = 1.0
80+
81+
fig = plotly.tools.make_subplots(
82+
len(df.columns), num_of_chart_types, print_grid=False,
83+
shared_xaxes=False, shared_yaxes=False,
84+
horizontal_spacing=0, vertical_spacing=0,
85+
column_width=column_width
86+
)
87+
88+
# layout options
89+
fig['layout'].update(
90+
title='Sparkline Chart',
91+
annotations=[],
92+
showlegend=False
93+
)
94+
95+
# update layout
96+
fig['layout'].update(layout_options)
97+
98+
for key in fig['layout'].keys():
99+
if 'axis' in key:
100+
fig['layout'][key].update(
101+
showgrid=False,
102+
zeroline=False,
103+
showticklabels=False
104+
)
105+
106+
# left aligned
107+
x = 0 if left_aligned else 1
108+
xanchor = 'left' if left_aligned else 'right'
109+
110+
# scatter options
111+
default_scatter = {
112+
'mode': 'markers',
113+
'marker': {'size': 9,
114+
'symbol': 'diamond-tall',
115+
'color': colors[0]}
116+
}
117+
118+
if not scatter_options:
119+
scatter_options = {}
120+
121+
if scatter_options == {}:
122+
scatter_options.update(default_scatter)
123+
else:
124+
# add default options to scatter_options if they are not present
125+
for k in default_scatter['marker']:
126+
if k not in scatter_options['marker']:
127+
scatter_options['marker'][k] = default_scatter['marker'][k]
128+
129+
# create and insert charts
130+
for j, key in enumerate(df):
131+
for c, chart in enumerate(chart_types):
132+
mean = np.mean(df[key])
133+
rounded_mean = round(mean, 2)
134+
if chart == 'name':
135+
fig['layout']['annotations'].append(
136+
dict(
137+
x=x,
138+
y=0.5,
139+
xref='x{}'.format(j * num_of_chart_types + c + 1),
140+
yref='y{}'.format(j * num_of_chart_types + c + 1),
141+
xanchor=xanchor,
142+
text=key,
143+
showarrow=False,
144+
font=dict(size=15),
145+
)
146+
)
147+
empty_data = go.Bar(
148+
x=[0],
149+
y=[0],
150+
visible=False
151+
)
152+
fig.append_trace(empty_data, j + 1, c + 1)
153+
154+
elif chart == 'bullet':
155+
bullet_range = go.Bar(
156+
x=[rounded_mean],
157+
y=[0],
158+
marker=dict(
159+
color=colors[0]
160+
),
161+
orientation='h'
162+
)
163+
164+
bullet_measure = go.Bar(
165+
x=[list(df[key])[-1]],
166+
y=[0],
167+
marker=dict(
168+
color=colors[1]
169+
),
170+
orientation='h',
171+
width=0.2,
172+
offset=-0.1
173+
)
174+
175+
bullet_pt = go.Scatter(
176+
x=[max(df[key])],
177+
y=[0],
178+
**scatter_options
179+
)
180+
fig.append_trace(bullet_range, j + 1, c + 1)
181+
fig.append_trace(bullet_measure, j + 1, c + 1)
182+
fig.append_trace(bullet_pt, j + 1, c + 1)
183+
elif chart == 'line':
184+
trace_line = go.Scatter(
185+
x=range(len(df[key])),
186+
y=df[key].tolist(),
187+
mode='lines',
188+
marker=dict(
189+
color=colors[0]
190+
)
191+
)
192+
fig.append_trace(trace_line, j + 1, c + 1)
193+
194+
trace_line_pt = go.Scatter(
195+
x=[len(df[key]) - 1],
196+
y=[list(df[key])[-1]],
197+
mode='markers',
198+
marker=dict(
199+
color=colors[1]
200+
)
201+
)
202+
fig.append_trace(trace_line_pt, j + 1, c + 1)
203+
elif chart == 'avg':
204+
fig['layout']['annotations'].append(
205+
dict(
206+
xref='x{}'.format(j * num_of_chart_types + c + 1),
207+
yref='y{}'.format(j * num_of_chart_types + c + 1),
208+
x=x,
209+
y=0.5,
210+
xanchor=xanchor,
211+
text='{}'.format(rounded_mean),
212+
showarrow=False,
213+
font=dict(size=15),
214+
)
215+
)
216+
empty_data = go.Bar(
217+
x=[0],
218+
y=[0],
219+
visible=False
220+
)
221+
fig.append_trace(empty_data, j + 1, c + 1)
222+
elif chart == 'bar':
223+
trace_bar = go.Bar(
224+
x=range(len(df[key])),
225+
y=df[key].tolist(),
226+
marker=dict(
227+
color=[colors[0] for _ in
228+
range(len(df[key]) - 1)] + [colors[1]]
229+
)
230+
)
231+
fig.append_trace(trace_bar, j + 1, c + 1)
232+
else:
233+
raise exceptions.PlotlyError(
234+
'Your chart type must be a list and may only contain any '
235+
'combination of the keys {}'.format(
236+
utils.list_of_options(
237+
VALID_CHART_TYPES, 'or')
238+
)
239+
)
240+
241+
# show titles
242+
if show_titles:
243+
for k, header in enumerate(chart_types):
244+
label = utils.annotation_dict_for_label(
245+
header, k + 1, 5, subplot_spacing=0, row_col='col',
246+
flipped=False, column_width=column_width
247+
)
248+
fig['layout']['annotations'].append(label)
249+
250+
# narrow columns with 'name' or 'avg' chart type
251+
for j in range(len(df.columns)):
252+
for idx in narrow_idxs:
253+
for axis in ['xaxis', 'yaxis']:
254+
fig['layout']['{}{}'.format(
255+
axis, j * num_of_chart_types + idx + 1
256+
)]['range'] = [0, 1]
257+
return fig

0 commit comments

Comments
 (0)