Skip to content

Commit 628a87c

Browse files
authored
Merge pull request #60 from neo4j/snowpark-example
Add Snowpark notebook example
2 parents f36b09f + 1264585 commit 628a87c

File tree

1 file changed

+276
-0
lines changed

1 file changed

+276
-0
lines changed
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "0d3ffc27",
6+
"metadata": {},
7+
"source": [
8+
"# Visualizing Snowflake Tables"
9+
]
10+
},
11+
{
12+
"cell_type": "markdown",
13+
"id": "6b83277d",
14+
"metadata": {},
15+
"source": [
16+
"\n",
17+
"This is a brief but complete example of how to visualize graphs represented by tables in Snowflake, using the Graph Visualization for Python library for Neo4j."
18+
]
19+
},
20+
{
21+
"cell_type": "markdown",
22+
"id": "168b2f0ec9520f4a",
23+
"metadata": {},
24+
"source": [
25+
"## Setup\n",
26+
"\n",
27+
"We will start by installing the necessary Python library requirements."
28+
]
29+
},
30+
{
31+
"cell_type": "code",
32+
"execution_count": null,
33+
"id": "39e8a71b",
34+
"metadata": {},
35+
"outputs": [],
36+
"source": [
37+
"%pip install snowflake-snowpark-python # Requires Python version <= 3.11\n",
38+
"%pip install neo4j-viz"
39+
]
40+
},
41+
{
42+
"cell_type": "markdown",
43+
"id": "c91214441edff2d",
44+
"metadata": {},
45+
"source": [
46+
"We can now proceed to set up our connection to Snowflake by initializing a new session.\n",
47+
"Please not that you may need more or fewer connection parameters depending on your Snowflake configuration."
48+
]
49+
},
50+
{
51+
"cell_type": "code",
52+
"execution_count": null,
53+
"id": "801d0bed",
54+
"metadata": {},
55+
"outputs": [],
56+
"source": [
57+
"import os\n",
58+
"\n",
59+
"from snowflake.snowpark import Session\n",
60+
"\n",
61+
"# Configure according to your own setup\n",
62+
"connection_parameters = {\n",
63+
" \"account\": os.environ.get(\"SNOWFLAKE_ACCOUNT\"),\n",
64+
" \"user\": os.environ.get(\"SNOWFLAKE_USER\"),\n",
65+
" \"password\": os.environ.get(\"SNOWFLAKE_PASSWORD\"),\n",
66+
" \"role\": os.environ.get(\"SNOWFLAKE_ROLE\"),\n",
67+
" \"warehouse\": os.environ.get(\"SNOWFLAKE_WAREHOUSE\"),\n",
68+
"}\n",
69+
"\n",
70+
"session = Session.builder.configs(connection_parameters).create()"
71+
]
72+
},
73+
{
74+
"cell_type": "markdown",
75+
"id": "5ff57d28a917c569",
76+
"metadata": {},
77+
"source": [
78+
"Now can we create a new Snowflake database where we can put our little example tables.\n",
79+
"If you already have a database you want to use, you can skip this step."
80+
]
81+
},
82+
{
83+
"cell_type": "code",
84+
"execution_count": null,
85+
"id": "41ad4289420a9b36",
86+
"metadata": {},
87+
"outputs": [],
88+
"source": [
89+
"session.sql(\n",
90+
" \"CREATE DATABASE IF NOT EXISTS nvl_example DATA_RETENTION_TIME_IN_DAYS = 1\"\n",
91+
").collect()\n",
92+
"session.sql(\"USE DATABASE nvl_example\").collect()"
93+
]
94+
},
95+
{
96+
"cell_type": "markdown",
97+
"id": "365a1c31",
98+
"metadata": {},
99+
"source": [
100+
"## Creating tables\n",
101+
"\n",
102+
"Next we will create a new table for the nodes in our graph, that will represent products of various categories."
103+
]
104+
},
105+
{
106+
"cell_type": "code",
107+
"execution_count": null,
108+
"id": "d935b3d4",
109+
"metadata": {},
110+
"outputs": [],
111+
"source": [
112+
"session.sql(\n",
113+
" \"CREATE OR REPLACE TABLE products (id INT, name VARCHAR, category INT)\"\n",
114+
").collect()\n",
115+
"\n",
116+
"session.sql(\"\"\"\n",
117+
"INSERT INTO products VALUES\n",
118+
"(1, 'Product 1', 1),\n",
119+
"(2, 'Product 1A', 1),\n",
120+
"(3, 'Product 1B', 1),\n",
121+
"(4, 'Product 2', 2),\n",
122+
"(5, 'Product 2A', 2),\n",
123+
"(6, 'Product 2B', 2),\n",
124+
"(7, 'Product 3', 3),\n",
125+
"(8, 'Product 3A', 3),\n",
126+
"(9, 'Product 3B', 3),\n",
127+
"(10, 'Product 4', 4),\n",
128+
"(11, 'Product 4A', 4),\n",
129+
"(12, 'Product 4B', 4)\n",
130+
"\"\"\").collect()"
131+
]
132+
},
133+
{
134+
"cell_type": "markdown",
135+
"id": "cf08716eb4275659",
136+
"metadata": {},
137+
"source": [
138+
"Some of the products, are \"subproducts\" of certain parent products.\n",
139+
"We now create a table that encodes these \"PARENT\" relationships between the products."
140+
]
141+
},
142+
{
143+
"cell_type": "code",
144+
"execution_count": null,
145+
"id": "be2ac16d3bd41e6",
146+
"metadata": {},
147+
"outputs": [],
148+
"source": [
149+
"session.sql(\n",
150+
" \"CREATE OR REPLACE TABLE parents (source INT, target INT, type VARCHAR)\"\n",
151+
").collect()\n",
152+
"\n",
153+
"session.sql(\"\"\"\n",
154+
"INSERT INTO parents VALUES\n",
155+
"(2, 1, 'PARENT'),\n",
156+
"(3, 1, 'PARENT'),\n",
157+
"(5, 4, 'PARENT'),\n",
158+
"(6, 4, 'PARENT'),\n",
159+
"(8, 7, 'PARENT'),\n",
160+
"(9, 7, 'PARENT'),\n",
161+
"(11, 10, 'PARENT'),\n",
162+
"(12, 10, 'PARENT')\n",
163+
"\"\"\").collect()"
164+
]
165+
},
166+
{
167+
"cell_type": "markdown",
168+
"id": "a28bd5aa",
169+
"metadata": {},
170+
"source": [
171+
"## Fetching the data\n",
172+
"\n",
173+
"Next we fetch our tables from Snowflake and convert them to pandas DataFrames.\n",
174+
"Additionally, we rename the most of the table columns so that they are named according to the `neo4j-viz` API."
175+
]
176+
},
177+
{
178+
"cell_type": "code",
179+
"execution_count": null,
180+
"id": "deb6353193e2338b",
181+
"metadata": {},
182+
"outputs": [],
183+
"source": [
184+
"products_df = (\n",
185+
" session.table(\"products\")\n",
186+
" .to_pandas()\n",
187+
" .rename(columns={\"ID\": \"id\", \"NAME\": \"caption\"})\n",
188+
")\n",
189+
"parents_df = (\n",
190+
" session.table(\"parents\")\n",
191+
" .to_pandas()\n",
192+
" .rename(columns={\"SOURCE\": \"source\", \"TARGET\": \"target\", \"TYPE\": \"caption\"})\n",
193+
")"
194+
]
195+
},
196+
{
197+
"cell_type": "markdown",
198+
"id": "950e0e76cfcaf3d6",
199+
"metadata": {},
200+
"source": [
201+
"## Rendering the visualization\n",
202+
"With only one command we can now create a `VisualizationGraph` from these tables representing nodes and relationships.\n",
203+
"In order to enhance the visualization, we will also be utilizing the `color_nodes` function, which will assign a distinct color to each product category."
204+
]
205+
},
206+
{
207+
"cell_type": "code",
208+
"execution_count": null,
209+
"id": "2322065c",
210+
"metadata": {},
211+
"outputs": [],
212+
"source": [
213+
"from neo4j_viz.pandas import from_dfs\n",
214+
"\n",
215+
"VG = from_dfs(products_df, parents_df)\n",
216+
"\n",
217+
"# Using the default Neo4j color scheme\n",
218+
"VG.color_nodes(\"CATEGORY\")"
219+
]
220+
},
221+
{
222+
"cell_type": "markdown",
223+
"id": "da39f29deb1569e2",
224+
"metadata": {},
225+
"source": [
226+
"Let us now render our graph, using only default render options."
227+
]
228+
},
229+
{
230+
"cell_type": "code",
231+
"execution_count": null,
232+
"id": "e8b0f4c6",
233+
"metadata": {},
234+
"outputs": [],
235+
"source": [
236+
"VG.render()"
237+
]
238+
},
239+
{
240+
"cell_type": "markdown",
241+
"id": "ac4c5e35a602ede2",
242+
"metadata": {},
243+
"source": [
244+
"You can scroll to zoom in and out in the visualization, and click-and-drag nodes to move them."
245+
]
246+
},
247+
{
248+
"cell_type": "markdown",
249+
"id": "8aa5576fa3b25383",
250+
"metadata": {},
251+
"source": [
252+
"## Cleanup\n",
253+
"\n",
254+
"Lastly, we clean up the example database we created."
255+
]
256+
},
257+
{
258+
"cell_type": "code",
259+
"execution_count": null,
260+
"id": "c6eb218e892d420e",
261+
"metadata": {},
262+
"outputs": [],
263+
"source": [
264+
"session.sql(\"DROP DATABASE IF EXISTS nvl_example\").collect()\n",
265+
"session.close()"
266+
]
267+
}
268+
],
269+
"metadata": {
270+
"language_info": {
271+
"name": "python"
272+
}
273+
},
274+
"nbformat": 4,
275+
"nbformat_minor": 5
276+
}

0 commit comments

Comments
 (0)