Skip to content

Instantly share code, notes, and snippets.

@valosekj
Last active October 31, 2023 16:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save valosekj/da0f371c5769263cc16845729a330479 to your computer and use it in GitHub Desktop.
Save valosekj/da0f371c5769263cc16845729a330479 to your computer and use it in GitHub Desktop.
Tips and hacks for plotting in python

Tips and hacks for plotting in python

This gist containts several useful tips, tricks and hacks for plotting of figures, plots and charts using python (matplotlib and seaborn packages).

Fix warning about matplotlib backend in PyCharm

import matplotlib
matplotlib.use('TkAgg')

or if running python in terminal, run simply export MPLBACKEND=TkAgg

Initialize figure for subplots

fig, ax = plt.subplots()                      # single plot  
fig, ax = plt.subplots(figsize=(14, 7))       # set figure size
fig, axes = plt.subplots(3, 2, figsize=(30, 20), sharex=True)     # set 3 x 2 grid and shared x-axis

Flatten 2D array into 1D to allow iteration by loop

axs = axes.ravel()

for index in range(0, len(axs)):
    sns.boxplot(ax=axs[index], ...)

OR another possible solution

for ax in range(axes.ravel()):
    sns.boxplot(ax=ax, ...)

TODO - ax.flat[0] could also work - try it

Font family

import matplotlib as mpl
mpl.rcParams['font.family'] = 'Arial'

Set title for individual plot/subplot

ax.set_title('Your title', fontsize=18)

Set master title for whole figure containing many subplots

plt.suptitle('My master title', fontsize=40, y=0.99)

Set labels for axis

# x-axis
ax.set_xlabel('Your x-axis', fontsize=18)
# y-axis
ax.set_ylabel('Your y-axis', fontsize=18)
# or turn off x-label
ax.set_xlabel('')

Increase size of xticks and yticks

plt.setp(ax.xaxis.get_majorticklabels(), fontsize=15)
plt.setp(ax.yaxis.get_majorticklabels(), fontsize=15)

Rotate xticklabels, align at end and set fontsize

plt.setp(ax.xaxis.get_majorticklabels(), rotation=45, ha="right", fontsize=24)

Move grid to background (i.e. behind other elements)

ax.set_axisbelow(True)

Add only horizontal grid lines

ax.yaxis.grid(True)

Add horizontal line only for defined coordinates (e.g., 0)

# Draw horizontal line only for 0
hor_line = axs[index].axhline(0, linestyle='-', color='k', alpha=0.5)
# Move horizontal line to background
hor_line.set_zorder(0)

Adjust y-lim

shift = 0.2
original_ylim = axs[index].get_ylim()
axs[index].set_ylim([original_ylim[0] - shift, original_ylim[1]])

Set legend and define its position

plt.legend(fontsize=15, loc='lower left')
# or remove legeng for certain subplot
axs[index].get_legend().remove()

Modify legend font and title size

axs[index].legend(fontsize=10, title='my title', title_fontsize=10, loc='lower left')

Change legend's box properties

legend = axs[index].legend(loc='upper left', fontsize=20, handletextpad=0)
# Make legend's box black
frame = legend.get_frame()
frame.set_edgecolor('black')
axs[index].add_artist(legend)

Create custom legend

# Create single custom legend for whole figure with several subplots
# circles
markers = [Line2D([0], [0], color=value, marker='o', markersize=8, alpha=0.7, linestyle='')
        for value in some_dictionary.values()]
# OR lines
markers = [Line2D([0], [0], color=value, linestyle='-', linewidth=5)
        for value in some_dictionary.values()]
labels = [f'My custom label for {key}'
         for key in some_dictionary.keys()]

# Insert legend below subplots, NB - this line has to be below the plt.tight_layout()
legend = fig.legend(markers, labels, loc='lower left', bbox_to_anchor=(0.2, 0),
                    bbox_transform=plt.gcf().transFigure, ncol=len(lines), fontsize=10)
# Change box's frame color to black
frame = legend.get_frame()
frame.set_edgecolor('black')

Set number of decimal places for y-ticks

from matplotlib.ticker import FormatStrFormatter
axs[index].yaxis.set_major_formatter(FormatStrFormatter('%.1f'))

Set number of y-ticks

ymin, ymax = ax.get_ylim()
custom_ticks = np.linspace(ymin, ymax, 5, dtype=float)
ax.set_yticks(custom_ticks)
ax.set_yticklabels(custom_ticks)

# Set one decimal place for y-axis
ax.yaxis.set_major_formatter(FormatStrFormatter('%.1f'))

# Save individual figures
plt.tight_layout()

Insert text into plot (e.g., significance symbol)

axs[index].text(x_positon, y_position, '*', fontsize=25, ha='center')

Remove left vertical line for all subplots

axs[index].spines['left'].set_visible(False)

Modify spacing between individual subplots

plt.subplots_adjust(wspace=0, hspace=0.2)
# Move subplots closer to each other
plt.subplots_adjust(wspace=-0.5)
plt.tight_layout()

Save figure

# list of extension which figure will be saved in
figure_extension = ['.png', '.pdf']
for ext in figure_extension:
    fname_figure = 'figure_name' + ext
    plt.savefig(fname_figure)
    print('Figure {} created in {}'.format(fname_figure, os.path.abspath(os.path.curdir)))

Pass properties which are not supported by seaborn to matplotlib

# Pass alpha through kwargs to matplotlib
ax = sns.boxplot(x='day', y='tip', data=tips, boxprops=dict(alpha=.3))
# https://github.com/mwaskom/seaborn/issues/979#issuecomment-235082271

Change seaborn violion plot transparency

for violin, alpha in zip(ax.collections[::2], len(ax.collections[::2]) * [0.8]):
    violin.set_alpha(alpha)

Remove figure spines (borders)

ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['top'].set_visible(False)

Make longer subplot tick marks

from matplotlib import pyplot as plt
plt.rcParams["figure.figsize"] = [7.00, 3.50]
plt.rcParams["figure.autolayout"] = True
ax1 = plt.subplot()
ax1.plot(range(2), range(2), linewidth=2)
ax1.minorticks_on()
ax1.tick_params('both', length=20, width=2, which='major')
ax1.tick_params('both', length=10, width=1, which='minor')
plt.show()

Expand numpy ndarray dimension

# Create 1D vector
X = np.random.random(size=20)
X.shape
(20,)
# NOTE - all three method are equivalent
# X.reshape(-1, 1)
# np.expand_dims(X, axis=1)
# X[:, np.newaxis]
(20, 1)

Get colors for given colormap

from matplotlib.cm import get_cmap
get_cmap('Set1').colors[:4]

zorder - order of figure's artists

https://matplotlib.org/3.1.1/gallery/misc/zorder_demo.html

Show median in RainCloudPlot

box_medianprops={"zorder": 11}

Source

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment