1010
1111pd = optional_imports .get_module ('pandas' )
1212
13- VALID_KEYS = ['title' , 'subtitle' , 'ranges' , 'measures' , 'markers' ]
1413
15-
16- def _bullet (df , markers , measures , ranges , subtitle , title , orientation ,
14+ def _bullet (df , markers , measures , ranges , subtitles , titles , orientation ,
1715 range_colors , measure_colors , horizontal_spacing ,
18- vertical_spacing , scatter_options ):
16+ vertical_spacing , scatter_options , layout_options ):
17+
1918 num_of_lanes = len (df )
2019 num_of_rows = num_of_lanes if orientation == 'h' else 1
2120 num_of_cols = 1 if orientation == 'h' else num_of_lanes
@@ -30,11 +29,18 @@ def _bullet(df, markers, measures, ranges, subtitle, title, orientation,
3029 # layout
3130 fig ['layout' ].update (
3231 dict (shapes = []),
32+ title = 'Bullet Chart' ,
33+ height = 600 ,
34+ width = 1000 ,
3335 showlegend = False ,
3436 barmode = 'stack' ,
37+ annotations = [],
3538 margin = dict (l = 120 if orientation == 'h' else 80 ),
3639 )
3740
41+ # update layout
42+ fig ['layout' ].update (layout_options )
43+
3844 if orientation == 'h' :
3945 width_axis = 'yaxis'
4046 length_axis = 'xaxis'
@@ -120,22 +126,23 @@ def _bullet(df, markers, measures, ranges, subtitle, title, orientation,
120126 markers = go .Scatter (
121127 x = x ,
122128 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' ],
128130 name = 'markers' ,
129131 hoverinfo = 'x' if orientation == 'h' else 'y' ,
130132 xaxis = 'x{}' .format (row + 1 ),
131133 yaxis = 'y{}' .format (row + 1 )
132134 )
135+
136+ for k in scatter_options :
137+ if k != 'marker' :
138+ markers [k ] = scatter_options [k ]
139+
133140 fig ['data' ].append (markers )
134141
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 ' ])
139146 else :
140147 subtitle = ''
141148 label = '<b>{}</b>' .format (title ) + subtitle
@@ -154,16 +161,29 @@ def _bullet(df, markers, measures, ranges, subtitle, title, orientation,
154161
155162
156163def 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 ):
161168 """
162169 Returns figure for bullet chart.
163170
164171 :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.
167187 :param (bool) orientation: if 'h', the bars are placed horizontally as
168188 rows. If 'v' the bars are placed vertically in the chart.
169189 :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,
181201 plotly.tools.make_subplots. Ranges between 0 and 1.
182202 :param (float) vertical_spacing: see the 'vertical_spacing' param in
183203 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+ ```
187253 """
188254 # validate df
189255 if not pd :
@@ -203,12 +269,12 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
203269 )
204270
205271 # make DataFrame from data with correct column headers
206- col_names = ['title ' , 'subtitle' , 'markers' , 'measures' , 'ranges' ]
272+ col_names = ['titles ' , 'subtitle' , 'markers' , 'measures' , 'ranges' ]
207273 if isinstance (data , list ):
208274 df = pd .DataFrame (
209275 [
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 ),
212278 [d [markers ] for d in data ] if markers else [[]] * len (data ),
213279 [d [measures ] for d in data ] if measures else [[]] * len (data ),
214280 [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,
218284 elif isinstance (data , pd .DataFrame ):
219285 df = pd .DataFrame (
220286 [
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 ),
223289 data [markers ].tolist () if markers else [[]] * len (data ),
224290 data [measures ].tolist () if measures else [[]] * len (data ),
225291 data [ranges ].tolist () if ranges else [[]] * len (data ),
@@ -250,30 +316,25 @@ def create_bullet(data, markers=None, measures=None, ranges=None,
250316 colors_list = colors .convert_colors_to_same_type (colors_list ,
251317 'rgb' )[0 ]
252318
253- # scatter options
254- default_scatter_options = {
319+ # default scatter options
320+ default_scatter = {
255321 'marker' : {'size' : 12 ,
256322 'symbol' : 'diamond-tall' ,
257323 'color' : 'rgb(0, 0, 0)' }
258324 }
325+
259326 if scatter_options == {}:
260- scatter_options .update (default_scatter_options )
327+ scatter_options .update (default_scatter )
261328 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 ]
266333
267334 fig = _bullet (
268- df , markers , measures , ranges , subtitle , title , orientation ,
335+ df , markers , measures , ranges , subtitles , titles , orientation ,
269336 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 ,
277338 )
278339
279340 return fig
0 commit comments