I'm currently using matplotlib to plot a measurement against 2 or 3 other measurements (sometimes categorical) on the x-axis. Currently, I am grouping the data on the x-axis into tuples and sorting them before plotting... the result looks something like the left image below. What I would like to do is to plot the data with multiple x-axes as you see in the right image. The grouping of the "treatment" x-axis labels would be icing on the cake.
Create multiple y axes with a shared x axis. This is done by creating a twinx axes, turning all spines but the right one invisible and offset its position using set_position . Note that this approach uses matplotlib.
We will use the add_axes() method of matplotlib module to add multiple axes to a figure.
In Matplotlib, we can draw multiple graphs in a single plot in two ways. One is by using subplot() function and other by superimposition of second graph on the first i.e, all graphs will appear on the same plot.
First off, cool question! It's definitely possible with matplotlib >= 1.0.0. (The new spines functionality allows it)
It requires a fair bit of voodoo, though... My example is far from perfect, but hopefully it makes some sense:
import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl def main(): #-- Generate some data ---------------------------------------------------- nx = 10 x = np.linspace(0, 2*np.pi, 10) y = 2 * np.sin(x) groups = [('GroupA', (x[0], x[nx//3])), ('GroupB', (x[-2*nx//3], x[2*nx//3])), ('GroupC', (x[-nx//3], x[-1]))] #-- Plot the results ------------------------------------------------------ fig = plt.figure() ax = fig.add_subplot(111) # Give ourselves a bit more room at the bottom plt.subplots_adjust(bottom=0.2) ax.plot(x,y, 'k^') # Drop the bottom spine by 40 pts ax.spines['bottom'].set_position(('outward', 40)) # Make a second bottom spine in the position of the original bottom spine make_second_bottom_spine(label='Treatment') # Annotate the groups for name, xspan in groups: annotate_group(name, xspan) plt.xlabel('Dose') plt.ylabel('Response') plt.title('Experimental Data') plt.show() def annotate_group(name, xspan, ax=None): """Annotates a span of the x-axis""" def annotate(ax, name, left, right, y, pad): arrow = ax.annotate(name, xy=(left, y), xycoords='data', xytext=(right, y-pad), textcoords='data', annotation_clip=False, verticalalignment='top', horizontalalignment='center', linespacing=2.0, arrowprops=dict(arrowstyle='-', shrinkA=0, shrinkB=0, connectionstyle='angle,angleB=90,angleA=0,rad=5') ) return arrow if ax is None: ax = plt.gca() ymin = ax.get_ylim()[0] ypad = 0.01 * np.ptp(ax.get_ylim()) xcenter = np.mean(xspan) left_arrow = annotate(ax, name, xspan[0], xcenter, ymin, ypad) right_arrow = annotate(ax, name, xspan[1], xcenter, ymin, ypad) return left_arrow, right_arrow def make_second_bottom_spine(ax=None, label=None, offset=0, labeloffset=20): """Makes a second bottom spine""" if ax is None: ax = plt.gca() second_bottom = mpl.spines.Spine(ax, 'bottom', ax.spines['bottom']._path) second_bottom.set_position(('outward', offset)) ax.spines['second_bottom'] = second_bottom if label is not None: # Make a new xlabel ax.annotate(label, xy=(0.5, 0), xycoords='axes fraction', xytext=(0, -labeloffset), textcoords='offset points', verticalalignment='top', horizontalalignment='center') if __name__ == '__main__': main()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With