Portfolio Analysis
This use case shows how to query and analyze property portfolio data within a geographic area using shapes, filters, and accumulation.
The Python SDK wraps all portfolio endpoints in a typed client — client.reports_v1.points_selection(...), client.reports_v1.accumulation_selection(...), etc.
Scenario
You have a real estate portfolio and need to:
- Get available data sources and filters
- Define a geographic area of interest
- Query properties and entries within that area
- Aggregate metrics (count, sum, average) by column
Step 1: Discover Available Data
First, understand what data and filters are available:
curl -X GET "https://graph.quarticle.ro/graph/api/v1/reports/portfolio/provision?source=portfolio_01" \
-H "Authorization: YOUR_API_KEY"
Response:
{
"provisioning": {
"portfolio_01": {
"columns": [
{ "field": "property_id", "type": "string" },
{ "field": "name", "type": "string" },
{ "field": "value", "type": "number" },
{ "field": "occupancy_rate", "type": "number" },
{ "field": "year_built", "type": "string" },
{ "field": "property_type", "type": "string" }
],
"filters": [
{
"field": "oe_id",
"label": "Organization",
"required": true,
"values": ["chicago_portfolio", "nyc_portfolio"]
},
{
"field": "property_type",
"label": "Property Type",
"required": false,
"values": ["residential", "office", "retail", "industrial"]
}
],
"points": {
"cluster": {
"attributes": [
{ "field": "value", "label": "Total Value", "aggregation": "sum" }
]
}
},
"reports": {
"accumulation": {
"enabled": true,
"fields": [
{ "field": "value", "label": "Insured Value", "default": true },
{ "field": "occupancy_rate", "label": "Occupancy Rate" }
]
}
}
}
}
}
Use this response to discover available columns for entries queries, filters and their allowed values, and which reports are enabled for the source.
You can also retrieve just the filter hierarchy:
curl -X GET "https://graph.quarticle.ro/graph/api/v1/reports/portfolio/provision/filters" \
-H "Authorization: YOUR_API_KEY"
Step 2: Get Points in a Geographic Area
Define your area of interest as a GeoJSON polygon, then query for points:
{
"source": "portfolio_01",
"shape": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-87.6500, 41.8000],
[-87.5500, 41.8000],
[-87.5500, 41.9000],
[-87.6500, 41.9000],
[-87.6500, 41.8000]
]]
},
"properties": {}
},
"filters": [
{"field": "oe_id", "value": "chicago_portfolio"}
],
"properties": ["name", "address", "value", "property_type"]
}
Response:
[
{
"type": "Feature",
"properties": {
"name": "Downtown Office Tower",
"address": "100 N LaSalle, Chicago, IL",
"value": 850000000,
"property_type": "office"
},
"geometry": {"type": "Point", "coordinates": [-87.6301, 41.8857]}
},
{
"type": "Feature",
"properties": {
"name": "Residential Complex",
"address": "500 N Dearborn, Chicago, IL",
"value": 425000000,
"property_type": "residential"
},
"geometry": {"type": "Point", "coordinates": [-87.6220, 41.8886]}
}
]
Step 3: Get Detailed Entries in Area
For detailed records (not just points), use entries endpoint:
{
"source": "portfolio_01",
"shape": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-87.6500, 41.8000],
[-87.5500, 41.8000],
[-87.5500, 41.9000],
[-87.6500, 41.9000],
[-87.6500, 41.8000]
]]
},
"properties": {}
},
"filters": [{"field": "oe_id", "value": "chicago_portfolio"}],
"columns": ["property_id", "name", "value", "occupancy_rate", "year_built"],
"limit": 100,
"page": 0
}
Export as CSV by adding Accept: text/csv header.
Step 4: Accumulate Metrics
Aggregate data across the area using accumulation:
{
"source": "portfolio_01",
"shape": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-87.6500, 41.8000],
[-87.5500, 41.8000],
[-87.5500, 41.9000],
[-87.6500, 41.9000],
[-87.6500, 41.8000]
]]
},
"properties": {}
},
"filters": [{"field": "oe_id", "value": "chicago_portfolio"}],
"aggregationColumns": ["value", "occupancy_rate"],
"locale": "en-US"
}
Response:
[
{
"analysis": {
"count": 47,
"value": {
"sum": 12500000000,
"avg": 265957446,
"min": 2000000,
"max": 850000000
},
"occupancy_rate": {
"avg": 0.852,
"min": 0.65,
"max": 0.99
}
},
"radius": null
}
]
Step 5: Multi-Radius Buffer Analysis
Analyze data at multiple distances from a center point:
{
"source": "portfolio_01",
"shape": {
"type": "circle",
"coordinates": [{ "lat": 41.8857, "long": -87.6298 }]
},
"radiuses": [1000, 5000, 10000],
"filters": [{"field": "oe_id", "value": "chicago_portfolio"}],
"aggregationColumns": ["value", "occupancy_rate"]
}
Response shows results for each radius:
[
{
"analysis": {...},
"radius": 1000
},
{
"analysis": {...},
"radius": 5000
},
{
"analysis": {...},
"radius": 10000
}
]
Complete Workflow (JavaScript)
async function portfolioAnalysis() {
const apiKey = process.env.QARTA_API_KEY;
const source = 'portfolio_01';
// Step 1: Get provision info
const provision = await fetch(
`https://graph.quarticle.ro/graph/api/v1/reports/portfolio/provision?source=${source}`,
{ headers: { 'Authorization': `${apiKey}` } }
).then(r => r.json());
console.log('Available columns:', provision.provisioning[source].columns.map(c => c.field));
// Define area (downtown Chicago)
const area = {
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [[
[-87.6500, 41.8000],
[-87.5500, 41.8000],
[-87.5500, 41.9000],
[-87.6500, 41.9000],
[-87.6500, 41.8000]
]]
},
properties: {}
};
// Step 2: Get points
const points = await fetch(
'https://graph.quarticle.ro/graph/api/v1/reports/portfolio/points/selection',
{
method: 'POST',
headers: {
'Authorization': `${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
source,
shape: area,
filters: [{ field: 'oe_id', value: source }],
properties: ['name', 'value', 'property_type']
})
}
).then(r => r.json());
console.log(`Found ${points.length} properties`);
// Step 3: Accumulate metrics
const analysis = await fetch(
'https://graph.quarticle.ro/graph/api/v1/reports/portfolio/accumulation/selection',
{
method: 'POST',
headers: {
'Authorization': `${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
source,
shape: area,
filters: [{ field: 'oe_id', value: source }],
aggregationColumns: ['value', 'occupancy_rate']
})
}
).then(r => r.json());
console.log('Portfolio metrics:', analysis[0].analysis);
return {
pointCount: points.length,
metrics: analysis[0].analysis
};
}
const results = await portfolioAnalysis();
console.log(JSON.stringify(results, null, 2));
Use Cases
- Geographic market analysis - Understand property distribution and value by location
- Risk assessment - Identify concentrations and exposure in specific areas
- Performance reporting - Create market-level summaries for stakeholders
- Due diligence - Analyze acquisition targets and surrounding markets
- Portfolio optimization - Identify gaps or overlaps in coverage
Next Steps
- Risk Reporting Use Case - Generate risk assessment reports
- Spatial Data Guide - Working with GeoJSON shapes
- CSV Export Guide - Export results as CSV