Skip to content

Commit d9792de

Browse files
committed
Added logic to add bars with new is_bar test.
1 parent b49c84c commit d9792de

File tree

1 file changed

+64
-77
lines changed

1 file changed

+64
-77
lines changed

plotly/matplotlylib/renderer.py

Lines changed: 64 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)