@@ -50,7 +50,9 @@ def __init__(self):
5050 """
5151 self .plotly_fig = Figure (data = Data (), layout = Layout ())
5252 self .mpl_fig = None
53- self .current_ax_patches = []
53+ self .current_mpl_ax = None
54+ self .bar_containers = None
55+ self .current_bars = []
5456 self .axis_ct = 0
5557 self .mpl_x_bounds = (0 , 1 )
5658 self .mpl_y_bounds = (0 , 1 )
@@ -137,6 +139,10 @@ def open_axes(self, ax, props):
137139
138140 """
139141 self .msg += " Opening axes\n "
142+ self .current_mpl_ax = ax
143+ self .bar_containers = [c for c in ax .containers # empty is OK
144+ if c .__class__ .__name__ == 'BarContainer' ]
145+ self .current_bars = []
140146 self .axis_ct += 1
141147 # set defaults in axes
142148 xaxis = XAxis (
@@ -173,20 +179,27 @@ def close_axes(self, ax):
173179
174180 Bars from bar charts are given to PlotlyRenderer one-by-one,
175181 thus they need to be taken care of at the close of each axes object.
176- The self.current_ax_patches variable should be empty unless a bar
177- chart has been created or a rectangle object has been drawn that has
178- an edge exactly on the lines x=0 or y=0.
182+ The self.current_bars variable should be empty unless a bar
183+ chart has been created.
179184
180185 Positional arguments:
181186 ax -- an mpl axes object, not required at this time.
182187
183188 """
184- for patch_coll in self .current_ax_patches :
185- self .draw_bar (patch_coll )
186- self .current_ax_patches = [] # clear this for next axes obj
189+ self .draw_bars (self .current_bars )
187190 self .msg += " Closing axes\n "
188191
189- def draw_bar (self , patch_coll ):
192+ def draw_bars (self , bars ):
193+
194+ # sort bars according to bar containers
195+ mpl_traces = []
196+ for container in self .bar_containers :
197+ mpl_traces .append ([bar_props for bar_props in self .current_bars
198+ if bar_props ['mplobj' ] in container ])
199+ for trace in mpl_traces :
200+ self .draw_bar (trace )
201+
202+ def draw_bar (self , coll ):
190203 """Draw a collection of similar patches as a bar chart.
191204
192205 After bars are sorted, an appropriate data dictionary must be created
@@ -198,30 +211,53 @@ def draw_bar(self, patch_coll):
198211 patch_coll -- a collection of patches to be drawn as a bar chart.
199212
200213 """
201- orientation = patch_coll [0 ]['orientation' ]
214+ tol = 1e-10
215+ trace = [mpltools .make_bar (** bar_props ) for bar_props in coll ]
216+ widths = [bar_props ['x1' ] - bar_props ['x0' ] for bar_props in trace ]
217+ heights = [bar_props ['y1' ] - bar_props ['y0' ] for bar_props in trace ]
218+ vertical = abs (
219+ sum (widths [0 ]- widths [iii ] for iii in range (len (widths )))
220+ ) < tol
221+ horizontal = abs (
222+ sum (heights [0 ]- heights [iii ] for iii in range (len (heights )))
223+ ) < tol
224+ if vertical and horizontal :
225+ # Check for monotonic x. Can't both be true!
226+ x_zeros = [bar_props ['x0' ] for bar_props in trace ]
227+ if all ((x_zeros [iii + 1 ] > x_zeros [iii ]
228+ for iii in range (len (x_zeros [:- 1 ])))):
229+ orientation = 'v'
230+ else :
231+ orientation = 'h'
232+ elif vertical :
233+ orientation = 'v'
234+ else :
235+ orientation = 'h'
202236 if orientation == 'v' :
203237 self .msg += " Attempting to draw a vertical bar chart\n "
204- patch_coll .sort (key = lambda b : b ['x0' ])
205- x = [bar ['x0' ]+ (bar ['x1' ]- bar ['x0' ])/ 2 for bar in patch_coll ]
206- y = [bar ['y1' ] for bar in patch_coll ]
207- bar_gap = mpltools .get_bar_gap ([bar ['x0' ] for bar in patch_coll ],
208- [bar ['x1' ] for bar in patch_coll ])
238+ for bar in trace :
239+ bar ['y0' ], bar ['y1' ] = 0 , bar ['y1' ] - bar ['y0' ]
240+ x = [bar ['x0' ]+ (bar ['x1' ]- bar ['x0' ])/ 2 for bar in trace ]
241+ y = [bar ['y1' ] for bar in trace ]
242+ bar_gap = mpltools .get_bar_gap ([bar ['x0' ] for bar in trace ],
243+ [bar ['x1' ] for bar in trace ])
209244 else :
210245 self .msg += " Attempting to draw a horizontal bar chart\n "
211- patch_coll .sort (key = lambda b : b ['y0' ])
212- x = [bar ['x1' ] for bar in patch_coll ]
213- y = [bar ['y0' ]+ (bar ['y1' ]- bar ['y0' ])/ 2 for bar in patch_coll ]
214- bar_gap = mpltools .get_bar_gap ([bar ['y0' ] for bar in patch_coll ],
215- [bar ['y1' ] for bar in patch_coll ])
246+ for bar in trace :
247+ bar ['x0' ], bar ['x1' ] = 0 , bar ['x1' ] - bar ['x0' ]
248+ x = [bar ['x1' ] for bar in trace ]
249+ y = [bar ['y0' ]+ (bar ['y1' ]- bar ['y0' ])/ 2 for bar in trace ]
250+ bar_gap = mpltools .get_bar_gap ([bar ['y0' ] for bar in trace ],
251+ [bar ['y1' ] for bar in trace ])
216252 bar = Bar (orientation = orientation ,
217253 x = x ,
218254 y = y ,
219255 xaxis = 'x{0}' .format (self .axis_ct ),
220256 yaxis = 'y{0}' .format (self .axis_ct ),
221- opacity = patch_coll [0 ]['alpha' ],
257+ opacity = trace [0 ]['alpha' ], # TODO: get all alphas if array?
222258 marker = Marker (
223- color = patch_coll [0 ]['facecolor' ],
224- line = Line (width = patch_coll [0 ]['edgewidth' ])))
259+ color = trace [0 ]['facecolor' ], # TODO: get all
260+ line = Line (width = trace [0 ]['edgewidth' ]))) # TODO: get all
225261 if len (bar ['x' ]) > 1 :
226262 self .msg += " Heck yeah, I drew that bar chart\n "
227263 self .plotly_fig ['data' ] += bar ,
@@ -231,6 +267,8 @@ def draw_bar(self, patch_coll):
231267 self .msg += " Bar chart not drawn\n "
232268 warnings .warn ('found box chart data with length <= 1, '
233269 'assuming data redundancy, not plotting.' )
270+ print bar .to_string ()
271+
234272
235273 def draw_marked_line (self , ** props ):
236274 """Create a data dict for a line obj.
@@ -400,65 +438,14 @@ def draw_path(self, **props):
400438
401439 """
402440 self .msg += " Attempting to draw a path\n "
403- is_bar = mpltools .is_bar (** props )
404- is_barh = mpltools .is_barh (** props )
405- if is_bar : # if we think it's a bar, add it!
406- self .msg += " Assuming path is a vertical bar\n "
407- bar = mpltools .make_bar (orientation = 'v' , ** props )
408- self .file_bar (bar )
409- if is_barh : # perhaps a horizontal bar?
410- self .msg += " Assuming path is a horizontal bar\n "
411- bar = mpltools .make_bar (orientation = 'h' , ** props )
412- self .file_bar (bar )
413- if not (is_bar or is_barh ):
441+ is_bar = mpltools .is_bar (self .current_mpl_ax .containers , ** props )
442+ if is_bar :
443+ self .current_bars += [props ]
444+ else :
414445 self .msg += " This path isn't a bar, not drawing\n "
415446 warnings .warn ("I found a path object that I don't think is part "
416447 "of a bar chart. Ignoring." )
417448
418- def file_bar (self , bar ):
419- """Puts a given bar into an appropriate bar or barh collection.
420-
421- Bars come from the mplexporter one-by-one. To try to put them into
422- appropriate data sets, we must compare them to existing data.
423-
424- Positional arguments:
425- bar -- a bar dictionary created in mpltools.make_bar.py.
426-
427- bar.keys() -- [
428- 'bar', (mpl path object)
429- 'orientation', (bar direction, 'v' or 'h' for horizontal or vertical)
430- 'x0', ([x0, y0] = bottom-left corner of rectangle)
431- 'y0',
432- 'x1', ([x1, y1] = top-right corner of rectangle):
433- 'y1',
434- 'alpha', (opacity of rectangle)
435- 'edgecolor', (boundary line color)
436- 'facecolor', (rectangle color)
437- 'edgewidth', (boundary line width)
438- 'dasharray', (linestyle for boundary line)
439- 'zorder', (precedence when stacked)
440- ]
441-
442- """
443- self .msg += " Putting a bar into the proper bar collection\n "
444- if len (self .current_ax_patches ) == 0 :
445- self .msg += " Started a new bar collection with this " \
446- "bar\n "
447- self .current_ax_patches .append ([])
448- self .current_ax_patches [- 1 ] += bar ,
449- else :
450- match = False
451- for patch_collection in self .current_ax_patches :
452- if mpltools .check_bar_match (patch_collection [0 ], bar ):
453- match = True
454- patch_collection += bar ,
455- self .msg += " Filed bar into existing bar " \
456- "collection\n "
457- if not match :
458- self .msg += " Started a new bar collection with " \
459- "this bar\n "
460- self .current_ax_patches .append ([])
461- self .current_ax_patches [- 1 ] += bar ,
462449
463450 def draw_text (self , ** props ):
464451 """Create an annotation dict for a text obj.
0 commit comments