Create a Quine Icon Library with Python
Have you ever wanted to add flair to a graph visualization but are unsure which icons Quine supports? In this blog, we explore a Python script that fetches valid icon names from the web, configures the Exploration UI, then creates a graph of icon nodes for reference. The script uses several popular Python libraries, including Requests, BeautifulSoup, and Halo, along with the /query-ui
and /query/cypher
API endpoints.
Environment
Before we start, we need to ensure that we have the necessary libraries installed. We will be using requests
, beautifulsoup4
, log_symbols
, and halo
. You can install them using pip
:
- Quine
- Python 3
- Requests library (
pip install requests
) - BeautifulSoup library (
pip install beautifulsoup4
) - Optional Halo library for operation visuals (
pip install log-symbols halo
)
Start Quine so that it is ready to run the script.
java -jar quine-1.5.3.jar
The Script
The script begins by importing the required libraries:
import requests
import json
from halo import Halo
from log_symbols import LogSymbols
from bs4 import BeautifulSoup
Build a list of icon names
We use the requests
library to GET the webpage referenced in the Replace Node Appearances API documentation. Quine supports version 2.0.0 of the [Ionicons] icon set from the Ionic Framework. The link contains a list of 733 icons supported by Quine. A try...except
block handles any errors that might occur during the request. If the request is successful, the script saves the HTML content of the page.
try:
url = "https://ionic.io/ionicons/v2/cheatsheet.html"
response = requests.get(url)
html = response.content
print(LogSymbols.SUCCESS.value, "GET Icon Cheatsheet")
except requests.exceptions.RequestException as e:
raise SystemExit(e)
Next, we use BeautifulSoup to parse the HTML content of the page to extract all of the icon names. The soup.select
method finds all <input>
elements with a name
attribute and returns a list, which are then looped over to extract the value
attribute of each tag later. We output len(all_icons)
to verify that we identified all of the icons.
soup = BeautifulSoup(html, "html.parser")
all_icons = soup.select("input.name")
print(LogSymbols.SUCCESS.value, "Extract Icon Names:", len(all_icons)
Create Node Appearances
Now that we have the icon names, we can use them to create node appearances for the Quine Exploration UI. We’ll use the json
package to format the nodeAppearances
data as JSON, and requests
to replace the current nodeAppearances
with a PUT to the /query-ui/node-appearances
endpoint. We wrap the API call in try...expect
as before to handle any errors.
predicate
: filter which nodes to apply this stylesize
: the size of the icon in pixelsicon
: the name of the iconlabel
: the label of the node
Note: Cypher does not allow dash (-
) characters in node labels. We get around this by replacing all of the dashes with underscores in the node labels.
nodeAppearances = [
{
"predicate": {
"propertyKeys": [],
"knownValues": {},
"dbLabel": icon_name["value"].replace("-", "_")
},
"size":40.0,
"icon": icon_name["value"],
"label": {
"key": "name",
"type": "Property"
}
} for icon_name in all_icons]
json_data = json.dumps(nodeAppearances)
try:
headers = {"Content-type": "application/json"}
response = requests.put(
"http://localhost:8080/api/v1/query-ui/node-appearances", data=json_data, headers=headers)
except requests.exceptions.RequestException as e:
raise SystemExit(e)
print(LogSymbols.SUCCESS.value, "PUT Node Appearances")
Create Icon Nodes
Finally, our script creates icon nodes by sending a series of POST requests to the Quine /query/cypher
endpoint. For each icon name, a Cypher query creates the corresponding icon node and connects it to the appropriate group node. We use Halo
to create a spinner while we POST the icon data to Quine.
try:
quineSpinner.start()
for icon_name in all_icons:
group = icon_name["value"].split('-',2)
query_text = (
f'MATCH (a), (b), (c) '
f'WHERE id(a) = idFrom("{group[0]}") '
f' AND id(b) = idFrom("{group[1]}") '
f' AND id(c) = idFrom("{icon_name["value"]}") '
f'SET a:{group[0]}, a.name = "{group[0]}" '
f'SET b:{group[1]}, b.name = "{group[1]}" '
f'SET c:{icon_name["value"].replace("-", "_")}, c.name = "{icon_name["value"]}" '
f'CREATE (a)<-[:GROUP]-(b)<-[:GROUP]-(c)'
) if len(group) == 3 else (
f'MATCH (a), (c) '
f'WHERE id(a) = idFrom("{group[0]}") '
f' AND id(c) = idFrom("{icon_name["value"]}") '
f'SET a:{group[0]}, a.name = "{group[0]}" '
f'SET c:{icon_name["value"].replace("-", "_")}, c.name = "{icon_name["value"]}" '
f'CREATE (a)<-[:GROUP]-(c)'
)
quineSpinner.text = query_text
headers = {'Content-type': 'text/plain'}
# print(query_text)
response = requests.post(
'http://localhost:8080/api/v1/query/cypher', data=query_text, headers=headers)
quineSpinner.succeed('POST Icon Nodes')
except requests.exceptions.Timeout as timeout:
quineSpinner.stop('Request Timeout: ' + timeout)
except requests.exceptions.RequestException as e:
raise SystemExit(e)
Running the script
At this point, we are ready to run the script and visualize the icons supported in Quine.
python3 iconLibrary.py
The script updates the console as it moves through the blocks of code that we described above:
✔ GET Icon Cheatsheet
✔ Extract Icon Names: 733
✔ PUT Node Appearances
✔ POST Icon Nodes
Navigate to Quine in your browser and load all of the nodes that we just created into the Exploration UI. There are multiple ways to load all of the nodes in the UI, for this example, we use MATCH (n) RETURN n
. The Exploration UI will warn that you are about to render 787 nodes which is correct for all of the icons and grouping nodes generated by the script. Hit the OK button to view the graph.
Note: If you already had Quine open in a browser before running the script, you will need to refresh your browser window to load the new nodeAppearances
submitted by the query in order for the nodes to render correctly.
In our case, the nodes are jumbled when they are first rendered. Click the play button in the top nav to have Quine organize the graph. Our result produced the graph visualization of all supported icons below:
Conclusion
There you have it, a graph visualization using all of the icons Quine supports!
This script can generate the nodeAppearances
graph and serve as a starting point if you are looking to automate fetching non-streaming data from websites to enrich streaming data stored in Quine.
If you want to learn more about Quine or explore using other API libraries with Quine, check out the interactive REST API documentation available via the document icon in the left nav bar. The interactive documentation is a great place to submit API requests. Code samples in popular languages are quickly mocked up in the docs for use when experimenting with small projects like this yourself.
You can download this script and try it for yourself in this GitHub Repo.
Related posts
-
Stream Processing World Meets Streaming Graph at Current 2024
The thatDot team had a great time last week at Confluent’s big conference, Current 2024. We talked to a lot of folks about the power of Streaming Graph,…
-
Streaming Graph Get Started
It’s been said that graphs are everywhere. Graph-based data models provide a flexible and intuitive way to represent complex relationships and interconnectedness in data. They are particularly well-suited…
-
Streaming Graph for Real-Time Risk Analysis at Data Connect in Columbus 2024
After more than 25 years in the data management and analysis industry, I had a brand new experience. I attended a technical conference. No, that wasn’t the new…