paperplotter 0.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/Data_Analysis_Utils/data_analysis_utils_example.png +0 -0
- examples/Data_Analysis_Utils/data_analysis_utils_example.py +81 -0
- examples/Data_Analysis_Utils/utility_functions_example.png +0 -0
- examples/Data_Analysis_Utils/utility_functions_example.py +82 -0
- examples/Domain_Specific_Plots/bifurcation_diagram_example.png +0 -0
- examples/Domain_Specific_Plots/bifurcation_diagram_example.py +70 -0
- examples/Domain_Specific_Plots/concentration_map_example.png +0 -0
- examples/Domain_Specific_Plots/concentration_map_example.py +54 -0
- examples/Domain_Specific_Plots/domain_specific_plots.png +0 -0
- examples/Domain_Specific_Plots/domain_specific_plots_example.py +104 -0
- examples/Domain_Specific_Plots/learning_curve_example.png +0 -0
- examples/Domain_Specific_Plots/learning_curve_example.py +86 -0
- examples/Domain_Specific_Plots/phasor_diagram_example.png +0 -0
- examples/Domain_Specific_Plots/phasor_diagram_example.py +49 -0
- examples/Domain_Specific_Plots/power_timeseries_example.png +0 -0
- examples/Domain_Specific_Plots/power_timeseries_example.py +65 -0
- examples/Features_Customization/advanced_customization.py +70 -0
- examples/Features_Customization/advanced_customization_figure.png +0 -0
- examples/Features_Customization/cleanup_demonstration.py +62 -0
- examples/Features_Customization/cleanup_demonstration_figure.png +0 -0
- examples/Features_Customization/composite_figure.png +0 -0
- examples/Features_Customization/composite_figure_example.py +88 -0
- examples/Features_Customization/error_handling_test.py +75 -0
- examples/Features_Customization/feature_expansion_example.py +84 -0
- examples/Features_Customization/feature_expansion_figure.png +0 -0
- examples/Features_Customization/fig_annotation_example.png +0 -0
- examples/Features_Customization/fig_annotation_example.py +72 -0
- examples/Features_Customization/fig_text_example.png +0 -0
- examples/Features_Customization/fig_text_example.py +51 -0
- examples/Features_Customization/global_controls_example.py +66 -0
- examples/Features_Customization/global_controls_figure.png +0 -0
- examples/Features_Customization/heatmap_colorbar_example.py +68 -0
- examples/Features_Customization/heatmap_default_figure.png +0 -0
- examples/Features_Customization/heatmap_shared_colorbar_figure.png +0 -0
- examples/Features_Customization/highlighting_example.png +0 -0
- examples/Features_Customization/highlighting_example.py +62 -0
- examples/Features_Customization/multi_plot_grid.py +91 -0
- examples/Features_Customization/multi_plot_grid_figure.png +0 -0
- examples/Features_Customization/resources/placeholder_image.png +0 -0
- examples/Layout/advanced_layout_example.py +70 -0
- examples/Layout/advanced_layout_figure.png +0 -0
- examples/Layout/aspect_ratio_example.py +72 -0
- examples/Layout/aspect_ratio_mosaic.png +0 -0
- examples/Layout/aspect_ratio_simple_grid.png +0 -0
- examples/Layout/block_span_example.py +64 -0
- examples/Layout/block_span_figure.png +0 -0
- examples/Layout/declarative_nested_layout.png +0 -0
- examples/Layout/declarative_nested_layout_example.py +91 -0
- examples/Layout/row_span_example.py +68 -0
- examples/Layout/row_span_figure.png +0 -0
- examples/Styles_Aesthetics/aesthetic_and_processing_example.png +0 -0
- examples/Styles_Aesthetics/aesthetic_and_processing_example.py +85 -0
- examples/Styles_Aesthetics/statistical_annotation_example.png +0 -0
- examples/Styles_Aesthetics/statistical_annotation_example.py +65 -0
- examples/Styles_Aesthetics/style_gallery_example.py +64 -0
- examples/Styles_Aesthetics/style_gallery_flat.png +0 -0
- examples/Styles_Aesthetics/style_gallery_nord.png +0 -0
- examples/Styles_Aesthetics/style_gallery_presentation.png +0 -0
- examples/Styles_Aesthetics/style_gallery_publication.png +0 -0
- examples/Styles_Aesthetics/style_gallery_solarized_light.png +0 -0
- paperplot/__init__.py +30 -0
- paperplot/core.py +254 -0
- paperplot/exceptions.py +35 -0
- paperplot/mixins/__init__.py +1 -0
- paperplot/mixins/domain.py +331 -0
- paperplot/mixins/generic.py +95 -0
- paperplot/mixins/modifiers.py +504 -0
- paperplot/styles/flat.mplstyle +40 -0
- paperplot/styles/nord.mplstyle +44 -0
- paperplot/styles/presentation.mplstyle +41 -0
- paperplot/styles/publication.mplstyle +24 -0
- paperplot/styles/solarized_light.mplstyle +44 -0
- paperplot/utils.py +510 -0
- paperplotter-0.1.4.dist-info/METADATA +163 -0
- paperplotter-0.1.4.dist-info/RECORD +78 -0
- paperplotter-0.1.4.dist-info/WHEEL +5 -0
- paperplotter-0.1.4.dist-info/licenses/LICENSE +21 -0
- paperplotter-0.1.4.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# examples/cleanup_demonstration.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
from paperplot import Plotter
|
|
9
|
+
|
|
10
|
+
print(f"--- Running Example: {__file__} ---")
|
|
11
|
+
|
|
12
|
+
# --- 1. 准备一组适合共享坐标轴的数据 ---
|
|
13
|
+
# 假设我们有4个实验条件,每个条件下都有一条相似的时间序列数据
|
|
14
|
+
def generate_data(offset):
|
|
15
|
+
time = np.linspace(0, 10, 50)
|
|
16
|
+
signal = np.sin(time) + np.random.randn(50) * 0.3 + offset
|
|
17
|
+
return pd.DataFrame({'time': time, 'signal': signal})
|
|
18
|
+
|
|
19
|
+
df1 = generate_data(offset=0)
|
|
20
|
+
df2 = generate_data(offset=0.5)
|
|
21
|
+
df3 = generate_data(offset=-0.5)
|
|
22
|
+
df4 = generate_data(offset=1)
|
|
23
|
+
|
|
24
|
+
# --- 2. 初始化一个 2x2 的独立坐标轴画布 ---
|
|
25
|
+
# 注意:这里我们特意将 sharex 和 sharey 设置为 False
|
|
26
|
+
# 目的是为了后续演示 cleanup 函数如何动态地创建共享关系
|
|
27
|
+
try:
|
|
28
|
+
print("Creating a 2x2 plot with INDEPENDENT axes...")
|
|
29
|
+
plotter = Plotter(layout=(2, 2), figsize=(10, 8), style='flat')
|
|
30
|
+
|
|
31
|
+
# --- 3. 填充图表 ---
|
|
32
|
+
plotter.add_line(data=df1, x='time', y='signal', tag='cond1')
|
|
33
|
+
plotter.add_line(data=df2, x='time', y='signal', tag='cond2')
|
|
34
|
+
plotter.add_line(data=df3, x='time', y='signal', tag='cond3')
|
|
35
|
+
plotter.add_line(data=df4, x='time', y='signal', tag='cond4')
|
|
36
|
+
|
|
37
|
+
# --- 4. 为每个图表设置标签 ---
|
|
38
|
+
# 在不使用cleanup时,每个图表都需要自己的标签
|
|
39
|
+
plotter.set_title('cond1', 'Condition 1').set_ylabel('cond1', 'Signal')
|
|
40
|
+
plotter.set_title('cond2', 'Condition 2')
|
|
41
|
+
plotter.set_title('cond3', 'Condition 3').set_xlabel('cond3', 'Time (s)').set_ylabel('cond3', 'Signal')
|
|
42
|
+
plotter.set_title('cond4', 'Condition 4').set_xlabel('cond4', 'Time (s)')
|
|
43
|
+
|
|
44
|
+
# --- 5. 使用 cleanup 函数进行智能清理 ---
|
|
45
|
+
print("\nApplying cleanup() to dynamically share axes...")
|
|
46
|
+
# 我们指令cleanup函数:
|
|
47
|
+
# - 对第0行和第1行的Y轴进行共享和清理
|
|
48
|
+
# - 对第0列和第1列的X轴进行共享和清理
|
|
49
|
+
plotter.cleanup(auto_share=True)
|
|
50
|
+
|
|
51
|
+
# --- 6. 保存图像 ---
|
|
52
|
+
plotter.save("cleanup_demonstration_figure.png")
|
|
53
|
+
|
|
54
|
+
except pp.PaperPlotError as e:
|
|
55
|
+
print(f"\nA PaperPlot error occurred:\n{e}")
|
|
56
|
+
except Exception as e:
|
|
57
|
+
print(f"An unexpected error occurred: {e}")
|
|
58
|
+
finally:
|
|
59
|
+
plt.close('all')
|
|
60
|
+
|
|
61
|
+
print(f"--- Finished Example: {__file__} ---")
|
|
62
|
+
print("A new file 'cleanup_demonstration_figure.png' was generated.")
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# examples/composite_figure_example.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
print(f"--- Running Example: {__file__} ---")
|
|
9
|
+
|
|
10
|
+
# --- 1. 准备数据 ---
|
|
11
|
+
def generate_spectra_data(label):
|
|
12
|
+
x = np.linspace(400, 1800, 200)
|
|
13
|
+
peak_pos = np.random.uniform(600, 1600)
|
|
14
|
+
peak_width = np.random.uniform(50, 150)
|
|
15
|
+
peak_intensity = np.random.uniform(0.5, 1)
|
|
16
|
+
y = peak_intensity * np.exp(-((x - peak_pos)**2) / (2 * peak_width**2)) + np.random.rand(200) * 0.1
|
|
17
|
+
return pd.DataFrame({'wavenumber': x, 'intensity': y, 'label': label})
|
|
18
|
+
|
|
19
|
+
df1 = generate_spectra_data('Sample A')
|
|
20
|
+
df2 = generate_spectra_data('Sample B')
|
|
21
|
+
|
|
22
|
+
df_pca = pd.DataFrame({
|
|
23
|
+
'PC1': np.random.randn(50),
|
|
24
|
+
'PC2': np.random.randn(50),
|
|
25
|
+
'cluster': np.random.choice(['Group 1', 'Group 2', 'Group 3'], 50)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
# --- 2. 定义一个带空白占位符的复杂布局 ---
|
|
29
|
+
# 我们创建一个 L 型布局,右下角是空白的
|
|
30
|
+
layout = [
|
|
31
|
+
['SERS_Spectra', 'SERS_Spectra'],
|
|
32
|
+
['PCA_Result', '.'] # '.' 代表空白区域
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
plotter = pp.Plotter(layout=layout, figsize=(10, 8))
|
|
37
|
+
plotter.set_suptitle("Composite Figure with Inset Image", fontsize=16, weight='bold')
|
|
38
|
+
|
|
39
|
+
# --- 3. 在 SERS 图区域绘图 ---
|
|
40
|
+
# 由于 'SERS_Spectra' 占据了两个单元格,我们通过 get_ax_by_name 获取合并后的 Axes
|
|
41
|
+
ax_sers = plotter.get_ax_by_name('SERS_Spectra')
|
|
42
|
+
# 在同一个 Axes 上绘制两条光谱
|
|
43
|
+
plotter.add_line(data=df1, x='wavenumber', y='intensity', ax=ax_sers, tag='spectra_A', label='Sample A')
|
|
44
|
+
plotter.add_line(data=df2, x='wavenumber', y='intensity', ax=ax_sers, tag='spectra_B', label='Sample B')
|
|
45
|
+
plotter.set_title('spectra_A', 'SERS Spectra of Samples') # tag 'spectra_A' 和 'spectra_B' 都指向同一个 ax
|
|
46
|
+
plotter.set_xlabel('spectra_A', 'Wavenumber (cm⁻¹)')
|
|
47
|
+
plotter.set_ylabel('spectra_A', 'Intensity (a.u.)')
|
|
48
|
+
plotter.set_legend('spectra_A')
|
|
49
|
+
|
|
50
|
+
# --- 4. 在 SERS 图上嵌入占位符图片 ---
|
|
51
|
+
print("Adding an inset image to the 'SERS_Spectra' plot...")
|
|
52
|
+
plotter.add_inset_image(
|
|
53
|
+
host_tag='spectra_A',
|
|
54
|
+
image_path='./examples/Features_Customization/resources/placeholder_image.png',
|
|
55
|
+
rect=[0.7, 0.65, 0.28, 0.28] # [x, y, width, height] in relative coordinates
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# --- 5. 在 PCA 图区域绘图 ---
|
|
59
|
+
ax_pca = plotter.get_ax_by_name('PCA_Result')
|
|
60
|
+
# 使用 add_seaborn 绘制分组散点图
|
|
61
|
+
import seaborn as sns
|
|
62
|
+
plotter.add_seaborn(
|
|
63
|
+
plot_func=sns.scatterplot,
|
|
64
|
+
data=df_pca,
|
|
65
|
+
x='PC1',
|
|
66
|
+
y='PC2',
|
|
67
|
+
hue='cluster',
|
|
68
|
+
ax=ax_pca,
|
|
69
|
+
tag='pca'
|
|
70
|
+
)
|
|
71
|
+
plotter.set_title('pca', 'PCA of Spectral Data')
|
|
72
|
+
plotter.set_xlabel('pca', 'Principal Component 1')
|
|
73
|
+
plotter.set_ylabel('pca', 'Principal Component 2')
|
|
74
|
+
|
|
75
|
+
# --- 6. 清理和保存 ---
|
|
76
|
+
plotter.cleanup(align_labels=True)
|
|
77
|
+
plotter.save("composite_figure.png")
|
|
78
|
+
|
|
79
|
+
except (pp.PaperPlotError, FileNotFoundError, ValueError) as e:
|
|
80
|
+
print(f"\nAn error occurred:\n{e}")
|
|
81
|
+
except Exception as e:
|
|
82
|
+
print(f"An unexpected error occurred: {e}")
|
|
83
|
+
finally:
|
|
84
|
+
plt.close('all')
|
|
85
|
+
|
|
86
|
+
print(f"\n--- Finished Example: {__file__} ---")
|
|
87
|
+
print("A new file 'composite_figure.png' was generated.")
|
|
88
|
+
print("Check for the L-shaped layout and the inset image in the top-right plot.")
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# examples/error_handling_test.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
print(f"--- Running Example: {__file__} ---")
|
|
9
|
+
|
|
10
|
+
# --- 1. 测试 DuplicateTagError ---
|
|
11
|
+
print("\n--- Test 1: Catching DuplicateTagError ---")
|
|
12
|
+
try:
|
|
13
|
+
plotter = pp.Plotter(layout=(2, 1))
|
|
14
|
+
df = pd.DataFrame({'x': [1], 'y': [1]})
|
|
15
|
+
|
|
16
|
+
plotter.add_bar(data=df, x='x', y='y', tag='my_tag')
|
|
17
|
+
print("First plot with tag 'my_tag' added successfully.")
|
|
18
|
+
|
|
19
|
+
# 故意再次使用同一个tag
|
|
20
|
+
print("Attempting to add another plot with the same tag...")
|
|
21
|
+
plotter.add_bar(data=df, x='x', y='y', tag='my_tag')
|
|
22
|
+
|
|
23
|
+
except pp.DuplicateTagError as e:
|
|
24
|
+
print("\nSuccessfully caught expected error!")
|
|
25
|
+
print(f"Error Type: {type(e).__name__}")
|
|
26
|
+
print(f"Message:\n{e}")
|
|
27
|
+
except Exception as e:
|
|
28
|
+
print(f"Caught an unexpected error: {e}")
|
|
29
|
+
finally:
|
|
30
|
+
plt.close('all')
|
|
31
|
+
|
|
32
|
+
# --- 2. 测试 TagNotFoundError ---
|
|
33
|
+
print("\n--- Test 2: Catching TagNotFoundError ---")
|
|
34
|
+
try:
|
|
35
|
+
plotter = pp.Plotter(layout=(1, 1))
|
|
36
|
+
plotter.add_line(pd.DataFrame({'t': [0], 'v': [0]}), x='t', y='v', tag='actual_tag')
|
|
37
|
+
print("Plot with tag 'actual_tag' added successfully.")
|
|
38
|
+
|
|
39
|
+
# 故意使用一个不存在的tag
|
|
40
|
+
print("Attempting to modify a plot with a non-existent tag...")
|
|
41
|
+
plotter.set_title('non_existent_tag', 'My Title')
|
|
42
|
+
|
|
43
|
+
except pp.TagNotFoundError as e:
|
|
44
|
+
print("\nSuccessfully caught expected error!")
|
|
45
|
+
print(f"Error Type: {type(e).__name__}")
|
|
46
|
+
print(f"Message:\n{e}")
|
|
47
|
+
except Exception as e:
|
|
48
|
+
print(f"Caught an unexpected error: {e}")
|
|
49
|
+
finally:
|
|
50
|
+
plt.close('all')
|
|
51
|
+
|
|
52
|
+
# --- 3. 测试 PlottingSpaceError ---
|
|
53
|
+
print("\n--- Test 3: Catching PlottingSpaceError ---")
|
|
54
|
+
try:
|
|
55
|
+
# 创建一个只能放1个图的画布
|
|
56
|
+
plotter = pp.Plotter(layout=(1, 1))
|
|
57
|
+
df = pd.DataFrame({'x': [1], 'y': [1]})
|
|
58
|
+
|
|
59
|
+
plotter.add_bar(data=df, x='x', y='y')
|
|
60
|
+
print("First plot added successfully to a 1x1 grid.")
|
|
61
|
+
|
|
62
|
+
# 故意添加第二个图
|
|
63
|
+
print("Attempting to add a second plot to the full grid...")
|
|
64
|
+
plotter.add_bar(data=df, x='x', y='y')
|
|
65
|
+
|
|
66
|
+
except pp.PlottingSpaceError as e:
|
|
67
|
+
print("\nSuccessfully caught expected error!")
|
|
68
|
+
print(f"Error Type: {type(e).__name__}")
|
|
69
|
+
print(f"Message:\n{e}")
|
|
70
|
+
except Exception as e:
|
|
71
|
+
print(f"Caught an unexpected error: {e}")
|
|
72
|
+
finally:
|
|
73
|
+
plt.close('all')
|
|
74
|
+
|
|
75
|
+
print(f"\n--- Finished Example: {__file__} ---")
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# examples/feature_expansion_example.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
from matplotlib.patches import Rectangle
|
|
8
|
+
|
|
9
|
+
print(f"--- Running Example: {__file__} ---")
|
|
10
|
+
|
|
11
|
+
# --- 1. 准备数据 ---
|
|
12
|
+
# 主Y轴数据:温度
|
|
13
|
+
df_temp = pd.DataFrame({
|
|
14
|
+
'time': np.linspace(0, 24, 50),
|
|
15
|
+
'temperature': 20 + 5 * np.sin(np.linspace(0, 2 * np.pi, 50)) + np.random.randn(50) * 0.5
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
# 次Y轴数据:降雨量
|
|
19
|
+
df_rain = pd.DataFrame({
|
|
20
|
+
'time': np.linspace(0, 24, 10),
|
|
21
|
+
'rainfall': np.random.rand(10) * 10 + 5
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
# 回归数据
|
|
25
|
+
df_scatter = pd.DataFrame({
|
|
26
|
+
'x_val': np.random.rand(100) * 10,
|
|
27
|
+
'y_val': 2 * np.random.rand(100) * 10 + 5 + np.random.randn(100) * 2
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
# --- 2. 创建一个1x2的网格 ---
|
|
31
|
+
try:
|
|
32
|
+
plotter = pp.Plotter(layout=(1, 2), figsize=(12, 5))
|
|
33
|
+
|
|
34
|
+
# --- 左侧子图:双Y轴示例 ---
|
|
35
|
+
# 1. 绘制主Y轴(温度)
|
|
36
|
+
plotter.add_line(data=df_temp, x='time', y='temperature', tag='weather_plot', label='Temperature (°C)', color='red')
|
|
37
|
+
plotter.set_title('weather_plot', 'Hourly Weather Data')
|
|
38
|
+
plotter.set_xlabel('weather_plot', 'Time (hours)')
|
|
39
|
+
plotter.set_ylabel('weather_plot', 'Temperature (°C)', color='red')
|
|
40
|
+
plotter.tick_params('weather_plot', axis='y', labelcolor='red')
|
|
41
|
+
|
|
42
|
+
# 2. 创建twinx轴并绘制次Y轴(降雨量)
|
|
43
|
+
ax2 = plotter.add_twinx('weather_plot')
|
|
44
|
+
ax2.bar(df_rain['time'], df_rain['rainfall'], width=0.8, alpha=0.3, color='blue', label='Rainfall (mm)')
|
|
45
|
+
ax2.set_ylabel('Rainfall (mm)', color='blue')
|
|
46
|
+
ax2.tick_params(axis='y', labelcolor='blue')
|
|
47
|
+
|
|
48
|
+
# 3. 添加参考线和文本
|
|
49
|
+
plotter.add_hline('weather_plot', y=25, linestyle='--', color='red', label='Avg Temp')
|
|
50
|
+
plotter.add_text('weather_plot', x=12, y=26, text='High Temp Zone', color='red', ha='center')
|
|
51
|
+
|
|
52
|
+
# 4. 添加一个Patch (例如,一个表示夜间的矩形)
|
|
53
|
+
night_rect = Rectangle((20, 0), 4, 30, facecolor='gray', alpha=0.2, transform=plotter.get_ax('weather_plot').transData)
|
|
54
|
+
plotter.add_patch('weather_plot', night_rect)
|
|
55
|
+
|
|
56
|
+
# --- 右侧子图:回归图示例 ---
|
|
57
|
+
plotter.add_regplot(data=df_scatter, x='x_val', y='y_val', tag='reg_plot', color='green', scatter_kws={'alpha':0.6})
|
|
58
|
+
plotter.set_title('reg_plot', 'Regression Analysis')
|
|
59
|
+
plotter.set_xlabel('reg_plot', 'Independent Variable')
|
|
60
|
+
plotter.set_ylabel('reg_plot', 'Dependent Variable')
|
|
61
|
+
plotter.add_vline('reg_plot', x=5, linestyle=':', color='gray', label='Threshold')
|
|
62
|
+
plotter.add_text('reg_plot', x=5, y=25, text='Critical Point', color='gray', ha='left', va='bottom')
|
|
63
|
+
|
|
64
|
+
# --- 全局美化 ---
|
|
65
|
+
plotter.set_suptitle("Advanced Plotting Features Demonstration", fontsize=16, weight='bold', y=1.02)
|
|
66
|
+
# 注意:全局图例需要手动收集twinx轴的label
|
|
67
|
+
# 或者,我们可以让add_twinx返回的ax2也注册到tag_to_ax,这样add_global_legend就能自动收集
|
|
68
|
+
# 但目前add_twinx只返回ax2,所以需要手动处理
|
|
69
|
+
# 暂时不添加全局图例,因为twinx的图例收集需要更复杂的逻辑
|
|
70
|
+
# plotter.add_global_legend(loc='upper right')
|
|
71
|
+
plotter.cleanup(align_labels=True)
|
|
72
|
+
|
|
73
|
+
# --- 5. 保存图像 ---
|
|
74
|
+
plotter.save("feature_expansion_figure.png")
|
|
75
|
+
|
|
76
|
+
except (pp.PaperPlotError, ValueError) as e:
|
|
77
|
+
print(f"\nA PaperPlot error occurred:\n{e}")
|
|
78
|
+
except Exception as e:
|
|
79
|
+
print(f"An unexpected error occurred: {e}")
|
|
80
|
+
finally:
|
|
81
|
+
plt.close('all')
|
|
82
|
+
|
|
83
|
+
print(f"\n--- Finished Example: {__file__} ---")
|
|
84
|
+
print("A new file 'feature_expansion_figure.png' was generated.")
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# examples/Features_Customization/fig_annotation_example.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
print(f"--- Running Example: {__file__} ---")
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
# 1. Create a Plotter instance with a 2x2 layout
|
|
12
|
+
plotter = pp.Plotter(layout=(2, 2), figsize=(12, 10), style='publication')
|
|
13
|
+
|
|
14
|
+
# 2. Add some plots to the subplots
|
|
15
|
+
df = pd.DataFrame({
|
|
16
|
+
'x': np.linspace(0, 10, 50),
|
|
17
|
+
'y1': np.sin(np.linspace(0, 10, 50)),
|
|
18
|
+
'y2': np.cos(np.linspace(0, 10, 50)),
|
|
19
|
+
'y3': np.random.rand(50) * 5
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
plotter.add_line(data=df, x='x', y='y1', tag='ax00', label='Sine')
|
|
23
|
+
plotter.set_title('ax00', 'Top-Left Plot')
|
|
24
|
+
plotter.set_legend('ax00')
|
|
25
|
+
|
|
26
|
+
plotter.add_scatter(data=df, x='x', y='y2', tag='ax01', label='Cosine', marker='o')
|
|
27
|
+
plotter.set_title('ax01', 'Top-Right Plot')
|
|
28
|
+
plotter.set_legend('ax01')
|
|
29
|
+
|
|
30
|
+
plotter.add_hist(data=df, x='y3', tag='ax10', bins=10, color='skyblue')
|
|
31
|
+
plotter.set_title('ax10', 'Bottom-Left Plot')
|
|
32
|
+
|
|
33
|
+
plotter.add_bar(data=pd.DataFrame({'cat': ['A', 'B', 'C'], 'val': [1, 3, 2]}), x='cat', y='val', tag='ax11')
|
|
34
|
+
plotter.set_title('ax11', 'Bottom-Right Plot')
|
|
35
|
+
|
|
36
|
+
# Apply cleanup for shared axes
|
|
37
|
+
plotter.cleanup(auto_share=True)
|
|
38
|
+
|
|
39
|
+
# 3. Use the new global figure-level annotation APIs
|
|
40
|
+
|
|
41
|
+
# fig_add_text
|
|
42
|
+
plotter.fig_add_text(0.5, 0.96, 'Comprehensive Figure Analysis', ha='center', va='top', fontsize=16, weight='bold', color='darkblue')
|
|
43
|
+
plotter.fig_add_text(0.02, 0.02, 'Generated by PaperPlot', ha='left', va='bottom', fontsize=8, style='italic')
|
|
44
|
+
|
|
45
|
+
# fig_add_line - draw a line across the figure
|
|
46
|
+
plotter.fig_add_line([0.1, 0.9], [0.5, 0.5], color='red', linestyle=':', linewidth=2)
|
|
47
|
+
plotter.fig_add_text(0.5, 0.51, 'Mid-Figure Separator', ha='center', va='bottom', color='red', fontsize=10)
|
|
48
|
+
|
|
49
|
+
# fig_add_box - box around top row plots
|
|
50
|
+
plotter.fig_add_box(tags=['ax00', 'ax01'], padding=0.01, edgecolor='green', linewidth=2, linestyle='-')
|
|
51
|
+
plotter.fig_add_label(tags=['ax00', 'ax01'], text='Top Row Insights', position='top_center', padding=0.02, fontsize=12, color='green')
|
|
52
|
+
|
|
53
|
+
# fig_add_box - box around bottom-left plot
|
|
54
|
+
plotter.fig_add_box(tags='ax10', padding=0.005, edgecolor='purple', linewidth=1, linestyle='-.')
|
|
55
|
+
plotter.fig_add_label(tags='ax10', text='Distribution', position='bottom_right', padding=0.01, fontsize=10, color='purple')
|
|
56
|
+
|
|
57
|
+
# fig_add_label - label for the entire figure (relative to all axes)
|
|
58
|
+
plotter.fig_add_label(tags=['ax00', 'ax01', 'ax10', 'ax11'], text='Overall Study Results', position='right_center', padding=0.05, rotation=-90, fontsize=14, color='gray')
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# 4. Save the figure
|
|
62
|
+
plotter.save("fig_annotation_example.png")
|
|
63
|
+
|
|
64
|
+
except pp.PaperPlotError as e:
|
|
65
|
+
print(f"\nA PaperPlot error occurred:\n{e}")
|
|
66
|
+
except Exception as e:
|
|
67
|
+
print(f"An unexpected error occurred: {e}")
|
|
68
|
+
finally:
|
|
69
|
+
plt.close('all')
|
|
70
|
+
|
|
71
|
+
print(f"--- Finished Example: {__file__} ---")
|
|
72
|
+
print("A new file 'fig_annotation_example.png' was generated.")
|
|
Binary file
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# examples/Features_Customization/fig_text_example.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
print(f"--- Running Example: {__file__} ---")
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
# 1. Create a Plotter instance with a 1x2 layout
|
|
12
|
+
plotter = pp.Plotter(layout=(1, 2), figsize=(10, 5), style='publication')
|
|
13
|
+
|
|
14
|
+
# 2. Add some plots to the subplots
|
|
15
|
+
df = pd.DataFrame({
|
|
16
|
+
'x': np.linspace(0, 10, 100),
|
|
17
|
+
'y1': np.sin(np.linspace(0, 10, 100)),
|
|
18
|
+
'y2': np.cos(np.linspace(0, 10, 100))
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
plotter.add_line(data=df, x='x', y='y1', tag='ax00', label='Sine Wave')
|
|
22
|
+
plotter.set_title('ax00', 'Left Subplot')
|
|
23
|
+
plotter.set_xlabel('ax00', 'X-axis')
|
|
24
|
+
plotter.set_ylabel('ax00', 'Y-axis')
|
|
25
|
+
plotter.set_legend('ax00')
|
|
26
|
+
|
|
27
|
+
plotter.add_scatter(data=df, x='x', y='y2', tag='ax01', label='Cosine Points', marker='o', s=20)
|
|
28
|
+
plotter.set_title('ax01', 'Right Subplot')
|
|
29
|
+
plotter.set_xlabel('ax01', 'X-axis')
|
|
30
|
+
plotter.set_ylabel('ax01', 'Y-axis')
|
|
31
|
+
plotter.set_legend('ax01')
|
|
32
|
+
|
|
33
|
+
# 3. Add figure-level text using fig_text
|
|
34
|
+
plotter.fig_add_text(0.5, 0.96, 'Overall Figure Title (using fig_add_text)', ha='center', va='top', fontsize=14, weight='bold')
|
|
35
|
+
plotter.fig_add_text(0.02, 0.5, 'Left Side Annotation', rotation=90, va='center', ha='left', fontsize=10, color='gray')
|
|
36
|
+
plotter.fig_add_text(0.98, 0.5, 'Right Side Annotation', rotation=-90, va='center', ha='right', fontsize=10, color='gray')
|
|
37
|
+
plotter.fig_add_text(0.5, 0.02, 'Figure Footer - Source: Example Data', ha='center', va='bottom', fontsize=8, style='italic')
|
|
38
|
+
|
|
39
|
+
# 4. Apply cleanup and save the figure
|
|
40
|
+
plotter.cleanup(auto_share=True) # Auto-share for demonstration
|
|
41
|
+
plotter.save("fig_text_example.png")
|
|
42
|
+
|
|
43
|
+
except pp.PaperPlotError as e:
|
|
44
|
+
print(f"\nA PaperPlot error occurred:\n{e}")
|
|
45
|
+
except Exception as e:
|
|
46
|
+
print(f"An unexpected error occurred: {e}")
|
|
47
|
+
finally:
|
|
48
|
+
plt.close('all')
|
|
49
|
+
|
|
50
|
+
print(f"--- Finished Example: {__file__} ---")
|
|
51
|
+
print("A new file 'fig_text_example.png' was generated.")
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# examples/global_controls_example.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
print(f"--- Running Example: {__file__} ---")
|
|
9
|
+
|
|
10
|
+
# --- 1. 准备数据 ---
|
|
11
|
+
def generate_data(label):
|
|
12
|
+
x = np.linspace(0, 10, 40)
|
|
13
|
+
y = np.sin(x + np.random.rand() * 5) * np.random.rand() + np.random.randn(40) * 0.1
|
|
14
|
+
return pd.DataFrame({'x': x, 'y': y, 'label': label})
|
|
15
|
+
|
|
16
|
+
df1 = generate_data('Series A')
|
|
17
|
+
df2 = generate_data('Series B')
|
|
18
|
+
df3 = generate_data('Series C')
|
|
19
|
+
df4 = generate_data('Series D')
|
|
20
|
+
|
|
21
|
+
# --- 2. 创建一个2x2的简单网格 ---
|
|
22
|
+
try:
|
|
23
|
+
# 使用 (2, 2) 元组来创建一个简单的2x2布局
|
|
24
|
+
plotter = pp.Plotter(layout=(2, 2), figsize=(10, 8))
|
|
25
|
+
|
|
26
|
+
# --- 3. 填充图表 ---
|
|
27
|
+
# 注意我们为每条线都设置了label,以便全局图例能收集到它们
|
|
28
|
+
plotter.add_line(data=df1, x='x', y='y', tag='tl', label='Series A', color='blue')
|
|
29
|
+
plotter.add_line(data=df2, x='x', y='y', tag='tr', label='Series B', color='red')
|
|
30
|
+
plotter.add_line(data=df3, x='x', y='y', tag='bl', label='Series C', color='green')
|
|
31
|
+
plotter.add_line(data=df4, x='x', y='y', tag='br', label='Series D', color='purple')
|
|
32
|
+
|
|
33
|
+
# --- 4. 使用新的全局控制功能 ---
|
|
34
|
+
|
|
35
|
+
# a. 设置一个全局主标题
|
|
36
|
+
print("Setting a global suptitle...")
|
|
37
|
+
plotter.set_suptitle("Global Figure Title (Suptitle)", fontsize=20, weight='bold')
|
|
38
|
+
|
|
39
|
+
# b. 为所有子图设置独立的标题
|
|
40
|
+
plotter.set_title('tl', 'Top-Left Plot')
|
|
41
|
+
plotter.set_title('tr', 'Top-Right Plot')
|
|
42
|
+
plotter.set_title('bl', 'Bottom-Left Plot')
|
|
43
|
+
plotter.set_title('br', 'Bottom-Right Plot')
|
|
44
|
+
|
|
45
|
+
# c. 创建一个全局图例
|
|
46
|
+
# 它会自动收集所有子图的'label',并移除子图自身的图例
|
|
47
|
+
print("Adding a global legend...")
|
|
48
|
+
plotter.add_global_legend(loc='upper right')
|
|
49
|
+
|
|
50
|
+
# d. 使用增强的cleanup功能
|
|
51
|
+
# 我们共享所有行和列的轴,并确保标签对齐
|
|
52
|
+
print("Running cleanup with label alignment...")
|
|
53
|
+
plotter.cleanup(share_y_on_rows=[0, 1], share_x_on_cols=[0, 1], align_labels=True)
|
|
54
|
+
|
|
55
|
+
# --- 5. 保存图像 ---
|
|
56
|
+
plotter.save("global_controls_figure.png")
|
|
57
|
+
|
|
58
|
+
except (pp.PaperPlotError, ValueError) as e:
|
|
59
|
+
print(f"\nA PaperPlot error occurred:\n{e}")
|
|
60
|
+
except Exception as e:
|
|
61
|
+
print(f"An unexpected error occurred: {e}")
|
|
62
|
+
finally:
|
|
63
|
+
plt.close('all')
|
|
64
|
+
|
|
65
|
+
print(f"\n--- Finished Example: {__file__} ---")
|
|
66
|
+
print("A new file 'global_controls_figure.png' was generated.")
|
|
Binary file
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# examples/heatmap_colorbar_example.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
print(f"--- Running Example: {__file__} ---")
|
|
9
|
+
|
|
10
|
+
# --- 1. 准备三组数据范围不同的热图数据 ---
|
|
11
|
+
def generate_heatmap_data(vmin, vmax, size=5):
|
|
12
|
+
return pd.DataFrame(np.random.rand(size, size) * (vmax - vmin) + vmin)
|
|
13
|
+
|
|
14
|
+
df1 = generate_heatmap_data(0, 10)
|
|
15
|
+
df2 = generate_heatmap_data(5, 15)
|
|
16
|
+
df3 = generate_heatmap_data(-5, 5)
|
|
17
|
+
|
|
18
|
+
# --- 2. 演示共享颜色条功能 ---
|
|
19
|
+
try:
|
|
20
|
+
print("Creating 3 heatmaps with a shared colorbar...")
|
|
21
|
+
plotter = pp.Plotter(layout=(1, 3), figsize=(12, 4))
|
|
22
|
+
|
|
23
|
+
# --- 3. 添加热图,并明确指定 cbar=False ---
|
|
24
|
+
# 这是关键一步:我们告诉plotter不要为每个热图单独创建颜色条
|
|
25
|
+
plotter.add_heatmap(data=df1, tag='h1', cbar=False, annot=True, fmt='.0f')
|
|
26
|
+
plotter.add_heatmap(data=df2, tag='h2', cbar=False, annot=True, fmt='.0f')
|
|
27
|
+
plotter.add_heatmap(data=df3, tag='h3', cbar=False, annot=True, fmt='.0f')
|
|
28
|
+
|
|
29
|
+
# --- 4. 设置标题 ---
|
|
30
|
+
plotter.set_title('h1', 'Range 0-10')
|
|
31
|
+
plotter.set_title('h2', 'Range 5-15')
|
|
32
|
+
plotter.set_title('h3', 'Range -5-5')
|
|
33
|
+
|
|
34
|
+
# --- 5. 调用 cleanup_heatmaps 来创建共享颜色条 ---
|
|
35
|
+
# 函数会自动找到所有热图的全局数据范围 (-5 到 15)
|
|
36
|
+
# 并创建一个能代表这个全局范围的颜色条
|
|
37
|
+
plotter.cleanup_heatmaps(tags=['h1', 'h2', 'h3'])
|
|
38
|
+
|
|
39
|
+
# 我们也可以顺便清理一下Y轴,让它们对齐
|
|
40
|
+
plotter.cleanup(share_y_on_rows=[0])
|
|
41
|
+
|
|
42
|
+
# --- 6. 保存图像 ---
|
|
43
|
+
plotter.save("heatmap_shared_colorbar_figure.png")
|
|
44
|
+
|
|
45
|
+
except pp.PaperPlotError as e:
|
|
46
|
+
print(f"\nA PaperPlot error occurred:\n{e}")
|
|
47
|
+
except Exception as e:
|
|
48
|
+
print(f"An unexpected error occurred: {e}")
|
|
49
|
+
finally:
|
|
50
|
+
plt.close('all')
|
|
51
|
+
|
|
52
|
+
# --- 7. 作为对比,创建一个带独立颜色条的热图 ---
|
|
53
|
+
try:
|
|
54
|
+
print("\nCreating a single heatmap with its own colorbar (default behavior)...")
|
|
55
|
+
plotter_single = pp.Plotter(layout=(1, 1))
|
|
56
|
+
# 默认调用,不加 cbar 参数,会自动创建颜色条
|
|
57
|
+
plotter_single.add_heatmap(data=df1, tag='single')
|
|
58
|
+
plotter_single.set_title('single', 'Default Behavior with cbar=True')
|
|
59
|
+
plotter_single.save("heatmap_default_figure.png")
|
|
60
|
+
|
|
61
|
+
except pp.PaperPlotError as e:
|
|
62
|
+
print(f"\nA PaperPlot error occurred:\n{e}")
|
|
63
|
+
finally:
|
|
64
|
+
plt.close('all')
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
print(f"\n--- Finished Example: {__file__} ---")
|
|
68
|
+
print("Two files were generated: 'heatmap_shared_colorbar_figure.png' and 'heatmap_default_figure.png'")
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# examples/Features_Customization/highlighting_example.py
|
|
2
|
+
|
|
3
|
+
import paperplot as pp
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
print(f"--- Running Example: {__file__} ---")
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
# 1. Create a Plotter instance
|
|
12
|
+
plotter = pp.Plotter(layout=(1, 1), figsize=(8, 6), style='publication')
|
|
13
|
+
|
|
14
|
+
# 2. Add a plot with some interesting features
|
|
15
|
+
x = np.linspace(0, 2 * np.pi, 200)
|
|
16
|
+
y = np.sin(x) * np.exp(-x / 4)
|
|
17
|
+
df = pd.DataFrame({'x': x, 'y': y})
|
|
18
|
+
|
|
19
|
+
plotter.add_line(data=df, x='x', y='y', tag='main_plot', label='Damped Sine Wave')
|
|
20
|
+
plotter.set_title('main_plot', 'Highlighting Data Regions and Figure Boundary')
|
|
21
|
+
plotter.set_xlabel('main_plot', 'Time')
|
|
22
|
+
plotter.set_ylabel('main_plot', 'Amplitude')
|
|
23
|
+
plotter.set_legend('main_plot')
|
|
24
|
+
|
|
25
|
+
# 3. Use add_highlight_box to highlight a specific data region
|
|
26
|
+
# Highlight the first peak of the wave
|
|
27
|
+
plotter.add_highlight_box(
|
|
28
|
+
tag='main_plot',
|
|
29
|
+
x_range=(0.5, 2.5),
|
|
30
|
+
y_range=(0.4, 0.8),
|
|
31
|
+
facecolor='orange',
|
|
32
|
+
alpha=0.3,
|
|
33
|
+
label='First Peak Region' # Note: label won't show by default, but can be used with legends
|
|
34
|
+
)
|
|
35
|
+
plotter.add_text('main_plot', 1.5, 0.6, 'First Peak', ha='center', va='center', fontsize=10)
|
|
36
|
+
|
|
37
|
+
# Highlight the region where the wave decays
|
|
38
|
+
plotter.add_highlight_box(
|
|
39
|
+
tag='main_plot',
|
|
40
|
+
x_range=(4, 6),
|
|
41
|
+
y_range=(-0.2, 0.2),
|
|
42
|
+
facecolor='lightblue',
|
|
43
|
+
alpha=0.4
|
|
44
|
+
)
|
|
45
|
+
plotter.add_text('main_plot', 5, 0, 'Decay Region', ha='center', va='center', fontsize=10)
|
|
46
|
+
|
|
47
|
+
# 4. Use fig_add_boundary_box to draw a border around the axes area
|
|
48
|
+
|
|
49
|
+
# plotter.fig_add_text(0.5, 0.98, 'Figure with Smart Boundary Box', ha='center', va='top', fontsize=12)
|
|
50
|
+
plotter.fig_add_boundary_box(padding=0.08, edgecolor='darkgray', linewidth=2)
|
|
51
|
+
# 5. Save the figure
|
|
52
|
+
plotter.save("highlighting_example.png")
|
|
53
|
+
|
|
54
|
+
except pp.PaperPlotError as e:
|
|
55
|
+
print(f"\nA PaperPlot error occurred:\n{e}")
|
|
56
|
+
except Exception as e:
|
|
57
|
+
print(f"An unexpected error occurred: {e}")
|
|
58
|
+
finally:
|
|
59
|
+
plt.close('all')
|
|
60
|
+
|
|
61
|
+
print(f"--- Finished Example: {__file__} ---")
|
|
62
|
+
print("A new file 'highlighting_example.png' was generated.")
|