Geologist
Geologist

Reputation: 9

Different sized Subplots with same scale in Python

I would like to plot some drilling data with python. As these are drilled at different levels above sea, I would like to align that all three subplots are aligned with the main plot Y-axis. I prepared a sketch how I imagined to look at at the end.

enter image description here

The issue I encounter right now is, that I can not generate different sized subplotboxes which are the same scale and the that they are not aligned with the Y-Axis zero.

If you have any suggestions or alternatives approaches, I really appreciate.

I hope my given Information are enough, as this is my first post here.

As I am just having mediatae experience in python, I have no issues in loading in data or generating plots in the past but this case is different. I asked colleagues and ChatGPT. I tried using matplotlib and GridSpec.

Upvotes: 0

Views: 80

Answers (2)

Noorvh
Noorvh

Reputation: 44

Online I found a solution with the insert_axes function. This however makes it very difficult to align the extra axes of the borehole boxes with the original y axis, and results in boxes all over the place. A simpler (though less elegant) solution would be to just draw rectangles manually on an x and y axis with a function.

Try running this code to see if it works:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as patches

# Simulated borehole data
depth1 = np.linspace(-50, 300, 100)
values1 = np.sin(np.linspace(0, 3, 100)) * 20  # You would need to alter this to be the proper function for the boreholes.

depth2 = np.linspace(-400, 200, 100)
values2 = np.sin(np.linspace(0, 2, 100)) * 20

depth3 = np.linspace(-250, 250, 100)
values3 = np.sin(np.linspace(0, 4, 100)) * 20

fig, ax = plt.subplots(figsize=(6, 8))

# Set main Y-axis (not sure what the limits should be here)
ax.set_ylim(-500, 400)
ax.set_xlim(-100, 120)
ax.set_yticks(np.arange(-500, 450, 100))
ax.set_xticks([])
ax.set_ylabel("Elevation (m)")

# Function to draw borehole boxes and data with depth labels. Will draw a borehole box based on the information you define above
def draw_borehole(ax, x_center, depth, values, label):
    top, bottom = depth[0], depth[-1]
    width = 40  # Box width

    # Draw borehole box
    rect = patches.Rectangle((x_center - width / 2, bottom), width, top - bottom,
                             linewidth=2, edgecolor='black', facecolor='none')
    ax.add_patch(rect)

    # Plot borehole data within the box
    ax.plot(x_center + values, depth, 'r')

    # Add borehole label
    ax.text(x_center, top + 10, label, ha='center', fontsize=10)

    # Add depth labels (top and bottom). They stick out a bit as of now, but you could fiddle around with the size and location of the borehole boxes to make them fit better
    ax.text(x_center + width / 2 + 5, top, f"{top:.0f} m", va='center', fontsize=8, color='black')
    ax.text(x_center + width / 2 + 5, bottom, f"{bottom:.0f} m", va='center', fontsize=8, color='black')

# Draw boreholes at different X positions, they have a width of 40 now, but you can alter all that.
draw_borehole(ax, -50, depth1, values1, "Borehole 1")
draw_borehole(ax, 10, depth2, values2, "Borehole 2")
draw_borehole(ax, 70, depth3, values3, "Borehole 3")

plt.show()

This should give you a plot like this: this.

Let me know if this works for you.

Upvotes: -1

RuthC
RuthC

Reputation: 3896

I would use inset_axes. Note the use of the transform keyword: setting this to transData means the inset axes get placed in data coordinates rather than the default axes fraction.

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

ax.set_ylim(-500, 300)
ax.set_xlim(0.4, 4)

# Only show the left-hand y-axis
ax.xaxis.set_visible(False)
ax.spines.right.set_visible(False)
ax.spines.bottom.set_visible(False)
ax.spines.top.set_visible(False)

borehole_tops = [300, 200, 250]
borehole_bottoms = [-50, -400, -250]

for i, (bottom, top) in enumerate(zip(borehole_bottoms, borehole_tops), 1):
    ax_ins = ax.inset_axes([i, bottom, 0.6, top - bottom], transform=ax.transData)
    ax_ins.set_ylim(bottom, top)
    ax_ins.set_title(f'Borehole {i}')
    ax_ins.plot([0, 1], [bottom, top], color='red')
    
plt.show()

enter image description here

Upvotes: 1

Related Questions