Skip to content

Commit 5cf2e4a

Browse files
authored
Merge pull request #198 from ToFuProject/devel
Prepare 0.0.46
2 parents e219d6f + cb6fb26 commit 5cf2e4a

File tree

6 files changed

+348
-25
lines changed

6 files changed

+348
-25
lines changed

datastock/_class1.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from . import _class1_binning
2222
from . import _class1_interpolate
2323
from . import _class1_uniformize
24+
from . import _class1_color_touch as _color_touch
2425
from . import _export_dataframe
2526
from . import _find_plateau
2627

@@ -923,6 +924,32 @@ def interpolate(
923924
inplace=inplace,
924925
)
925926

927+
# ---------------------
928+
# color touch array
929+
# ---------------------
930+
931+
def get_color_touch(
932+
self,
933+
data=None,
934+
dcolor=None,
935+
# options
936+
color_default=None,
937+
vmin=None,
938+
vmax=None,
939+
log=None,
940+
):
941+
942+
return _color_touch.main(
943+
coll=self,
944+
data=data,
945+
dcolor=dcolor,
946+
# options
947+
color_default=color_default,
948+
vmin=vmin,
949+
vmax=vmax,
950+
log=log,
951+
)
952+
926953
# ---------------------
927954
# Methods computing correlations
928955
# ---------------------

datastock/_class1_color_touch.py

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Created on Fri Feb 28 08:53:00 2025
4+
5+
@author: dvezinet
6+
"""
7+
8+
9+
import numpy as np
10+
import matplotlib.pyplot as plt
11+
import matplotlib.colors as mcolors
12+
import datastock as ds
13+
14+
15+
# ###############################################################
16+
# ###############################################################
17+
# Main
18+
# ###############################################################
19+
20+
21+
def main(
22+
coll=None,
23+
data=None,
24+
dcolor=None,
25+
# options
26+
color_default=None,
27+
vmin=None,
28+
vmax=None,
29+
log=None,
30+
):
31+
32+
# ------------------
33+
# check inputs
34+
# ------------------
35+
36+
data, dcolor, color_default, vmin, vmax, log = _check(
37+
coll=coll,
38+
data=data,
39+
dcolor=dcolor,
40+
color_default=color_default,
41+
vmin=vmin,
42+
vmax=vmax,
43+
log=log,
44+
)
45+
46+
# ------------------
47+
# initialize
48+
# ------------------
49+
50+
shape = data.shape + (4,)
51+
color = np.zeros(shape, dtype=float)
52+
53+
# ------------------
54+
# compute - alpha
55+
# ------------------
56+
57+
if log is True:
58+
vmin = np.log10(vmin)
59+
vmax = np.log10(vmax)
60+
61+
alpha = (np.log10(data) - vmin) / (vmax - vmin)
62+
63+
else:
64+
alpha = (data - vmin) / (vmax - vmin)
65+
66+
# ------------------
67+
# compute - colors
68+
# ------------------
69+
70+
for k0, v0 in dcolor.items():
71+
72+
sli = (v0['ind'], slice(0, 3))
73+
color[sli] = v0['color']
74+
75+
sli = tuple([slice(None) for ii in range(data.ndim)] + [-1])
76+
color[sli] = alpha
77+
78+
# ------------------
79+
# output
80+
# ------------------
81+
82+
lcol = set([v0['color'] for v0 in dcolor.values()])
83+
dcolor = {
84+
'color': color,
85+
'meaning': {
86+
kc: [k0 for k0, v0 in dcolor.items() if v0['color'] == kc]
87+
for kc in lcol
88+
},
89+
}
90+
91+
return dcolor
92+
93+
94+
# ###############################################################
95+
# ###############################################################
96+
# check
97+
# ###############################################################
98+
99+
100+
def _check(
101+
coll=None,
102+
data=None,
103+
dcolor=None,
104+
# options
105+
color_default=None,
106+
vmin=None,
107+
vmax=None,
108+
log=None,
109+
):
110+
111+
# ------------------
112+
# data
113+
# ------------------
114+
115+
lc = [
116+
isinstance(data, np.ndarray),
117+
isinstance(data, str) and data in coll.ddata.keys(),
118+
]
119+
if lc[0]:
120+
pass
121+
elif lc[1]:
122+
data = coll.ddata[data]['data']
123+
else:
124+
msg = (
125+
"Arg data must be a np.ndarray or a key to an existing data!\n"
126+
f"Provided: {data}\n"
127+
)
128+
raise Exception(msg)
129+
130+
131+
# ------------------
132+
# dcolor
133+
# ------------------
134+
135+
# --------------------
136+
# dcolor format check
137+
138+
c0 = (
139+
isinstance(dcolor, dict)
140+
and all([
141+
isinstance(k0, str)
142+
and isinstance(v0, dict)
143+
and sorted(v0.keys()) == ['color', 'ind']
144+
for k0, v0 in dcolor.items()
145+
])
146+
)
147+
if not c0:
148+
msg = (
149+
"Arg dcolor must be a dict of sub-dicts of shape:\n"
150+
"\t- 'key0': {'ind': ..., 'color': ...}\n"
151+
"\t- ...\n"
152+
"\t- 'keyN': {'ind': ..., 'color': ...}\n"
153+
f"Provided:\n{dcolor}\n"
154+
)
155+
raise Exception(msg)
156+
157+
# --------------------
158+
# ind and color checks
159+
160+
dfail = {}
161+
shape = data.shape
162+
for k0, v0 in dcolor.items():
163+
164+
c0 = (
165+
isinstance(v0['ind'], np.ndarray)
166+
and v0['ind'].shape == data.shape
167+
and v0['ind'].dtype == bool
168+
)
169+
if not c0:
170+
msg = f"'ind' must be a {shape} bool array, not {v0['ind']}"
171+
dfail[k0] = (msg,)
172+
173+
if not mcolors.is_color_like(v0['color']):
174+
msg = f"'color' must be color-like, not {v0['color']}"
175+
if k0 in dfail:
176+
dfail[k0] = dfail[k0] + (msg,)
177+
else:
178+
dfail[k0] = (msg,)
179+
180+
# raise exception
181+
if len(dfail) > 0:
182+
lmax = np.max([len(f"\t- {k0}: ") for k0 in dfail.keys()])
183+
lstr = [
184+
f"\t- {k0}:\n".ljust(lmax) + '\n'.join([
185+
"".ljust(lmax+4) + f"\t- {v1}".rjust(lmax)
186+
for ii, v1 in enumerate(v0)
187+
])
188+
for k0, v0 in dfail.items()
189+
]
190+
msg = (
191+
"Arg dcolor, the following keys have incorrect keys / values:\n"
192+
+ "\n".join(lstr)
193+
)
194+
raise Exception(msg)
195+
196+
# ----------------------
197+
# format colors to rgb
198+
199+
dcol = {}
200+
for k0, v0 in dcolor.items():
201+
if np.any(v0['ind']):
202+
dcol[k0] = {
203+
'ind': v0['ind'],
204+
'color': mcolors.to_rgb(v0['color']),
205+
}
206+
207+
# ------------------
208+
# color_default
209+
# ------------------
210+
211+
if color_default is None:
212+
color_default = 'k'
213+
if not mcolors.is_color_like(color_default):
214+
msg = (
215+
"Arg color_default must be color-like!\n"
216+
f"Provided: {color_default}\n"
217+
)
218+
raise Exception(msg)
219+
220+
color_default = mcolors.to_rgb(color_default)
221+
222+
# ------------------
223+
# vmin, vmax
224+
# ------------------
225+
226+
vmin0 = np.nanmin(data)
227+
vmax0 = np.nanmax(data)
228+
229+
# vmin
230+
if vmin is None:
231+
vmin = vmin0
232+
c0 = (np.isscalar(vmin) and np.isfinite(vmin) and vmin < vmax0)
233+
if not c0:
234+
msg = (
235+
f"Arg vmin must be a finite scalar below max ({vmax0})\n"
236+
f"Provided: {vmin}\n"
237+
)
238+
raise Exception(msg)
239+
240+
# vmax
241+
if vmax is None:
242+
vmax = vmax0
243+
c0 = (np.isscalar(vmax) and np.isfinite(vmax) and vmax > vmin0)
244+
if not c0:
245+
msg = (
246+
f"Arg vmax must be a finite scalar above min ({vmin0})\n"
247+
f"Provided: {vmax}\n"
248+
)
249+
raise Exception(msg)
250+
251+
# ordering
252+
if vmin >= vmax:
253+
msg = (
254+
"Arg vmin must be below vmax!\n"
255+
f"Provided:\n\t- vmin = {vmin}\n\t- vmax = {vmax}\n"
256+
)
257+
raise Exception(msg)
258+
259+
# ------------------
260+
# log
261+
# ------------------
262+
263+
log = ds._generic_check._check_var(
264+
log, 'log',
265+
types=bool,
266+
default=False,
267+
)
268+
269+
return data, dcol, color_default, vmin, vmax, log

datastock/_class1_compute.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,4 +1233,4 @@ def _extract_select(
12331233
# lkey=[idq2dR],
12341234
# return_all=True,
12351235
# )
1236-
# return out
1236+
# return out

datastock/_class1_interpolate.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,7 +1574,8 @@ def _xunique(dout=None, domain=None):
15741574
}
15751575

15761576
# Number of Nones expected
1577-
nNone = 1 + len(domain)
1577+
ndom = 0 if domain is None else len(domain)
1578+
nNone = 1 + ndom
15781579

15791580
# check
15801581
dwrong = {k0: v0 for k0, v0 in dind.items() if len(v0) != nNone}
@@ -1583,7 +1584,7 @@ def _xunique(dout=None, domain=None):
15831584
f"\t- {k0}: {dout[k0]['ref']} => {v0}" for k0, v0 in dwrong.items()
15841585
]
15851586
msg = (
1586-
"Interpolate unique pt => ref should have nNone = 1 + {len(domain)}:\n"
1587+
"Interpolate unique pt => ref should have nNone = 1 + {ndom}:\n"
15871588
+ "\n".join(lstr)
15881589
)
15891590
raise Exception(msg)
@@ -1626,7 +1627,12 @@ def _store(
16261627
ldata = list(set(itt.chain.from_iterable([
16271628
v0['ref'] for v0 in dout.values()
16281629
])))
1629-
coll2 = coll.extract(keys=ldata, vectors=True)
1630+
1631+
coll2 = coll.extract(
1632+
keys=ldata,
1633+
inc_vectors=True,
1634+
return_keys=False,
1635+
)
16301636

16311637
# -------------
16321638
# store_keys
@@ -1644,7 +1650,13 @@ def _store(
16441650
excluded=lout,
16451651
)
16461652

1647-
assert len(store_keys) == len(dout)
1653+
if len(store_keys) != len(dout):
1654+
msg = (
1655+
"Nb of store_keys != nb of keys in dout!\n"
1656+
f"\t- store_keys:\n{store_keys}\n "
1657+
f"\t- dout.keys():\n{sorted(dout.keys())}\n "
1658+
)
1659+
raise Exception(msg)
16481660

16491661
# ---------
16501662
# add data
@@ -1658,4 +1670,4 @@ def _store(
16581670
units=v0['units'],
16591671
)
16601672

1661-
return coll2
1673+
return coll2

0 commit comments

Comments
 (0)