scitex 2.3.0__py3-none-any.whl → 2.4.1__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.
- scitex/ai/classification/reporters/reporter_utils/_Plotter.py +1 -1
- scitex/ai/plt/__init__.py +2 -2
- scitex/ai/plt/{_plot_conf_mat.py → _stx_conf_mat.py} +3 -3
- scitex/config/PriorityConfig.py +195 -0
- scitex/config/__init__.py +24 -0
- scitex/io/_save.py +125 -34
- scitex/io/_save_modules/_image.py +37 -20
- scitex/plt/__init__.py +470 -17
- scitex/plt/_subplots/_AxisWrapper.py +98 -50
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +559 -124
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +49 -8
- scitex/plt/_subplots/_SubplotsWrapper.py +76 -91
- scitex/plt/_subplots/_export_as_csv.py +127 -58
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +25 -16
- scitex/plt/_subplots/_export_as_csv_formatters/_format_contourf.py +54 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hexbin.py +41 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hist2d.py +41 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow.py +59 -47
- scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +42 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_pie.py +42 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +72 -35
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_box.py +1 -1
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +53 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stem.py +42 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_step.py +42 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +48 -0
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_conf_mat.py → _format_stx_conf_mat.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_ecdf.py → _format_stx_ecdf.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_fillv.py → _format_stx_fillv.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_heatmap.py → _format_stx_heatmap.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_image.py → _format_stx_image.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_joyplot.py → _format_stx_joyplot.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_line.py → _format_stx_line.py} +3 -3
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_mean_ci.py → _format_stx_mean_ci.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_mean_std.py → _format_stx_mean_std.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_median_iqr.py → _format_stx_median_iqr.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_raster.py → _format_stx_raster.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_rectangle.py → _format_stx_rectangle.py} +1 -1
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_scatter_hist.py → _format_stx_scatter_hist.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_shaded_line.py → _format_stx_shaded_line.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_violin.py → _format_stx_violin.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/verify_formatters.py +23 -23
- scitex/plt/ax/__init__.py +16 -15
- scitex/plt/ax/_plot/__init__.py +30 -30
- scitex/plt/ax/_plot/_add_fitted_line.py +65 -11
- scitex/plt/ax/_plot/_plot_statistical_shaded_line.py +104 -76
- scitex/plt/ax/_plot/{_plot_conf_mat.py → _stx_conf_mat.py} +10 -10
- scitex/plt/ax/_plot/_stx_ecdf.py +109 -0
- scitex/plt/ax/_plot/{_plot_fillv.py → _stx_fillv.py} +7 -7
- scitex/plt/ax/_plot/_stx_heatmap.py +366 -0
- scitex/plt/ax/_plot/{_plot_image.py → _stx_image.py} +1 -1
- scitex/plt/ax/_plot/_stx_joyplot.py +113 -0
- scitex/plt/ax/_plot/{_plot_raster.py → _stx_raster.py} +37 -25
- scitex/plt/ax/_plot/{_plot_rectangle.py → _stx_rectangle.py} +10 -9
- scitex/plt/ax/_plot/{_plot_scatter_hist.py → _stx_scatter_hist.py} +1 -1
- scitex/plt/ax/_plot/_stx_shaded_line.py +215 -0
- scitex/plt/ax/_plot/{_plot_violin.py → _stx_violin.py} +13 -6
- scitex/plt/ax/_style/__init__.py +3 -0
- scitex/plt/ax/_style/_style_barplot.py +13 -2
- scitex/plt/ax/_style/_style_boxplot.py +78 -32
- scitex/plt/ax/_style/_style_errorbar.py +17 -3
- scitex/plt/ax/_style/_style_scatter.py +17 -3
- scitex/plt/ax/_style/_style_violinplot.py +109 -0
- scitex/plt/color/_vizualize_colors.py +3 -3
- scitex/plt/styles/SCITEX_STYLE.yaml +104 -0
- scitex/plt/styles/__init__.py +57 -0
- scitex/plt/styles/_plot_defaults.py +209 -0
- scitex/plt/styles/_plot_postprocess.py +518 -0
- scitex/plt/styles/_style_loader.py +268 -0
- scitex/plt/styles/presets.py +208 -0
- scitex/plt/utils/_collect_figure_metadata.py +160 -18
- scitex/plt/utils/_colorbar.py +72 -10
- scitex/plt/utils/_configure_mpl.py +108 -52
- scitex/plt/utils/_crop.py +21 -7
- scitex/plt/utils/_figure_mm.py +21 -7
- scitex/stats/__init__.py +13 -1
- scitex/stats/_schema.py +578 -0
- scitex/stats/tests/__init__.py +13 -0
- scitex/stats/tests/correlation/__init__.py +13 -0
- scitex/stats/tests/correlation/_test_pearson.py +262 -0
- scitex/vis/__init__.py +6 -0
- scitex/vis/editor/__init__.py +23 -0
- scitex/vis/editor/_defaults.py +205 -0
- scitex/vis/editor/_edit.py +342 -0
- scitex/vis/editor/_mpl_editor.py +231 -0
- scitex/vis/editor/_tkinter_editor.py +466 -0
- scitex/vis/editor/_web_editor.py +1440 -0
- scitex/vis/model/plot_types.py +15 -15
- {scitex-2.3.0.dist-info → scitex-2.4.1.dist-info}/METADATA +2 -1
- {scitex-2.3.0.dist-info → scitex-2.4.1.dist-info}/RECORD +94 -67
- {scitex-2.3.0.dist-info → scitex-2.4.1.dist-info}/WHEEL +1 -1
- scitex/plt/ax/_plot/_plot_ecdf.py +0 -84
- scitex/plt/ax/_plot/_plot_heatmap.py +0 -277
- scitex/plt/ax/_plot/_plot_joyplot.py +0 -77
- scitex/plt/ax/_plot/_plot_shaded_line.py +0 -142
- scitex/plt/presets.py +0 -224
- {scitex-2.3.0.dist-info → scitex-2.4.1.dist-info}/entry_points.txt +0 -0
- {scitex-2.3.0.dist-info → scitex-2.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-11-29 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/stats/tests/correlation/_test_pearson.py
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Pearson correlation test with publication-ready output.
|
|
8
|
+
|
|
9
|
+
Functionalities:
|
|
10
|
+
- Compute Pearson correlation coefficient and p-value
|
|
11
|
+
- Calculate confidence intervals using Fisher's z-transformation
|
|
12
|
+
- Optional scatter plot with regression line and statistics
|
|
13
|
+
- Return standardized result dictionary
|
|
14
|
+
|
|
15
|
+
Dependencies:
|
|
16
|
+
- packages: numpy, pandas, scipy
|
|
17
|
+
|
|
18
|
+
IO:
|
|
19
|
+
- input: Two continuous variables (arrays or Series)
|
|
20
|
+
- output: Correlation result dictionary with r, p-value, CI
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
from typing import Optional, Union, Tuple
|
|
25
|
+
|
|
26
|
+
import numpy as np
|
|
27
|
+
import pandas as pd
|
|
28
|
+
from scipy import stats as scipy_stats
|
|
29
|
+
|
|
30
|
+
import scitex as stx
|
|
31
|
+
from scitex.logging import getLogger
|
|
32
|
+
|
|
33
|
+
logger = getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_pearson(
|
|
37
|
+
x: Union[np.ndarray, pd.Series],
|
|
38
|
+
y: Union[np.ndarray, pd.Series],
|
|
39
|
+
var_x: Optional[str] = None,
|
|
40
|
+
var_y: Optional[str] = None,
|
|
41
|
+
alpha: float = 0.05,
|
|
42
|
+
plot: bool = False,
|
|
43
|
+
**plot_kwargs
|
|
44
|
+
) -> Union['StatResult', Tuple['StatResult', 'matplotlib.figure.Figure']]:
|
|
45
|
+
"""
|
|
46
|
+
Pearson correlation test for linear relationship between two continuous variables.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
x : array or Series
|
|
51
|
+
First variable (continuous)
|
|
52
|
+
y : array or Series
|
|
53
|
+
Second variable (continuous)
|
|
54
|
+
var_x : str, optional
|
|
55
|
+
Name of first variable for display
|
|
56
|
+
var_y : str, optional
|
|
57
|
+
Name of second variable for display
|
|
58
|
+
alpha : float, default 0.05
|
|
59
|
+
Significance level for confidence intervals
|
|
60
|
+
plot : bool, default False
|
|
61
|
+
Whether to create scatter plot with regression line
|
|
62
|
+
**plot_kwargs
|
|
63
|
+
Additional arguments passed to plotting function
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
result : StatResult
|
|
68
|
+
StatResult instance containing:
|
|
69
|
+
- statistic: Pearson's r coefficient
|
|
70
|
+
- p_value: Two-tailed p-value
|
|
71
|
+
- stars: Significance stars (*, **, ***, ns)
|
|
72
|
+
- ci_95: Confidence interval [lower, upper]
|
|
73
|
+
- effect_size: R² and interpretation
|
|
74
|
+
- samples: Sample information
|
|
75
|
+
Access as attributes or use .to_dict() for dictionary
|
|
76
|
+
fig : matplotlib.figure.Figure, optional
|
|
77
|
+
Figure object if plot=True
|
|
78
|
+
|
|
79
|
+
Notes
|
|
80
|
+
-----
|
|
81
|
+
Pearson correlation coefficient r is calculated as:
|
|
82
|
+
|
|
83
|
+
.. math::
|
|
84
|
+
r = \\frac{\\sum_{i=1}^{n}(x_i - \\bar{x})(y_i - \\bar{y})}{\\sqrt{\\sum_{i=1}^{n}(x_i - \\bar{x})^2 \\sum_{i=1}^{n}(y_i - \\bar{y})^2}}
|
|
85
|
+
|
|
86
|
+
Confidence intervals use Fisher's z-transformation:
|
|
87
|
+
|
|
88
|
+
.. math::
|
|
89
|
+
z = 0.5 \\ln\\left(\\frac{1+r}{1-r}\\right)
|
|
90
|
+
|
|
91
|
+
Interpretation guidelines (Cohen, 1988):
|
|
92
|
+
- |r| < 0.1: Negligible
|
|
93
|
+
- |r| < 0.3: Small
|
|
94
|
+
- |r| < 0.5: Medium
|
|
95
|
+
- |r| ≥ 0.5: Large
|
|
96
|
+
|
|
97
|
+
Examples
|
|
98
|
+
--------
|
|
99
|
+
>>> import numpy as np
|
|
100
|
+
>>> from scitex.stats.tests.correlation import test_pearson
|
|
101
|
+
>>>
|
|
102
|
+
>>> # Generate correlated data
|
|
103
|
+
>>> np.random.seed(42)
|
|
104
|
+
>>> x = np.random.randn(100)
|
|
105
|
+
>>> y = 2 * x + np.random.randn(100) * 0.5
|
|
106
|
+
>>>
|
|
107
|
+
>>> # Basic usage
|
|
108
|
+
>>> result = test_pearson(x, y)
|
|
109
|
+
>>> print(f"r = {result.statistic['value']:.3f}, p = {result.p_value:.3e}")
|
|
110
|
+
>>>
|
|
111
|
+
>>> # With variable names and plot
|
|
112
|
+
>>> result, fig = test_pearson(
|
|
113
|
+
... x, y,
|
|
114
|
+
... var_x='Height',
|
|
115
|
+
... var_y='Weight',
|
|
116
|
+
... plot=True
|
|
117
|
+
... )
|
|
118
|
+
>>>
|
|
119
|
+
>>> # Check significance
|
|
120
|
+
>>> if result.p_value < 0.05:
|
|
121
|
+
... print(f"Significant correlation: r = {result.statistic['value']:.3f}{result.stars}")
|
|
122
|
+
>>>
|
|
123
|
+
>>> # Use as dictionary (backward compatibility)
|
|
124
|
+
>>> result_dict = result.to_dict()
|
|
125
|
+
>>> print(result_dict['statistic']['value'])
|
|
126
|
+
"""
|
|
127
|
+
from scitex.stats.utils._formatters import p2stars
|
|
128
|
+
from scitex.stats._schema import StatResult
|
|
129
|
+
|
|
130
|
+
# Convert to numpy arrays and remove NaN
|
|
131
|
+
x = np.asarray(x)
|
|
132
|
+
y = np.asarray(y)
|
|
133
|
+
|
|
134
|
+
# Check for matching lengths
|
|
135
|
+
if len(x) != len(y):
|
|
136
|
+
raise ValueError(f"x and y must have same length (got {len(x)} and {len(y)})")
|
|
137
|
+
|
|
138
|
+
# Remove NaN pairs
|
|
139
|
+
mask = ~(np.isnan(x) | np.isnan(y))
|
|
140
|
+
x_clean = x[mask]
|
|
141
|
+
y_clean = y[mask]
|
|
142
|
+
n = len(x_clean)
|
|
143
|
+
|
|
144
|
+
if n < 3:
|
|
145
|
+
raise ValueError(f"Need at least 3 valid pairs (got {n})")
|
|
146
|
+
|
|
147
|
+
# Compute Pearson correlation
|
|
148
|
+
r, p_value = scipy_stats.pearsonr(x_clean, y_clean)
|
|
149
|
+
|
|
150
|
+
# Calculate confidence interval using Fisher's z-transformation
|
|
151
|
+
z = np.arctanh(r) # Fisher's z = 0.5 * ln((1+r)/(1-r))
|
|
152
|
+
se = 1 / np.sqrt(n - 3) # Standard error of z
|
|
153
|
+
z_crit = scipy_stats.norm.ppf(1 - alpha/2) # Critical value for two-tailed test
|
|
154
|
+
|
|
155
|
+
ci_lower_z = z - z_crit * se
|
|
156
|
+
ci_upper_z = z + z_crit * se
|
|
157
|
+
|
|
158
|
+
# Transform back to r scale
|
|
159
|
+
ci_lower = np.tanh(ci_lower_z)
|
|
160
|
+
ci_upper = np.tanh(ci_upper_z)
|
|
161
|
+
|
|
162
|
+
# Convert p-value to stars
|
|
163
|
+
stars = p2stars(p_value, ns_symbol=False)
|
|
164
|
+
if not stars:
|
|
165
|
+
stars = 'ns'
|
|
166
|
+
|
|
167
|
+
# Calculate R²
|
|
168
|
+
r_squared = r ** 2
|
|
169
|
+
|
|
170
|
+
# Interpret effect size
|
|
171
|
+
r_abs = abs(r)
|
|
172
|
+
if r_abs < 0.1:
|
|
173
|
+
interpretation = "negligible"
|
|
174
|
+
elif r_abs < 0.3:
|
|
175
|
+
interpretation = "small"
|
|
176
|
+
elif r_abs < 0.5:
|
|
177
|
+
interpretation = "medium"
|
|
178
|
+
else:
|
|
179
|
+
interpretation = "large"
|
|
180
|
+
|
|
181
|
+
# Set variable names
|
|
182
|
+
if var_x is None:
|
|
183
|
+
var_x = 'X'
|
|
184
|
+
if var_y is None:
|
|
185
|
+
var_y = 'Y'
|
|
186
|
+
|
|
187
|
+
# Build StatResult instance
|
|
188
|
+
result = StatResult(
|
|
189
|
+
test_type='pearson',
|
|
190
|
+
test_category='correlation',
|
|
191
|
+
statistic={'name': 'r', 'value': r},
|
|
192
|
+
p_value=p_value,
|
|
193
|
+
stars=stars,
|
|
194
|
+
effect_size={
|
|
195
|
+
'name': 'r_squared',
|
|
196
|
+
'value': r_squared,
|
|
197
|
+
'interpretation': interpretation,
|
|
198
|
+
'ci_95': [ci_lower, ci_upper]
|
|
199
|
+
},
|
|
200
|
+
samples={
|
|
201
|
+
'n_total': n,
|
|
202
|
+
'n_valid': n,
|
|
203
|
+
'var_x': var_x,
|
|
204
|
+
'var_y': var_y
|
|
205
|
+
},
|
|
206
|
+
ci_95=[ci_lower, ci_upper],
|
|
207
|
+
extra={
|
|
208
|
+
'test': 'Pearson correlation',
|
|
209
|
+
'ci_level': 1 - alpha,
|
|
210
|
+
'method': 'pearson',
|
|
211
|
+
'alpha': alpha
|
|
212
|
+
},
|
|
213
|
+
software_version=stx.__version__
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
# Create plot if requested
|
|
217
|
+
if plot:
|
|
218
|
+
fig = _plot_pearson(x_clean, y_clean, result, **plot_kwargs)
|
|
219
|
+
return result, fig
|
|
220
|
+
|
|
221
|
+
return result
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _plot_pearson(
|
|
225
|
+
x: np.ndarray,
|
|
226
|
+
y: np.ndarray,
|
|
227
|
+
result: 'StatResult',
|
|
228
|
+
**kwargs
|
|
229
|
+
) -> 'matplotlib.figure.Figure':
|
|
230
|
+
"""
|
|
231
|
+
Create scatter plot with regression line for Pearson correlation.
|
|
232
|
+
|
|
233
|
+
Internal function called by test_pearson when plot=True.
|
|
234
|
+
"""
|
|
235
|
+
# Create figure
|
|
236
|
+
fig, ax = stx.plt.subplots(**stx.plt.presets.SCITEX_STYLE)
|
|
237
|
+
|
|
238
|
+
# Scatter plot
|
|
239
|
+
scatter = ax.scatter(x, y, alpha=0.6, c="steelblue", label="Data")
|
|
240
|
+
stx.plt.ax.style_scatter(scatter, size_mm=0.8)
|
|
241
|
+
|
|
242
|
+
# Add fitted line with statistics
|
|
243
|
+
stx.plt.ax.add_fitted_line(
|
|
244
|
+
ax, x, y,
|
|
245
|
+
color='black',
|
|
246
|
+
linestyle='--',
|
|
247
|
+
label='Fit',
|
|
248
|
+
show_stats=True
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Labels
|
|
252
|
+
var_x = result.samples.get('var_x', 'X')
|
|
253
|
+
var_y = result.samples.get('var_y', 'Y')
|
|
254
|
+
ax.set_xlabel(stx.plt.ax.format_label(var_x, ""))
|
|
255
|
+
ax.set_ylabel(stx.plt.ax.format_label(var_y, ""))
|
|
256
|
+
ax.set_title(f"Pearson Correlation (r = {result.statistic['value']:.3f}{result.stars})")
|
|
257
|
+
ax.legend(frameon=False, fontsize=6)
|
|
258
|
+
|
|
259
|
+
return fig
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# EOF
|
scitex/vis/__init__.py
CHANGED
|
@@ -54,6 +54,7 @@ from . import model
|
|
|
54
54
|
from . import backend
|
|
55
55
|
from . import io
|
|
56
56
|
from . import utils
|
|
57
|
+
from . import editor
|
|
57
58
|
|
|
58
59
|
# Convenient top-level imports for common use cases
|
|
59
60
|
from .model import FigureModel, AxesModel, PlotModel, GuideModel, AnnotationModel
|
|
@@ -79,12 +80,17 @@ from .utils import (
|
|
|
79
80
|
NATURE_DOUBLE_COLUMN_MM,
|
|
80
81
|
)
|
|
81
82
|
|
|
83
|
+
from .editor import edit
|
|
84
|
+
|
|
82
85
|
__all__ = [
|
|
83
86
|
# Submodules
|
|
84
87
|
"model",
|
|
85
88
|
"backend",
|
|
86
89
|
"io",
|
|
87
90
|
"utils",
|
|
91
|
+
"editor",
|
|
92
|
+
# Editor
|
|
93
|
+
"edit",
|
|
88
94
|
# Models
|
|
89
95
|
"FigureModel",
|
|
90
96
|
"AxesModel",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# File: ./src/scitex/vis/editor/__init__.py
|
|
4
|
+
"""
|
|
5
|
+
SciTeX Visual Editor Module
|
|
6
|
+
|
|
7
|
+
Provides interactive GUI for editing figure styles and annotations.
|
|
8
|
+
Supports multiple backends with graceful degradation:
|
|
9
|
+
- web: Browser-based (Flask/FastAPI) - modern UI
|
|
10
|
+
- dearpygui: GPU-accelerated desktop (fast)
|
|
11
|
+
- qt: Rich desktop (PyQt/PySide)
|
|
12
|
+
- tkinter: Built-in Python (works everywhere)
|
|
13
|
+
- mpl: Minimal matplotlib (always works)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from ._edit import edit, save_manual_overrides
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"edit",
|
|
20
|
+
"save_manual_overrides",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
# EOF
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# File: ./src/scitex/vis/editor/_defaults.py
|
|
4
|
+
"""Default style settings for SciTeX visual editor."""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_scitex_defaults():
|
|
8
|
+
"""
|
|
9
|
+
Get default style values based on SciTeX publication standards.
|
|
10
|
+
|
|
11
|
+
Returns
|
|
12
|
+
-------
|
|
13
|
+
dict
|
|
14
|
+
Dictionary of default style settings
|
|
15
|
+
"""
|
|
16
|
+
return {
|
|
17
|
+
# Font sizes (from _configure_mpl.py)
|
|
18
|
+
'fontsize': 7, # Base font size for publication
|
|
19
|
+
'title_fontsize': 8, # Title size
|
|
20
|
+
'axis_fontsize': 7, # Axis label size
|
|
21
|
+
'tick_fontsize': 7, # Tick label size
|
|
22
|
+
'legend_fontsize': 6, # Legend font size
|
|
23
|
+
|
|
24
|
+
# Line settings (in points, 1mm = 2.83465pt)
|
|
25
|
+
'linewidth': 0.57, # Default line width (0.2mm)
|
|
26
|
+
|
|
27
|
+
# Tick settings
|
|
28
|
+
'n_ticks': 4, # Number of ticks
|
|
29
|
+
'tick_length': 0.8, # Tick length in mm
|
|
30
|
+
'tick_width': 0.2, # Tick width in mm
|
|
31
|
+
'tick_direction': 'out', # Tick direction
|
|
32
|
+
|
|
33
|
+
# Axes settings
|
|
34
|
+
'axis_width': 0.2, # Spine/axes line width in mm
|
|
35
|
+
'hide_top_spine': True, # Hide top spine
|
|
36
|
+
'hide_right_spine': True, # Hide right spine
|
|
37
|
+
|
|
38
|
+
# Grid settings
|
|
39
|
+
'grid': False, # Grid off by default
|
|
40
|
+
'grid_linewidth': 0.6,
|
|
41
|
+
'grid_alpha': 0.3,
|
|
42
|
+
|
|
43
|
+
# Figure settings
|
|
44
|
+
'dpi': 300, # Default DPI
|
|
45
|
+
'fig_size': [3.15, 2.68], # Default figure size in inches
|
|
46
|
+
|
|
47
|
+
# Colors (SciTeX defaults)
|
|
48
|
+
'facecolor': '#ffffff', # White background
|
|
49
|
+
'transparent': True, # Transparent background
|
|
50
|
+
|
|
51
|
+
# Legend
|
|
52
|
+
'legend_visible': True,
|
|
53
|
+
'legend_frameon': False,
|
|
54
|
+
'legend_loc': 'best',
|
|
55
|
+
|
|
56
|
+
# Font family
|
|
57
|
+
'font_family': 'Arial', # Sans-serif for publication
|
|
58
|
+
|
|
59
|
+
# Annotations
|
|
60
|
+
'annotations': [],
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_scitex_colors():
|
|
65
|
+
"""
|
|
66
|
+
Get SciTeX color palette.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
dict
|
|
71
|
+
Dictionary of named colors with hex values
|
|
72
|
+
"""
|
|
73
|
+
# Based on scitex.plt.color.PARAMS
|
|
74
|
+
return {
|
|
75
|
+
'blue': '#1f77b4',
|
|
76
|
+
'orange': '#ff7f0e',
|
|
77
|
+
'green': '#2ca02c',
|
|
78
|
+
'red': '#d62728',
|
|
79
|
+
'purple': '#9467bd',
|
|
80
|
+
'brown': '#8c564b',
|
|
81
|
+
'pink': '#e377c2',
|
|
82
|
+
'gray': '#7f7f7f',
|
|
83
|
+
'olive': '#bcbd22',
|
|
84
|
+
'cyan': '#17becf',
|
|
85
|
+
# Additional publication colors
|
|
86
|
+
'black': '#000000',
|
|
87
|
+
'white': '#ffffff',
|
|
88
|
+
'dark_gray': '#404040',
|
|
89
|
+
'light_gray': '#d0d0d0',
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def extract_defaults_from_metadata(metadata):
|
|
94
|
+
"""
|
|
95
|
+
Extract style defaults from loaded figure metadata.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
metadata : dict
|
|
100
|
+
Figure metadata loaded from JSON
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
dict
|
|
105
|
+
Dictionary of style values extracted from metadata
|
|
106
|
+
"""
|
|
107
|
+
defaults = get_scitex_defaults()
|
|
108
|
+
|
|
109
|
+
if not metadata:
|
|
110
|
+
return defaults
|
|
111
|
+
|
|
112
|
+
# Extract from scitex section (new format)
|
|
113
|
+
scitex_meta = metadata.get('scitex', {})
|
|
114
|
+
style_mm = scitex_meta.get('style_mm', {})
|
|
115
|
+
|
|
116
|
+
# Font sizes from style_mm
|
|
117
|
+
if 'axis_font_size_pt' in style_mm:
|
|
118
|
+
defaults['axis_fontsize'] = style_mm['axis_font_size_pt']
|
|
119
|
+
if 'tick_font_size_pt' in style_mm:
|
|
120
|
+
defaults['tick_fontsize'] = style_mm['tick_font_size_pt']
|
|
121
|
+
if 'title_font_size_pt' in style_mm:
|
|
122
|
+
defaults['title_fontsize'] = style_mm['title_font_size_pt']
|
|
123
|
+
if 'legend_font_size_pt' in style_mm:
|
|
124
|
+
defaults['legend_fontsize'] = style_mm['legend_font_size_pt']
|
|
125
|
+
|
|
126
|
+
# Line/axis thickness from metadata (in mm)
|
|
127
|
+
if 'trace_thickness_mm' in style_mm:
|
|
128
|
+
defaults['linewidth'] = style_mm['trace_thickness_mm'] * 2.83465 # mm to pt
|
|
129
|
+
if 'axis_thickness_mm' in style_mm:
|
|
130
|
+
defaults['axis_width'] = style_mm['axis_thickness_mm']
|
|
131
|
+
if 'tick_length_mm' in style_mm:
|
|
132
|
+
defaults['tick_length'] = style_mm['tick_length_mm']
|
|
133
|
+
if 'tick_thickness_mm' in style_mm:
|
|
134
|
+
defaults['tick_width'] = style_mm['tick_thickness_mm']
|
|
135
|
+
if 'n_ticks' in style_mm:
|
|
136
|
+
defaults['n_ticks'] = style_mm['n_ticks']
|
|
137
|
+
|
|
138
|
+
# Dimensions from metadata
|
|
139
|
+
dimensions = metadata.get('dimensions', {})
|
|
140
|
+
if 'dpi' in dimensions:
|
|
141
|
+
defaults['dpi'] = dimensions['dpi']
|
|
142
|
+
if 'figure_size_inch' in dimensions:
|
|
143
|
+
defaults['fig_size'] = dimensions['figure_size_inch']
|
|
144
|
+
|
|
145
|
+
# Axis labels from metadata
|
|
146
|
+
if 'xlabel' in metadata:
|
|
147
|
+
defaults['xlabel'] = metadata['xlabel']
|
|
148
|
+
if 'ylabel' in metadata:
|
|
149
|
+
defaults['ylabel'] = metadata['ylabel']
|
|
150
|
+
if 'title' in metadata:
|
|
151
|
+
defaults['title'] = metadata['title']
|
|
152
|
+
|
|
153
|
+
# Try to extract from axes if present
|
|
154
|
+
axes = metadata.get('axes', {})
|
|
155
|
+
if isinstance(axes, dict):
|
|
156
|
+
# New format: {'x': {'label': ...}, 'y': {'label': ...}}
|
|
157
|
+
x_axis = axes.get('x', {})
|
|
158
|
+
y_axis = axes.get('y', {})
|
|
159
|
+
if 'label' in x_axis:
|
|
160
|
+
unit = x_axis.get('unit', '')
|
|
161
|
+
label = x_axis['label']
|
|
162
|
+
if unit:
|
|
163
|
+
defaults['xlabel'] = f"{label} [{unit}]"
|
|
164
|
+
else:
|
|
165
|
+
defaults['xlabel'] = label
|
|
166
|
+
if 'label' in y_axis:
|
|
167
|
+
unit = y_axis.get('unit', '')
|
|
168
|
+
label = y_axis['label']
|
|
169
|
+
if unit:
|
|
170
|
+
defaults['ylabel'] = f"{label} [{unit}]"
|
|
171
|
+
else:
|
|
172
|
+
defaults['ylabel'] = label
|
|
173
|
+
# Extract axis limits
|
|
174
|
+
if 'lim' in x_axis:
|
|
175
|
+
defaults['xlim'] = x_axis['lim']
|
|
176
|
+
if 'lim' in y_axis:
|
|
177
|
+
defaults['ylim'] = y_axis['lim']
|
|
178
|
+
elif isinstance(axes, list) and len(axes) > 0:
|
|
179
|
+
# Legacy format: list of axes
|
|
180
|
+
ax = axes[0]
|
|
181
|
+
if 'xlabel' in ax:
|
|
182
|
+
defaults['xlabel'] = ax['xlabel']
|
|
183
|
+
if 'ylabel' in ax:
|
|
184
|
+
defaults['ylabel'] = ax['ylabel']
|
|
185
|
+
if 'title' in ax:
|
|
186
|
+
defaults['title'] = ax['title']
|
|
187
|
+
if 'grid' in ax:
|
|
188
|
+
defaults['grid'] = ax['grid']
|
|
189
|
+
|
|
190
|
+
# Extract traces information
|
|
191
|
+
traces = metadata.get('traces', [])
|
|
192
|
+
if traces:
|
|
193
|
+
defaults['traces'] = traces
|
|
194
|
+
|
|
195
|
+
# Extract legend information
|
|
196
|
+
legend = metadata.get('legend', {})
|
|
197
|
+
if legend:
|
|
198
|
+
defaults['legend_visible'] = legend.get('visible', True)
|
|
199
|
+
defaults['legend_frameon'] = legend.get('frameon', False)
|
|
200
|
+
defaults['legend_loc'] = legend.get('loc', 'best')
|
|
201
|
+
|
|
202
|
+
return defaults
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# EOF
|