def plot_grouped_bars(tick_names: List[str], data_lists: List[List], \ colors: List[str], gap_percent: float, axis_obj = None, \ orientation: str = 'vertical', **kwargs): if len(data_lists) > len(colors): raise ValueError num_data_lists = len(data_lists) locations_centered = np.arange(len(tick_names)) usable_for_bars = 1.0 - (gap_percent / 100.0) bar_width = usable_for_bars / num_data_lists center_offset = (bar_width / 2.0) * (1 - num_data_lists % 2) tick_positions = locations_centered + usable_for_bars / 2.0 category_starts = locations_centered + center_offset offset = 0.0 for cur_height_list, cur_color in zip(data_lists, colors): if len(tick_names) != len(cur_height_list): raise ValueError if axis_obj: # AXIS object is already provided, use it if orientation == 'vertical': plt.xticks(locations_centered, tick_names) axis_obj.bar(category_starts + offset, cur_height_list, \ bar_width, color=cur_color, **kwargs) else: plt.yticks(locations_centered, tick_names) axis_obj.barh(category_starts + offset, cur_height_list, \ bar_width, color=cur_color, **kwargs) else: # AXIS object is not provided, use "plt." if orientation == 'vertical': plt.xticks(locations_centered, tick_names) plt.bar(category_starts + offset, cur_height_list, bar_width, \ color=cur_color, **kwargs) else: plt.yticks(locations_centered, tick_names) plt.barh(category_starts + offset, cur_height_list, bar_width, \ color=cur_color, **kwargs) offset = offset - bar_width # return category_starts + (bar_width / 2.0), bar_width return locations_centered, bar_width