123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- 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
|