0

I have three arrays: time, steps and volume. I want to plot how the volume (Y-axis) changes over time (X-axis) and demonstrate how the time correlates with steps (2nd X-axis).

time = np.array([1.280000e-07, 1.322240e-07, 1.364480e-07, 1.288448e-06,
       1.288448e-06, 1.288448e-06, 1.292672e-06, 1.292672e-06,
       1.420672e-06, 1.424896e-06, 1.429120e-06, 2.581120e-06,
       2.581120e-06, 2.581120e-06, 2.585344e-06, 2.585344e-06,
       2.586400e-06, 2.587456e-06, 2.603456e-06])

steps = np.arange(1,20)

volume = np.array([256., 384., 512., 512., 384., 256., 128.,   0., 256., 384., 512.,
   512., 384., 256., 128.,   0.,  32.,  64.,  96.])

Time values from time are linked to the corresponding steps values, such as step[1] happens at time[1], step[2] at time[2] and etc.

I tried twiny() but it seems to work only if the scale is the same between the two axes. In the plot below both axes have uniform intervals between values and are evenly distributed.

fig, ax1 = plt.subplots(1, 1, figsize=(10, 4.5), dpi=160, facecolor='w', edgecolor='k', sharey=True)
ax1.plot(t,volume)
ax2 = ax1.twiny()
ax2.set_xticks(steps)

enter image description here

How do I scale the steps axis in correspondence with time axis?

user40
  • 1,361
  • 5
  • 19
  • 34

1 Answers1

2

A twin ax is a new ax placed at the same position as the original, but setting its ticks at the other side. Default, there isn't a relation between the original ticks and the new ticks, though such a relation could be implied by carefully setting the axis limits.

On the contrary, a secondary ax sets a fixed relationship between the ticks. If no relation is explicitly set, it will be the identity relation.

To get the result you want, you can set such a secondary axis, and put the steps as labels, using the time for positioning.

That would look like:

import numpy as np
import matplotlib.pyplot as plt

time = np.array([1.28e-07, 1.32224e-07, 1.36448e-07, 1.288448e-06, 1.288448e-06, 1.288448e-06, 1.292672e-06, 1.292672e-06, 1.420672e-06, 1.424896e-06, 1.42912e-06, 2.58112e-06, 2.58112e-06, 2.58112e-06, 2.585344e-06, 2.585344e-06, 2.5864e-06, 2.587456e-06, 2.603456e-06])
steps = np.arange(1, 20)
volume = np.array([256., 384., 512., 512., 384., 256., 128., 0., 256., 384., 512., 512., 384., 256., 128., 0., 32., 64., 96.])

fig, ax1 = plt.subplots(1, 1, figsize=(10, 4.5),  facecolor='w', edgecolor='k')
ax1.plot(time, volume)
secax = ax1.secondary_xaxis('top')
secax.set_xticks(time)
secax.set_xticklabels(steps)
plt.show()

secondary axis using the steps as labels

As many time positions are either identical or close together, the resulting labels overlap. A solution could be to grab together these overlapping label and create a label range:

pos = []
labels = []
start_step = steps[0]
for prev_t, t, prev_step, step in zip(time,
                                      np.append(time[1:], np.inf),
                                      steps,
                                      np.append(steps[1:], 0)):
    if (t - prev_t) > prev_t / 20:
        pos += [prev_t]
        if start_step == prev_step:
            labels += [f'{start_step}']
        else:
            labels += [f'{start_step}-{prev_step}']
        start_step = step
secax.set_xticks(pos)
secax.set_xticklabels(labels)

secondary axis with concatenated labels

JohanC
  • 71,591
  • 8
  • 33
  • 66