File size: 5,265 Bytes
0ef56b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a7325a
0ef56b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a7325a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0ef56b6
 
 
 
 
4a7325a
0ef56b6
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import plotly.graph_objects as go
import pandas as pd
import numpy as np

# 生成符合学术规范的模拟数据
np.random.seed(42)  # 确保可重复性
methods = ['RSM', 'PSRN', 'NGGP', 'PySR', 'BMS', 'uDSR', 'AIF', 
          'DGSR', 'E2E', 'SymINDy', 'physo', 'TPSR', 'SPL', 
          'DEAP', 'SINDy', 'NSRS', 'gplearn', 'SNIP', 'KAN', 'EQL']

# 生成0-1之间的RMSE数据(保持原图分布模式)
rmse_values = np.clip(np.abs(np.random.normal(0.3, 0.15, len(methods))), 0.05, 0.95)
uncertainty = np.random.uniform(0.02, 0.08, len(methods))
param_sizes = np.array([1e3, 1e4, 5e4, 1e5, 5e5, 1e6, 2e6])  # 定义标准参数规模

# 构建分类系统(基于方法原理)
method_categories = {
    'Symbolic': ['RSM', 'PySR', 'SymINDy', 'gplearn', 'EQL'],
    'Neural': ['NGGP', 'DGSR', 'E2E', 'KAN'],
    'Evolutionary': ['PSRN', 'DEAP', 'NSRS'],
    'Physics-based': ['physo', 'TPSR', 'SPL'],
    'Hybrid': ['BMS', 'uDSR', 'AIF', 'SINDy', 'SNIP']
}

# 创建数据框架
df = pd.DataFrame({
    'Method': methods,
    'RMSE': rmse_values,
    'Uncertainty': uncertainty,
    'ParamSize': np.random.choice(param_sizes, len(methods))
}).sort_values('RMSE', ascending=True)

# 添加分类信息
df['Category'] = df['Method'].apply(lambda x: next((k for k,v in method_categories.items() if x in v), 'Other'))

# 颜色映射系统(学术级调色板)
category_colors = {
    'Symbolic': '#1f77b4',
    'Neural': '#ff7f0e',
    'Evolutionary': '#2ca02c',
    'Physics-based': '#d62728',
    'Hybrid': '#9467bd'
}

# 创建基础图表
fig = go.Figure()

# 动态尺寸计算系统
size_min = np.log(df['ParamSize'].min())
size_max = np.log(df['ParamSize'].max())
sizes = 15 + 25 * (np.log(df['ParamSize']) - size_min) / (size_max - size_min)  # 动态尺寸范围

# 添加主数据轨迹
for category in df['Category'].unique():
    df_sub = df[df['Category'] == category]
    fig.add_trace(go.Scatter(
        x=df_sub['RMSE'],
        y=df_sub['Method'],
        mode='markers',
        name=category,
        marker=dict(
            size=sizes[df_sub.index],
            color=category_colors[category],
            opacity=0.9,
            line=dict(width=1, color='black')
        ),
        error_x=dict(
            type='data',
            array=df_sub['Uncertainty'],
            color='rgba(40,40,40,0.6)',
            thickness=1.2,
            width=10
        ),
        hoverinfo='text',
        hovertext=df_sub.apply(lambda r: f"{r['Method']}<br>RMSE: {r['RMSE']:.3f} ± {r['Uncertainty']:.3f}<br>Params: {r['ParamSize']:,.0f}", axis=1)
    ))

# 动态轴范围计算
data_min = (df['RMSE'] - df['Uncertainty']).min()
x_min = max(data_min - 0.05, 0)  # 保证最小值不低于0
x_max = min(df['RMSE'].max() + df['Uncertainty'].max(), 1)  # 保证最大值不超过1

# 专业级布局配置
fig.update_layout(
    title='Methods RMSE Comparison with Parameter Scale',
    xaxis=dict(
        title='Root Mean Square Error (RMSE) → Lower is better',
        range=[x_min, x_max],
        tickvals=np.arange(0, 1.1, 0.1),
        gridcolor='#F0F0F0',
        zeroline=False,
        showspikes=True
    ),
    yaxis=dict(
        categoryorder='array',
        categoryarray=df['Method'].tolist(),
        tickfont=dict(size=12),
        showticklabels=False  # 禁用默认标签
    ),
    plot_bgcolor='white',
    width=1100,
    height=700,
    margin=dict(l=180, r=50, t=80, b=40),
    legend=dict(
        title='Method Categories',
        orientation='v',
        yanchor="top",
        y=0.98,
        xanchor="left",
        x=1.02
    )
)

# 添加自定义y轴标签(分类着色)
y_positions = np.linspace(0.03, 0.97, len(methods))  # 动态计算标签位置
for idx, method in enumerate(df['Method']):
    category = df[df['Method'] == method]['Category'].values[0]
    fig.add_annotation(
        x=0.01,
        y=y_positions[idx],
        xref='paper',
        yref='paper',
        text=method,
        showarrow=False,
        font=dict(
            size=12,
            color=category_colors[category]
        ),
        xanchor='right'
    )

# 添加专业级尺寸图例系统
# size_legend_values = [1e3, 1e4, 1e5, 1e6]  # 定义标准参数规模
# size_legend_sizes = 15 + 25 * (np.log(size_legend_values) - size_min) / (size_max - size_min)

# fig.add_trace(go.Scatter(
#     x=[0.52, 0.55, 0.58, 0.61],
#     y=np.array([0.00, 0.05, 0.10, 0.15]),
#     mode='markers',
#     marker=dict(
#         size=size_legend_sizes,
#         color='#444444',
#         opacity=0.8
#     ),
#     showlegend=False,
#     text=[f'{size:.2e}' for size in size_legend_values],
# ))

# # 添加尺寸图例标注
# size_labels = ['1K', '10K', '100K', '1M']
# for i, (x, y, label) in enumerate(zip([0.95]*4, [0.15,0.20,0.25,0.30], size_labels)):
#     fig.add_annotation(
#         x=x,
#         y=y,
#         xref="paper",
#         yref="paper",
#         text=label,
#         showarrow=False,
#         font=dict(size=10),
#         xanchor='left'
#     )

# | Parameters (log scale)

# 添加最终标注
fig.add_annotation(
    x=0.98, y=0.02,
    xref='paper', yref='paper',
    text='叶璨铭绘制',
    showarrow=False,
    font=dict(size=10, color='#666666'),
    bgcolor='white'
)

fig.show()