File size: 3,877 Bytes
1d12e97 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
import streamlit as st
import pandas as pd
from rdflib import Graph, Namespace
import os
# Page Config
st.set_page_config(page_title="Cars Knowledge Graph Demo", layout="wide")
# Load Graph
@st.cache_resource
def load_graph():
g = Graph()
graph_path = "cars_knowledge_graph.ttl"
if os.path.exists(graph_path):
g.parse(graph_path, format="turtle")
return g
try:
g = load_graph()
except Exception as e:
st.error(f"Failed to load graph: {e}")
st.stop()
if len(g) == 0:
st.warning("Graph is empty or not found. Please run 'src/convert_data.py' first.")
st.stop()
# Namespaces
EX = Namespace("http://example.org/cars/")
# Sidebar Filters
st.sidebar.header("Filter Cars")
# 1. Manufacturer Filter
manu_query = """
PREFIX ex: <http://example.org/cars/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?name WHERE {
?m a ex:Manufacturer ; rdfs:label ?name .
} ORDER BY ?name
"""
manufacturers = ["All"] + [str(row.name) for row in g.query(manu_query)]
selected_manu = st.sidebar.selectbox("Manufacturer", manufacturers)
# 2. Price Range
price_query = """
PREFIX ex: <http://example.org/cars/>
SELECT (MIN(?p) as ?min) (MAX(?p) as ?max) WHERE { ?s ex:hasPriceValue ?p }
"""
price_res = list(g.query(price_query))[0]
min_price, max_price = float(price_res.min), float(price_res.max)
selected_price = st.sidebar.slider("Max Price (USD)", min_price, max_price, max_price)
# 3. Min Horsepower
hp_query = """
PREFIX ex: <http://example.org/cars/>
SELECT (MIN(?hp) as ?min) (MAX(?hp) as ?max) WHERE { ?s ex:hasHorsePowerValue ?hp }
"""
hp_res = list(g.query(hp_query))[0]
min_hp, max_hp = int(hp_res.min), int(hp_res.max)
selected_hp = st.sidebar.slider("Min Horsepower", min_hp, max_hp, min_hp)
# Main Area
st.title("π Cars Knowledge Graph Explorer")
st.markdown("This application queries the RDF Knowledge Graph directly using **SPARQL**.")
# Construct Query based on filters
sparql_query = f"""
PREFIX ex: <http://example.org/cars/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?carName ?manuName ?price ?hp ?topSpeed ?seats
WHERE {{
?car a ex:Car ;
rdfs:label ?carName ;
ex:hasManufacturer ?manu ;
ex:hasPriceValue ?price ;
ex:hasHorsePowerValue ?hp ;
ex:hasTopSpeedKMH ?topSpeed ;
ex:hasSeatCount ?seats .
?manu rdfs:label ?manuName .
FILTER (?price <= {selected_price})
FILTER (?hp >= {selected_hp})
{f'FILTER (?manuName = "{selected_manu}")' if selected_manu != "All" else ""}
}}
ORDER BY DESC(?price)
LIMIT 100
"""
# Run Query
results = g.query(sparql_query)
# Display Results
data = []
for row in results:
data.append({
"Car Model": str(row.carName),
"Manufacturer": str(row.manuName),
"Price ($)": f"${float(row.price):,.2f}",
"Horsepower": int(row.hp),
"Top Speed (km/h)": int(row.topSpeed),
"Seats": int(row.seats)
})
df = pd.DataFrame(data)
col1, col2, col3 = st.columns(3)
col1.metric("Total Cars Found", len(df))
col2.metric("Graph Triples", len(g))
col3.metric("Selected Manufacturer", selected_manu)
if not df.empty:
st.dataframe(df, use_container_width=True)
else:
st.info("No cars match your filters.")
# Advanced: Raw SPARQL
with st.expander("Run Custom SPARQL Query"):
custom_query = st.text_area("SPARQL Query", """
PREFIX ex: <http://example.org/cars/>
SELECT ?name ?price WHERE {
?c ex:hasPriceValue ?price ;
rdfs:label ?name .
} LIMIT 5
""")
if st.button("Run Query"):
try:
raw_res = g.query(custom_query)
st.write(list(raw_res))
except Exception as e:
st.error(f"Error: {e}")
|