Skip to content

Commit 9c44b85

Browse files
committed
restructred viz settings
1 parent a5f0006 commit 9c44b85

File tree

3 files changed

+90
-144
lines changed

3 files changed

+90
-144
lines changed

notebooks/sp_layout.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,20 @@
2424
datax, datay = np.random.rand(50), np.random.rand(50)
2525

2626

27-
# %%
28-
import layout_v2 as l2
29-
from matplotlib.ticker import AutoMinorLocator, NullLocator
30-
3127
# %%
3228
axs = sp.montage_plot(1, panel_size=(6.5, 4.5))
3329
axs.scatter(datax, datay)
3430

3531
# axs.xaxis.set_minor_locator(AutoMinorLocator())
36-
l2.layout(
32+
sp.layout_v2(
3733
axs,
38-
title='Scatter',
39-
# ticks='all',
40-
grid='major',
41-
minor='2',
42-
x_label_color='crimson',
43-
x_label='X-axis',
44-
y_label='Y-axis',
45-
# grid_zorder=10
34+
title='Scatter Plot',
35+
x_grid='both',
36+
minor=False
4637
)
4738

4839

4940

50-
5141
# %%
5242
axs = sp.montage_plot(1, panel_size=(4.5, 3.5))
5343
axs.scatter(datax, datay)

src/spaceplot/appearance/layout_v2.py

Lines changed: 61 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
# I think currently, tick visibility will override settings from other setters... need to fix that
1717
# implement allowed_params check like started in layout_v1
1818
# find solution for tick_labels
19-
# parse_axis_params needs better input filtering... currently everything goes through
2019

2120

2221
def layout_v2(
@@ -56,7 +55,7 @@ def layout_v2(
5655
x_label_params, x_tick_params, x_params = compile_axis_settings(axis_params, axis='x')
5756
y_label_params, y_tick_params, y_params = compile_axis_settings(axis_params, axis='y')
5857

59-
title_settings = get_hook_dict(static_kwargs, 'title_', remove_hook=True)
58+
title_settings = utils.get_hook_dict_v2(static_kwargs, 'title_', remove_hook=True)
6059

6160
# ensure axs is a list
6261
if not isinstance(axs, Iterable):
@@ -113,9 +112,25 @@ def viz(
113112
*,
114113
ticks: _tick_vis = None,
115114
grid: _grid_vis = None,
116-
minor: bool = None,
115+
minor: _tick_vis = None,
117116
**kwargs,
118117
):
118+
def value_check(param, value):
119+
if value is None:
120+
return
121+
if type(value) is bool:
122+
return
123+
if value not in [v for v in _tick_vis.__args__ if type(v) is str]:
124+
raise ValueError(f'Invalid {param} param: {value} ')
125+
126+
value_check('ticks', ticks)
127+
value_check('minor', minor)
128+
for k, v in kwargs.items():
129+
if k.endswith('_ticks'):
130+
value_check(k, v)
131+
if k.endswith('_minor'):
132+
value_check(k, v)
133+
119134
viz_args = {
120135
k: v
121136
for k, v in {
@@ -135,35 +150,17 @@ def viz(
135150

136151
# break down merged into x_ and y_ specific params
137152
viz_params = parse_axis_params(params=merged)
138-
xviz = get_hook_dict(viz_params, 'x_', remove_hook=True)
139-
yviz = get_hook_dict(viz_params, 'y_', remove_hook=True)
153+
xviz = utils.get_hook_dict_v2(viz_params, 'x_', remove_hook=True, check=False)
154+
yviz = utils.get_hook_dict_v2(viz_params, 'y_', remove_hook=True, check=False)
140155

141156
# apply settings
142157
set_tick_grid_visibility(ax, axis='x', **xviz)
143158
set_tick_grid_visibility(ax, axis='y', **yviz)
144159

145160

146-
def parse_grid_visibility(
147-
grid: _grid_vis | None = None,
148-
minor: bool | None = None,
149-
):
150-
if grid is None:
151-
return None, None
152-
153-
if isinstance(grid, bool):
154-
if not grid:
155-
major_setter = minor_setter = False
156-
else:
157-
major_setter = grid
158-
minor_setter = grid if minor is None else minor
159-
elif isinstance(grid, str):
160-
major_setter = True if grid in ('both', 'major') else False
161-
minor_setter = True if grid in ('both', 'minor') else False
162-
163-
return major_setter, minor_setter
164-
165-
166161
def set_tick_grid_visibility(ax, *, axis='x', ticks=None, minor=None, grid=None):
162+
axis_obj = getattr(ax, f'{axis}axis')
163+
167164
# mapping for tick visibility in x/y axis
168165
p1 = 'bottom' if axis == 'x' else 'left'
169166
p2 = 'top' if axis == 'x' else 'right'
@@ -172,13 +169,6 @@ def set_tick_grid_visibility(ax, *, axis='x', ticks=None, minor=None, grid=None)
172169
def apply_logic(value):
173170
logic_1 = True if value in ('1', 'both', 'all', True) else False
174171
logic_2 = True if value in ('2', 'both', 'all') else False
175-
return logic_1, logic_2
176-
177-
if ticks is None:
178-
viz = {}
179-
# viz_min = {}
180-
else:
181-
logic_1, logic_2 = apply_logic(ticks)
182172

183173
viz = {
184174
p1: logic_1,
@@ -187,37 +177,49 @@ def apply_logic(value):
187177
f'label{p2}': logic_2,
188178
}
189179

190-
logic_1, logic_2 = apply_logic(minor)
180+
return viz
191181

192-
viz_min = {
193-
p1: viz.get(p1, logic_1),
194-
f'label{p1}': viz.get(f'label{p1}', logic_1),
195-
p2: viz.get(p2, logic_2),
196-
f'label{p2}': viz.get(f'label{p2}', logic_2),
197-
}
182+
if ticks is None:
183+
viz = {}
184+
else:
185+
viz = apply_logic(ticks)
186+
187+
if minor is None and ticks is None:
188+
viz_min = {}
189+
elif minor is None and ticks:
190+
viz_min = {}
191+
elif minor is True:
192+
# axis_obj.minorticks_on()
193+
viz_min = viz.copy()
194+
else:
195+
# axis_obj.minorticks_on()
196+
viz_min = apply_logic(minor)
198197

198+
axis_obj.minorticks_on()
199199
grid_maj, grid_min = parse_grid_visibility(grid=grid, minor=minor)
200200

201-
axis_obj = getattr(ax, f'{axis}axis')
202-
203201
axis_obj.set_tick_params(which='major', gridOn=grid_maj, **viz)
204-
axis_obj.minorticks_on()
205202
axis_obj.set_tick_params(which='minor', gridOn=grid_min, **viz_min)
206203

207204

208-
def get_hook_dict(params, hook, remove_hook: bool = True) -> dict:
209-
hook_params = {}
210-
if params == {}:
211-
return hook_params
205+
def parse_grid_visibility(
206+
grid: _grid_vis | None = None,
207+
minor: bool | None = None,
208+
):
209+
if grid is None:
210+
return None, None
212211

213-
for key, value in params.items():
214-
if not key.startswith(hook):
215-
continue
216-
param = key.removeprefix(hook) if remove_hook else key
217-
d = {param: value}
218-
hook_params.update(d)
212+
if isinstance(grid, bool):
213+
if not grid:
214+
major_setter = minor_setter = False
215+
else:
216+
major_setter = grid
217+
minor_setter = grid if minor is None else minor
218+
elif isinstance(grid, str):
219+
major_setter = True if grid in ('both', 'major') else False
220+
minor_setter = True if grid in ('both', 'minor') else False
219221

220-
return hook_params
222+
return major_setter, minor_setter
221223

222224

223225
def parse_axis_params(params: dict):
@@ -241,7 +243,8 @@ def parse_axis_params(params: dict):
241243
# 4: check for duplicates and merge
242244
duplicate_keys = set(specific_axis_params.keys()) & set(axis_global.keys())
243245
if duplicate_keys:
244-
raise ValueError(f'Duplicate keys found: {duplicate_keys}')
246+
param_names = [p.removeprefix('x_') if p.startswith('x_') else p.removeprefix('y_') for p in duplicate_keys]
247+
raise ValueError(f'Duplicate axis param for: {duplicate_keys} and {param_names}')
245248

246249
axis_params = {**specific_axis_params, **axis_global}
247250

@@ -265,10 +268,10 @@ def merge_axis_kwargs(kwargs):
265268

266269

267270
def compile_axis_settings(axis_params, axis: str) -> dict:
268-
settings = get_hook_dict(axis_params, f'{axis}_', remove_hook=True)
269-
tick_settings = get_hook_dict(settings, 'tick_', remove_hook=True)
270-
grid_settings = get_hook_dict(settings, 'grid_', remove_hook=False)
271-
label_settings = get_hook_dict(settings, 'label_', remove_hook=True)
271+
settings = utils.get_hook_dict_v2(axis_params, f'{axis}_', remove_hook=True, check=False)
272+
tick_settings = utils.get_hook_dict_v2(settings, 'tick_', remove_hook=True)
273+
grid_settings = utils.get_hook_dict_v2(settings, 'grid_', remove_hook=False)
274+
label_settings = utils.get_hook_dict_v2(settings, 'label_', remove_hook=True)
272275
tick_settings.update(grid_settings)
273276
other_params = {k: v for k, v in settings.items() if not (k.startswith('tick_') or k.startswith('grid_'))}
274277

src/spaceplot/utils.py

Lines changed: 25 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from matplotlib.colors import ListedColormap, to_rgba
33

44
allowed_params = {
5-
'tick': [
5+
'tick_': [
66
'size',
77
'width',
88
'color',
@@ -13,39 +13,26 @@
1313
'labelrotation',
1414
'labelfontfamily',
1515
'zorder',
16-
# 'tick1On',
17-
# 'tick2On',
18-
# 'label1On',
19-
# 'label2On',
2016
# 'tickdir',
21-
# 'gridOn',
2217
# 'length',
23-
# 'left',
24-
# 'bottom',
25-
# 'right',
26-
# 'top',
27-
# 'labelleft',
28-
# 'labelbottom',
29-
# 'labelright',
30-
# 'labeltop',
3118
],
32-
'label': [
19+
'label_': [
3320
'size',
3421
'color',
3522
'pad',
3623
'rotation',
3724
'fontfamily',
3825
'zorder',
3926
],
40-
'title': [
27+
'title_': [
4128
'size',
4229
'color',
4330
'pad',
4431
'rotation',
4532
'fontfamily',
4633
'zorder',
4734
],
48-
'grid': [
35+
'grid_': [
4936
'color',
5037
'alpha',
5138
'linestyle',
@@ -103,61 +90,27 @@
10390
}
10491

10592

106-
[
107-
'grid_agg_filter',
108-
'grid_alpha',
109-
'grid_animated',
110-
'grid_antialiased',
111-
'grid_clip_box',
112-
'grid_clip_on',
113-
'grid_clip_path',
114-
'grid_color',
115-
'grid_dash_capstyle',
116-
'grid_dash_joinstyle',
117-
'grid_dashes',
118-
'grid_data',
119-
'grid_drawstyle',
120-
'grid_figure',
121-
'grid_fillstyle',
122-
'grid_gapcolor',
123-
'grid_gid',
124-
'grid_in_layout',
125-
'grid_label',
126-
'grid_linestyle',
127-
'grid_linewidth',
128-
'grid_marker',
129-
'grid_markeredgecolor',
130-
'grid_markeredgewidth',
131-
'grid_markerfacecolor',
132-
'grid_markerfacecoloralt',
133-
'grid_markersize',
134-
'grid_markevery',
135-
'grid_mouseover',
136-
'grid_path_effects',
137-
'grid_picker',
138-
'grid_pickradius',
139-
'grid_rasterized',
140-
'grid_sketch_params',
141-
'grid_snap',
142-
'grid_solid_capstyle',
143-
'grid_solid_joinstyle',
144-
'grid_transform',
145-
'grid_url',
146-
'grid_visible',
147-
'grid_xdata',
148-
'grid_ydata',
149-
'grid_zorder',
150-
'grid_aa',
151-
'grid_c',
152-
'grid_ds',
153-
'grid_ls',
154-
'grid_lw',
155-
'grid_mec',
156-
'grid_mew',
157-
'grid_mfc',
158-
'grid_mfcalt',
159-
'grid_ms',
160-
]
93+
def get_hook_dict_v2(params, hook, remove_hook: bool = True, check: bool = True) -> dict:
94+
hook_params = {}
95+
if params == {}:
96+
return hook_params
97+
98+
for key, value in params.items():
99+
if not key.startswith(hook):
100+
continue
101+
param = key.removeprefix(hook) if remove_hook else key
102+
103+
# print(f"recognized '{hook}' parameter: {key}")
104+
if check:
105+
if param not in allowed_params.get(hook, []):
106+
raise ValueError(
107+
f"Invalid {hook} parameter: '{param}'.\nSupported parameters are: {allowed_params.get(hook, [])}"
108+
)
109+
110+
d = {param: value}
111+
hook_params.update(d)
112+
113+
return hook_params
161114

162115

163116
def get_hook_dict(params, hook, remove_hook=True) -> dict:

0 commit comments

Comments
 (0)