Is there a way that I can set two different scales at the x-axis in a python plot?
I have following code:
import numpy as np
from matplotlib import pyplot as plt
import pandas as pd
data=pd.read_csv(file, names=['Wavenumber', 'Intensity'])
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(data['Wavenumber'], data['Intensity'])
ax.invert_xaxis()
ax.set_xticks([4000,3000,2000,1600,1200,800,400])
plt.show()
This gives:
But I would like to have equal spacing between the ticks, so a linear scaling from 4000 to 2000 in steps of 1000, and then again linear scaling from 2000 to 400 in steps of 400. This should look like this:
Creating a custom scale in matplotlib can be quite an effort. As you only need two different linear scales, it is easier to use a workaround consisting of joining two subplots together. With many data points located near the boundary between the two scales (as in your case), the jump from one to the other will not cause any irregular space between the ticks around the boundary if you were to show many tick marks (contrary to here). All you need is to find the data point closest to the boundary to seamlessly connect both subplots, as illustrated in the following example:
import numpy as np # v 1.19.2
import pandas as pd # v 1.1.3
import matplotlib.pyplot as plt # v 3.3.2
# Create sample dataset
rng = np.random.default_rng(seed=1)
x = np.linspace(4000, 400, num=50)
y = 1 - rng.exponential(scale=0.1, size=x.size)
df = pd.DataFrame(dict(Wavenumber=x, Intensity=y))
# Select data for each subplot by using a boundary point
x_boundary = min(df['Wavenumber'], key=lambda x: abs(x-2000))
df1 = df[df['Wavenumber'] >= x_boundary]
df2 = df[df['Wavenumber'] <= x_boundary]
# Select x-axis ticks for each subplot
ticks = np.array([4000, 3000, 2000, 1600, 1200, 800, 400])
tk1 = ticks[ticks >= x_boundary]
tk2 = ticks[ticks <= x_boundary]
# Create figure with 2 Axes side-by-side with no space in between
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5), sharey=True,
gridspec_kw=dict(wspace=0))
# Loop through both Axes to plot data, adjust x-axis limits and remove boundary spines
for ax, data, spine, tk in zip((ax1, ax2), (df1, df2), ('right','left'), (tk1, tk2)):
data.plot(x='Wavenumber', xlabel='', ax=ax, legend=None)
ax.set_xlim(data['Wavenumber'].iloc[[0,-1]])
ax.spines[spine].set_visible(False)
ax.set_xticks(tk)
# Additional formatting
ax2.tick_params(axis='y', length=0)
ax1.set_xlabel('Wavenumber', x=1, labelpad=10, size=12)
ax1.set_ylabel('Intensity', labelpad=10, size=12)
fig.suptitle('Plot with two linear x-axis scales joined together', size=16, y=0.95);