paperplotter 0.1.3__tar.gz → 0.1.4__tar.gz
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.
- {paperplotter-0.1.3/paperplotter.egg-info → paperplotter-0.1.4}/PKG-INFO +9 -4
- {paperplotter-0.1.3 → paperplotter-0.1.4}/README.md +9 -4
- paperplotter-0.1.4/examples/Layout/declarative_nested_layout.png +0 -0
- paperplotter-0.1.4/examples/Layout/declarative_nested_layout_example.py +91 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/core.py +89 -15
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/mixins/domain.py +36 -64
- paperplotter-0.1.4/paperplot/mixins/generic.py +95 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4/paperplotter.egg-info}/PKG-INFO +9 -4
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplotter.egg-info/SOURCES.txt +2 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplotter.egg-info/top_level.txt +1 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/pyproject.toml +1 -1
- paperplotter-0.1.3/paperplot/mixins/generic.py +0 -144
- {paperplotter-0.1.3 → paperplotter-0.1.4}/LICENSE +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/MANIFEST.in +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Data_Analysis_Utils/data_analysis_utils_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Data_Analysis_Utils/data_analysis_utils_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Data_Analysis_Utils/utility_functions_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Data_Analysis_Utils/utility_functions_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/bifurcation_diagram_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/bifurcation_diagram_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/concentration_map_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/concentration_map_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/domain_specific_plots.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/domain_specific_plots_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/learning_curve_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/learning_curve_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/phasor_diagram_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/phasor_diagram_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/power_timeseries_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/power_timeseries_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/advanced_customization.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/advanced_customization_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/cleanup_demonstration.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/cleanup_demonstration_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/composite_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/composite_figure_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/error_handling_test.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/feature_expansion_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/feature_expansion_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/fig_annotation_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/fig_annotation_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/fig_text_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/fig_text_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/global_controls_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/global_controls_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/heatmap_colorbar_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/heatmap_default_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/heatmap_shared_colorbar_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/highlighting_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/highlighting_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/multi_plot_grid.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/multi_plot_grid_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/resources/placeholder_image.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/advanced_layout_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/advanced_layout_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/aspect_ratio_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/aspect_ratio_mosaic.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/aspect_ratio_simple_grid.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/block_span_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/block_span_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/row_span_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Layout/row_span_figure.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/aesthetic_and_processing_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/aesthetic_and_processing_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/statistical_annotation_example.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/statistical_annotation_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_example.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_flat.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_nord.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_presentation.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_publication.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_solarized_light.png +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/__init__.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/exceptions.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/mixins/__init__.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/mixins/modifiers.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/styles/flat.mplstyle +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/styles/nord.mplstyle +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/styles/presentation.mplstyle +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/styles/publication.mplstyle +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/styles/solarized_light.mplstyle +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplot/utils.py +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplotter.egg-info/dependency_links.txt +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/paperplotter.egg-info/requires.txt +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/setup.cfg +0 -0
- {paperplotter-0.1.3 → paperplotter-0.1.4}/tests/test_plotter.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: paperplotter
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: 一个为科研论文设计的声明式 Matplotlib 封装库,让复杂图表的创建变得简单直观。
|
|
5
5
|
Author-email: VerNe <yuu_seeing@foxmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -36,6 +36,7 @@ Dynamic: license-file
|
|
|
36
36
|
* **🎨 声明式链式调用**: 像写句子一样构建你的图表,例如 `plotter.add_line(...).set_title(...).set_xlabel(...)`。
|
|
37
37
|
* **🏷️ 基于标签的控制**: 给每个子图一个独一无二的 `tag`,之后就可以随时通过 `tag` 对其进行任何修改,告别混乱的 `axes[i][j]` 索引。
|
|
38
38
|
* **🧩 强大的布局系统**: 无论是简单的 `(行, 列)` 网格,还是使用 `mosaic` 实现的跨行跨列复杂布局,都能轻松定义。
|
|
39
|
+
* **🧱 声明式嵌套布局**: 通过一个字典即可一次性定义包含子网格的复杂层级布局,并使用 `'容器.子图'` 这样的直观路径进行引用,完美实现“图中图”。
|
|
39
40
|
* **📐 灵活的尺寸控制**: 除了传统的 `figsize`,还可以通过 `subplot_aspect` 指定子图单元格的宽高比,让 `PaperPlot` 自动计算最合适的画布尺寸。
|
|
40
41
|
* **✨ 内置科研主题**: 提供多种专业美观的内置样式,如 `publication`, `presentation` 等,一键切换图表风格。
|
|
41
42
|
* **🌐 全局图层级标注**: 提供了在整个画布(Figure)上添加文本、线条、方框和标签的 API,非常适合添加全局注释或高亮一组图表。
|
|
@@ -68,10 +69,13 @@ df_scatter = pd.DataFrame({
|
|
|
68
69
|
})
|
|
69
70
|
|
|
70
71
|
# 2. 初始化 Plotter 并绘图
|
|
72
|
+
# 对于简单布局,可以直接使用元组 (rows, cols)
|
|
71
73
|
plotter = pp.Plotter(layout=(1, 2), figsize=(10, 4))
|
|
72
74
|
|
|
73
|
-
# 3.
|
|
75
|
+
# 3. 顺序添加图表,Plotter会自动填充网格
|
|
76
|
+
# 第一次调用 add_line 会画在左边
|
|
74
77
|
plotter.add_line(data=df_line, x='time', y='signal', tag='time_series')
|
|
78
|
+
# 第二次调用 add_scatter 会画在右边
|
|
75
79
|
plotter.add_scatter(data=df_scatter, x='x', y='y', tag='scatter_plot')
|
|
76
80
|
|
|
77
81
|
# 4. 通过 tag 设置标题和标签
|
|
@@ -96,7 +100,8 @@ plotter.save("quick_start_figure.png")
|
|
|
96
100
|
|
|
97
101
|
| 示例 | 描述 | 关键功能 |
|
|
98
102
|
| :--- | :--- | :--- |
|
|
99
|
-
|
|
|
103
|
+
| **声明式嵌套布局**<br/> `Layout/declarative_nested_layout_example.py` | 使用字典来声明式地定义一个包含子网格的复杂、多层级布局,实现“图中图”的效果。 | `layout={...}`<br/> `tag='容器.子图'` |
|
|
104
|
+
| **高级布局**<br/> `Layout/advanced_layout_example.py` | 展示如何使用列表定义一个跨列的复杂布局。 | `layout=[['A', 'B', 'B'], ...]` |
|
|
100
105
|
| **行跨越**<br/> `Layout/row_span_example.py` | 创建一个图表,其中某个子图跨越多行。 | `layout=[['A', 'B'], ['A', 'C']]` |
|
|
101
106
|
| **块跨越**<br/> `Layout/block_span_example.py` | 创建一个图表,其中某个子图同时跨越多行和多列。 | `layout=[['A', 'A', 'B'], ['A', 'A', 'C']]` |
|
|
102
107
|
| **固定子图宽高比**<br/> `Layout/aspect_ratio_example.py` | 在不指定 `figsize` 的情况下,通过 `subplot_aspect` 保证每个子图单元格的宽高比,Plotter 会自动计算画布大小。 | `subplot_aspect=(16, 9)` |
|
|
@@ -105,7 +110,7 @@ plotter.save("quick_start_figure.png")
|
|
|
105
110
|
|
|
106
111
|
| 示例 | 描述 | 关键功能 |
|
|
107
112
|
| :--- | :--- | :--- |
|
|
108
|
-
| **多图网格**<br/> `Features_Customization/multi_plot_grid.py` |
|
|
113
|
+
| **多图网格**<br/> `Features_Customization/multi_plot_grid.py` | 在一个网格中通过链式调用混合绘制不同类型的图表。 | `plotter.add_...().add_...()` |
|
|
109
114
|
| **高级定制**<br/> `Features_Customization/advanced_customization.py` | 演示如何使用 `get_ax()` "逃生舱口" 来获取原生的 Matplotlib `Axes` 对象,并添加任意 `Patch`(如椭圆)。 | `get_ax()`, `ax.add_patch()` |
|
|
110
115
|
| **全局控制**<br/> `Features_Customization/global_controls_example.py` | 展示如何设置全局标题 (`suptitle`) 和创建全局图例。 | `set_suptitle()`, `add_global_legend()` |
|
|
111
116
|
| **共享颜色条**<br/> `Features_Customization/heatmap_colorbar_example.py` | 为多个热图创建一个共享的、能反映全局数据范围的颜色条。 | `add_heatmap(cbar=False)`, `cleanup_heatmaps()` |
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* **🎨 声明式链式调用**: 像写句子一样构建你的图表,例如 `plotter.add_line(...).set_title(...).set_xlabel(...)`。
|
|
13
13
|
* **🏷️ 基于标签的控制**: 给每个子图一个独一无二的 `tag`,之后就可以随时通过 `tag` 对其进行任何修改,告别混乱的 `axes[i][j]` 索引。
|
|
14
14
|
* **🧩 强大的布局系统**: 无论是简单的 `(行, 列)` 网格,还是使用 `mosaic` 实现的跨行跨列复杂布局,都能轻松定义。
|
|
15
|
+
* **🧱 声明式嵌套布局**: 通过一个字典即可一次性定义包含子网格的复杂层级布局,并使用 `'容器.子图'` 这样的直观路径进行引用,完美实现“图中图”。
|
|
15
16
|
* **📐 灵活的尺寸控制**: 除了传统的 `figsize`,还可以通过 `subplot_aspect` 指定子图单元格的宽高比,让 `PaperPlot` 自动计算最合适的画布尺寸。
|
|
16
17
|
* **✨ 内置科研主题**: 提供多种专业美观的内置样式,如 `publication`, `presentation` 等,一键切换图表风格。
|
|
17
18
|
* **🌐 全局图层级标注**: 提供了在整个画布(Figure)上添加文本、线条、方框和标签的 API,非常适合添加全局注释或高亮一组图表。
|
|
@@ -44,10 +45,13 @@ df_scatter = pd.DataFrame({
|
|
|
44
45
|
})
|
|
45
46
|
|
|
46
47
|
# 2. 初始化 Plotter 并绘图
|
|
48
|
+
# 对于简单布局,可以直接使用元组 (rows, cols)
|
|
47
49
|
plotter = pp.Plotter(layout=(1, 2), figsize=(10, 4))
|
|
48
50
|
|
|
49
|
-
# 3.
|
|
51
|
+
# 3. 顺序添加图表,Plotter会自动填充网格
|
|
52
|
+
# 第一次调用 add_line 会画在左边
|
|
50
53
|
plotter.add_line(data=df_line, x='time', y='signal', tag='time_series')
|
|
54
|
+
# 第二次调用 add_scatter 会画在右边
|
|
51
55
|
plotter.add_scatter(data=df_scatter, x='x', y='y', tag='scatter_plot')
|
|
52
56
|
|
|
53
57
|
# 4. 通过 tag 设置标题和标签
|
|
@@ -72,7 +76,8 @@ plotter.save("quick_start_figure.png")
|
|
|
72
76
|
|
|
73
77
|
| 示例 | 描述 | 关键功能 |
|
|
74
78
|
| :--- | :--- | :--- |
|
|
75
|
-
|
|
|
79
|
+
| **声明式嵌套布局**<br/> `Layout/declarative_nested_layout_example.py` | 使用字典来声明式地定义一个包含子网格的复杂、多层级布局,实现“图中图”的效果。 | `layout={...}`<br/> `tag='容器.子图'` |
|
|
80
|
+
| **高级布局**<br/> `Layout/advanced_layout_example.py` | 展示如何使用列表定义一个跨列的复杂布局。 | `layout=[['A', 'B', 'B'], ...]` |
|
|
76
81
|
| **行跨越**<br/> `Layout/row_span_example.py` | 创建一个图表,其中某个子图跨越多行。 | `layout=[['A', 'B'], ['A', 'C']]` |
|
|
77
82
|
| **块跨越**<br/> `Layout/block_span_example.py` | 创建一个图表,其中某个子图同时跨越多行和多列。 | `layout=[['A', 'A', 'B'], ['A', 'A', 'C']]` |
|
|
78
83
|
| **固定子图宽高比**<br/> `Layout/aspect_ratio_example.py` | 在不指定 `figsize` 的情况下,通过 `subplot_aspect` 保证每个子图单元格的宽高比,Plotter 会自动计算画布大小。 | `subplot_aspect=(16, 9)` |
|
|
@@ -81,7 +86,7 @@ plotter.save("quick_start_figure.png")
|
|
|
81
86
|
|
|
82
87
|
| 示例 | 描述 | 关键功能 |
|
|
83
88
|
| :--- | :--- | :--- |
|
|
84
|
-
| **多图网格**<br/> `Features_Customization/multi_plot_grid.py` |
|
|
89
|
+
| **多图网格**<br/> `Features_Customization/multi_plot_grid.py` | 在一个网格中通过链式调用混合绘制不同类型的图表。 | `plotter.add_...().add_...()` |
|
|
85
90
|
| **高级定制**<br/> `Features_Customization/advanced_customization.py` | 演示如何使用 `get_ax()` "逃生舱口" 来获取原生的 Matplotlib `Axes` 对象,并添加任意 `Patch`(如椭圆)。 | `get_ax()`, `ax.add_patch()` |
|
|
86
91
|
| **全局控制**<br/> `Features_Customization/global_controls_example.py` | 展示如何设置全局标题 (`suptitle`) 和创建全局图例。 | `set_suptitle()`, `add_global_legend()` |
|
|
87
92
|
| **共享颜色条**<br/> `Features_Customization/heatmap_colorbar_example.py` | 为多个热图创建一个共享的、能反映全局数据范围的颜色条。 | `add_heatmap(cbar=False)`, `cleanup_heatmaps()` |
|
|
@@ -131,4 +136,4 @@ plotter.save("quick_start_figure.png")
|
|
|
131
136
|
|
|
132
137
|
## 许可证
|
|
133
138
|
|
|
134
|
-
本项目采用 [MIT License](LICENSE)授权。
|
|
139
|
+
本项目采用 [MIT License](LICENSE)授权。
|
|
Binary file
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# examples/Layout/declarative_nested_layout_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
|
+
# 主图数据
|
|
12
|
+
df_line = pd.DataFrame({
|
|
13
|
+
'x': np.linspace(0, 2 * np.pi, 100),
|
|
14
|
+
'y': np.sin(np.linspace(0, 2 * np.pi, 100))
|
|
15
|
+
})
|
|
16
|
+
# 子网格的热图数据
|
|
17
|
+
heatmap_data_1 = pd.DataFrame(np.random.rand(8, 50))
|
|
18
|
+
heatmap_data_2 = pd.DataFrame(np.random.rand(8, 50))
|
|
19
|
+
heatmap_data_3 = pd.DataFrame(np.random.rand(8, 50))
|
|
20
|
+
# Y轴标签
|
|
21
|
+
y_labels = ['~NH₂', 'v(C-N-C)', 'v(C-C)ring']
|
|
22
|
+
all_heatmap_data = [heatmap_data_1, heatmap_data_2, heatmap_data_3]
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
# --- 2. 使用字典声明式地定义整个嵌套布局 ---
|
|
26
|
+
# 这是新API的核心:一个字典描述了所有层级和结构
|
|
27
|
+
nested_layout = {
|
|
28
|
+
# 'main' 定义了顶层 1x2 布局
|
|
29
|
+
'main': [
|
|
30
|
+
['main_plot', 'heatmap_group']
|
|
31
|
+
],
|
|
32
|
+
# 'subgrids' 定义了 'heatmap_group' 区域如何被再次划分
|
|
33
|
+
'subgrids': {
|
|
34
|
+
'heatmap_group': {
|
|
35
|
+
# 'layout' 定义了 3x1 的内部网格,并为每个单元命名
|
|
36
|
+
'layout': [
|
|
37
|
+
['nh2_map'],
|
|
38
|
+
['cnc_map'],
|
|
39
|
+
['ring_map']
|
|
40
|
+
],
|
|
41
|
+
# 'hspace' 控制这个子网格内部的垂直间距,使其紧凑
|
|
42
|
+
'hspace': 0.05
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# --- 3. 初始化 Plotter ---
|
|
48
|
+
# 直接将定义好的字典传给 layout 参数
|
|
49
|
+
# layout_engine=None 确保我们可以手动控制间距
|
|
50
|
+
plotter = pp.Plotter(layout=nested_layout, figsize=(12, 6), layout_engine=None)
|
|
51
|
+
plotter.set_suptitle("Declarative Nested Layout Example", fontsize=16, weight='bold')
|
|
52
|
+
|
|
53
|
+
# --- 4. 填充主图区域 ---
|
|
54
|
+
# 直接使用顶层布局中定义的名字 'main_plot' 作为 tag
|
|
55
|
+
plotter.add_line(data=df_line, x='x', y='y', tag='main_plot')
|
|
56
|
+
plotter.set_title('main_plot', 'Standard Plot')
|
|
57
|
+
plotter.set_xlabel('main_plot', 'X-axis')
|
|
58
|
+
plotter.set_ylabel('main_plot', 'Y-axis')
|
|
59
|
+
|
|
60
|
+
# --- 5. 填充子网格区域 ---
|
|
61
|
+
# 使用 '容器名.子图名' 的层级结构来直接引用嵌套的子图
|
|
62
|
+
subgrid_names = ['nh2_map', 'cnc_map', 'ring_map']
|
|
63
|
+
for i, sub_name in enumerate(subgrid_names):
|
|
64
|
+
# 构造层级 tag, e.g., 'heatmap_group.nh2_map'
|
|
65
|
+
hierarchical_tag = f"heatmap_group.{sub_name}"
|
|
66
|
+
|
|
67
|
+
plotter.add_heatmap(data=all_heatmap_data[i], tag=hierarchical_tag)
|
|
68
|
+
plotter.set_ylabel(hierarchical_tag, y_labels[i], fontsize=14, weight='bold')
|
|
69
|
+
|
|
70
|
+
# --- 6. 对子网格进行精细化设置 ---
|
|
71
|
+
# a. 只在最顶部的子图上添加标题
|
|
72
|
+
plotter.set_title('heatmap_group.nh2_map', 'Nested Heatmap Group', fontsize=14)
|
|
73
|
+
|
|
74
|
+
# b. 隐藏不需要的 X 轴刻度标签,实现共享X轴的效果
|
|
75
|
+
# (这里我们假设您已经实现了更精细的 hide_axes 或 tick_params)
|
|
76
|
+
plotter.tick_params('heatmap_group.nh2_map', axis='x', labelbottom=False)
|
|
77
|
+
plotter.tick_params('heatmap_group.cnc_map', axis='x', labelbottom=False)
|
|
78
|
+
|
|
79
|
+
# c. 只在最底部的子图上添加 X 轴标签
|
|
80
|
+
plotter.set_xlabel('heatmap_group.ring_map', 'Time (min)', fontsize=14, weight='bold')
|
|
81
|
+
|
|
82
|
+
# --- 7. 保存图像 ---
|
|
83
|
+
plotter.save("declarative_nested_layout.png")
|
|
84
|
+
|
|
85
|
+
except (pp.PaperPlotError, ValueError, KeyError) as e:
|
|
86
|
+
print(f"\nAn error occurred:\n{e}")
|
|
87
|
+
finally:
|
|
88
|
+
plt.close('all')
|
|
89
|
+
|
|
90
|
+
print(f"\n--- Finished Example: {__file__} ---")
|
|
91
|
+
print("A new file 'declarative_nested_layout.png' was generated.")
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
|
|
3
|
+
from matplotlib.gridspec import GridSpecFromSubplotSpec
|
|
4
|
+
|
|
2
5
|
logger = logging.getLogger(__name__)
|
|
3
6
|
from typing import Optional, Union, List, Tuple, Callable, Dict
|
|
4
7
|
import matplotlib.pyplot as plt
|
|
@@ -91,7 +94,9 @@ class Plotter(GenericPlotsMixin, ModifiersMixin, DomainSpecificPlotsMixin):
|
|
|
91
94
|
self.axes_dict: Dict[Union[str, int], plt.Axes] = {}
|
|
92
95
|
self.axes: List[plt.Axes] = []
|
|
93
96
|
|
|
94
|
-
if isinstance(layout,
|
|
97
|
+
if isinstance(layout, dict):
|
|
98
|
+
self._create_nested_layout(layout)
|
|
99
|
+
elif isinstance(layout, tuple) and len(layout) == 2:
|
|
95
100
|
n_rows, n_cols = layout
|
|
96
101
|
for r in range(n_rows):
|
|
97
102
|
for c in range(n_cols):
|
|
@@ -114,11 +119,58 @@ class Plotter(GenericPlotsMixin, ModifiersMixin, DomainSpecificPlotsMixin):
|
|
|
114
119
|
else:
|
|
115
120
|
raise ValueError("Invalid layout format. Must be (rows, cols) tuple or list of lists for mosaic.")
|
|
116
121
|
|
|
117
|
-
self.tag_to_ax: Dict[Union[str, int], plt.Axes] = {} # This will store user-assigned tags to actual axes
|
|
122
|
+
# self.tag_to_ax: Dict[Union[str, int], plt.Axes] = {} # This will store user-assigned tags to actual axes
|
|
123
|
+
self.tag_to_ax = self.axes_dict.copy()
|
|
124
|
+
|
|
118
125
|
self.tag_to_mappable: Dict[Union[str, int], plt.cm.ScalarMappable] = {}
|
|
119
126
|
self.current_ax_index: int = 0
|
|
120
127
|
self.next_default_tag: int = 1
|
|
121
128
|
|
|
129
|
+
def _create_nested_layout(self, layout_def: Dict):
|
|
130
|
+
"""
|
|
131
|
+
[私有] 根据声明式定义,递归创建嵌套布局。
|
|
132
|
+
"""
|
|
133
|
+
main_layout_list = layout_def['main']
|
|
134
|
+
subgrids_def = layout_def.get('subgrids', {})
|
|
135
|
+
|
|
136
|
+
# 1. 创建主网格
|
|
137
|
+
parsed_main_layout, (n_rows, n_cols) = utils.parse_mosaic_layout(main_layout_list)
|
|
138
|
+
main_gs = self.fig.add_gridspec(n_rows, n_cols)
|
|
139
|
+
|
|
140
|
+
# 2. 遍历主网格中的所有命名区域
|
|
141
|
+
for name, spec in parsed_main_layout.items():
|
|
142
|
+
|
|
143
|
+
# 检查这个区域是否需要被进一步划分为子网格
|
|
144
|
+
if name in subgrids_def:
|
|
145
|
+
# --- 是一个容器,需要创建子网格 ---
|
|
146
|
+
subgrid_info = subgrids_def[name]
|
|
147
|
+
sub_layout_list = subgrid_info['layout']
|
|
148
|
+
subgrid_kwargs = {k: v for k, v in subgrid_info.items() if k != 'layout'}
|
|
149
|
+
|
|
150
|
+
# 创建 GridSpecFromSubplotSpec
|
|
151
|
+
main_subplot_spec = main_gs[spec['row_start']:spec['row_start'] + spec['row_span'],
|
|
152
|
+
spec['col_start']:spec['col_start'] + spec['col_span']]
|
|
153
|
+
|
|
154
|
+
parsed_sub_layout, (sub_rows, sub_cols) = utils.parse_mosaic_layout(sub_layout_list)
|
|
155
|
+
sub_gs = GridSpecFromSubplotSpec(sub_rows, sub_cols, subplot_spec=main_subplot_spec, **subgrid_kwargs)
|
|
156
|
+
|
|
157
|
+
# 在子网格中创建最终的 Axes
|
|
158
|
+
for sub_name, sub_spec in parsed_sub_layout.items():
|
|
159
|
+
# 生成层级名称,例如:'heatmap_container.nh2_map'
|
|
160
|
+
hierarchical_name = f"{name}.{sub_name}"
|
|
161
|
+
|
|
162
|
+
ax = self.fig.add_subplot(sub_gs[sub_spec['row_start']:sub_spec['row_start'] + sub_spec['row_span'],
|
|
163
|
+
sub_spec['col_start']:sub_spec['col_start'] + sub_spec['col_span']])
|
|
164
|
+
|
|
165
|
+
self.axes_dict[hierarchical_name] = ax
|
|
166
|
+
self.axes.append(ax)
|
|
167
|
+
|
|
168
|
+
else:
|
|
169
|
+
ax = self.fig.add_subplot(main_gs[spec['row_start']:spec['row_start'] + spec['row_span'],
|
|
170
|
+
spec['col_start']:spec['col_start'] + spec['col_span']])
|
|
171
|
+
self.axes_dict[name] = ax
|
|
172
|
+
self.axes.append(ax)
|
|
173
|
+
|
|
122
174
|
def _get_ax_by_tag(self, tag: Union[str, int]) -> plt.Axes:
|
|
123
175
|
"""
|
|
124
176
|
通过tag获取对应的Axes对象。
|
|
@@ -139,29 +191,32 @@ class Plotter(GenericPlotsMixin, ModifiersMixin, DomainSpecificPlotsMixin):
|
|
|
139
191
|
def _get_next_ax_and_assign_tag(self, tag: Optional[Union[str, int]] = None) -> Tuple[plt.Axes, Union[str, int]]:
|
|
140
192
|
"""
|
|
141
193
|
获取下一个可用的Axes对象,并为其分配一个tag。
|
|
194
|
+
此方法用于顺序绘图模式。
|
|
142
195
|
"""
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
ax_to_use = None
|
|
146
|
-
while self.current_ax_index < len(self.axes):
|
|
147
|
-
potential_ax = self.axes[self.current_ax_index]
|
|
148
|
-
if potential_ax not in claimed_axes:
|
|
149
|
-
ax_to_use = potential_ax
|
|
150
|
-
break
|
|
151
|
-
self.current_ax_index += 1
|
|
152
|
-
|
|
153
|
-
if ax_to_use is None:
|
|
196
|
+
# 步骤 1: 检查索引是否已经超出了可用 Axes 的范围。
|
|
197
|
+
if self.current_ax_index >= len(self.axes):
|
|
154
198
|
raise PlottingSpaceError(len(self.axes))
|
|
155
199
|
|
|
200
|
+
# 步骤 2: 根据当前索引直接获取下一个 Axes。
|
|
201
|
+
# 我们不再检查它是否已被“认领”,因为我们就是要覆盖或赋予它新标签。
|
|
202
|
+
ax_to_use = self.axes[self.current_ax_index]
|
|
203
|
+
|
|
204
|
+
# 步骤 3: 处理并检查新标签是否重复。
|
|
156
205
|
current_tag = tag if tag is not None else self.next_default_tag
|
|
157
206
|
if current_tag in self.tag_to_ax:
|
|
207
|
+
# 顺序绘图模式下,一个已经存在的标签意味着重复,这是不允许的。
|
|
208
|
+
# 声明式模式会在 _resolve_ax 中被提前捕获,不会进入此方法。
|
|
158
209
|
raise DuplicateTagError(current_tag)
|
|
159
|
-
|
|
210
|
+
|
|
160
211
|
if tag is None:
|
|
161
212
|
self.next_default_tag += 1
|
|
162
|
-
|
|
213
|
+
|
|
214
|
+
# 步骤 4: 将新标签与选定的 Axes 关联起来。
|
|
163
215
|
self.tag_to_ax[current_tag] = ax_to_use
|
|
216
|
+
|
|
217
|
+
# 步骤 5: 将索引向前移动,为下一次调用做准备。
|
|
164
218
|
self.current_ax_index += 1
|
|
219
|
+
|
|
165
220
|
return ax_to_use, current_tag
|
|
166
221
|
|
|
167
222
|
def get_ax(self, tag: Union[str, int]) -> plt.Axes:
|
|
@@ -178,3 +233,22 @@ class Plotter(GenericPlotsMixin, ModifiersMixin, DomainSpecificPlotsMixin):
|
|
|
178
233
|
available_names = list(self.axes_dict.keys()) if isinstance(self.axes_dict, dict) else []
|
|
179
234
|
raise ValueError(f"Name '{name}' not found in layout. Available names are: {available_names}")
|
|
180
235
|
return self.axes_dict[name]
|
|
236
|
+
|
|
237
|
+
def _resolve_ax(self, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None) -> plt.Axes:
|
|
238
|
+
"""[私有] 智能解析并返回正确的 Axes 对象。"""
|
|
239
|
+
_ax: plt.Axes
|
|
240
|
+
if ax is not None:
|
|
241
|
+
_ax = ax
|
|
242
|
+
# 如果用户同时提供了 ax 和 tag,需要注册这个关联
|
|
243
|
+
if tag is not None:
|
|
244
|
+
# 检查是否存在冲突
|
|
245
|
+
if tag in self.tag_to_ax and self.tag_to_ax[tag] is not _ax:
|
|
246
|
+
raise DuplicateTagError(tag)
|
|
247
|
+
self.tag_to_ax[tag] = _ax
|
|
248
|
+
elif tag is not None and tag in self.tag_to_ax:
|
|
249
|
+
# tag 在布局时已定义,直接使用
|
|
250
|
+
_ax = self.tag_to_ax[tag]
|
|
251
|
+
else:
|
|
252
|
+
# ax 未提供,tag 也是新的或 None,按顺序分配
|
|
253
|
+
_ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
254
|
+
return _ax
|
|
@@ -31,16 +31,11 @@ class DomainSpecificPlotsMixin:
|
|
|
31
31
|
Returns:
|
|
32
32
|
Plotter: 返回Plotter实例以支持链式调用。
|
|
33
33
|
"""
|
|
34
|
-
|
|
35
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
36
|
-
elif tag is not None:
|
|
37
|
-
if tag in self.tag_to_ax:
|
|
38
|
-
raise DuplicateTagError(tag)
|
|
39
|
-
self.tag_to_ax[tag] = ax
|
|
34
|
+
_ax = self._resolve_ax(tag, ax)
|
|
40
35
|
|
|
41
36
|
for i, y_col in enumerate(y_cols):
|
|
42
37
|
label = kwargs.pop('label', y_col) # 如果用户没有提供label,则使用列名
|
|
43
|
-
|
|
38
|
+
_ax.plot(data[x], data[y_col] + i * offset, label=label, **kwargs)
|
|
44
39
|
|
|
45
40
|
return self
|
|
46
41
|
|
|
@@ -61,24 +56,19 @@ class DomainSpecificPlotsMixin:
|
|
|
61
56
|
Returns:
|
|
62
57
|
Plotter: 返回Plotter实例以支持链式调用。
|
|
63
58
|
"""
|
|
64
|
-
|
|
65
|
-
ax, tag = self._get_next_ax_and_assign_tag(tag)
|
|
66
|
-
elif tag is not None:
|
|
67
|
-
if tag in self.tag_to_ax:
|
|
68
|
-
raise DuplicateTagError(tag)
|
|
69
|
-
self.tag_to_ax[tag] = ax
|
|
59
|
+
_ax = self._resolve_ax(tag, ax)
|
|
70
60
|
|
|
71
61
|
create_cbar = kwargs.pop('cbar', True)
|
|
72
62
|
kwargs.setdefault('cmap', 'inferno') # 默认使用 inferno 颜色映射
|
|
73
63
|
|
|
74
64
|
import seaborn as sns
|
|
75
|
-
sns.heatmap(data, ax=
|
|
65
|
+
sns.heatmap(data, ax=_ax, cbar=create_cbar, **kwargs)
|
|
76
66
|
|
|
77
|
-
if tag and
|
|
78
|
-
self.tag_to_mappable[tag] =
|
|
67
|
+
if tag and _ax.collections:
|
|
68
|
+
self.tag_to_mappable[tag] = _ax.collections[0]
|
|
79
69
|
|
|
80
|
-
|
|
81
|
-
|
|
70
|
+
_ax.set_xlabel(kwargs.pop('xlabel', 'X (μm)'))
|
|
71
|
+
_ax.set_ylabel(kwargs.pop('ylabel', 'Y (μm)'))
|
|
82
72
|
|
|
83
73
|
return self
|
|
84
74
|
|
|
@@ -101,12 +91,7 @@ class DomainSpecificPlotsMixin:
|
|
|
101
91
|
Returns:
|
|
102
92
|
Plotter: 返回Plotter实例以支持链式调用。
|
|
103
93
|
"""
|
|
104
|
-
|
|
105
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
106
|
-
elif tag is not None:
|
|
107
|
-
if tag in self.tag_to_ax:
|
|
108
|
-
raise DuplicateTagError(tag)
|
|
109
|
-
self.tag_to_ax[tag] = ax
|
|
94
|
+
_ax = self._resolve_ax(tag, ax)
|
|
110
95
|
|
|
111
96
|
if normalize:
|
|
112
97
|
matrix = matrix.astype('float') / matrix.sum(axis=1)[:, np.newaxis]
|
|
@@ -121,10 +106,10 @@ class DomainSpecificPlotsMixin:
|
|
|
121
106
|
kwargs.setdefault('fmt', fmt)
|
|
122
107
|
kwargs.setdefault('cmap', 'Blues')
|
|
123
108
|
|
|
124
|
-
sns.heatmap(df_cm, ax=
|
|
109
|
+
sns.heatmap(df_cm, ax=_ax, **kwargs)
|
|
125
110
|
|
|
126
|
-
|
|
127
|
-
|
|
111
|
+
_ax.set_xlabel('Predicted Label')
|
|
112
|
+
_ax.set_ylabel('True Label')
|
|
128
113
|
|
|
129
114
|
return self
|
|
130
115
|
|
|
@@ -145,27 +130,22 @@ class DomainSpecificPlotsMixin:
|
|
|
145
130
|
Returns:
|
|
146
131
|
Plotter: 返回Plotter实例以支持链式调用。
|
|
147
132
|
"""
|
|
148
|
-
|
|
149
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
150
|
-
elif tag is not None:
|
|
151
|
-
if tag in self.tag_to_ax:
|
|
152
|
-
raise DuplicateTagError(tag)
|
|
153
|
-
self.tag_to_ax[tag] = ax
|
|
133
|
+
_ax = self._resolve_ax(tag, ax)
|
|
154
134
|
|
|
155
135
|
# 绘制每个类别的ROC曲线
|
|
156
136
|
for key in fpr.keys():
|
|
157
137
|
label = f'{key} (AUC = {roc_auc[key]:.2f})'
|
|
158
|
-
|
|
138
|
+
_ax.plot(fpr[key], tpr[key], label=label, **kwargs)
|
|
159
139
|
|
|
160
140
|
# 绘制对角参考线
|
|
161
|
-
|
|
141
|
+
_ax.plot([0, 1], [0, 1], 'k--', lw=2)
|
|
162
142
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
143
|
+
_ax.set_xlim([0.0, 1.0])
|
|
144
|
+
_ax.set_ylim([0.0, 1.05])
|
|
145
|
+
_ax.set_xlabel('False Positive Rate')
|
|
146
|
+
_ax.set_ylabel('True Positive Rate')
|
|
147
|
+
_ax.set_title('Receiver Operating Characteristic (ROC) Curve')
|
|
148
|
+
_ax.legend(loc="lower right")
|
|
169
149
|
|
|
170
150
|
return self
|
|
171
151
|
|
|
@@ -188,15 +168,10 @@ class DomainSpecificPlotsMixin:
|
|
|
188
168
|
Returns:
|
|
189
169
|
Plotter: 返回Plotter实例以支持链式调用。
|
|
190
170
|
"""
|
|
191
|
-
|
|
192
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
193
|
-
elif tag is not None:
|
|
194
|
-
if tag in self.tag_to_ax:
|
|
195
|
-
raise DuplicateTagError(tag)
|
|
196
|
-
self.tag_to_ax[tag] = ax
|
|
171
|
+
_ax = self._resolve_ax(tag, ax)
|
|
197
172
|
|
|
198
173
|
import seaborn as sns
|
|
199
|
-
sns.scatterplot(data=data, x=x_pc, y=y_pc, hue=hue, ax=
|
|
174
|
+
sns.scatterplot(data=data, x=x_pc, y=y_pc, hue=hue, ax=_ax, **kwargs)
|
|
200
175
|
|
|
201
176
|
return self
|
|
202
177
|
|
|
@@ -221,31 +196,26 @@ class DomainSpecificPlotsMixin:
|
|
|
221
196
|
Returns:
|
|
222
197
|
Plotter: 返回Plotter实例以支持链式调用。
|
|
223
198
|
"""
|
|
224
|
-
|
|
225
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
226
|
-
elif tag is not None:
|
|
227
|
-
if tag in self.tag_to_ax:
|
|
228
|
-
raise DuplicateTagError(tag)
|
|
229
|
-
self.tag_to_ax[tag] = ax
|
|
199
|
+
_ax = self._resolve_ax(tag, ax)
|
|
230
200
|
|
|
231
201
|
# 绘制时间序列线
|
|
232
202
|
for y_col in y_cols:
|
|
233
203
|
label = kwargs.pop('label', y_col)
|
|
234
|
-
|
|
204
|
+
_ax.plot(data[x], data[y_col], label=label, **kwargs)
|
|
235
205
|
|
|
236
206
|
# 标记事件
|
|
237
207
|
if events and isinstance(events, dict):
|
|
238
208
|
utils.add_event_markers(
|
|
239
|
-
ax=
|
|
209
|
+
ax=_ax,
|
|
240
210
|
event_dates=list(events.values()),
|
|
241
211
|
labels=list(events.keys())
|
|
242
212
|
)
|
|
243
213
|
|
|
244
214
|
# 设置默认标签和图例
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if any(
|
|
248
|
-
|
|
215
|
+
_ax.set_xlabel(kwargs.pop('xlabel', 'Time (s)'))
|
|
216
|
+
_ax.set_ylabel(kwargs.pop('ylabel', 'Value'))
|
|
217
|
+
if any(_ax.get_legend_handles_labels()):
|
|
218
|
+
_ax.legend()
|
|
249
219
|
|
|
250
220
|
return self
|
|
251
221
|
|
|
@@ -276,21 +246,23 @@ class DomainSpecificPlotsMixin:
|
|
|
276
246
|
DuplicateTagError: 如果尝试使用一个已经存在的tag。
|
|
277
247
|
TagNotFoundError: 如果指定的tag未找到。
|
|
278
248
|
"""
|
|
249
|
+
_ax = self._resolve_ax(tag, ax)
|
|
250
|
+
|
|
279
251
|
if len(magnitudes) != len(angles):
|
|
280
252
|
raise ValueError("Magnitudes and angles lists must have the same length.")
|
|
281
253
|
|
|
282
254
|
_target_ax: plt.Axes
|
|
283
255
|
_assigned_tag: Union[str, int]
|
|
284
256
|
|
|
285
|
-
if
|
|
257
|
+
if _ax is None:
|
|
286
258
|
_target_ax, _assigned_tag = self._get_next_ax_and_assign_tag(tag)
|
|
287
259
|
else:
|
|
288
260
|
if tag is None:
|
|
289
261
|
raise ValueError("When 'ax' is explicitly provided, a 'tag' must also be provided.")
|
|
290
|
-
if tag in self.tag_to_ax and self.tag_to_ax[tag] !=
|
|
262
|
+
if tag in self.tag_to_ax and self.tag_to_ax[tag] != _ax:
|
|
291
263
|
raise DuplicateTagError(tag)
|
|
292
|
-
self.tag_to_ax[tag] =
|
|
293
|
-
_target_ax =
|
|
264
|
+
self.tag_to_ax[tag] = _ax
|
|
265
|
+
_target_ax = _ax
|
|
294
266
|
_assigned_tag = tag
|
|
295
267
|
|
|
296
268
|
# 检查轴是否为极坐标投影
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# paperplot/mixins/generic.py
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Union, List, Callable
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
from ..exceptions import DuplicateTagError
|
|
7
|
+
|
|
8
|
+
class GenericPlotsMixin:
|
|
9
|
+
"""
|
|
10
|
+
包含通用绘图方法的 Mixin 类。
|
|
11
|
+
这些方法是常见图表类型(如线图、散点图、柱状图等)的直接封装。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def add_line(self, data: pd.DataFrame, x: str, y: str, tag: Optional[Union[str, int]] = None,
|
|
15
|
+
ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
16
|
+
"""在子图上绘制线图。"""
|
|
17
|
+
_ax = self._resolve_ax(tag, ax)
|
|
18
|
+
_ax.plot(data[x], data[y], **kwargs)
|
|
19
|
+
return self
|
|
20
|
+
|
|
21
|
+
def add_bar(self, data: pd.DataFrame, x: str, y: str, y_err: Optional[str] = None,
|
|
22
|
+
tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
23
|
+
"""在子图上绘制柱状图。"""
|
|
24
|
+
_ax = self._resolve_ax(tag, ax)
|
|
25
|
+
y_error_values = data[y_err] if y_err and y_err in data else None
|
|
26
|
+
_ax.bar(data[x], data[y], yerr=y_error_values, **kwargs)
|
|
27
|
+
return self
|
|
28
|
+
|
|
29
|
+
def add_scatter(self, data: pd.DataFrame, x: str, y: str, tag: Optional[Union[str, int]] = None,
|
|
30
|
+
ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
31
|
+
"""在子图上绘制散点图。"""
|
|
32
|
+
_ax = self._resolve_ax(tag, ax)
|
|
33
|
+
|
|
34
|
+
resolved_kwargs = kwargs.copy()
|
|
35
|
+
for param in ['s', 'c']:
|
|
36
|
+
if param in resolved_kwargs and isinstance(resolved_kwargs[param], str):
|
|
37
|
+
column_name = resolved_kwargs[param]
|
|
38
|
+
if column_name in data.columns:
|
|
39
|
+
resolved_kwargs[param] = data[column_name]
|
|
40
|
+
|
|
41
|
+
_ax.scatter(data[x], data[y], **resolved_kwargs)
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
def add_hist(self, data: pd.DataFrame, x: str, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None,
|
|
45
|
+
**kwargs) -> 'Plotter':
|
|
46
|
+
"""在子图上绘制直方图。"""
|
|
47
|
+
_ax = self._resolve_ax(tag, ax)
|
|
48
|
+
_ax.hist(data[x], **kwargs)
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def add_box(self, data: pd.DataFrame, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None,
|
|
52
|
+
**kwargs) -> 'Plotter':
|
|
53
|
+
"""在子图上绘制箱线图。"""
|
|
54
|
+
_ax = self._resolve_ax(tag, ax)
|
|
55
|
+
import seaborn as sns
|
|
56
|
+
sns.boxplot(data=data, ax=_ax, **kwargs)
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
def add_heatmap(self, data: pd.DataFrame, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None,
|
|
60
|
+
**kwargs) -> 'Plotter':
|
|
61
|
+
"""在子图上绘制热图。"""
|
|
62
|
+
_ax = self._resolve_ax(tag, ax)
|
|
63
|
+
|
|
64
|
+
create_cbar = kwargs.pop('cbar', True)
|
|
65
|
+
import seaborn as sns
|
|
66
|
+
sns.heatmap(data, ax=_ax, cbar=create_cbar, **kwargs)
|
|
67
|
+
|
|
68
|
+
# 确保 tag 被正确赋值以便后续使用
|
|
69
|
+
resolved_tag = tag if tag is not None else [k for k, v in self.tag_to_ax.items() if v is _ax][-1]
|
|
70
|
+
|
|
71
|
+
if resolved_tag and hasattr(_ax, 'collections') and _ax.collections:
|
|
72
|
+
self.tag_to_mappable[resolved_tag] = _ax.collections[0]
|
|
73
|
+
|
|
74
|
+
return self
|
|
75
|
+
|
|
76
|
+
def add_seaborn(self, plot_func: Callable, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None,
|
|
77
|
+
**kwargs) -> 'Plotter':
|
|
78
|
+
"""在子图上绘制Seaborn图。"""
|
|
79
|
+
_ax = self._resolve_ax(tag, ax)
|
|
80
|
+
plot_func(ax=_ax, **kwargs)
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
def add_blank(self, tag: Optional[Union[str, int]] = None) -> 'Plotter':
|
|
84
|
+
"""在下一个可用的子图位置创建一个空白区域。"""
|
|
85
|
+
_ax = self._resolve_ax(tag)
|
|
86
|
+
_ax.axis('off')
|
|
87
|
+
return self
|
|
88
|
+
|
|
89
|
+
def add_regplot(self, data: pd.DataFrame, x: str, y: str, tag: Optional[str] = None, ax: Optional[plt.Axes] = None,
|
|
90
|
+
**kwargs) -> 'Plotter':
|
|
91
|
+
"""绘制散点图和线性回归趋势线。"""
|
|
92
|
+
_ax = self._resolve_ax(tag, ax)
|
|
93
|
+
import seaborn as sns
|
|
94
|
+
sns.regplot(data=data, x=x, y=y, ax=_ax, **kwargs)
|
|
95
|
+
return self
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: paperplotter
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: 一个为科研论文设计的声明式 Matplotlib 封装库,让复杂图表的创建变得简单直观。
|
|
5
5
|
Author-email: VerNe <yuu_seeing@foxmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -36,6 +36,7 @@ Dynamic: license-file
|
|
|
36
36
|
* **🎨 声明式链式调用**: 像写句子一样构建你的图表,例如 `plotter.add_line(...).set_title(...).set_xlabel(...)`。
|
|
37
37
|
* **🏷️ 基于标签的控制**: 给每个子图一个独一无二的 `tag`,之后就可以随时通过 `tag` 对其进行任何修改,告别混乱的 `axes[i][j]` 索引。
|
|
38
38
|
* **🧩 强大的布局系统**: 无论是简单的 `(行, 列)` 网格,还是使用 `mosaic` 实现的跨行跨列复杂布局,都能轻松定义。
|
|
39
|
+
* **🧱 声明式嵌套布局**: 通过一个字典即可一次性定义包含子网格的复杂层级布局,并使用 `'容器.子图'` 这样的直观路径进行引用,完美实现“图中图”。
|
|
39
40
|
* **📐 灵活的尺寸控制**: 除了传统的 `figsize`,还可以通过 `subplot_aspect` 指定子图单元格的宽高比,让 `PaperPlot` 自动计算最合适的画布尺寸。
|
|
40
41
|
* **✨ 内置科研主题**: 提供多种专业美观的内置样式,如 `publication`, `presentation` 等,一键切换图表风格。
|
|
41
42
|
* **🌐 全局图层级标注**: 提供了在整个画布(Figure)上添加文本、线条、方框和标签的 API,非常适合添加全局注释或高亮一组图表。
|
|
@@ -68,10 +69,13 @@ df_scatter = pd.DataFrame({
|
|
|
68
69
|
})
|
|
69
70
|
|
|
70
71
|
# 2. 初始化 Plotter 并绘图
|
|
72
|
+
# 对于简单布局,可以直接使用元组 (rows, cols)
|
|
71
73
|
plotter = pp.Plotter(layout=(1, 2), figsize=(10, 4))
|
|
72
74
|
|
|
73
|
-
# 3.
|
|
75
|
+
# 3. 顺序添加图表,Plotter会自动填充网格
|
|
76
|
+
# 第一次调用 add_line 会画在左边
|
|
74
77
|
plotter.add_line(data=df_line, x='time', y='signal', tag='time_series')
|
|
78
|
+
# 第二次调用 add_scatter 会画在右边
|
|
75
79
|
plotter.add_scatter(data=df_scatter, x='x', y='y', tag='scatter_plot')
|
|
76
80
|
|
|
77
81
|
# 4. 通过 tag 设置标题和标签
|
|
@@ -96,7 +100,8 @@ plotter.save("quick_start_figure.png")
|
|
|
96
100
|
|
|
97
101
|
| 示例 | 描述 | 关键功能 |
|
|
98
102
|
| :--- | :--- | :--- |
|
|
99
|
-
|
|
|
103
|
+
| **声明式嵌套布局**<br/> `Layout/declarative_nested_layout_example.py` | 使用字典来声明式地定义一个包含子网格的复杂、多层级布局,实现“图中图”的效果。 | `layout={...}`<br/> `tag='容器.子图'` |
|
|
104
|
+
| **高级布局**<br/> `Layout/advanced_layout_example.py` | 展示如何使用列表定义一个跨列的复杂布局。 | `layout=[['A', 'B', 'B'], ...]` |
|
|
100
105
|
| **行跨越**<br/> `Layout/row_span_example.py` | 创建一个图表,其中某个子图跨越多行。 | `layout=[['A', 'B'], ['A', 'C']]` |
|
|
101
106
|
| **块跨越**<br/> `Layout/block_span_example.py` | 创建一个图表,其中某个子图同时跨越多行和多列。 | `layout=[['A', 'A', 'B'], ['A', 'A', 'C']]` |
|
|
102
107
|
| **固定子图宽高比**<br/> `Layout/aspect_ratio_example.py` | 在不指定 `figsize` 的情况下,通过 `subplot_aspect` 保证每个子图单元格的宽高比,Plotter 会自动计算画布大小。 | `subplot_aspect=(16, 9)` |
|
|
@@ -105,7 +110,7 @@ plotter.save("quick_start_figure.png")
|
|
|
105
110
|
|
|
106
111
|
| 示例 | 描述 | 关键功能 |
|
|
107
112
|
| :--- | :--- | :--- |
|
|
108
|
-
| **多图网格**<br/> `Features_Customization/multi_plot_grid.py` |
|
|
113
|
+
| **多图网格**<br/> `Features_Customization/multi_plot_grid.py` | 在一个网格中通过链式调用混合绘制不同类型的图表。 | `plotter.add_...().add_...()` |
|
|
109
114
|
| **高级定制**<br/> `Features_Customization/advanced_customization.py` | 演示如何使用 `get_ax()` "逃生舱口" 来获取原生的 Matplotlib `Axes` 对象,并添加任意 `Patch`(如椭圆)。 | `get_ax()`, `ax.add_patch()` |
|
|
110
115
|
| **全局控制**<br/> `Features_Customization/global_controls_example.py` | 展示如何设置全局标题 (`suptitle`) 和创建全局图例。 | `set_suptitle()`, `add_global_legend()` |
|
|
111
116
|
| **共享颜色条**<br/> `Features_Customization/heatmap_colorbar_example.py` | 为多个热图创建一个共享的、能反映全局数据范围的颜色条。 | `add_heatmap(cbar=False)`, `cleanup_heatmaps()` |
|
|
@@ -48,6 +48,8 @@ examples/Layout/aspect_ratio_mosaic.png
|
|
|
48
48
|
examples/Layout/aspect_ratio_simple_grid.png
|
|
49
49
|
examples/Layout/block_span_example.py
|
|
50
50
|
examples/Layout/block_span_figure.png
|
|
51
|
+
examples/Layout/declarative_nested_layout.png
|
|
52
|
+
examples/Layout/declarative_nested_layout_example.py
|
|
51
53
|
examples/Layout/row_span_example.py
|
|
52
54
|
examples/Layout/row_span_figure.png
|
|
53
55
|
examples/Styles_Aesthetics/aesthetic_and_processing_example.png
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
# paperplot/mixins/generic.py
|
|
2
|
-
|
|
3
|
-
from typing import Optional, Union, List, Callable
|
|
4
|
-
import pandas as pd
|
|
5
|
-
import matplotlib.pyplot as plt
|
|
6
|
-
from ..exceptions import DuplicateTagError
|
|
7
|
-
|
|
8
|
-
class GenericPlotsMixin:
|
|
9
|
-
"""
|
|
10
|
-
包含通用绘图方法的 Mixin 类。
|
|
11
|
-
这些方法是常见图表类型(如线图、散点图、柱状图等)的直接封装。
|
|
12
|
-
"""
|
|
13
|
-
def add_line(self, data: pd.DataFrame, x: str, y: str, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
14
|
-
"""
|
|
15
|
-
在子图上绘制线图。
|
|
16
|
-
"""
|
|
17
|
-
if ax is None:
|
|
18
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
19
|
-
elif tag is not None:
|
|
20
|
-
if tag in self.tag_to_ax:
|
|
21
|
-
raise DuplicateTagError(tag)
|
|
22
|
-
self.tag_to_ax[tag] = ax
|
|
23
|
-
ax.plot(data[x], data[y], **kwargs)
|
|
24
|
-
return self
|
|
25
|
-
|
|
26
|
-
def add_bar(self, data: pd.DataFrame, x: str, y: str, y_err: Optional[str] = None, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
27
|
-
"""
|
|
28
|
-
在子图上绘制柱状图。
|
|
29
|
-
"""
|
|
30
|
-
if ax is None:
|
|
31
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
32
|
-
elif tag is not None:
|
|
33
|
-
if tag in self.tag_to_ax:
|
|
34
|
-
raise DuplicateTagError(tag)
|
|
35
|
-
self.tag_to_ax[tag] = ax
|
|
36
|
-
y_error_values = data[y_err] if y_err and y_err in data else None
|
|
37
|
-
ax.bar(data[x], data[y], yerr=y_error_values, **kwargs)
|
|
38
|
-
return self
|
|
39
|
-
|
|
40
|
-
def add_scatter(self, data: pd.DataFrame, x: str, y: str, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
41
|
-
"""
|
|
42
|
-
在子图上绘制散点图。
|
|
43
|
-
"""
|
|
44
|
-
if ax is None:
|
|
45
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
46
|
-
elif tag is not None:
|
|
47
|
-
if tag in self.tag_to_ax:
|
|
48
|
-
raise DuplicateTagError(tag)
|
|
49
|
-
self.tag_to_ax[tag] = ax
|
|
50
|
-
|
|
51
|
-
resolved_kwargs = kwargs.copy()
|
|
52
|
-
for param in ['s', 'c']:
|
|
53
|
-
if param in resolved_kwargs and isinstance(resolved_kwargs[param], str):
|
|
54
|
-
column_name = resolved_kwargs[param]
|
|
55
|
-
if column_name in data.columns:
|
|
56
|
-
resolved_kwargs[param] = data[column_name]
|
|
57
|
-
|
|
58
|
-
ax.scatter(data[x], data[y], **resolved_kwargs)
|
|
59
|
-
return self
|
|
60
|
-
|
|
61
|
-
def add_hist(self, data: pd.DataFrame, x: str, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
62
|
-
"""
|
|
63
|
-
在子图上绘制直方图。
|
|
64
|
-
"""
|
|
65
|
-
if ax is None:
|
|
66
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
67
|
-
elif tag is not None:
|
|
68
|
-
if tag in self.tag_to_ax:
|
|
69
|
-
raise DuplicateTagError(tag)
|
|
70
|
-
self.tag_to_ax[tag] = ax
|
|
71
|
-
ax.hist(data[x], **kwargs)
|
|
72
|
-
return self
|
|
73
|
-
|
|
74
|
-
def add_box(self, data: pd.DataFrame, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
75
|
-
"""
|
|
76
|
-
在子图上绘制箱线图。
|
|
77
|
-
"""
|
|
78
|
-
if ax is None:
|
|
79
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
80
|
-
elif tag is not None:
|
|
81
|
-
if tag in self.tag_to_ax:
|
|
82
|
-
raise DuplicateTagError(tag)
|
|
83
|
-
self.tag_to_ax[tag] = ax
|
|
84
|
-
|
|
85
|
-
import seaborn as sns
|
|
86
|
-
sns.boxplot(data=data, ax=ax, **kwargs)
|
|
87
|
-
return self
|
|
88
|
-
|
|
89
|
-
def add_heatmap(self, data: pd.DataFrame, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
90
|
-
"""
|
|
91
|
-
在子图上绘制热图。
|
|
92
|
-
"""
|
|
93
|
-
if ax is None:
|
|
94
|
-
ax, tag = self._get_next_ax_and_assign_tag(tag)
|
|
95
|
-
elif tag is not None:
|
|
96
|
-
if tag in self.tag_to_ax:
|
|
97
|
-
raise DuplicateTagError(tag)
|
|
98
|
-
self.tag_to_ax[tag] = ax
|
|
99
|
-
|
|
100
|
-
create_cbar = kwargs.pop('cbar', True)
|
|
101
|
-
|
|
102
|
-
import seaborn as sns
|
|
103
|
-
sns.heatmap(data, ax=ax, cbar=create_cbar, **kwargs)
|
|
104
|
-
|
|
105
|
-
if tag and hasattr(ax, 'collections') and ax.collections:
|
|
106
|
-
self.tag_to_mappable[tag] = ax.collections[0]
|
|
107
|
-
|
|
108
|
-
return self
|
|
109
|
-
|
|
110
|
-
def add_seaborn(self, plot_func: Callable, tag: Optional[Union[str, int]] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
111
|
-
"""
|
|
112
|
-
在子图上绘制Seaborn图。
|
|
113
|
-
"""
|
|
114
|
-
if ax is None:
|
|
115
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
116
|
-
elif tag is not None:
|
|
117
|
-
if tag in self.tag_to_ax:
|
|
118
|
-
raise DuplicateTagError(tag)
|
|
119
|
-
self.tag_to_ax[tag] = ax
|
|
120
|
-
plot_func(ax=ax, **kwargs)
|
|
121
|
-
return self
|
|
122
|
-
|
|
123
|
-
def add_blank(self, tag: Optional[Union[str, int]] = None) -> 'Plotter':
|
|
124
|
-
"""
|
|
125
|
-
在下一个可用的子图位置创建一个空白区域。
|
|
126
|
-
"""
|
|
127
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
128
|
-
ax.axis('off')
|
|
129
|
-
return self
|
|
130
|
-
|
|
131
|
-
def add_regplot(self, data: pd.DataFrame, x: str, y: str, tag: Optional[str] = None, ax: Optional[plt.Axes] = None, **kwargs) -> 'Plotter':
|
|
132
|
-
"""
|
|
133
|
-
绘制散点图和线性回归趋势线。
|
|
134
|
-
"""
|
|
135
|
-
if ax is None:
|
|
136
|
-
ax, _ = self._get_next_ax_and_assign_tag(tag)
|
|
137
|
-
elif tag is not None:
|
|
138
|
-
if tag in self.tag_to_ax:
|
|
139
|
-
raise DuplicateTagError(tag)
|
|
140
|
-
self.tag_to_ax[tag] = ax
|
|
141
|
-
|
|
142
|
-
import seaborn as sns
|
|
143
|
-
sns.regplot(data=data, x=x, y=y, ax=ax, **kwargs)
|
|
144
|
-
return self
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Data_Analysis_Utils/utility_functions_example.png
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Data_Analysis_Utils/utility_functions_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/domain_specific_plots.png
RENAMED
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/learning_curve_example.png
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/learning_curve_example.py
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/phasor_diagram_example.png
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/phasor_diagram_example.py
RENAMED
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Domain_Specific_Plots/power_timeseries_example.py
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/advanced_customization.py
RENAMED
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/cleanup_demonstration.py
RENAMED
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/composite_figure.png
RENAMED
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/error_handling_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/fig_annotation_example.png
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/fig_annotation_example.py
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/fig_text_example.png
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/fig_text_example.py
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/global_controls_example.py
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/global_controls_figure.png
RENAMED
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/heatmap_default_figure.png
RENAMED
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/highlighting_example.png
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/highlighting_example.py
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/multi_plot_grid.py
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Features_Customization/multi_plot_grid_figure.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_presentation.png
RENAMED
|
File without changes
|
{paperplotter-0.1.3 → paperplotter-0.1.4}/examples/Styles_Aesthetics/style_gallery_publication.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|