Skip to content

Commit 015fc3a

Browse files
committed
Added Sample to find items with thumbnails under a certain pixel size.
1 parent 2b41766 commit 015fc3a

File tree

1 file changed

+348
-0
lines changed

1 file changed

+348
-0
lines changed
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Setting Up the Notebook:\n",
8+
"\n",
9+
"This notebook requires `Pillow` which is a fork of `PIL`. To install this module run the cell below:"
10+
]
11+
},
12+
{
13+
"cell_type": "code",
14+
"execution_count": null,
15+
"metadata": {},
16+
"outputs": [],
17+
"source": [
18+
"import sys\n",
19+
"prefix = '\\\"%s\\\"' % sys.prefix\n",
20+
"!conda install --yes --prefix {prefix} pillow"
21+
]
22+
},
23+
{
24+
"cell_type": "markdown",
25+
"metadata": {},
26+
"source": [
27+
"# About Item Thumbnails\n",
28+
"\n",
29+
"A thumbnail image is created by default when you add the item to the site. It appears in galleries, search results, contents, and the item page. You can create and load a different image if the default image does not convey the information you want.\n",
30+
"\n",
31+
"In ArcGIS Online, you can drag an image or browse to a file. For best results, add an image that is 600 pixels wide by 400 pixels high or larger with an aspect ratio of 1.5:1 in a web file format such as PNG, JPEG, or GIF. Pan and zoom to what you want to appear in your thumbnail. Depending on the size and resolution of your image file and how far you zoom in to customize the thumbnail, the image may be resampled and scaled when it's saved. If you add an image in GIF or JPEG format, it will be converted to PNG when it's saved.\n",
32+
"\n",
33+
"## Finding Missing and Invalid Images\n",
34+
"\n",
35+
"This notebook shows how a user can find images under the 600x400 pixel size for a given user."
36+
]
37+
},
38+
{
39+
"cell_type": "code",
40+
"execution_count": 1,
41+
"metadata": {},
42+
"outputs": [],
43+
"source": [
44+
"import os\n",
45+
"import io\n",
46+
"import base64\n",
47+
"import shutil\n",
48+
"from getpass import getpass"
49+
]
50+
},
51+
{
52+
"cell_type": "code",
53+
"execution_count": 2,
54+
"metadata": {},
55+
"outputs": [],
56+
"source": [
57+
"import pandas as pd\n",
58+
"from PIL import Image\n",
59+
"from IPython.display import HTML\n",
60+
"import ipywidgets as widgets\n",
61+
"from arcgis.gis import GIS, Item, User\n",
62+
"\n",
63+
"pd.set_option('display.max_colwidth', -1)"
64+
]
65+
},
66+
{
67+
"cell_type": "markdown",
68+
"metadata": {},
69+
"source": [
70+
"### Connect to the GIS\n",
71+
"\n",
72+
"Use the login credentials to your site to populate the interactive application below."
73+
]
74+
},
75+
{
76+
"cell_type": "code",
77+
"execution_count": 3,
78+
"metadata": {},
79+
"outputs": [
80+
{
81+
"name": "stdout",
82+
"output_type": "stream",
83+
"text": [
84+
"········\n",
85+
"········\n"
86+
]
87+
}
88+
],
89+
"source": [
90+
"username = getpass()\n",
91+
"password = getpass()"
92+
]
93+
},
94+
{
95+
"cell_type": "code",
96+
"execution_count": 4,
97+
"metadata": {},
98+
"outputs": [],
99+
"source": [
100+
"gis = GIS(username=username, password=password, verify_cert=False)"
101+
]
102+
},
103+
{
104+
"cell_type": "code",
105+
"execution_count": 12,
106+
"metadata": {},
107+
"outputs": [],
108+
"source": [
109+
"def get_images(username, gis, min_width=600, min_height=400, show_image=True):\n",
110+
" \"\"\"\n",
111+
" Finds all images for a given user under a specific image size in pixels.\n",
112+
" \n",
113+
" ================ ===========================================\n",
114+
" **Inputs** **Description**\n",
115+
" ---------------- -------------------------------------------\n",
116+
" username Required string. The name of the user items \n",
117+
" to exmine.\n",
118+
" ---------------- -------------------------------------------\n",
119+
" gis Required GIS. The connection to Portal/AGOL\n",
120+
" ---------------- -------------------------------------------\n",
121+
" min_height Optional Integer. The height in pixels of \n",
122+
" the image. Any image below this height will \n",
123+
" be returned in the dataframe.\n",
124+
" ---------------- -------------------------------------------\n",
125+
" min_width Optional Integer. The width of the image. \n",
126+
" Anything below this width will be returned.\n",
127+
" ---------------- -------------------------------------------\n",
128+
" show_image Optional boolean. If True, the results will \n",
129+
" be returned as an HTML table. Else, they \n",
130+
" will be returned as a pandas DataFrame.\n",
131+
" ================ ===========================================\n",
132+
" \n",
133+
" returns: string or pd.DataFrame\n",
134+
" \n",
135+
" \"\"\"\n",
136+
" results = []\n",
137+
" show_image_columns=['title', 'username','folder', 'item_id', 'item_thumbnail','width', 'height']\n",
138+
" no_show_image_columns=['title', 'username','folder', 'item_id', 'width', 'height']\n",
139+
" user = gis.users.get(username)\n",
140+
" username = user.username\n",
141+
" folders = [fld['title'] for fld in user.folders] + [None]\n",
142+
" for folder in folders:\n",
143+
" items = user.items(folder=folder, max_items=1000)\n",
144+
" for item in items:\n",
145+
" thumbnail = item.thumbnail\n",
146+
" if show_image:\n",
147+
" if thumbnail:\n",
148+
" bn = os.path.basename(thumbnail)\n",
149+
" image_bytes = item.get_thumbnail()\n",
150+
" img = Image.open(io.BytesIO(image_bytes))\n",
151+
" b64_item = base64.b64encode(image_bytes)\n",
152+
" b64thmb = \"data:image/png;base64,\" + str(b64_item,\"utf-8\") + \"' width='200' height='133\"\n",
153+
" item_thumbnail = \"\"\"<img src='\"\"\" + str(b64thmb) + \"\"\"' class=\"itemThumbnail\">\"\"\"\n",
154+
" results.append([item.title, username, folder, item.id, item_thumbnail] + list(img.size))\n",
155+
" img.close()\n",
156+
" del img\n",
157+
" else:\n",
158+
" results.append([item.title, username, folder, item.id, \"\", -999,-999])\n",
159+
" else:\n",
160+
" if thumbnail:\n",
161+
" image_bytes = item.get_thumbnail()\n",
162+
" img = Image.open(io.BytesIO(image_bytes))\n",
163+
" results.append([item.title, username, folder, item.id] + list(img.size))\n",
164+
" img.close()\n",
165+
" del img\n",
166+
" else:\n",
167+
" results.append([item.title, username, folder, item.id,None,None])\n",
168+
" \n",
169+
" if show_image:\n",
170+
" df = pd.DataFrame(results, columns=show_image_columns)\n",
171+
" q = (df.width <= float(min_width)) | (df.height < float(min_height)) | (df.height.isnull()) | (df.width.isnull())\n",
172+
" df = (df[q]\n",
173+
" .copy()\n",
174+
" .reset_index(drop=True))\n",
175+
" return HTML(df.to_html(escape=False))\n",
176+
" else:\n",
177+
" df = pd.DataFrame(results, columns=no_show_image_columns)\n",
178+
" q = (df.width <= float(min_width)) | (df.height < float(min_height)) | (df.height.isnull()) | (df.width.isnull())\n",
179+
" df = (df[q]\n",
180+
" .copy()\n",
181+
" .reset_index(drop=True))\n",
182+
" return df"
183+
]
184+
},
185+
{
186+
"cell_type": "markdown",
187+
"metadata": {},
188+
"source": [
189+
"# Usage\n",
190+
"\n",
191+
"To get a DataFrame that can be queried, set `show_image` to `False`. This will return an object that can be further used for analysis. The dataframe reports back the width/height of the image. If an image is missing, the value will be **NaN** for width/height. \n",
192+
"\n",
193+
"### Example: Retrieve All Thumbnails Under 400x300"
194+
]
195+
},
196+
{
197+
"cell_type": "code",
198+
"execution_count": 18,
199+
"metadata": {},
200+
"outputs": [
201+
{
202+
"data": {
203+
"text/html": [
204+
"<div>\n",
205+
"<style scoped>\n",
206+
" .dataframe tbody tr th:only-of-type {\n",
207+
" vertical-align: middle;\n",
208+
" }\n",
209+
"\n",
210+
" .dataframe tbody tr th {\n",
211+
" vertical-align: top;\n",
212+
" }\n",
213+
"\n",
214+
" .dataframe thead th {\n",
215+
" text-align: right;\n",
216+
" }\n",
217+
"</style>\n",
218+
"<table border=\"1\" class=\"dataframe\">\n",
219+
" <thead>\n",
220+
" <tr style=\"text-align: right;\">\n",
221+
" <th></th>\n",
222+
" <th>title</th>\n",
223+
" <th>username</th>\n",
224+
" <th>folder</th>\n",
225+
" <th>item_id</th>\n",
226+
" <th>width</th>\n",
227+
" <th>height</th>\n",
228+
" </tr>\n",
229+
" </thead>\n",
230+
" <tbody>\n",
231+
" <tr>\n",
232+
" <th>0</th>\n",
233+
" <td>four_five_month</td>\n",
234+
" <td>geodev0</td>\n",
235+
" <td>None</td>\n",
236+
" <td>a416597cdf88422db321b8e29708745f</td>\n",
237+
" <td>200</td>\n",
238+
" <td>133</td>\n",
239+
" </tr>\n",
240+
" </tbody>\n",
241+
"</table>\n",
242+
"</div>"
243+
],
244+
"text/plain": [
245+
" title username folder item_id width \\\n",
246+
"0 four_five_month geodev0 None a416597cdf88422db321b8e29708745f 200 \n",
247+
"\n",
248+
" height \n",
249+
"0 133 "
250+
]
251+
},
252+
"execution_count": 18,
253+
"metadata": {},
254+
"output_type": "execute_result"
255+
}
256+
],
257+
"source": [
258+
"username = \"geodev0\"\n",
259+
"df = get_images(username, gis=gis, \n",
260+
" min_height=300, min_width=400, \n",
261+
" show_image=False)\n",
262+
"df"
263+
]
264+
},
265+
{
266+
"cell_type": "markdown",
267+
"metadata": {},
268+
"source": [
269+
"## Item Thumbnails Back as HTML Report\n",
270+
"\n",
271+
"Sometimes just creating a table to see what is there is good enough. By setting `show_image` to `True`, the method allows for a quick visualization approach to the thumbnail problem. \n",
272+
"\n",
273+
"### Example: Find all Images Under 600x400 Pixels:"
274+
]
275+
},
276+
{
277+
"cell_type": "code",
278+
"execution_count": 19,
279+
"metadata": {},
280+
"outputs": [
281+
{
282+
"data": {
283+
"text/html": [
284+
"<table border=\"1\" class=\"dataframe\">\n",
285+
" <thead>\n",
286+
" <tr style=\"text-align: right;\">\n",
287+
" <th></th>\n",
288+
" <th>title</th>\n",
289+
" <th>username</th>\n",
290+
" <th>folder</th>\n",
291+
" <th>item_id</th>\n",
292+
" <th>item_thumbnail</th>\n",
293+
" <th>width</th>\n",
294+
" <th>height</th>\n",
295+
" </tr>\n",
296+
" </thead>\n",
297+
" <tbody>\n",
298+
" <tr>\n",
299+
" <th>0</th>\n",
300+
" <td>four_five_month</td>\n",
301+
" <td>geodev0</td>\n",
302+
" <td>None</td>\n",
303+
" <td>a416597cdf88422db321b8e29708745f</td>\n",
304+
" <td><img src='data:image/png;base64,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' width='200' height='133' class=\"itemThumbnail\"></td>\n",
305+
" <td>200</td>\n",
306+
" <td>133</td>\n",
307+
" </tr>\n",
308+
" </tbody>\n",
309+
"</table>"
310+
],
311+
"text/plain": [
312+
"<IPython.core.display.HTML object>"
313+
]
314+
},
315+
"execution_count": 19,
316+
"metadata": {},
317+
"output_type": "execute_result"
318+
}
319+
],
320+
"source": [
321+
"df = get_images(username, gis=gis, \n",
322+
" show_image=True)\n",
323+
"df"
324+
]
325+
}
326+
],
327+
"metadata": {
328+
"kernelspec": {
329+
"display_name": "Python 3",
330+
"language": "python",
331+
"name": "python3"
332+
},
333+
"language_info": {
334+
"codemirror_mode": {
335+
"name": "ipython",
336+
"version": 3
337+
},
338+
"file_extension": ".py",
339+
"mimetype": "text/x-python",
340+
"name": "python",
341+
"nbconvert_exporter": "python",
342+
"pygments_lexer": "ipython3",
343+
"version": "3.6.5"
344+
}
345+
},
346+
"nbformat": 4,
347+
"nbformat_minor": 2
348+
}

0 commit comments

Comments
 (0)