Skip to content

Commit b23fea9

Browse files
authored
Merge pull request #107 from ianhi/imshow
create imshow function
2 parents 7d6e789 + 7896e12 commit b23fea9

File tree

5 files changed

+454
-8
lines changed

5 files changed

+454
-8
lines changed

docs/API.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ will use the built-in Matplotlib widgets.
1919
~mpl_interactions.interactive_plot_factory
2020
~mpl_interactions.interactive_hist
2121
~mpl_interactions.interactive_scatter
22+
~mpl_interactions.interactive_imshow
2223

2324

2425
generic
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"\n",
10+
"%matplotlib ipympl\n",
11+
"import matplotlib.pyplot as plt\n",
12+
"import numpy as np\n",
13+
"import ipywidgets as widgets\n",
14+
"%load_ext autoreload\n",
15+
"%autoreload 2\n",
16+
"from mpl_interactions import *"
17+
]
18+
},
19+
{
20+
"cell_type": "code",
21+
"execution_count": null,
22+
"metadata": {},
23+
"outputs": [],
24+
"source": [
25+
"\n",
26+
"import numpy as np\n",
27+
"parameter1 = np.linspace(-5,5)\n",
28+
"parameter2 = np.linspace(-5,5, 25)\n",
29+
"x = np.linspace(0,np.pi,200)\n",
30+
"y = np.linspace(0,10,200)\n",
31+
"X,Y = np.meshgrid(x,y)\n",
32+
"image_stack1 = np.sin(X)[None,:,:]+np.exp(np.cos(Y[None,:,:]*parameter1[:,None,None]))\n",
33+
"print(f\"image_stack1.shape : {image_stack1.shape}\")\n",
34+
"# image_stack1.shape : (50, 200, 200)\n",
35+
"\n",
36+
"# create another image stack with shape (50, 25, 200, 200)\n",
37+
"image_stack2 = np.sin(X)[None,None,:,:]*parameter2[:,None,None] + np.exp(np.cos(Y[None,:,:]*parameter1[:,None,None]))[:,None, ...]\n",
38+
"print(f\"image_stack2.shape : {image_stack2.shape}\")\n",
39+
"# image_stack2.shape : (50, 25, 200, 200)\n"
40+
]
41+
},
42+
{
43+
"cell_type": "code",
44+
"execution_count": null,
45+
"metadata": {},
46+
"outputs": [],
47+
"source": [
48+
"fig, ax = plt.subplots()\n",
49+
"im = ax.imshow(image_stack1[0])"
50+
]
51+
},
52+
{
53+
"cell_type": "code",
54+
"execution_count": null,
55+
"metadata": {},
56+
"outputs": [],
57+
"source": [
58+
"im.norm.vmin=4"
59+
]
60+
},
61+
{
62+
"cell_type": "code",
63+
"execution_count": null,
64+
"metadata": {},
65+
"outputs": [],
66+
"source": [
67+
"arr = image_stack1[0] + 15\n",
68+
"im.set_data(arr)\n",
69+
"# im.norm.autoscale(arr)"
70+
]
71+
},
72+
{
73+
"cell_type": "code",
74+
"execution_count": null,
75+
"metadata": {},
76+
"outputs": [],
77+
"source": [
78+
"im.norm.autoscale??"
79+
]
80+
},
81+
{
82+
"cell_type": "code",
83+
"execution_count": null,
84+
"metadata": {},
85+
"outputs": [],
86+
"source": [
87+
"im.norm.vmin = arr.min()\n",
88+
"im.norm.vmax = arr.max()\n",
89+
"fig.canvas.draw()"
90+
]
91+
},
92+
{
93+
"cell_type": "code",
94+
"execution_count": null,
95+
"metadata": {},
96+
"outputs": [],
97+
"source": [
98+
"def f(i):\n",
99+
" return image_stack1[i] + i\n",
100+
"fig, ax, controls = interactive_imshow(f, i = np.arange(0,50),cmap='plasma')"
101+
]
102+
},
103+
{
104+
"cell_type": "code",
105+
"execution_count": null,
106+
"metadata": {},
107+
"outputs": [],
108+
"source": [
109+
"im = ax._gci()"
110+
]
111+
},
112+
{
113+
"cell_type": "code",
114+
"execution_count": null,
115+
"metadata": {},
116+
"outputs": [],
117+
"source": [
118+
"im.norm.vmin = 1\n",
119+
"im.norm.vmax = 6"
120+
]
121+
},
122+
{
123+
"cell_type": "code",
124+
"execution_count": null,
125+
"metadata": {},
126+
"outputs": [],
127+
"source": [
128+
"im.norm._stale = True"
129+
]
130+
},
131+
{
132+
"cell_type": "code",
133+
"execution_count": null,
134+
"metadata": {},
135+
"outputs": [],
136+
"source": []
137+
}
138+
],
139+
"metadata": {
140+
"kernelspec": {
141+
"display_name": "Python 3",
142+
"language": "python",
143+
"name": "python3"
144+
},
145+
"language_info": {
146+
"codemirror_mode": {
147+
"name": "ipython",
148+
"version": 3
149+
},
150+
"file_extension": ".py",
151+
"mimetype": "text/x-python",
152+
"name": "python",
153+
"nbconvert_exporter": "python",
154+
"pygments_lexer": "ipython3",
155+
"version": "3.8.5"
156+
}
157+
},
158+
"nbformat": 4,
159+
"nbformat_minor": 4
160+
}

examples/interactive_imshow.ipynb

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"%matplotlib ipympl\n",
10+
"import matplotlib.pyplot as plt\n",
11+
"import numpy as np\n",
12+
"from mpl_interactions import interactive_imshow, ioff, callable_else_value"
13+
]
14+
},
15+
{
16+
"cell_type": "code",
17+
"execution_count": null,
18+
"metadata": {},
19+
"outputs": [],
20+
"source": [
21+
"x = np.linspace(0,np.pi,200)\n",
22+
"y = np.linspace(0,10,200)\n",
23+
"X, Y = np.meshgrid(x,y)\n",
24+
"\n",
25+
"def f(param1, param2):\n",
26+
" return np.sin(X)*param2 + np.exp(np.cos(Y*param1)) + param2"
27+
]
28+
},
29+
{
30+
"cell_type": "code",
31+
"execution_count": null,
32+
"metadata": {},
33+
"outputs": [],
34+
"source": [
35+
"fig, ax, controls = interactive_imshow(f, param1 = (-5,5), param2 = (-3,12))"
36+
]
37+
},
38+
{
39+
"cell_type": "markdown",
40+
"metadata": {},
41+
"source": [
42+
"### Providing an axis\n",
43+
"\n",
44+
"You can also embed the interactive plot into an existing figure"
45+
]
46+
},
47+
{
48+
"cell_type": "code",
49+
"execution_count": null,
50+
"metadata": {},
51+
"outputs": [],
52+
"source": [
53+
"with ioff:\n",
54+
" fig, (ax1, ax2) = plt.subplots(1,2,figsize=(10,5))\n",
55+
"\n",
56+
"ax1.plot(np.sin(np.linspace(0,np.pi)))\n",
57+
"fig2, ax2, controls2 = interactive_imshow(f, param1=(-5,5), param2=(-3, 12), ax=ax2)"
58+
]
59+
},
60+
{
61+
"cell_type": "markdown",
62+
"metadata": {},
63+
"source": [
64+
"### Preventing colormap autoscaling\n",
65+
"\n",
66+
"The if you do not specify vmin/vmax and your function does not return an RGB(A) image then the default behavior is to rescale the colormap for each parameter change. This can disabled using this `autoscale_cmap` argument."
67+
]
68+
},
69+
{
70+
"cell_type": "code",
71+
"execution_count": null,
72+
"metadata": {},
73+
"outputs": [],
74+
"source": [
75+
"fig3, ax3, controls3 = interactive_imshow(f, param1 = (-5,5), param2 = (-3,12), autoscale_cmap=False)"
76+
]
77+
},
78+
{
79+
"cell_type": "markdown",
80+
"metadata": {},
81+
"source": [
82+
"### vmin and vmax: thresholding an image\n",
83+
"\n",
84+
"You can also pass `vmin` and `vmax` as functions. Additionally you do not need to use a function to provide the image, you can also provide an array"
85+
]
86+
},
87+
{
88+
"cell_type": "code",
89+
"execution_count": null,
90+
"metadata": {},
91+
"outputs": [],
92+
"source": [
93+
"img = plt.imread(\"https://matplotlib.org/3.3.1/_images/stinkbug.png\")\n",
94+
"def vmin(min_, max_):\n",
95+
" return min(min_, max_)\n",
96+
"def vmax(min_, max_):\n",
97+
" return max(min_, max_)\n",
98+
"fig4, ax4, controls4 = interactive_imshow(img, vmin=vmin, vmax = vmax, min_= (0,.7), max_= (.3,1))"
99+
]
100+
},
101+
{
102+
"cell_type": "code",
103+
"execution_count": null,
104+
"metadata": {},
105+
"outputs": [],
106+
"source": []
107+
}
108+
],
109+
"metadata": {
110+
"kernelspec": {
111+
"display_name": "Python 3",
112+
"language": "python",
113+
"name": "python3"
114+
},
115+
"language_info": {
116+
"codemirror_mode": {
117+
"name": "ipython",
118+
"version": 3
119+
},
120+
"file_extension": ".py",
121+
"mimetype": "text/x-python",
122+
"name": "python",
123+
"nbconvert_exporter": "python",
124+
"pygments_lexer": "ipython3",
125+
"version": "3.8.5"
126+
}
127+
},
128+
"nbformat": 4,
129+
"nbformat_minor": 4
130+
}

mpl_interactions/helpers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"broadcast_arrays",
1616
"broadcast_many",
1717
"notebook_backend",
18+
"callable_else_value",
1819
]
1920

2021

@@ -153,3 +154,9 @@ def notebook_backend():
153154
elif backend == "nbAgg".lower():
154155
return True
155156
return False
157+
158+
159+
def callable_else_value(arg, params):
160+
if isinstance(arg, Callable):
161+
return arg(**params)
162+
return arg

0 commit comments

Comments
 (0)