10
10
11
11
pd = optional_imports .get_module ('pandas' )
12
12
13
- VALID_KEYS = ['title' , 'subtitle' , 'ranges' , 'measures' , 'markers' ]
14
13
15
-
16
- def _bullet (df , markers , measures , ranges , subtitle , title , orientation ,
14
+ def _bullet (df , markers , measures , ranges , subtitles , titles , orientation ,
17
15
range_colors , measure_colors , horizontal_spacing ,
18
- vertical_spacing , scatter_options ):
16
+ vertical_spacing , scatter_options , layout_options ):
17
+
19
18
num_of_lanes = len (df )
20
19
num_of_rows = num_of_lanes if orientation == 'h' else 1
21
20
num_of_cols = 1 if orientation == 'h' else num_of_lanes
@@ -30,11 +29,18 @@ def _bullet(df, markers, measures, ranges, subtitle, title, orientation,
30
29
# layout
31
30
fig ['layout' ].update (
32
31
dict (shapes = []),
32
+ title = 'Bullet Chart' ,
33
+ height = 600 ,
34
+ width = 1000 ,
33
35
showlegend = False ,
34
36
barmode = 'stack' ,
37
+ annotations = [],
35
38
margin = dict (l = 120 if orientation == 'h' else 80 ),
36
39
)
37
40
41
+ # update layout
42
+ fig ['layout' ].update (layout_options )
43
+
38
44
if orientation == 'h' :
39
45
width_axis = 'yaxis'
40
46
length_axis = 'xaxis'
@@ -120,22 +126,23 @@ def _bullet(df, markers, measures, ranges, subtitle, title, orientation,
120
126
markers = go .Scatter (
121
127
x = x ,
122
128
y = y ,
123
- marker = dict (
124
- color = 'rgb(0, 0, 0)' ,
125
- symbol = marker_symbol ,
126
- size = marker_size
127
- ),
129
+ marker = scatter_options ['marker' ],
128
130
name = 'markers' ,
129
131
hoverinfo = 'x' if orientation == 'h' else 'y' ,
130
132
xaxis = 'x{}' .format (row + 1 ),
131
133
yaxis = 'y{}' .format (row + 1 )
132
134
)
135
+
136
+ for k in scatter_options :
137
+ if k != 'marker' :
138
+ markers [k ] = scatter_options [k ]
139
+
133
140
fig ['data' ].append (markers )
134
141
135
- # labels
136
- title = df .iloc [row ]['title ' ]
137
- if 'subtitle ' in df :
138
- subtitle = '<br>{}' .format (df .iloc [row ]['subtitle ' ])
142
+ # titles and subtitles
143
+ title = df .iloc [row ]['titles ' ]
144
+ if 'subtitles ' in df :
145
+ subtitle = '<br>{}' .format (df .iloc [row ]['subtitles ' ])
139
146
else :
140
147
subtitle = ''
141
148
label = '<b>{}</b>' .format (title ) + subtitle
@@ -154,16 +161,29 @@ def _bullet(df, markers, measures, ranges, subtitle, title, orientation,
154
161
155
162
156
163
def create_bullet (data , markers = None , measures = None , ranges = None ,
157
- subtitle = None , title = None , orientation = 'h' ,
158
- range_colors = None , measure_colors = None , horizontal_spacing = None ,
159
- vertical_spacing = None , chart_title = 'Bullet Chart' ,
160
- height = 600 , width = 1000 , ** scatter_options ):
164
+ subtitles = None , titles = None , orientation = 'h' ,
165
+ range_colors = None , measure_colors = None ,
166
+ horizontal_spacing = None , vertical_spacing = None ,
167
+ scatter_options = {}, ** layout_options ):
161
168
"""
162
169
Returns figure for bullet chart.
163
170
164
171
:param (pd.DataFrame | list) data: either a JSON list of dicts or a pandas
165
- DataFrame. All keys must be one of 'title', 'subtitle', 'ranges',
166
- 'measures', and 'markers'.
172
+ DataFrame.
173
+ :param (str) markers: the column name or dictionary key for the markers in
174
+ each subplot.
175
+ :param (str) measures: the column name or dictionary key for the measure
176
+ bars in each subplot. This bar usually represents the quantitative
177
+ measure of performance, usually a list of two values [a, b] and are
178
+ the blue bars in the foreground of each subplot by default.
179
+ :param (str) ranges: the column name or dictionary key for the qualitative
180
+ ranges of performance, usually a 3-item list [bad, okay, good]. They
181
+ correspond to the grey bars in the background of each chart.
182
+ :param (str) subtitles: the column name or dictionary key for the subtitle
183
+ of each subplot chart. The subplots are displayed right underneath
184
+ each title.
185
+ :param (str) titles: the column name or dictionary key for the main label
186
+ of each subplot chart.
167
187
:param (bool) orientation: if 'h', the bars are placed horizontally as
168
188
rows. If 'v' the bars are placed vertically in the chart.
169
189
:param (int) marker_size: sets the size of the markers in the chart.
@@ -181,9 +201,55 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
181
201
plotly.tools.make_subplots. Ranges between 0 and 1.
182
202
:param (float) vertical_spacing: see the 'vertical_spacing' param in
183
203
plotly.tools.make_subplots. Ranges between 0 and 1.
184
- :param (str) title: title of the bullet chart.
185
- :param (float) height: height of the chart.
186
- :param (float) width width of the chart.
204
+ :param (dict) scatter_options: describes attributes for the scatter trace
205
+ in each subplot such as name and marker size. Call
206
+ help(plotly.graph_objs.Scatter) for more information on valid params.
207
+ :param layout_options: describes attributes for the layout of the figure
208
+ such as title, height and width. Call help(plotly.graph_objs.Layout)
209
+ for more information on valid params.
210
+
211
+ Example 1: Use a Dictionary
212
+ ```
213
+ import plotly
214
+ import plotly.plotly as py
215
+ import plotly.figure_factory as ff
216
+
217
+ data = [
218
+ {"e": "Revenue", "d": "US$, in thousands", "c": [150, 225, 300],
219
+ "b": [220,270], "a": [250]},
220
+ {"e": "Profit", "d": "%", "c": [20, 25, 30], "b": [21, 23], "a": [26]},
221
+ {"e": "Order Size", "d":"US$, average","c": [350, 500, 600],
222
+ "b": [100,320],"a": [550]},
223
+ {"e": "New Customers", "d": "count", "c": [1400, 2000, 2500],
224
+ "b": [1000,1650],"a": [2100]},
225
+ {"e": "Satisfaction", "d": "out of 5","c": [3.5, 4.25, 5],
226
+ "b": [3.2,4.7], "a": [4.4]}
227
+ ]
228
+
229
+ fig = ff.create_bullet(
230
+ data, titles='e', subtitles='d', markers='a', measures='b',
231
+ ranges='c', orientation='h', title='my simple bullet chart'
232
+ )
233
+ py.iplot(fig)
234
+ ```
235
+
236
+ Example 2: Use a DataFrame with Custom Colors
237
+ ```
238
+ import plotly.plotly as py
239
+ import plotly.figure_factory as ff
240
+
241
+ import pandas as pd
242
+
243
+ data = pd.read_json('https://cdn.rawgit.com/plotly/datasets/master/BulletData.json')
244
+
245
+ fig = ff.create_bullet(
246
+ data, titles='title', markers='markers', measures='measures',
247
+ orientation='v', measure_colors=['rgb(14, 52, 75)', 'rgb(31, 141, 127)'],
248
+ scatter_options={'marker': {'symbol': 'circle'}}, width=700
249
+
250
+ )
251
+ py.iplot(fig)
252
+ ```
187
253
"""
188
254
# validate df
189
255
if not pd :
@@ -203,12 +269,12 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
203
269
)
204
270
205
271
# make DataFrame from data with correct column headers
206
- col_names = ['title ' , 'subtitle' , 'markers' , 'measures' , 'ranges' ]
272
+ col_names = ['titles ' , 'subtitle' , 'markers' , 'measures' , 'ranges' ]
207
273
if isinstance (data , list ):
208
274
df = pd .DataFrame (
209
275
[
210
- [d [title ] for d in data ] if title else ['' ] * len (data ),
211
- [d [subtitle ] for d in data ] if subtitle else ['' ] * len (data ),
276
+ [d [titles ] for d in data ] if titles else ['' ] * len (data ),
277
+ [d [subtitles ] for d in data ] if subtitles else ['' ] * len (data ),
212
278
[d [markers ] for d in data ] if markers else [[]] * len (data ),
213
279
[d [measures ] for d in data ] if measures else [[]] * len (data ),
214
280
[d [ranges ] for d in data ] if ranges else [[]] * len (data ),
@@ -218,8 +284,8 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
218
284
elif isinstance (data , pd .DataFrame ):
219
285
df = pd .DataFrame (
220
286
[
221
- data [title ].tolist () if title else ['' ] * len (data ),
222
- data [subtitle ].tolist () if subtitle else ['' ] * len (data ),
287
+ data [titles ].tolist () if titles else ['' ] * len (data ),
288
+ data [subtitles ].tolist () if subtitles else ['' ] * len (data ),
223
289
data [markers ].tolist () if markers else [[]] * len (data ),
224
290
data [measures ].tolist () if measures else [[]] * len (data ),
225
291
data [ranges ].tolist () if ranges else [[]] * len (data ),
@@ -250,30 +316,25 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
250
316
colors_list = colors .convert_colors_to_same_type (colors_list ,
251
317
'rgb' )[0 ]
252
318
253
- # scatter options
254
- default_scatter_options = {
319
+ # default scatter options
320
+ default_scatter = {
255
321
'marker' : {'size' : 12 ,
256
322
'symbol' : 'diamond-tall' ,
257
323
'color' : 'rgb(0, 0, 0)' }
258
324
}
325
+
259
326
if scatter_options == {}:
260
- scatter_options .update (default_scatter_options )
327
+ scatter_options .update (default_scatter )
261
328
else :
262
-
263
-
264
-
265
-
329
+ # add default options to scatter_options if they are not present
330
+ for k in default_scatter [ 'marker' ]:
331
+ if k not in scatter_options [ 'marker' ]:
332
+ scatter_options [ 'marker' ][ k ] = default_scatter [ 'marker' ][ k ]
266
333
267
334
fig = _bullet (
268
- df , markers , measures , ranges , subtitle , title , orientation ,
335
+ df , markers , measures , ranges , subtitles , titles , orientation ,
269
336
range_colors , measure_colors , horizontal_spacing , vertical_spacing ,
270
- scatter_options
271
- )
272
-
273
- fig ['layout' ].update (
274
- title = chart_title ,
275
- height = height ,
276
- width = width ,
337
+ scatter_options , layout_options ,
277
338
)
278
339
279
340
return fig
0 commit comments