1010
1111pd = optional_imports .get_module ('pandas' )
1212
13- SUBPLOT_SPACING = 0.015
1413VALID_KEYS = ['title' , 'subtitle' , 'ranges' , 'measures' , 'markers' ]
1514
1615
17- # add shapes
18- def rectangle (color , x0 , x1 , y0 , y1 , xref , yref , layer ):
19- return {
20- 'fillcolor' : color ,
21- 'line' : {'width' : 0 },
22- 'opacity' : 1 ,
23- 'type' : 'rect' ,
24- 'x0' : x0 ,
25- 'x1' : x1 ,
26- 'xref' : xref ,
27- 'y0' : y0 ,
28- 'y1' : y1 ,
29- 'yref' : yref ,
30- 'layer' : layer
31- }
32-
33-
3416def _bullet (df , as_rows , marker_size , marker_symbol , range_colors ,
35- measure_colors ):
17+ measure_colors , subplot_spacing ):
3618 num_of_lanes = len (df )
3719 num_of_rows = num_of_lanes if as_rows else 1
3820 num_of_cols = 1 if as_rows else num_of_lanes
21+ if not subplot_spacing :
22+ subplot_spacing = 1. / num_of_lanes
3923 fig = plotly .tools .make_subplots (
4024 num_of_rows , num_of_cols , print_grid = False ,
41- horizontal_spacing = SUBPLOT_SPACING ,
42- vertical_spacing = SUBPLOT_SPACING
25+ horizontal_spacing = subplot_spacing ,
26+ vertical_spacing = subplot_spacing
4327 )
4428
4529 # layout
4630 fig ['layout' ].update (
4731 dict (shapes = []),
4832 showlegend = False ,
49- annotations = [] ,
33+ barmode = 'stack' ,
5034 margin = dict (l = 120 if as_rows else 80 ),
5135 )
5236
5337 if as_rows :
54- length_axis = 'xaxis'
5538 width_axis = 'yaxis'
39+ length_axis = 'xaxis'
5640 else :
5741 width_axis = 'xaxis'
5842 length_axis = 'yaxis'
@@ -67,105 +51,102 @@ def _bullet(df, as_rows, marker_size, marker_symbol, range_colors,
6751 fig ['layout' ][key ]['showticklabels' ] = False
6852 fig ['layout' ][key ]['range' ] = [0 , 1 ]
6953
54+ # narrow domain if 1 bar
55+ if num_of_lanes <= 1 :
56+ fig ['layout' ][width_axis + '1' ]['domain' ] = [0.4 , 0.6 ]
57+
7058 # marker symbol size
7159 if not marker_size :
72- if num_of_lanes <= 3 :
60+ if num_of_lanes <= 4 :
7361 marker_size = 18
7462 else :
75- marker_size = 12
76- for idx in range (num_of_lanes ):
77- # marker
78- x = df .iloc [idx ]['markers' ] if as_rows else [0.5 ]
79- y = [0.5 ] if as_rows else df .iloc [idx ]['markers' ]
80- fig ['data' ].append (
81- go .Scatter (
63+ marker_size = 8
64+
65+ if not range_colors :
66+ range_colors = ['rgb(200, 200, 200)' , 'rgb(245, 245, 245)' ]
67+ if not measure_colors :
68+ measure_colors = ['rgb(31, 119, 180)' , 'rgb(176, 196, 221)' ]
69+
70+ for row in range (num_of_lanes ):
71+ # ranges bars
72+ for idx in range (len (df .iloc [row ]['ranges' ])):
73+ inter_colors = colors .n_colors (
74+ range_colors [0 ], range_colors [1 ],
75+ len (df .iloc [row ]['ranges' ]), 'rgb'
76+ )
77+ x = [sorted (df .iloc [row ]['ranges' ])[- 1 - idx ]] if as_rows else [0 ]
78+ y = [0 ] if as_rows else [sorted (df .iloc [row ]['ranges' ])[- 1 - idx ]]
79+ bar = go .Bar (
8280 x = x ,
8381 y = y ,
8482 marker = dict (
85- size = marker_size ,
86- color = 'rgb(0, 0, 0)' ,
87- symbol = marker_symbol
83+ color = inter_colors [- 1 - idx ]
8884 ),
89- xaxis = 'x{}' .format (idx + 1 ),
90- yaxis = 'y{}' .format (idx + 1 )
85+ name = 'ranges' ,
86+ hoverinfo = 'x' if as_rows else 'y' ,
87+ orientation = 'h' if as_rows else 'v' ,
88+ width = 2 ,
89+ base = 0 ,
90+ xaxis = 'x{}' .format (row + 1 ),
91+ yaxis = 'y{}' .format (row + 1 )
9192 )
92- )
93+ fig [ 'data' ]. append ( bar )
9394
94- # ranges
95- y0_ranges = 0.35
96- y1_ranges = 0.65
97- if not range_colors :
98- range_colors = ['rgb(200, 200, 200)' , 'rgb(245, 245, 245)' ]
99- ranges_len = len (df .iloc [idx ]['ranges' ])
100- if ranges_len <= 1 :
101- inter_colors = [range_colors [0 ]]
102- else :
95+ # measures bars
96+ for idx in range (len (df .iloc [row ]['measures' ])):
10397 inter_colors = colors .n_colors (
104- range_colors [0 ], range_colors [1 ], ranges_len , 'rgb'
105- )
106- for range_idx in range (ranges_len ):
107- color = inter_colors [range_idx ]
108- if range_idx == 0 :
109- start_range = 0
110- else :
111- start_range = df .iloc [idx ]['ranges' ][range_idx - 1 ]
112- end_range = df .iloc [idx ]['ranges' ][range_idx ]
113-
114- x0 = start_range if as_rows else y0_ranges
115- x1 = end_range if as_rows else y1_ranges
116- y0 = y0_ranges if as_rows else start_range
117- y1 = y1_ranges if as_rows else end_range
118- fig ['layout' ]['shapes' ].append (
119- rectangle (
120- color , x0 , x1 , y0 , y1 ,
121- 'x{}' .format (idx + 1 ),
122- 'y{}' .format (idx + 1 ),
123- 'below'
124- )
98+ measure_colors [0 ], measure_colors [1 ],
99+ len (df .iloc [row ]['measures' ]), 'rgb'
125100 )
126-
127- # measures
128- y0_measures = 0.45
129- y1_measures = 0.55
130- if not measure_colors :
131- measure_colors = ['rgb(31, 119, 180)' , 'rgb(176, 196, 221)' ]
132- measures_len = len (df .iloc [idx ]['measures' ])
133- if measures_len <= 1 :
134- inter_colors = [measure_colors [0 ]]
135- else :
136- inter_colors = colors .n_colors (
137- measure_colors [0 ], measure_colors [1 ], measures_len , 'rgb'
101+ x = ([sorted (df .iloc [row ]['measures' ])[- 1 - idx ]] if as_rows
102+ else [0.5 ])
103+ y = ([0.5 ] if as_rows
104+ else [sorted (df .iloc [row ]['measures' ])[- 1 - idx ]])
105+ bar = go .Bar (
106+ x = x ,
107+ y = y ,
108+ marker = dict (
109+ color = inter_colors [- 1 - idx ]
110+ ),
111+ name = 'measures' ,
112+ hoverinfo = 'x' if as_rows else 'y' ,
113+ orientation = 'h' if as_rows else 'v' ,
114+ width = 0.4 ,
115+ base = 0 ,
116+ xaxis = 'x{}' .format (row + 1 ),
117+ yaxis = 'y{}' .format (row + 1 )
138118 )
139- for range_idx in range (measures_len ):
140- color = inter_colors [range_idx ]
141- if range_idx == 0 :
142- start_range = 0
143- else :
144- start_range = df .iloc [idx ]['measures' ][range_idx - 1 ]
145- end_range = df .iloc [idx ]['measures' ][range_idx ]
119+ fig ['data' ].append (bar )
146120
147- x0 = start_range if as_rows else y0_measures
148- x1 = end_range if as_rows else y1_measures
149- y0 = y0_measures if as_rows else start_range
150- y1 = y1_measures if as_rows else end_range
151- fig ['layout' ]['shapes' ].append (
152- rectangle (
153- color , x0 , x1 , y0 , y1 ,
154- 'x{}' .format (idx + 1 ),
155- 'y{}' .format (idx + 1 ),
156- 'below'
157- )
158- )
121+ # markers
122+ x = df .iloc [row ]['markers' ] if as_rows else [0.5 ]
123+ y = [0.5 ] if as_rows else df .iloc [row ]['markers' ]
124+ markers = go .Scatter (
125+ x = x ,
126+ y = y ,
127+ marker = dict (
128+ color = 'rgb(0, 0, 0)' ,
129+ symbol = marker_symbol ,
130+ size = marker_size
131+ ),
132+ name = 'markers' ,
133+ hoverinfo = 'x' if as_rows else 'y' ,
134+ xaxis = 'x{}' .format (row + 1 ),
135+ yaxis = 'y{}' .format (row + 1 )
136+ )
137+ fig ['data' ].append (markers )
159138
160139 # labels
161- title = df .iloc [idx ]['title' ]
140+ title = df .iloc [row ]['title' ]
162141 if 'subtitle' in df :
163- subtitle = '<br>{}' .format (df .iloc [idx ]['subtitle' ])
142+ subtitle = '<br>{}' .format (df .iloc [row ]['subtitle' ])
164143 else :
165144 subtitle = ''
166145 label = '<b>{}</b>' .format (title ) + subtitle
167146 annot = utils .annotation_dict_for_label (
168- label , num_of_lanes - idx , num_of_lanes , SUBPLOT_SPACING ,
147+ label ,
148+ (num_of_lanes - row if as_rows else row + 1 ),
149+ num_of_lanes , subplot_spacing ,
169150 'row' if as_rows else 'col' ,
170151 True if as_rows else False ,
171152 False
@@ -177,8 +158,8 @@ def _bullet(df, as_rows, marker_size, marker_symbol, range_colors,
177158
178159def create_bullet (df , as_rows = True , marker_size = 16 ,
179160 marker_symbol = 'diamond-tall' , range_colors = None ,
180- measure_colors = None , title = 'Bullet Chart' , height = 600 ,
181- width = 1000 ):
161+ measure_colors = None , subplot_spacing = None ,
162+ title = 'Bullet Chart' , height = 600 , width = 1000 ):
182163 """
183164 Returns figure for bullet chart.
184165
@@ -198,6 +179,9 @@ def create_bullet(df, as_rows=True, marker_size=16,
198179 :param (list) measure_colors: a list of two colors which is used to color
199180 the thin quantitative bars in the bullet chart.
200181 Default=['rgb(31, 119, 180)', 'rgb(176, 196, 221)']
182+ :param (float) subplot_spacing: set the distance between each bar chart.
183+ If not specified an automatic spacing is assigned based on the number
184+ of bars to be plotted.
201185 :param (str) title: title of the bullet chart.
202186 :param (float) height: height of the chart.
203187 :param (float) width width of the chart.
@@ -260,7 +244,8 @@ def create_bullet(df, as_rows=True, marker_size=16,
260244 'rgb' )[0 ]
261245
262246 fig = _bullet (
263- df , as_rows , marker_size , marker_symbol , range_colors , measure_colors
247+ df , as_rows , marker_size , marker_symbol , range_colors , measure_colors ,
248+ subplot_spacing
264249 )
265250
266251 fig ['layout' ].update (
0 commit comments