def multi_bar(df="dataframe", dim=(5, 4), colbar=None, colerrorbar=None, bw=0.4, colorbar=None, xbarcol=None, r=300, show=False, axtickfontname="Arial", axtickfontsize=9, ax_x_ticklabel=None, ar=90, figtype='png', figname='multi_bar', valphabar=1, legendpos='best', errorbar=False, yerrlw=None, yerrcw=None, plotlegend=False, hbsize=4, ylm=None, add_sign_line=False, pv=None, sign_line_opts={'symbol': '*', 'fontsize': 8, 'linewidth':0.8, 'arrowstyle': '-', 'dist_y_pos': 2.5, 'dist_y_neg': 4.2}, add_sign_symbol=False, sign_symbol_opts={'symbol': '*', 'fontsize': 8 }, dotplot=False, sub_cat=None, sub_cat_opts={'y_neg_dist': 3.5, 'fontsize': 8}, sub_cat_label_dist=None, theme=None): xbar = np.arange(df.shape[0]) xbar_temp = xbar if theme == 'dark': general.dark_bg() fig, ax = plt.subplots(figsize=dim) assert len(colbar) >= 2, "number of bar should be atleast 2" assert len(colbar) == len(colorbar), "number of color should be equivalent to number of column bars" if colbar is not None and isinstance(colbar, (tuple, list)): for i in range(len(colbar)): if errorbar: ax.bar(x=xbar_temp, height=df[colbar[i]], yerr=df[colerrorbar[i]], width=bw, color=colorbar[i], alpha=valphabar, capsize=hbsize, label=colbar[i], error_kw={'elinewidth': yerrlw, 'capthick': yerrcw}) xbar_temp = xbar_temp+bw else: ax.bar(x=xbar_temp, height=df[colbar[i]], width=bw, color=colorbar[i], alpha=valphabar, label=colbar[i]) xbar_temp = xbar_temp + bw ax.set_xticks(xbar+( (bw*(len(colbar)-1)) / (1+(len(colbar)-1)) )) if ax_x_ticklabel: x_ticklabel = ax_x_ticklabel else: x_ticklabel = df[xbarcol] ax.set_xticklabels(x_ticklabel, fontsize=axtickfontsize, rotation=ar, fontname=axtickfontname) # ylm must be tuple of start, end, interval if ylm: plt.ylim(bottom=ylm[0], top=ylm[1]) plt.yticks(np.arange(ylm[0], ylm[1], ylm[2]), fontsize=axtickfontsize, fontname=axtickfontname) if plotlegend: plt.legend(loc=legendpos) if dotplot: for cols in range(len(df2['factors'].unique())): ax.scatter(x=np.linspace(xbar[cols] - bw / 2, xbar[cols] + bw / 2, int(reps)), y=df2[(df2['factors'] == df2['factors'].unique()[cols]) & (df2['sample'] == 'M')]['value'], s=dotsize, color="#7d0013", zorder=1, alpha=valphadot, marker=markerdot) if add_sign_line: if len(colbar) == 2: for i in xbar: x_pos = xbar[i] x_pos_2 = xbar[i] + bw y_pos = df[colbar[0]].to_numpy()[i] + df[colerrorbar[0]].to_numpy()[i] y_pos_2 = df[colbar[1]].to_numpy()[i] + df[colerrorbar[1]].to_numpy()[i] # only if y axis is positive if y_pos > 0: y_pos += 0.5 y_pos_2 += 0.5 pv_symb = general.pvalue_symbol(pv[i], sign_line_opts['symbol']) if pv_symb: ax.annotate('', xy=(x_pos, y_pos), xytext=(x_pos_2, y_pos), arrowprops={'connectionstyle': 'bar, armA=50, armB=50, angle=180, fraction=0 ', 'arrowstyle': sign_line_opts['arrowstyle'], 'linewidth': sign_line_opts['linewidth']}) ax.annotate(pv_symb, xy=(np.mean([x_pos, x_pos_2]), max(y_pos, y_pos_2) + sign_line_opts['dist_y_pos']), fontsize=sign_line_opts['fontsize'], ha="center") else: y_pos -= 0.5 y_pos_2 -= 0.5 pv_symb = general.pvalue_symbol(pv[i], sign_line_opts['symbol']) if pv_symb: ax.annotate('', xy=(x_pos, y_pos), xytext=(x_pos_2, y_pos), arrowprops={'connectionstyle': 'bar, armA=50, armB=50, angle=180, fraction=-1 ', 'arrowstyle': sign_line_opts['arrowstyle'], 'linewidth': sign_line_opts['linewidth']}) ax.annotate(pv_symb, xy=(np.mean([x_pos, x_pos_2]), min(y_pos_2, y_pos) - sign_line_opts['dist_y_neg']), fontsize=sign_line_opts['fontsize'], ha="center") if add_sign_symbol: if len(colbar) == 2: for i in xbar: x_pos = xbar[i] x_pos_2 = xbar[i] + bw # max value size factor is essential for rel pos of symbol y_pos = df[colbar[0]].to_numpy()[i] + df[colerrorbar[0]].to_numpy()[i] + \ (max(df[colbar[0]].to_numpy()) / 20) y_pos_2 = df[colbar[1]].to_numpy()[i] + df[colerrorbar[1]].to_numpy()[i] + \ (max(df[colbar[1]].to_numpy()) / 20) # only if y axis is positive if y_pos > 0: pv_symb_1 = general.pvalue_symbol(pv[i][0], sign_symbol_opts['symbol']) pv_symb_2 = general.pvalue_symbol(pv[i][1], sign_symbol_opts['symbol']) if pv_symb_1: plt.annotate(pv_symb_1, xy=(x_pos, y_pos), fontsize=sign_symbol_opts['fontsize'], ha="center") if pv_symb_2: plt.annotate(pv_symb_2, xy=(x_pos_2, y_pos_2), fontsize=sign_symbol_opts['fontsize'], ha="center") elif len(colbar) == 3: for i in xbar: x_pos = xbar[i] x_pos_2 = xbar[i] + bw x_pos_3 = xbar[i] + (2 * bw) # max value size factor is essential for rel pos of symbol y_pos = df[colbar[0]].to_numpy()[i] + df[colerrorbar[0]].to_numpy()[i] + \ (max(df[colbar[0]].to_numpy()) / 20) y_pos_2 = df[colbar[1]].to_numpy()[i] + df[colerrorbar[1]].to_numpy()[i] + \ (max(df[colbar[1]].to_numpy()) / 20) y_pos_3 = df[colbar[2]].to_numpy()[i] + df[colerrorbar[2]].to_numpy()[i] + \ (max(df[colbar[2]].to_numpy()) / 20) # only if y axis is positive if y_pos > 0: pv_symb_1 = general.pvalue_symbol(pv[i][0], sign_symbol_opts['symbol']) pv_symb_2 = general.pvalue_symbol(pv[i][1], sign_symbol_opts['symbol']) pv_symb_3 = general.pvalue_symbol(pv[i][2], sign_symbol_opts['symbol']) if pv_symb_1: plt.annotate(pv_symb_1, xy=(x_pos, y_pos), fontsize=sign_symbol_opts['fontsize'], ha="center") if pv_symb_2: plt.annotate(pv_symb_2, xy=(x_pos_2, y_pos_2), fontsize=sign_symbol_opts['fontsize'], ha="center") if pv_symb_3: plt.annotate(pv_symb_3, xy=(x_pos_3, y_pos_3), fontsize=sign_symbol_opts['fontsize'], ha="center") # update this later for min_value min_value = 0 sub_cat_i = 0 if sub_cat: if isinstance(sub_cat, dict): for k in sub_cat: if isinstance(k, tuple) and len(k) == 2: cat_x_pos, cat_y_pos, cat_x_pos_2 = k[0], min_value - \ (sub_cat_opts[ 'y_neg_dist'] * size_factor_to_start_line), k[1] plt.annotate('', xy=(cat_x_pos - (bw / 2), cat_y_pos), xytext=(cat_x_pos_2 + (bw / 2), cat_y_pos), arrowprops={'arrowstyle': '-', 'linewidth': 0.5}, annotation_clip=False) if sub_cat_label_dist and isinstance(sub_cat_label_dist, list): plt.annotate(sub_cat[k], xy=(np.mean([cat_x_pos, cat_x_pos_2]), cat_y_pos - size_factor_to_start_line - sub_cat_label_dist[ sub_cat_i]), ha="center", fontsize=sub_cat_opts['fontsize'], annotation_clip=False) sub_cat_i += 1 else: plt.annotate(sub_cat[k], xy=(np.mean([cat_x_pos, cat_x_pos_2]), cat_y_pos - size_factor_to_start_line), ha="center", fontsize=sub_cat_opts['fontsize'], annotation_clip=False) else: raise KeyError("Sub category keys must be tuple of size 2") general.get_figure(show, r, figtype, figname, theme) # with replicates values stacked replicates # need to work on this later