kplot 1.0.6__tar.gz → 1.1.0__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.
- {kplot-1.0.6 → kplot-1.1.0}/PKG-INFO +2 -2
- {kplot-1.0.6 → kplot-1.1.0}/pyproject.toml +2 -2
- kplot-1.1.0/src/kplot/axes.py +63 -0
- kplot-1.1.0/src/kplot/cmaps.py +98 -0
- {kplot-1.0.6 → kplot-1.1.0}/src/kplot/hist.py +3 -7
- kplot-1.1.0/src/kplot/image.py +375 -0
- kplot-1.1.0/src/kplot/movie.py +173 -0
- {kplot-1.0.6 → kplot-1.1.0}/src/kplot/plot.py +28 -16
- {kplot-1.0.6 → kplot-1.1.0}/src/kplot/threeD/slider_images.py +20 -2
- {kplot-1.0.6 → kplot-1.1.0}/src/kplot/utils.py +20 -4
- kplot-1.0.6/src/kplot/.git/COMMIT_EDITMSG +0 -1
- kplot-1.0.6/src/kplot/.git/HEAD +0 -1
- kplot-1.0.6/src/kplot/.git/config +0 -13
- kplot-1.0.6/src/kplot/.git/description +0 -1
- kplot-1.0.6/src/kplot/.git/hooks/applypatch-msg.sample +0 -15
- kplot-1.0.6/src/kplot/.git/hooks/commit-msg.sample +0 -24
- kplot-1.0.6/src/kplot/.git/hooks/fsmonitor-watchman.sample +0 -174
- kplot-1.0.6/src/kplot/.git/hooks/post-update.sample +0 -8
- kplot-1.0.6/src/kplot/.git/hooks/pre-applypatch.sample +0 -14
- kplot-1.0.6/src/kplot/.git/hooks/pre-commit.sample +0 -49
- kplot-1.0.6/src/kplot/.git/hooks/pre-merge-commit.sample +0 -13
- kplot-1.0.6/src/kplot/.git/hooks/pre-push.sample +0 -53
- kplot-1.0.6/src/kplot/.git/hooks/pre-rebase.sample +0 -169
- kplot-1.0.6/src/kplot/.git/hooks/pre-receive.sample +0 -24
- kplot-1.0.6/src/kplot/.git/hooks/prepare-commit-msg.sample +0 -42
- kplot-1.0.6/src/kplot/.git/hooks/push-to-checkout.sample +0 -78
- kplot-1.0.6/src/kplot/.git/hooks/sendemail-validate.sample +0 -77
- kplot-1.0.6/src/kplot/.git/hooks/update.sample +0 -128
- kplot-1.0.6/src/kplot/.git/index +0 -0
- kplot-1.0.6/src/kplot/.git/info/exclude +0 -6
- kplot-1.0.6/src/kplot/.git/logs/HEAD +0 -1
- kplot-1.0.6/src/kplot/.git/logs/refs/heads/master +0 -1
- kplot-1.0.6/src/kplot/.git/logs/refs/remotes/origin/master +0 -1
- kplot-1.0.6/src/kplot/.git/objects/07/58a12cf558f1c1052d5d85fc11183eaa8c5a0e +0 -1
- kplot-1.0.6/src/kplot/.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/4b/ec2657a7dbd45dbe73e37138d116f523faa959 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/4f/5409d618f7e38d537b978d5f41a3631b32b711 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/51/3c1f584825f2ef997c0b00889ad1e6bb8bc8b1 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/53/95a83111291f805f440b8fed0dad2591e90c4b +0 -2
- kplot-1.0.6/src/kplot/.git/objects/66/594a4f54fe76d07b6cc028ea590f8cfa3d43f6 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/73/77c78423a1b6d14a6d87a8748bf57f229ce10f +0 -0
- kplot-1.0.6/src/kplot/.git/objects/7e/836e7020b269a8d4f8fd1add726cf6c32ffa61 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/b0/df8909fba782cf7f1bda3436475eca0f3246d4 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/b2/98659e19d2219f0191793d2d22f41e58f70a32 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/d5/8e4034057f2585ea9dd383bfca171cbe9d6842 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/dd/527a8b9e974453467c66d8f54053eb0f220435 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/dd/ab85719ab389187ded217518e30e0f1b6d6bf9 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/e2/c2413a8beac9a9fb63279a8c01bcc0d63db27a +0 -0
- kplot-1.0.6/src/kplot/.git/objects/e4/6a79e332a3be7fe4514bab28f14acae9f4f3bd +0 -0
- kplot-1.0.6/src/kplot/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
- kplot-1.0.6/src/kplot/.git/objects/fe/004a1dce30bd84414e6ce55f7ff17dd098e37c +0 -0
- kplot-1.0.6/src/kplot/.git/refs/heads/master +0 -1
- kplot-1.0.6/src/kplot/.git/refs/remotes/origin/master +0 -1
- kplot-1.0.6/src/kplot/axes.py +0 -45
- kplot-1.0.6/src/kplot/cmaps.py +0 -10
- kplot-1.0.6/src/kplot/image.py +0 -214
- kplot-1.0.6/src/kplot/movie.py +0 -41
- kplot-1.0.6/src/kplot/py.typed +0 -0
- {kplot-1.0.6 → kplot-1.1.0}/README.md +0 -0
- {kplot-1.0.6 → kplot-1.1.0}/src/kplot/__init__.py +0 -0
- {kplot-1.0.6 → kplot-1.1.0}/src/kplot/styles/example.mpl +0 -0
- {kplot-1.0.6 → kplot-1.1.0}/src/kplot/styles/publication.mpl +0 -0
- {kplot-1.0.6 → kplot-1.1.0}/src/kplot/threeD/__init__.py +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
from kplot.utils import column_width, two_column_width
|
|
5
|
+
|
|
6
|
+
from matplotlib.pyplot import subplots as matplotlib_subplots
|
|
7
|
+
from matplotlib.pyplot import subplot_mosaic
|
|
8
|
+
from matplotlib.figure import Figure
|
|
9
|
+
from matplotlib.axes import Axes
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
13
|
+
# >-|===|> Types <|===|-<
|
|
14
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
15
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
16
|
+
# >-|===|> Definitions <|===|-<
|
|
17
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
18
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
19
|
+
# >-|===|> Functions <|===|-<
|
|
20
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
21
|
+
def decode_subplots_args(*args, **kwargs):
|
|
22
|
+
if 'figsize' in kwargs: kwargs['figsize'] = tuple(
|
|
23
|
+
column_width if kwargs['figsize'][i]==1 else two_column_width if kwargs['figsize'][i]==2 else kwargs['figsize'][i]
|
|
24
|
+
for i in range(2))
|
|
25
|
+
match args:
|
|
26
|
+
case (int(), int())|((int(), int())):
|
|
27
|
+
return matplotlib_subplots(*args, **kwargs)
|
|
28
|
+
case (str(),):
|
|
29
|
+
return subplot_mosaic(*args, **kwargs)
|
|
30
|
+
case ():
|
|
31
|
+
return matplotlib_subplots(**kwargs)
|
|
32
|
+
def subplots(*args, **kwargs): return decode_subplots_args(*args, **kwargs)
|
|
33
|
+
def access_subplots(
|
|
34
|
+
fig: None|Figure = None,
|
|
35
|
+
axes: None|Axes|list = None,
|
|
36
|
+
figsize: None|tuple = None
|
|
37
|
+
) -> tuple[Figure, list]:
|
|
38
|
+
match fig, axes:
|
|
39
|
+
# if given nothing
|
|
40
|
+
case None, None:
|
|
41
|
+
fig, axes = subplots(figsize=figsize)
|
|
42
|
+
axes = [axes]
|
|
43
|
+
case Figure(), None:
|
|
44
|
+
axes = fig.get_axes()
|
|
45
|
+
axes = axes if len(axes) > 0 else [fig.add_subplot(111)]
|
|
46
|
+
case None, Axes():
|
|
47
|
+
fig = axes.get_figure()
|
|
48
|
+
axes = [axes]
|
|
49
|
+
case None, list()|np.ndarray():
|
|
50
|
+
axes = axes.flatten()
|
|
51
|
+
fig = axes[0].get_figure()
|
|
52
|
+
case Figure(), Axes():
|
|
53
|
+
axes = [axes]
|
|
54
|
+
case Figure(), list()|np.ndarray():
|
|
55
|
+
return fig, axes
|
|
56
|
+
return fig, axes
|
|
57
|
+
|
|
58
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
59
|
+
# >-|===|> Decorators <|===|-<
|
|
60
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
61
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
62
|
+
# >-|===|> Classes <|===|-<
|
|
63
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
from kbasic.array import tile
|
|
5
|
+
from functools import wraps
|
|
6
|
+
from glob import glob
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from matplotlib.pyplot import cm
|
|
9
|
+
from matplotlib.colors import Colormap, LinearSegmentedColormap, ListedColormap, hex2color, Normalize, LogNorm, FuncNorm, AsinhNorm, PowerNorm, SymLogNorm, BoundaryNorm, CenteredNorm, TwoSlopeNorm
|
|
10
|
+
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
14
|
+
# >-|===|> Types <|===|-<
|
|
15
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
16
|
+
class Norm:
|
|
17
|
+
types: list = [Normalize, LogNorm, FuncNorm, AsinhNorm, PowerNorm, SymLogNorm, BoundaryNorm, CenteredNorm, TwoSlopeNorm]
|
|
18
|
+
class Cmap:
|
|
19
|
+
types: list = [Colormap, ListedColormap, LinearSegmentedColormap]
|
|
20
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
21
|
+
# >-|===|> Definitions <|===|-<
|
|
22
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
23
|
+
pink = "#E34F68"
|
|
24
|
+
lightpink = "#E39FAA"
|
|
25
|
+
blue = "#7350E6"
|
|
26
|
+
lightblue = "#AE9FE3"
|
|
27
|
+
shadow = "#B8B7B8"
|
|
28
|
+
manoaskies = LinearSegmentedColormap.from_list("manoaskies", [pink, blue])
|
|
29
|
+
manoaskies_centered = LinearSegmentedColormap.from_list("manoaskies_centered", [lightpink, pink, "#000000", blue, lightblue])
|
|
30
|
+
manoaskies_background_blue = "#0C0524"
|
|
31
|
+
pink2grey = LinearSegmentedColormap.from_list("p2g", [pink, shadow])
|
|
32
|
+
grey2black = LinearSegmentedColormap.from_list("g2b", [shadow, "#000000"])
|
|
33
|
+
colors_list = np.zeros((256, 4))
|
|
34
|
+
colors_list[:128] = list(hex2color(manoaskies_background_blue))+[1]
|
|
35
|
+
for i in range(28): colors_list[128+i] = pink2grey(i/28)
|
|
36
|
+
for i in range(100): colors_list[156+i] = grey2black(i/150)
|
|
37
|
+
manoaskies_beauty = ListedColormap(colors_list)
|
|
38
|
+
default_cmap = cm.plasma
|
|
39
|
+
|
|
40
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
41
|
+
# >-|===|> Functions <|===|-<
|
|
42
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
43
|
+
# # Ploting utils
|
|
44
|
+
def auto_norm(
|
|
45
|
+
norm: str,
|
|
46
|
+
frames: np.ndarray,
|
|
47
|
+
linear_threshold: float|None = None,
|
|
48
|
+
center: float|None = None,
|
|
49
|
+
saturate: float|None = None
|
|
50
|
+
) -> Norm:
|
|
51
|
+
"""A function to create a matplotlib normalization given a set images.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
norm (str): what type of scale to use, e.g. lognorm or centerednorm
|
|
55
|
+
frames (np.ndarray): the images to base the normalization on
|
|
56
|
+
linear_threshold (float | None, optional): for symlognorm. Defaults to None.
|
|
57
|
+
center (float | None, optional): for centered normalizations. Defaults to None.
|
|
58
|
+
saturate (float | None, optional): the level at which to saturate the norm, e.g. if saturate=0.01 then the
|
|
59
|
+
max is the 99th percentile. Defaults to None.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
matplotlib normalization
|
|
63
|
+
"""
|
|
64
|
+
frames = frames[(-np.inf < frames)&(frames < np.inf)]
|
|
65
|
+
# set min/max IF saturate is None or IF saturate is a tuple ELSE assume its a float
|
|
66
|
+
low = np.nanmin(frames) if saturate is None else np.nanquantile(frames, 1-saturate[0]) if isinstance(saturate, tuple) else np.nanquantile(frames, 1-saturate)
|
|
67
|
+
high = np.nanmax(frames) if saturate is None else np.nanquantile(frames, 0+saturate[1]) if isinstance(saturate, tuple) else np.nanquantile(frames, 0+saturate)
|
|
68
|
+
match norm.lower():
|
|
69
|
+
case "lognorm"|"log":
|
|
70
|
+
if low < 0: raise ValueError(f"minimum is {low}, LogNorm only takes positive values")
|
|
71
|
+
if low==0: low=np.nanmin(frames[frames!=0])
|
|
72
|
+
return LogNorm(vmin=low, vmax=high)
|
|
73
|
+
case "symlognorm"|"symlog"|"sym":
|
|
74
|
+
sig = np.nanstd(frames)
|
|
75
|
+
mu = np.nanmean(frames)
|
|
76
|
+
if np.abs(mu)-sig > 0: raise TypeError("SymLogNorm is only designed for stuff close to zero!")
|
|
77
|
+
return SymLogNorm(sig if linear_threshold is None else linear_threshold, vmin=low, vmax=high)
|
|
78
|
+
case n if n in ["centerednorm", "twoslope", "twoslopenorm"]:
|
|
79
|
+
sig = np.nanstd(frames)
|
|
80
|
+
mu = np.nanmean(frames)
|
|
81
|
+
# for the center use center if give otherwise use 0 if mean is small, else use mean
|
|
82
|
+
vcenter = center if not center is None else 0 if np.abs(mu)-sig > 0 else mu
|
|
83
|
+
return TwoSlopeNorm(vmin=low, vcenter=vcenter, vmax=high)
|
|
84
|
+
case _: return Normalize(vmin=low, vmax=high)
|
|
85
|
+
def align_algorithm(x: list|np.ndarray, mode: str):
|
|
86
|
+
match mode:
|
|
87
|
+
case 'mid'|'m'|'center'|'c':
|
|
88
|
+
return [(x[i] + x[i+1])/2 for i in range(len(x)-1)]
|
|
89
|
+
case 'logmid'|'lm':
|
|
90
|
+
return [np.log10((10**x[i] + 10**x[i+1])/ 2) for i in range(len(x)-1)]
|
|
91
|
+
case 'left'|'l':
|
|
92
|
+
return x[:-1]
|
|
93
|
+
case 'right'|'r':
|
|
94
|
+
return x[1:]
|
|
95
|
+
|
|
96
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
97
|
+
# >-|===|> Decorators <|===|-<
|
|
98
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
@@ -5,11 +5,9 @@
|
|
|
5
5
|
from kplot.utils import alias_kwarg, column_width
|
|
6
6
|
from kplot.axes import access_subplots
|
|
7
7
|
from kplot.utils import alias_kwarg, column_width, parse_multiax_params
|
|
8
|
-
|
|
8
|
+
from kplot.cmaps import Cmap
|
|
9
9
|
import numpy as np
|
|
10
10
|
import matplotlib.pyplot as plt
|
|
11
|
-
from matplotlib.colors import ListedColormap, LinearSegmentedColormap, Colormap
|
|
12
|
-
CmapTypes = [ListedColormap, LinearSegmentedColormap, Colormap]
|
|
13
11
|
|
|
14
12
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
15
13
|
# >-|===|> Definitions <|===|-<
|
|
@@ -21,8 +19,6 @@ CmapTypes = [ListedColormap, LinearSegmentedColormap, Colormap]
|
|
|
21
19
|
def decode_hist_src(src) -> tuple:
|
|
22
20
|
match src:
|
|
23
21
|
case np.ndarray()|list(): return src
|
|
24
|
-
|
|
25
|
-
|
|
26
22
|
def hist(
|
|
27
23
|
*src,
|
|
28
24
|
#figure setup
|
|
@@ -32,8 +28,8 @@ def hist(
|
|
|
32
28
|
show: bool = False,
|
|
33
29
|
close: bool = False,
|
|
34
30
|
#line formating
|
|
35
|
-
color: str|
|
|
36
|
-
cmap: str|
|
|
31
|
+
color: str|Cmap|list[int] = "black",
|
|
32
|
+
cmap: str|Cmap = plt.cm.plasma,
|
|
37
33
|
linewidth: int = None, lw: int = None,
|
|
38
34
|
linestyle: str = None, ls: str = None,
|
|
39
35
|
#plot formating
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
from kplot.axes import access_subplots
|
|
5
|
+
from kplot.utils import alias_kwarg, parse_multiax_params, column_width, two_column_width
|
|
6
|
+
from kplot.cmaps import Norm, Cmap
|
|
7
|
+
import numpy as np
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
|
10
|
+
from matplotlib.colors import ListedColormap, LinearSegmentedColormap, Colormap
|
|
11
|
+
|
|
12
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
13
|
+
# >-|===|> Types <|===|-<
|
|
14
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
15
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
16
|
+
# >-|===|> Definitions <|===|-<
|
|
17
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
18
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
19
|
+
# >-|===|> Functions <|===|-<
|
|
20
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
21
|
+
def decode_image_src(src) -> np.ndarray:
|
|
22
|
+
match src:
|
|
23
|
+
case str():
|
|
24
|
+
return np.loadtxt(src)
|
|
25
|
+
case np.ndarray():
|
|
26
|
+
return src
|
|
27
|
+
case list():
|
|
28
|
+
return np.array(src)
|
|
29
|
+
def _show_one_frame(plot_dict, axes_dict, cbar_dict, **kwargs):
|
|
30
|
+
# populate name space
|
|
31
|
+
x, y, image = plot_dict['x'], plot_dict['y'], plot_dict['image']
|
|
32
|
+
fig, ax, cmap, norm = plot_dict['fig'], plot_dict['axes'][0], plot_dict['cmap'], plot_dict['norm']
|
|
33
|
+
# plot
|
|
34
|
+
img = ax.pcolormesh(x, y, image, cmap=cmap, norm=norm, **kwargs)
|
|
35
|
+
# label axes
|
|
36
|
+
ax.set_xlabel(axes_dict['xlabel'])
|
|
37
|
+
ax.set_ylabel(axes_dict['ylabel'])
|
|
38
|
+
# set limits
|
|
39
|
+
ax.set_xlim(axes_dict['xlim'])
|
|
40
|
+
ax.set_ylim(axes_dict['ylim'])
|
|
41
|
+
# set title
|
|
42
|
+
ax.set_title(axes_dict['title'])
|
|
43
|
+
# set aspect
|
|
44
|
+
ax.set_aspect(axes_dict['aspect'])
|
|
45
|
+
if cbar_dict['colorbar']:
|
|
46
|
+
divider = make_axes_locatable(ax)
|
|
47
|
+
cax = divider.append_axes(
|
|
48
|
+
cbar_dict['location'],
|
|
49
|
+
size=cbar_dict['size'],
|
|
50
|
+
pad=cbar_dict['pad']
|
|
51
|
+
)
|
|
52
|
+
fig.colorbar(
|
|
53
|
+
img,
|
|
54
|
+
cax=cax, ax=ax,
|
|
55
|
+
ticks=cbar_dict['cticks'],
|
|
56
|
+
label=cbar_dict['units']
|
|
57
|
+
)
|
|
58
|
+
return [img]
|
|
59
|
+
def construct_mass_norm(images: np.ndarray, norm):
|
|
60
|
+
match norm:
|
|
61
|
+
# linear norms
|
|
62
|
+
case Normalize():
|
|
63
|
+
vmin = np.nanmin(images) if norm.vmin is None else norm.vmin
|
|
64
|
+
vmax = np.nanmax(images) if norm.vmax is None else norm.vmax
|
|
65
|
+
return Normalize(vmin=vmin, vmax=vmax, clip=norm.clip)
|
|
66
|
+
|
|
67
|
+
case CenteredNorm():
|
|
68
|
+
vmin = np.nanmin(images) if norm.vmin is None else norm.vmin
|
|
69
|
+
vmax = np.nanmax(images) if norm.vmax is None else norm.vmax
|
|
70
|
+
# only center at 0 if the mean is close to 0 to avoid weird balance
|
|
71
|
+
vcen = norm.vcenter if norm.vcenter else 0 if np.nanmean(images) - np.nanstd(images)/2 else np.nanmean(images)
|
|
72
|
+
hrng = norm.halfrange if norm.halfrange else vmax/2 if vcen==0 else abs(vmax-vmin)/2
|
|
73
|
+
return CenteredNorm(vcenter=vcen, halfrange=hrng, clip=norm.clip)
|
|
74
|
+
|
|
75
|
+
case TwoSlopeNorm():
|
|
76
|
+
vmin = np.nanmin(images) if norm.vmin is None else norm.vmin
|
|
77
|
+
vmax = np.nanmax(images) if norm.vmax is None else norm.vmax
|
|
78
|
+
vcen = norm.vcenter if norm.vcenter else 0 if np.nanmean(images) - np.nanstd(images)/2 else np.nanmean(images)
|
|
79
|
+
return TwoSlopeNorm(vcenter=vcen, vmin=vmin, vmax=vmax)
|
|
80
|
+
|
|
81
|
+
case BoundaryNorm():
|
|
82
|
+
return BoundaryNorm(norm.boundaries, norm.ncolors, clip=norm.clip, extend=norm.extend)
|
|
83
|
+
|
|
84
|
+
# log-like norms
|
|
85
|
+
case LogNorm():
|
|
86
|
+
vmin = np.nanmin(images) if norm.vmin is None else norm.vmin
|
|
87
|
+
vmax = np.nanmax(images) if norm.vmax is None else norm.vmax
|
|
88
|
+
return LogNorm(vmin=vmin, vmax=vmax, clip=norm.clip)
|
|
89
|
+
|
|
90
|
+
case SymLogNorm():
|
|
91
|
+
vmin = np.nanmin(images) if norm.vmin is None else norm.vmin
|
|
92
|
+
vmax = np.nanmax(images) if norm.vmax is None else norm.vmax
|
|
93
|
+
#check that this isn't trivially the same as LogNorm
|
|
94
|
+
if vmin > 0: return LogNorm(vmin=vmin, vmax=vmax, clip=norm.clip)
|
|
95
|
+
linthresh = np.nanquantile(images, .1) if norm.linthresh is None else norm.linthresh
|
|
96
|
+
return SymLogNorm(linthresh, linscale=norm.linscale, vmin=vmin, vmax=vmax, clip=norm.clip)
|
|
97
|
+
|
|
98
|
+
case AsinhNorm():
|
|
99
|
+
vmin = np.nanmin(images) if norm.vmin is None else norm.vmin
|
|
100
|
+
vmax = np.nanmax(images) if norm.vmax is None else norm.vmax
|
|
101
|
+
linwidth = np.nanquantile(images, .1) if norm.linear_width is None else norm.linear_width
|
|
102
|
+
return AsinhNorm(linear_width=linwidth, vmin=vmin, vmax=vmax, clip=norm.clip)
|
|
103
|
+
|
|
104
|
+
case PowerNorm():
|
|
105
|
+
vmin = np.nanmin(images) if norm.vmin is None else norm.vmin
|
|
106
|
+
vmax = np.nanmax(images) if norm.vmax is None else norm.vmax
|
|
107
|
+
return PowerNorm(norm.gamma, vmin=vmin, vmax=vmax, clip=norm.clip)
|
|
108
|
+
|
|
109
|
+
case FuncNorm():
|
|
110
|
+
vmin = np.nanmin(images) if norm.vmin is None else norm.vmin
|
|
111
|
+
vmax = np.nanmax(images) if norm.vmax is None else norm.vmax
|
|
112
|
+
return FuncNorm(norm.functions, vmin=vmin, vmax=vmax, clip=norm.clip)
|
|
113
|
+
|
|
114
|
+
pass
|
|
115
|
+
def _show_multiple_frames(plot_dict: dict, axes_dict: dict, cbar_dict: dict, N: int, **kwargs):
|
|
116
|
+
fig, axes, images = plot_dict['fig'], plot_dict['axes'], plot_dict['image'] # these are set as single and multiple before arriving to this function
|
|
117
|
+
xs = parse_multiax_params(plot_dict['x'], [np.ndarray], N)
|
|
118
|
+
ys = parse_multiax_params(plot_dict['y'], [np.ndarray], N)
|
|
119
|
+
cmaps = parse_multiax_params(plot_dict['cmap'], Cmap.types, N)
|
|
120
|
+
colorbars = 'single' if cbar_dict['colorbar']=='single' else parse_multiax_params(cbar_dict['colorbar'], [bool], N)
|
|
121
|
+
norms = 'single' if colorbars=='single' else parse_multiax_params(plot_dict['norm'], Norm.types, N)
|
|
122
|
+
cbar_locations = parse_multiax_params(cbar_dict['location'], [str], N)
|
|
123
|
+
cbar_sizes = parse_multiax_params(cbar_dict['size'], [str], N)
|
|
124
|
+
cbar_pads = parse_multiax_params(cbar_dict['pad'], [float], N)
|
|
125
|
+
cticks = parse_multiax_params(cbar_dict['cticks'], [list], N)
|
|
126
|
+
units = parse_multiax_params(cbar_dict['units'], [str], N)
|
|
127
|
+
xlims = parse_multiax_params(axes_dict['xlim'], [tuple], N)
|
|
128
|
+
ylims = parse_multiax_params(axes_dict['ylim'], [tuple], N)
|
|
129
|
+
xlabels = 'single' if type(axes_dict['xlabel'])==str else parse_multiax_params(axes_dict['xlabel'], [str], N)
|
|
130
|
+
ylabels = 'single' if type(axes_dict['ylabel'])==str else parse_multiax_params(axes_dict['ylabel'], [str], N)
|
|
131
|
+
titles = 'single' if type(axes_dict['title'])==str else parse_multiax_params(axes_dict['title'], [str], N)
|
|
132
|
+
aspects = parse_multiax_params(axes_dict['aspect'], [str], N)
|
|
133
|
+
imgs = []
|
|
134
|
+
for i in range(N):
|
|
135
|
+
ax, image = axes[i], images[i]
|
|
136
|
+
imgs.append(ax.pcolormesh(xs[i], ys[i], image, cmap=cmaps[i], norm=norms[i], **kwargs))
|
|
137
|
+
return imgs
|
|
138
|
+
def show(
|
|
139
|
+
field: np.ndarray,
|
|
140
|
+
tile_image: bool = False,
|
|
141
|
+
#x/y axes
|
|
142
|
+
x: np.ndarray|None = None,
|
|
143
|
+
y: np.ndarray|None = None,
|
|
144
|
+
#figure setup
|
|
145
|
+
fig = None,
|
|
146
|
+
ax = None,
|
|
147
|
+
axis: bool = True,
|
|
148
|
+
figsize: tuple[float, float] = (10, 10),
|
|
149
|
+
show: bool = False,
|
|
150
|
+
#plot parameters
|
|
151
|
+
cmap = default_cmap,
|
|
152
|
+
colorbar: bool = True,
|
|
153
|
+
colorbar_style: dict = {'location':'right', "size":"7%", "pad":0.05},
|
|
154
|
+
cticks: list|None = None,
|
|
155
|
+
units: str|None = None,
|
|
156
|
+
#contour options
|
|
157
|
+
contour: np.ndarray|None = None,
|
|
158
|
+
contour_style: dict = {'levels': 10, 'colors': 'black'},
|
|
159
|
+
#plot formating
|
|
160
|
+
xlim: tuple = (None, None),
|
|
161
|
+
ylim: tuple = (None, None),
|
|
162
|
+
title: str|None = None,
|
|
163
|
+
#presentation parameters
|
|
164
|
+
save: str = "",
|
|
165
|
+
dpi: int = 100,
|
|
166
|
+
#everything else goes into pcolormesh
|
|
167
|
+
**kwargs
|
|
168
|
+
):
|
|
169
|
+
"""a convinient way to plt.imshow and arrange it nicely
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
field (np.ndarray): The image to be plotted
|
|
173
|
+
tile_image (bool, optional): whether to tile the image. Defaults to False.
|
|
174
|
+
x (np.ndarray | None, optional): x coordinates of pixels. Defaults to None.
|
|
175
|
+
y (np.ndarray | None, optional): y coordinates of pixels. Defaults to None.
|
|
176
|
+
fig (plt.Figure, optional): the figure on which to plot. Defaults to None.
|
|
177
|
+
ax (plt.Axes, optional): the ax on which to plot this image. Defaults to None.
|
|
178
|
+
axis (bool, optional): whether to include the whole axis, if False then only the plot area will be shown.
|
|
179
|
+
figsize (tuple[float, float], optional): unless fig and ax are given plot on a figure of this size. Defaults to (10, 10).
|
|
180
|
+
show (bool, optional): whether to use the plt.show() command at the end. Defaults to True.
|
|
181
|
+
cmap (plt.ColorMap, optional): the colormap to use for the image. Defaults to plasma.
|
|
182
|
+
colorbar (bool, optional): whether to add a colorbar. Defaults to True.
|
|
183
|
+
colorbar_style (dict, optional): dictionary containing kwargs for the colorbar command. Defaults to {'location':'right', "size":"7%", "pad":0.05}.
|
|
184
|
+
cticks (list | None, optional): the ticks to use on the colorbar. Defaults to None.
|
|
185
|
+
units (str | None, optional): label for the colorbar. Defaults to None.
|
|
186
|
+
contour (np.ndarray | None, optional): whether to put a contour plot on top. Defaults to None.
|
|
187
|
+
contour_style (dict, optional): kwargs for contour plotting command. Defaults to {'levels': 10, 'colors': 'black'}.
|
|
188
|
+
xlim (tuple, optional): the limits on the x axis. Defaults to (None, None).
|
|
189
|
+
ylim (tuple, optional): the limits on the y axis. Defaults to (None, None).
|
|
190
|
+
title (str | None, optional): the plot title. Defaults to None.
|
|
191
|
+
save (str, optional): if given save the plot to this path. Defaults to "".
|
|
192
|
+
dpi (int, optional): dots per inch to save at. Defaults to 100.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
fig (plt.Figure): The figure on which the plot was put
|
|
196
|
+
ax (plt.Axes): The ax on which the plot was put
|
|
197
|
+
img (plt.Artist): the plot artist
|
|
198
|
+
"""
|
|
199
|
+
# prep data
|
|
200
|
+
assert (ndims:=len(field.shape))==2, f"show was given an image with {ndims} dimensions, please provide a 2d array"
|
|
201
|
+
image = tile(field) if tile_image else field
|
|
202
|
+
# check axes
|
|
203
|
+
if x is None: x, y = np.mgrid[:image.shape[0], :image.shape[1]]
|
|
204
|
+
if tile_image: x, y = np.r_[x, x+x[-1], x+2*x[-1]], np.r_[y, y+y[-1], y+2*y[-1]]
|
|
205
|
+
else: assert (len(x), len(y)) == image.shape, f"Given x of shape {len(x)} and y of shape {len(y)} but image is of shape {image.shape}"
|
|
206
|
+
# prep figure
|
|
207
|
+
if ax is None: (fig, ax) = plt.subplots(figsize=figsize)
|
|
208
|
+
fig = ax.get_figure()
|
|
209
|
+
if not axis:
|
|
210
|
+
ax.axis('off')
|
|
211
|
+
ax.set_position([0, 0, 1, 1])
|
|
212
|
+
colorbar = False
|
|
213
|
+
# plot data
|
|
214
|
+
img = ax.pcolormesh(x, y, image, cmap=cmap, **kwargs)
|
|
215
|
+
# colorbar
|
|
216
|
+
if colorbar:
|
|
217
|
+
divider = make_axes_locatable(ax)
|
|
218
|
+
colorbar_location = colorbar_style.pop("location") if "location" in colorbar_style.keys() else "right"
|
|
219
|
+
cax = divider.append_axes(colorbar_location, **colorbar_style)
|
|
220
|
+
fig.colorbar(img, cax=cax, ax=ax, ticks=cticks, label=units, orientation = 'vertical' if colorbar_location in ('right', 'left') else 'horizontal')
|
|
221
|
+
if colorbar_location=='top':
|
|
222
|
+
cax.xaxis.set_ticks_position('top')
|
|
223
|
+
cax.xaxis.set_label_position('top')
|
|
224
|
+
# contour
|
|
225
|
+
if not contour is None: ax.contour(contour, **contour_style)
|
|
226
|
+
# set limits
|
|
227
|
+
ax.set_xlim(xlim)
|
|
228
|
+
ax.set_ylim(ylim)
|
|
229
|
+
# set title
|
|
230
|
+
ax.set_title(title)
|
|
231
|
+
# set aspect
|
|
232
|
+
ax.set_aspect('equal')
|
|
233
|
+
# present the figure
|
|
234
|
+
if len(save)>0:
|
|
235
|
+
if not '.' in save: save +=".jpeg"
|
|
236
|
+
plt.savefig(save, dpi=dpi, bbox_inches='tight')
|
|
237
|
+
if show: plt.show()
|
|
238
|
+
return fig, ax, img
|
|
239
|
+
def contour(
|
|
240
|
+
Z: np.ndarray,
|
|
241
|
+
#x/y axes
|
|
242
|
+
x: np.ndarray|None = None,
|
|
243
|
+
y: np.ndarray|None = None,
|
|
244
|
+
#figure setup
|
|
245
|
+
fig = None,
|
|
246
|
+
ax = None,
|
|
247
|
+
axis: bool = True,
|
|
248
|
+
figsize: tuple[float, float] = (10, 10),
|
|
249
|
+
show: bool = False,
|
|
250
|
+
#plot parameters
|
|
251
|
+
levels = 10,
|
|
252
|
+
color = 'black',
|
|
253
|
+
colors = None,
|
|
254
|
+
cmap = None,
|
|
255
|
+
negative_linestyles = '-',
|
|
256
|
+
linestyles = '-',
|
|
257
|
+
#plot formating
|
|
258
|
+
xlim: tuple = (None, None),
|
|
259
|
+
ylim: tuple = (None, None),
|
|
260
|
+
title: str|None = None,
|
|
261
|
+
#presentation parameters
|
|
262
|
+
save: str = "",
|
|
263
|
+
dpi: int = 100,
|
|
264
|
+
#throw the rest in a dict
|
|
265
|
+
**kwds
|
|
266
|
+
):
|
|
267
|
+
# prep data
|
|
268
|
+
assert (ndims:=len(Z.shape))==2, f"show was given an image with {ndims} dimensions, please provide a 2d array"
|
|
269
|
+
# check axes
|
|
270
|
+
if x is None: x, y = np.mgrid[:Z.shape[0], :Z.shape[1]]
|
|
271
|
+
else: assert (len(x), len(y)) == Z.shape, f"Given x of shape {len(x)} and y of shape {len(y)} but image is of shape {image.shape}"
|
|
272
|
+
# prep figure
|
|
273
|
+
if ax is None: (fig, ax) = plt.subplots(figsize=figsize)
|
|
274
|
+
fig = ax.get_figure()
|
|
275
|
+
if not axis:
|
|
276
|
+
ax.axis('off')
|
|
277
|
+
ax.set_position([0, 0, 1, 1])
|
|
278
|
+
colorbar = False
|
|
279
|
+
# plot data
|
|
280
|
+
contour_dict = {'levels':levels,"linestyles":linestyles,'negative_linestyles':negative_linestyles}
|
|
281
|
+
if cmap: #plot with a cmap
|
|
282
|
+
contour_dict['cmap'] = cmap
|
|
283
|
+
else: #plot with a color
|
|
284
|
+
contour_dict['colors'] = color if not colors else colors
|
|
285
|
+
img = ax.contour(
|
|
286
|
+
x, y, Z,
|
|
287
|
+
**contour_dict,
|
|
288
|
+
**kwds
|
|
289
|
+
)
|
|
290
|
+
# set limits
|
|
291
|
+
ax.set_xlim(xlim)
|
|
292
|
+
ax.set_ylim(ylim)
|
|
293
|
+
# set title
|
|
294
|
+
ax.set_title(title)
|
|
295
|
+
# set aspect
|
|
296
|
+
ax.set_aspect('equal')
|
|
297
|
+
# present the figure
|
|
298
|
+
if len(save)>0:
|
|
299
|
+
if not '.' in save: save +=".jpeg"
|
|
300
|
+
plt.savefig(save, dpi=dpi)
|
|
301
|
+
if show: plt.show()
|
|
302
|
+
return fig, ax, img
|
|
303
|
+
def contourf(
|
|
304
|
+
Z: np.ndarray,
|
|
305
|
+
#x/y axes
|
|
306
|
+
x: np.ndarray|None = None,
|
|
307
|
+
y: np.ndarray|None = None,
|
|
308
|
+
#figure setup
|
|
309
|
+
fig = None,
|
|
310
|
+
ax = None,
|
|
311
|
+
axis: bool = True,
|
|
312
|
+
figsize: tuple[float, float] = (10, 10),
|
|
313
|
+
show: bool = False,
|
|
314
|
+
#plot parameters
|
|
315
|
+
levels = 10,
|
|
316
|
+
cmap = default_cmap,
|
|
317
|
+
colorbar: bool = True,
|
|
318
|
+
colorbar_style: dict = {'location':'right', "size":"7%", "pad":0.05},
|
|
319
|
+
cticks: list|None = None,
|
|
320
|
+
units: str|None = None,
|
|
321
|
+
#plot formating
|
|
322
|
+
xlim: tuple = (None, None),
|
|
323
|
+
ylim: tuple = (None, None),
|
|
324
|
+
title: str|None = None,
|
|
325
|
+
#presentation parameters
|
|
326
|
+
save: str = "",
|
|
327
|
+
dpi: int = 100,
|
|
328
|
+
#throw the rest in a dict
|
|
329
|
+
**kwds
|
|
330
|
+
):
|
|
331
|
+
# prep data
|
|
332
|
+
assert (ndims:=len(Z.shape))==2, f"show was given an image with {ndims} dimensions, please provide a 2d array"
|
|
333
|
+
# check axes
|
|
334
|
+
if x is None: x, y = np.mgrid[:z.shape[0], :z.shape[1]]
|
|
335
|
+
else: assert (len(x), len(y)) == z.shape, f"Given x of shape {len(x)} and y of shape {len(y)} but image is of shape {image.shape}"
|
|
336
|
+
# prep figure
|
|
337
|
+
if ax is None: (fig, ax) = plt.subplots(figsize=figsize)
|
|
338
|
+
fig = ax.get_figure()
|
|
339
|
+
if not axis:
|
|
340
|
+
ax.axis('off')
|
|
341
|
+
ax.set_position([0, 0, 1, 1])
|
|
342
|
+
colorbar = False
|
|
343
|
+
# plot data
|
|
344
|
+
contour_dict = {'levels':levels,"cmap":cmap}
|
|
345
|
+
img = ax.contourf(
|
|
346
|
+
x, y, Z,
|
|
347
|
+
**contour_dict,
|
|
348
|
+
**kwds
|
|
349
|
+
)
|
|
350
|
+
# colorbar
|
|
351
|
+
if colorbar:
|
|
352
|
+
divider = make_axes_locatable(ax)
|
|
353
|
+
colorbar_location = colorbar_style.pop("location") if "location" in colorbar_style.keys() else "right"
|
|
354
|
+
cax = divider.append_axes(colorbar_location, **colorbar_style)
|
|
355
|
+
fig.colorbar(img, cax=cax, ax=ax, ticks=cticks, label=units)
|
|
356
|
+
# set limits
|
|
357
|
+
ax.set_xlim(xlim)
|
|
358
|
+
ax.set_ylim(ylim)
|
|
359
|
+
# set title
|
|
360
|
+
ax.set_title(title)
|
|
361
|
+
# set aspect
|
|
362
|
+
ax.set_aspect('equal')
|
|
363
|
+
# present the figure
|
|
364
|
+
if len(save)>0:
|
|
365
|
+
if not '.' in save: save +=".jpeg"
|
|
366
|
+
plt.savefig(save, dpi=dpi)
|
|
367
|
+
if show: plt.show()
|
|
368
|
+
return fig, ax, img
|
|
369
|
+
|
|
370
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
371
|
+
# >-|===|> Decorators <|===|-<
|
|
372
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
373
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
374
|
+
# >-|===|> Classes <|===|-<
|
|
375
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|