[PYTHON] (Matplotlib) Tips for adjusting the appearance of graphs [Axis / Picture frame / Scale / Scale character edition]

Overview

Tips for adjusting the appearance and fine adjustment of the graph generated by matplotlib (~ axis, picture frame, scale, scale character ~ edition).
2.png

We have confirmed the operation with matplotlib 3.2.2 and GoogleColab. (Python 3.6.9).

Preparation / common

Install the japanize-matplotlib library so that you can use ** Japanese ** in the graph. For Google Colab., You can install it by executing the following in the code cell.

japanize-Install matplotlib (Google Colab.)


!pip install japanize-matplotlib

Import various libraries.

Preparation / common code


import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.transforms as transforms
import matplotlib.patheffects as patheffects
import japanize_matplotlib
import numpy as np

As a basic form, let's output a graph that has not been adjusted in particular.

Basic


x = np.linspace(-6,6,21)
y = 1/(1+np.exp(-x))
fig,ax = plt.subplots(figsize=(4,3),facecolor='white',dpi=150)
ax.plot(x,y,marker='.')
plt.show()

It is OK if the following graph can be output.

1.png

TickLabel formatting

The format of the X-axis main scale is ** the format that displays up to the first decimal place , and the format of the Y-axis main scale is " 2.0 x 10 -1 " * Try setting it to "*".

Don't forget import matplotlib.ticker as ticker.

Tick ​​character formatting


x = np.linspace(-6,6,21)
y = 1/(1+np.exp(-x))
fig,ax = plt.subplots(figsize=(4,3),facecolor='white',dpi=150)
ax.plot(x,y,marker='.')

ax.xaxis.set_major_formatter(ticker.FuncFormatter(lambda x,_: f'{x:.1f}'))
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y,_: f'{y*10:.1f}'+ r'$\times 10^{-1}$'))

plt.show()

3.png

Adjusting the position of the scale character (TickLabel)

If you set the scale to "Inward" as described below, the X-axis and Y-axis scale characters may be too close together and unsightly. To solve this, try fine-tuning the character position on the X-axis main scale downward. Don't forget matplotlib.transforms as transforms.

Adjusting the position of scale characters


x = np.linspace(1000,1010,11)
y = (x-1000)*0.5

fig,axes = plt.subplots(1,2,figsize=(8,3),facecolor='white',dpi=150)
axes = axes.ravel()
for ax in axes:
  ax.plot(x,y,marker='.')
  ax.set_xlim(1000,1010)
  ax.set_ylim(0,5)
  ax.tick_params(direction='in')

#Right side (axes[1]) Only xticklabels position adjustment
mv = transforms.ScaledTranslation(0,-0.07,fig.dpi_scale_trans)
for label in axes[1].xaxis.get_majorticklabels() :
    label.set_transform(label.get_transform() + mv)

axes[1].text(0.95,0.075,'x_tick_labels with position adjustment',ha='right',c='tab:red',transform=ax.transAxes)
plt.show()

There was an easier way to get there.

Position adjustment of scale characters (updated version)


x = np.linspace(1000,1010,11)
y = (x-1000)*0.5

fig,axes = plt.subplots(1,2,figsize=(8,3),facecolor='white',dpi=150)
axes = axes.ravel()
for ax in axes:
  ax.plot(x,y,marker='.')
  ax.set_xlim(1000,1010)
  ax.set_ylim(0,5)
  ax.tick_params(direction='in')

#Right side (axes[1]) Only xticklabels position adjustment
ax = axes[1]
ax.get_xaxis().set_tick_params(pad=8)
ax.text(0.95,0.075,'x_tick_labels with position adjustment',ha='right',c='tab:red',transform=ax.transAxes)

plt.show()

4.png

Hide Axis / Picture Frame

If you use imshow (...) etc., you may not want to display the axis / picture frame. Try hiding the axis / picture frame.

Hide axis / picture frame


x = np.linspace(-6,6,21)
y = 1/(1+np.exp(-x))
fig,ax = plt.subplots(figsize=(4,3),facecolor='white',dpi=150)
ax.plot(x,y,marker='.')

for p in ['left','top','right','bottom']:
  ax.spines[p].set_visible(False)

ax.grid() #grid
plt.show()

5.png

Adjust the orientation and length of the tick

Try changing the orientation of the axis scale to "inside", "outside", and "both sides". Also, try adjusting the "length" of the scale. You can effectively hide the tick marks by setting the length to zero.

Adjust the orientation and length of the scale


x = np.linspace(-6,6,21)
y = 10/(1+np.exp(-x))-5
fig,axes = plt.subplots(2,2,figsize=(8,6),facecolor='white',dpi=150)
axes = axes.ravel()

for ax in axes :
  ax.plot(x,y,marker='.')

axes[0].tick_params(direction='in')
axes[0].text(0.1,0.9,"direction='in'",c='tab:red',va='top',transform=axes[0].transAxes)
axes[1].tick_params(direction='inout')
axes[1].text(0.1,0.9,"direction='inout'",c='tab:red',va='top',transform=axes[1].transAxes)
axes[2].tick_params(direction='inout',length=8)
axes[2].text(0.1,0.9,"direction='inout'\nlength=8",c='tab:red',va='top',transform=axes[2].transAxes)
axes[3].tick_params(length=0)
axes[3].text(0.1,0.9,"length=0",c='tab:red',va='top',transform=axes[3].transAxes)

plt.show()

6.png

Change the color only for a specific scale character (TickLabel)

You may want to change the color of only certain items in TickLabel to get the other person's attention. For now, let's just put Carol, the second element of xticklabels, in red.

Change the color only for a specific scale character (TickLabel)


x = ['Alice','Bob','Carol','Dave','Ellen']
y = [40,20,25,40,20]

fig,ax = plt.subplots(figsize=(4,3),facecolor='white',dpi=150)
bars = ax.bar(x,y)
bars[2].set_facecolor('tab:red') #Bonus: Bar also changed to red
#print(type(bars[2])) # <class 'matplotlib.patches.Rectangle'>

labels = ax.get_xticklabels()
labels[2].set_color('tab:red') #Change the second element to red
#print(type(labels[2])) # <class 'matplotlib.text.Text'>

plt.show()

8.png

Invert the Y-axis upside down

The Y-axis TickLabel is aligned from bottom to top by default. Let's flip it over and line it up from top to bottom.

Invert the Y-axis upside down


x = ['Alice','Bob','Carol','Dave','Ellen']
y = [40,20,25,40,20]

fig,axes = plt.subplots(1,2,figsize=(8,3),facecolor='white',dpi=150)
axes = axes.ravel()

for ax in axes:
  ax.barh(x,y)
  ax.tick_params(length=0)
  ax.grid(axis='x')
  ax.set_axisbelow(True)

axes[0].set_title('Default (bottom to top)')
axes[1].set_title('Invert (top to bottom)')

#Flip upside down in the figure on the right
ax = axes[1]
ax.invert_yaxis()
t = axes[1].text(0.95,0.05,'ax.invert_yaxis( )',c='tab:red',ha='right',transform=ax.transAxes)
t.set_path_effects([patheffects.Stroke(linewidth=3,foreground='white'),patheffects.Normal()])

plt.show()

11.png

Adjusted Y-axis scale label placement (right-aligned, left-aligned, center-aligned)

Adjusted Y-axis scale label placement (right-aligned, left-aligned, center-aligned)


x = ['A','BB','CCC']
y = [40,20,25]

fig,axes = plt.subplots(3,1,figsize=(4,4),facecolor='white',dpi=150)
axes = axes.ravel()

text=['Right justified(Default)','Left justified','Centered']
for i, ax in enumerate(axes):
  ax.barh(x,y)
  ax.invert_yaxis()
  ax.tick_params(length=0)
  ax.set_xticklabels([])
  t = ax.text(0.95,0.1,text[i],c='tab:red',ha='right',transform=ax.transAxes)
  t.set_path_effects([patheffects.Stroke(linewidth=3,foreground='white'),patheffects.Normal()])

#Left justified
ax = axes[1]
ax.set_yticklabels(x,ha ='left')
ax.get_yaxis().set_tick_params(pad=25)

#Centered
ax = axes[2]
ax.set_yticklabels(x,ha ='center')
ax.get_yaxis().set_tick_params(pad=17.5)

plt.show()

10.png

Set the X and Y axes to the zero position

Try changing to a graph style as described in math textbooks (the X-axis and Y-axis scale letters are in the "zero" position).

Set the X and Y axes to the zero position


x = np.linspace(-6,6,21)
y = 10/(1+np.exp(-x))-5  #Change

fig,ax = plt.subplots(figsize=(4,3),facecolor='white',dpi=150)
ax.plot(x,y,marker='.')

ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.tick_params(direction='inout')

plt.show()

7.png

In addition, make fine adjustments.

Set the X and Y axes to the zero position 2


x = np.linspace(-6,6,21)
y = 10/(1+np.exp(-x))-5  #Change

fig,ax = plt.subplots(figsize=(4,4),facecolor='white',dpi=150)
ax.plot(x,y,marker='.')

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

ax.set_xlim(6,-6)
ax.set_ylim(6,-6)

#Main scale: Notched intervals 2 and 0 are hidden, characters are bordered with white
ax.set_xticks(np.arange(-6,6+1,2))
labels = ax.set_xticklabels( [ ( x if x!=0 else '') for x in np.arange(-6,6+1,2)] )
for t in labels :
  t.set_path_effects([patheffects.Stroke(linewidth=3,foreground='white'),patheffects.Normal()])

ax.set_yticks(np.arange(-6,6+1,2))
labels = ax.set_yticklabels( [ ( y if y!=0 else '') for y in np.arange(-6,6+1,2)] )
for t in labels :
  t.set_path_effects([patheffects.Stroke(linewidth=3,foreground='white'),patheffects.Normal()])

ax.tick_params(which='major',direction='inout',length=5)

#Auxiliary scale (minor): Preparation for grid drawing with a step interval of 1
ax.set_xticks(np.linspace(-6,6,13),minor=True)
ax.set_yticks(np.linspace(-6,6,13),minor=True)
ax.tick_params(which='minor',direction='inout',length=3)

#Grid (which='both'And the grid at the major and minor scales)
ax.grid(which='both')

plt.show()

2.png

Relation

-(Matplotlib) I want to draw a graph with a size specified in pixels -I want to create a graph with wavy lines omitted in the middle with matplotlib (I want to manipulate the impression) -I want to output a beautifully customized heat map of the correlation matrix. matplotlib -(Visualization of correlation) Alternative when points overlap in scatter plot

Recommended Posts

(Matplotlib) Tips for adjusting the appearance of graphs [Axis / Picture frame / Scale / Scale character edition]
About the X-axis notation of Matplotlib bar graphs
Put the second axis in 2dhistgram of matplotlib
Code for checking the operation of Python Matplotlib
Omit the decimal point of the graph scale in matplotlib
(For those unfamiliar with Matplotlib) Tips for drawing graphs with Seaborn