I have a dictionary, where each entry represents a pandas dataframe. The dictionary has 100 entrys.
The dataframes represent Absorption measurements over a given distance along the X-axis, keeping the Y-axis position fixed. Each dataframe corresponds to a different Y position. Those steps between the Y positions are fixed (100µm).
I want to plot those DataFrames next to each other, in a single plot, considering also the Y-axis. Therefore creating a 3D plot.
Up until now, I only can plot all the DataFrames in one single 2D plot.
The picture attached shows the idea.
See the code example below, which includes some test data.
The code assumes there's a common x-axis across all Absorption
entries. If each absorption list is recorded over different x, then an additional interpolation step would need to be added to map all the data onto a common axis.
import pandas as pd
import numpy as np
from mpl_toolkits import mplot3d
from matplotlib import pyplot as plt
#Synthesise data
# data_dict contains 100 dataframes, indexed data_dict[0] to data_dict[99].
# Each dataframe has 2 columns: Absorption, and the x values at which the measurement was made
np.random.seed(0)
num_x_points = 200
x_axis = np.linspace(0, 2*np.pi / 2, num_x_points)
data_dict = {}
for i in range(100):
abs_data = (np.random.uniform(0.9, 1.1)
- np.cos(x_axis + np.random.uniform(0, i*np.pi/180))
) / (0.1*i + 10)
data_dict[i] = pd.DataFrame({
'Absorption': abs_data,
'x_axis': x_axis
})
#Determine number of y points
num_y = len(data_dict)
#Create y axis (in um)
y_step = 100e-6
y_axis = 1e6 * np.linspace(0, num_y * y_step, num_y)
#Compile absorption lines into a single matrix
abs_lines = np.empty((num_y, len(x_axis)))
for y_idx, df in enumerate(data_dict.values()):
abs_lines[y_idx, :] = df.Absorption.to_numpy()
#Create a meshgrid for plotting in 3D
grid_x, grid_y = np.meshgrid(x_axis, y_axis)
#You can view the data either as lines with solid colours,
# or as points coloured by absorption
view_as_scatter = True
#Make 3d figure
figsize = 8
ax = plt.figure(figsize=[figsize] * 2).add_subplot(projection='3d')
#adjust the viewing angles
ax.view_init(elev=20, azim=240, roll=0)
if view_as_scatter:
ax.scatter3D(grid_x, grid_y, abs_lines, c=abs_lines, marker='.', s=3, cmap='brg')
else:
for y_idx, df in enumerate(data_dict.values()):
ax.plot3D(grid_x[y_idx, :], grid_y[y_idx, :], df.Absorption)
ax.set_xlabel('x')
ax.set_ylabel('y (um)')
ax.set_zlabel('absorption')