Search code examples
pythonmatplotlibinsets

Matplotlib change style of inset elements singularly


I am trying to plot some data on which I would like to make an inset to show some details. It is quite easy to create the inset and set the characteristics of the plot inside the inset.

What I have found cumbersome is how to set the properties of the inset itself, in particular the color and thickness of the inset frame, of the small box indicating where the plot is sampled and the lines to connect the small box to the inset. What I would need is to change them singularly. I know it is possible to change the properties of the mark_inset as a single piece, but not as separated parts.

Let's say, as example, the inset frame should be thinner and dashed, the sampling box thicker and red and the connecting lines dotted and of the same color as in the MWE.

Here is the MWE:

import scipy as sc
import matplotlib.pyplot as plt
from cycler import cycler
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
plt.close('all')

color = plt.get_cmap('viridis')(sc.linspace(0, 1, 4)[1:3])
params_IEEEtran = {'legend.fontsize': 10,
                   'axes.labelsize': 10,
                   'axes.titlesize': 10,
                   'xtick.labelsize': 9,
                   'ytick.labelsize': 9,
                   'mathtext.fontset': 'stix',
                   'font.family': 'Times New Roman',
                   'mathtext.rm': 'serif',
                   'mathtext.bf': 'serif:bold',
                   'mathtext.it': 'serif:italic',
                   'mathtext.sf': 'sans\\-serif',
                   'grid.color': 'k',
                   'grid.linestyle': ':',
                   'grid.linewidth': 0.5,
                   'axes.xmargin': 0,
                   'axes.axisbelow': False,
                   'lines.linewidth': 1.0,
                   'legend.frameon': False,
                   'axes.prop_cycle': cycler('color', plt.get_cmap('viridis')(
                           sc.linspace(0, 1, 4))),
                   'figure.figsize': [3, 2.4],
                   }
plt.rcParams.update(params_IEEEtran)

x = sc.linspace(0.1, 100)
y1 = sc.array(sc.sqrt(x)).T
y2 = sc.array(1/sc.sqrt(x)).T

fig = plt.figure('FIG')
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y1)

ax_twinx = ax.twinx()
ax_twinx.plot(x, y2)

ax.set_xlim(0, 100)
ax.set_ylim(0, 10)
ax_twinx.set_ylim(0, 1)

inset = fig.add_axes([0.6, 0.3, 0.12, 0.35], frameon=False)
inset.axes.get_xaxis().set_visible(False)
inset.axes.get_yaxis().set_visible(False)

inset.plot(x, y1)

inset_twinx = inset.twinx()
inset_twinx.axes.get_yaxis().set_visible(False)

inset_twinx.plot(x, y2)

inset.set_xlim(5, 15)
inset.set_ylim(2, 4)
inset_twinx.set_ylim(0.2, 0.4)

mark_inset(ax, inset, loc1=4, loc2=2, lw=0.3,
           fc="none", ec=color[0], zorder=200)
fig.savefig('./example.png', bbox_inches='tight', dpi=300)

And here result:

enter image description here


Solution

  • Changing the properties of the individual objects is usually not a big problem.

    • the inset frame should be thinner and dashed,

      plt.setp(inset_twinx.spines.values(), linewidth=0.5, linestyle="--") #python 2
      

      or

      plt.setp(list(inset_twinx.spines.values()), linewidth=0.5, linestyle="--") #python3
      

      or

      for d in ["left", "right", "top", "bottom"]:
          inset_twinx.spines[d].set_linewidth(0.5)
          inset_twinx.spines[d].set_linestyle("--")
      

    To change the inset connector and box, we need a handle to those objects first,

    box, c1, c2 = mark_inset(ax, inset, loc1=4, loc2=2, lw=0.3,
               fc="none", ec=color[0], zorder=200)
    
    • the sampling box thicker and red

      plt.setp(box, linewidth=3, color="red")
      

      or

      box.set_linewidth(3)
      box.set_color("red")
      
    • the connecting lines dotted and of the same color as in the MWE.

      plt.setp([c1,c2], linestyle=":")
      

      or

      for c in [c1,c2]:
          c.set_linestyle(":") 
      

    Result:
    enter image description here