| import gradio as gr |
| import numpy as np |
| import matplotlib.pyplot as plt |
| from matplotlib.patches import Circle |
|
|
| |
| def calculate_gravity_anomalies(mountain_height, subsurface_density, subsurface_position): |
| """ |
| 根據地形和地下異常體,計算並繪製重力異常曲線。 |
| (All plot labels are in English to prevent font issues on cloud platforms.) |
| """ |
| |
| x = np.linspace(-50, 50, 500) |
| |
| |
| mountain_width = 15 |
| topography = mountain_height * np.exp(-(x**2) / (2 * mountain_width**2)) |
| |
| topography[topography < 0.01] = 0 |
|
|
| |
| |
| body_width = 8 |
| |
| bouguer_anomaly = subsurface_density * np.exp(-((x - subsurface_position)**2) / (2 * body_width**2)) |
| |
| |
| |
| bouguer_correction = 0.112 * topography |
| |
| |
| |
| |
| free_air_anomaly = bouguer_anomaly + bouguer_correction |
|
|
| |
| fig, ax1 = plt.subplots(figsize=(12, 8)) |
| |
| |
| ax1.set_xlabel('Profile Position (km)', fontsize=14) |
| ax1.set_ylabel('Gravity Anomaly (mGal)', color='tab:red', fontsize=14) |
| ax1.tick_params(axis='y', labelcolor='tab:red') |
| ax1.grid(True, linestyle='--', alpha=0.6) |
| |
| |
| ax1.plot(x, free_air_anomaly, 'b--', label='Free-air Anomaly ($\Delta g_{fa}$)', linewidth=2) |
| ax1.plot(x, bouguer_anomaly, 'r-', label='Bouguer Anomaly ($\Delta g_{B}$)', linewidth=3, alpha=0.9) |
| ax1.legend(loc='upper left', fontsize=12) |
| ax1.set_ylim(-35, 85) |
|
|
| |
| ax2 = ax1.twinx() |
| ax2.set_ylabel('Elevation / Depth (m)', color='tab:green', fontsize=14) |
| ax2.tick_params(axis='y', labelcolor='tab:green') |
|
|
| |
| ax2.fill_between(x, 0, topography, color='saddlebrown', alpha=0.4, label='Topography') |
| |
| |
| subsurface_depth = -200 |
| body_color = 'darkred' if subsurface_density >= 0 else 'darkblue' |
| body_alpha = min(1.0, 0.2 + abs(subsurface_density)/50.0) |
| circle = Circle((subsurface_position, subsurface_depth), radius=body_width*0.8, color=body_color, alpha=body_alpha) |
| ax2.add_patch(circle) |
| ax2.set_ylim(-500, 1500) |
|
|
| fig.suptitle('Interactive Bouguer Anomaly Lab', fontsize=20, weight='bold') |
| plt.tight_layout(rect=[0, 0.03, 1, 0.95]) |
|
|
| |
| plt.close(fig) |
| |
| return fig |
|
|
| |
| with gr.Blocks(theme=gr.themes.Soft()) as demo: |
| gr.Markdown( |
| """ |
| # ⛰️ 布格異常互動實驗室 ⛏️ |
| 歡迎來到重力探勘互動實驗室!在這裡,你可以親手操作變數,理解地球物理學家如何「看透」地表。 |
| |
| ### 操作指南: |
| 1. **調整「山脈高度」滑桿:** 觀察藍色虛線 (Free-air Anomaly) 如何緊緊跟隨地形變化。 |
| 2. **調整「地下異常體密度」與「位置」:** 觀察紅色實線 (Bouguer Anomaly) 如何只反映地下物質的變化,幾乎不受地表高山的影響。 |
| |
| **核心思想:** 布格校正的目的,就是從充滿地形雜訊的「自由空間重力異常」中,減去地形的影響,得到能真正反映地下密度的「布格異常」。 |
| """ |
| ) |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| mountain_slider = gr.Slider(minimum=0, maximum=500, value=300, step=10, label="山脈高度 (公尺, h)") |
| density_slider = gr.Slider(minimum=-30, maximum=50, value=30, step=2, label="地下異常體密度 (mGal, 代表質量異常)") |
| position_slider = gr.Slider(minimum=-30, maximum=30, value=10, step=1, label="地下異常體水平位置 (km)") |
| |
| with gr.Column(scale=3): |
| output_plot = gr.Plot() |
| |
| |
| inputs = [mountain_slider, density_slider, position_slider] |
| for slider in inputs: |
| slider.change(fn=calculate_gravity_anomalies, inputs=inputs, outputs=output_plot) |
| |
| |
| demo.load(fn=calculate_gravity_anomalies, inputs=inputs, outputs=output_plot) |
|
|
| |
| demo.launch() |
|
|
|
|