Geospatial data is so widespread that no data science software would be complete without ability to manipulate it efficiently. In this example we will take a look how GIS data can be used in kamu using Apache Spark engine that comes with Apache Sedona extension.
ca.vancouver.opendata.property.local-area-boundaries - contains outlines and names of Vancouver’s districts
For geospatial data kamu supports several input formats including ESRI Shapefile and GeoJson. Take a look at dataset definitions to understand how data is being ingested.Quite often when ingesting GIS data you will need to deal with different projections. Example below shows how you can use a pre-processing step to convert data into another projection:
preprocess: kind: Sql engine: spark query: | SELECT ST_Transform(geometry, "epsg:3157", "epsg:4326") as geometry FROM input
Note: epsg:4326 is one of the more commonly used projections which is expected by many visualization tools.
The ST_Transform function here comes from Apache Sedona extension for the Apache Spark engine for working with GIS data. We will be relying on many of its function throughout this example.Lets add all these datasets to our workspace and ingest them:
# Create a kamu workspace in the example folderkamu init# Add all dataset manifests found in the current directorykamu add --recursive .kamu pull --all# Alternatively: Pull datasets in ODF format from Kamu's repository./init-s3.sh
The source data for tax-reports dataset is quite large (~400MB in CSV format) so if you don’t want to wait too long - use the init-s3.sh script.
This may take 10+ minutes as the tax report dataset is quite large. You can leave the ingest running and move on to the next step meanwhile.
For visualizing the GIS data we will be using the awesome Mapbox SDK. To follow the example you will need to create a free account and get your own access token. The token should look something like pk.eyJ...T6Q.
Once you have downloaded all datasets we can start with a simple notebook to get a feel for GIS visualization.Start the notebook server and pass it your Mapbox token via environment variable:
kamu notebook -e MAPBOX_ACCESS_TOKEN=<your mapbox token>
Now you can open the heatmap.ipynb and run through it executing each step. The notebook is pretty straightforward - it joins together the tax-reports dataset containing assessment values with parcel-polygons dataset containing land geometries in order to produce a heatmap.
%%sqlCREATE OR REPLACE TEMP VIEW lot_tax AS ( SELECT t.*, l.geometry FROM lots as l JOIN tax as t ON l.tax_coord = t.land_coordinate WHERE t.legal_type = 'LAND' AND t.tax_assessment_year = 2019 AND t.current_land_value is not null)
It then pulls the result from Spark into the notebook itself using this query:
%%sql -o df -n 100000SELECT land_coordinate, ST_AsGeoJSON(geometry) as geometry, current_land_value + current_improvement_value as current_total_valueFROM lot_tax
The -n 100000 parameter here overrides the default limit on the dataframe size, while ST_AsGeoJSON(geometry) also converts the internal binary geometry type into the GeoJson format. We later use custom-written df_to_geojson to combine individual geometries into GeoJson’s FeatureCollection objectm understood by the mapboxgl library.We can then use the resulting GeoJson data and render the heatmap using the mapboxgl-jupyter library which comes pre-installed with kamu’s notebook server image.
Let’s take a look how datasets can be joined using the geometries. The local-area-boundaries contains the names of the Vancouver’s neighbourhoods along with their geographical boundaries. We also have the block-outlines dataset containing boundaries of individual blocks, but there’s an issue - there is no identifier that would link a block to a specific neighbourhood. For us to associate a block with the neighbourhood we have to see if block’s boundaries are contained or intersect the boundaries of some neighbourhood. Apache Sedona used by kamu optimizes such spatial joins.You can open up the spatial_join.ipynb notebook and run through it step by step. The most important part ther is the join itself:
CREATE OR REPLACE TEMP VIEW blocks_by_hood AS ( SELECT h.name, b.geometry FROM blocks as b INNER JOIN hoods as h ON ST_Intersects(b.geometry, h.geometry))
The rest of the visualization steps should be familiar to you from the previous example.As an exercise - see if you can replace the median_value column that we have populated with RAND() for every block with an actual median property price. Just like before, there is unfortunately no identifier that would tie the property to a specific block, but see if Sedona can handle a massive spatial join between blocks and individual property outlines.
Last modified on March 16, 2026
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Kamu Docs","colors":{"primary":"#ec6e2a","light":"#ec6e2a","dark":"#ec6e2a"},"logo":{"light":"https://mintcdn.com/kamu/j1tx5fgzyFHd1DYS/images/kamu-logo-light.svg?fit=max\u0026auto=format\u0026n=j1tx5fgzyFHd1DYS\u0026q=85\u0026s=a09261b617da6e1515dea3d28495f633","dark":"https://mintcdn.com/kamu/j1tx5fgzyFHd1DYS/images/kamu-logo-dark.svg?fit=max\u0026auto=format\u0026n=j1tx5fgzyFHd1DYS\u0026q=85\u0026s=8c6d0d7ffa23ef050859453f64354192"},"favicon":"https://mintcdn.com/kamu/j1tx5fgzyFHd1DYS/images/favicon.svg?fit=max\u0026auto=format\u0026n=j1tx5fgzyFHd1DYS\u0026q=85\u0026s=a7b01f8f352427f5a4afe3aef1f8a9d3","background":{"color":{"dark":"#050C1E"}},"navbar":{"links":[{"href":"https://discord.gg/nU6TXRQNXC","label":"Get Help"}],"primary":{"type":"button","label":"Install","href":"/cli/install/"}},"footer":{"socials":{"github":"https://github.com/kamu-data","discord":"https://discord.gg/nU6TXRQNXC","youtube":"https://www.youtube.com/@kamudata","linkedin":"https://www.linkedin.com/company/kamu-data","medium":"https://medium.com/kamu-data","bluesky":"https://bsky.app/profile/kamu.dev","x":"https://x.com/kamu_data"},"links":[{"header":"Company","items":[{"label":"Blog","href":"https://kamu.dev/blog"},{"label":"Careers","href":"https://kamu.dev/jobs"}]}]},"seo":{"metatags":{"canonical":"https://docs.kamu.dev"}},"styling":{"eyebrows":"breadcrumbs","latex":false},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"metadata":{"timestamp":true},"navigation":{"global":{"anchors":[]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"kamu","hasAudioNarration":false,"actualSubdomain":"kamu","customDomains":["docs.kamu.dev"],"gitSource":{"type":"github","owner":"kamu-data","repo":"kamu-docs","deployBranch":"master","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ad05633011b02bffcb4463d","collectionId":"0127742b-6059-4668-b046-f443923b1bdd","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ad05633011b02bffcb4463d"},"entitlements":{},"buildId":"6ad05633011b02bffcb4463d","clientVersion":"0.0.3965","searchFilterCounts":[{"language":"default","tag":"Guides","count":75},{"language":"default","tag":"Reference","count":42},{"language":"default","tag":"Open Data Fabric","count":39},{"language":"default","tag":"Kamu CLI","count":31},{"language":"default","tag":"RFCs","count":22},{"language":"default","tag":"Kamu Node","count":17},{"language":"default","tag":"Specification","count":15},{"language":"default","tag":"APIs","count":13},{"language":"default","tag":"Get Started","count":12},{"language":"default","tag":"Datasets","count":10}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"isAtlas":false,"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"a.card:is(.dark *),div.card:is(.dark *){background:#09162d}a.card:is(.light *),div.card:is(.light *){background:#fafafa}a:has(svg[style*=\"wrench.svg\"]){pointer-events:none;opacity:.7}button:has(svg[style*=\"wrench.svg\"]){opacity:.7}a:has(svg[style*=\"wrench.svg\"])>div:first-child,button:has(svg[style*=\"wrench.svg\"])>svg[style*=\"wrench.svg\"]{order:2;margin-left:auto}.prose a.glossary-term:is(.dark *, .light *){color:inherit;font-weight:inherit;border-bottom:2px dotted #325495}.prose a.schema-object:is(.dark *, .light *){color:inherit;font-weight:inherit;border-bottom:2px dotted #2c802c}h4.project-title:is(.dark *, .light *){display:block;text-align:center}div.badges a,h4.project-title a{border-bottom:0}a.project-quicklink:is(.dark *, .light *){font-size:15px;font-weight:300;color:#ec6e2a;border-bottom:0}.prose div img:is(\n [src*=\"projects/odf.svg\"],\n [src*=\"projects/kamu-cli.svg\"],\n [src*=\"projects/kamu-node.svg\"],\n [src*=\"projects/kamu-platform.svg\"]\n ){display:block;margin:30px auto 0;height:100px;width:auto}div.badges{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;gap:10px;margin:20px}div.badges img{display:inline;margin:0}"}],"page":{"pagePath":"examples/housing-prices","slug":"/examples/housing-prices","pageMetadata":{"Title":"Housing Prices","description":null,"weight":0,"categories":[],"aliases":["/cli/learn/examples/housing-prices"],"title":null,"href":"/examples/housing-prices"},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];const Diagram=({src,alt})=>{return _jsxs(`div`,{style:{display:`flex`,\"flex-direction\":`column`,\"align-items\":`center`},children:[_jsx(`img`,{src,alt,style:{background:`#dddddd`,\"margin-bottom\":0}}),_jsx(`span`,{children:alt})]})};const YouTubeList=({id})=>{const src=`https://www.youtube.com/embed/videoseries?list=${id}`;return _jsx(`iframe`,{className:`mint-w-full mint-aspect-video mint-rounded-xl`,src,allow:`accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture`,allowFullScreen:true})};const YouTube=({id,width})=>{const src=`https://www.youtube.com/embed/${id}`;return _jsx(`iframe`,{className:`mint-w-full mint-aspect-video mint-rounded-xl`,src,allow:`accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture`,allowFullScreen:true,width})};const Schema=({t,id})=>{const _components={a:`a`,..._provideComponents()};const anchor=id?id:t.toLowerCase().replace(/\\s+/g,`-`);const link=`/odf/schemas#${anchor}`;return _jsx(_components.a,{class:`schema-object`,href:link,children:t})};const Term=({t,id})=>{const _components={a:`a`,..._provideComponents()};const anchor=id?id:t.toLowerCase().replace(/\\s+/g,`-`);const link=`/general/glossary#${anchor}`;return _jsx(_components.a,{class:`glossary-term`,href:link,children:t})};function _createMdxContent(props){const _components={a:`a`,blockquote:`blockquote`,code:`code`,li:`li`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Warning,_MdxComponentBoundary}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Warning)_missingMdxReference(`Warning`,true);if(!_MdxComponentBoundary)_missingMdxReference(`_MdxComponentBoundary`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:_jsx(_components.strong,{children:`Topics covered:`})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`GIS functions`}),`\n`,_jsx(_components.li,{children:`Spatial joins`}),`\n`,_jsx(_components.li,{children:`Notebooks`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`summary`,children:`Summary`}),`\n`,_jsxs(_components.p,{children:[`Geospatial data is so widespread that no data science software would be complete without ability to manipulate it efficiently. In this example we will take a look how GIS data can be used in `,_jsx(_components.code,{children:`kamu`}),` using `,_jsx(_components.code,{children:`Apache Spark`}),` engine that comes with `,_jsx(_components.a,{href:`http://sedona.apache.org/`,children:`Apache Sedona`}),` extension.`]}),`\n`,_jsx(Heading,{level:`2`,id:`steps`,children:`Steps`}),`\n`,_jsx(Heading,{level:`3`,id:`getting-started`,children:`Getting Started`}),`\n`,_jsxs(_components.p,{children:[`To follow this example checkout `,_jsx(_components.code,{children:`kamu-cli`}),` repository and navigate into `,_jsx(_components.a,{href:`https://github.com/kamu-data/kamu-cli/tree/master/examples/housing_prices`,children:`examples/housing_prices`}),` sub-directory.`]}),`\n`,_jsx(Heading,{level:`3`,id:`root-datasets`,children:`Root Datasets`}),`\n`,_jsx(_components.p,{children:`We will be using following root datasets:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`ca.vancouver.opendata.property.tax-reports`}),` - contains property assessment reports from the city of Vancouver`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`ca.vancouver.opendata.property.parcel-polygons`}),` - contains geographical outlines of properties`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`ca.vancouver.opendata.property.block-outlines`}),` - contains geographical block outlines`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`ca.vancouver.opendata.property.local-area-boundaries`}),` - contains outlines and names of Vancouver’s districts`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`For geospatial data `,_jsx(_components.code,{children:`kamu`}),` supports several input formats including `,_jsx(_components.a,{href:`https://en.wikipedia.org/wiki/Shapefile`,children:`ESRI Shapefile`}),` and `,_jsx(_components.a,{href:`https://geojson.org/`,children:`GeoJson`}),`. Take a look at dataset definitions to understand how data is being ingested.`]}),`\n`,_jsx(_components.p,{children:`Quite often when ingesting GIS data you will need to deal with different projections. Example below shows how you can use a pre-processing step to convert data into another projection:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`7`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`7`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`preprocess`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` kind`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Sql`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` engine`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`spark`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` query`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`|`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` SELECT`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ST_Transform(geometry, \"epsg:3157\", \"epsg:4326\") as geometry`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` FROM input`})}),`\n`]})})}),`\n`,_jsxs(_components.blockquote,{children:[`\n`,_jsxs(_components.p,{children:[`Note: `,_jsx(_components.a,{href:`https://epsg.io/4326`,children:`epsg:4326`}),` is one of the more commonly used projections which is expected by many visualization tools.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`ST_Transform`}),` function here comes from `,_jsx(_components.a,{href:`http://sedona.apache.org/`,children:`Apache Sedona`}),` extension for the Apache Spark engine for working with GIS data. We will be relying on many of its function throughout this example.`]}),`\n`,_jsx(_components.p,{children:`Lets add all these datasets to our workspace and ingest them:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`9`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Create a kamu workspace in the example folder`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`kamu`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` init`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Add all dataset manifests found in the current directory`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`kamu`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` add`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --recursive`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`kamu`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` pull`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --all`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Alternatively: Pull datasets in ODF format from Kamu's repository`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`./init-s3.sh`})}),`\n`]})})}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`The source data for `,_jsx(_components.code,{children:`tax-reports`}),` dataset is quite large (~400MB in CSV format) so if you don’t want to wait too long - use the `,_jsx(_components.code,{children:`init-s3.sh`}),` script.`]})}),`\n`,_jsx(_components.p,{children:`This may take 10+ minutes as the tax report dataset is quite large. You can leave the ingest running and move on to the next step meanwhile.`}),`\n`,_jsx(Heading,{level:`3`,id:`creating-mapbox-account`,children:`Creating MapBox Account`}),`\n`,_jsxs(_components.p,{children:[`For visualizing the GIS data we will be using the awesome `,_jsx(_components.a,{href:`https://www.mapbox.com/`,children:`Mapbox SDK`}),`. To follow the example you will need to create a free account and get your own access token. The token should look something like `,_jsx(_components.code,{children:`pk.eyJ...T6Q`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`visualizing-housing-prices`,children:`Visualizing Housing Prices`}),`\n`,_jsx(_components.p,{children:`Once you have downloaded all datasets we can start with a simple notebook to get a feel for GIS visualization.`}),`\n`,_jsx(_components.p,{children:`Start the notebook server and pass it your Mapbox token via environment variable:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`kamu`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` notebook`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -e`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` MAPBOX_ACCESS_TOKEN=`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` mapbox`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` toke`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`n`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Now you can open the `,_jsx(_components.code,{children:`heatmap.ipynb`}),` and run through it executing each step. The notebook is pretty straightforward - it joins together the `,_jsx(_components.code,{children:`tax-reports`}),` dataset containing assessment values with `,_jsx(_components.code,{children:`parcel-polygons`}),` dataset containing land geometries in order to produce a heatmap.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`13`,language:`sql`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`13`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`%%`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`sql`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`CREATE`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` OR`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` REPLACE`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` TEMP VIEW lot_tax `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`AS`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` (`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` SELECT`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` t.`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`*`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` l`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`geometry`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` FROM`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` lots `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`as`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` l`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` JOIN`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` tax `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`as`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` t`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` ON`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` l`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`tax_coord`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` t`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`land_coordinate`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` WHERE`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` t`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`legal_type`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` 'LAND'`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` AND`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` t`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`tax_assessment_year`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:` 2019`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` AND`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` t`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`current_land_value`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` is not null`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`})}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`It then pulls the result from Spark into the notebook itself using this query:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`sql`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`6`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`%%`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`sql`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` -`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`o df `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`-`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`n `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`100000`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` land_coordinate,`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ST_AsGeoJSON(`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`geometry`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`) `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`as`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` geometry`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` current_land_value `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`+`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` current_improvement_value `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`as`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` current_total_value`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`FROM`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` lot_tax`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`-n 100000`}),` parameter here overrides the default limit on the dataframe size, while `,_jsx(_components.code,{children:`ST_AsGeoJSON(geometry)`}),` also converts the internal binary `,_jsx(_components.code,{children:`geometry`}),` type into the GeoJson format. We later use custom-written `,_jsx(_components.code,{children:`df_to_geojson`}),` to combine individual geometries into `,_jsx(_components.code,{children:`GeoJson`}),`’s `,_jsx(_components.code,{children:`FeatureCollection`}),` objectm understood by the `,_jsx(_components.code,{children:`mapboxgl`}),` library.`]}),`\n`,_jsxs(_components.p,{children:[`We can then use the resulting GeoJson data and render the heatmap using the `,_jsx(_components.a,{href:`https://github.com/mapbox/mapboxgl-jupyter`,children:`mapboxgl-jupyter`}),` library which comes pre-installed with `,_jsx(_components.code,{children:`kamu`}),`’s notebook server image.`]}),`\n`,_jsx(_MdxComponentBoundary,{name:`Diagram`,children:_jsx(Diagram,{src:`/images/cli/examples/housing-prices/heatmap.png`,alt:`House prices heatmap`})}),`\n`,_jsx(Heading,{level:`3`,id:`spatial-joins`,children:`Spatial Joins`}),`\n`,_jsxs(_components.p,{children:[`Let’s take a look how datasets can be joined using the geometries. The `,_jsx(_components.code,{children:`local-area-boundaries`}),` contains the names of the Vancouver’s neighbourhoods along with their geographical boundaries. We also have the `,_jsx(_components.code,{children:`block-outlines`}),` dataset containing boundaries of individual blocks, but there’s an issue - there is no identifier that would link a block to a specific neighbourhood. For us to associate a block with the neighbourhood we have to see if block’s boundaries are contained or intersect the boundaries of some neighbourhood. `,_jsx(_components.code,{children:`Apache Sedona`}),` used by `,_jsx(_components.code,{children:`kamu`}),` optimizes such spatial joins.`]}),`\n`,_jsxs(_components.p,{children:[`You can open up the `,_jsx(_components.code,{children:`spatial_join.ipynb`}),` notebook and run through it step by step. The most important part ther is the join itself:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`sql`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`6`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`CREATE`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` OR`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` REPLACE`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` TEMP VIEW blocks_by_hood `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`AS`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` (`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` SELECT`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` h`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`b`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`geometry`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` FROM`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` blocks `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`as`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` b`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` INNER JOIN`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` hoods `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`as`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` h`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` ON`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ST_Intersects(`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`b`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`geometry`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`h`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`geometry`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`})}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The rest of the visualization steps should be familiar to you from the previous example.`}),`\n`,_jsxs(_components.p,{children:[`As an exercise - see if you can replace the `,_jsx(_components.code,{children:`median_value`}),` column that we have populated with `,_jsx(_components.code,{children:`RAND()`}),` for every block with an actual median property price. Just like before, there is unfortunately no identifier that would tie the property to a specific block, but see if `,_jsx(_components.code,{children:`Sedona`}),` can handle a massive spatial join between blocks and individual property outlines.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{Diagram,YouTubeList,YouTube,Schema,Term,default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"Title":"Housing Prices","description":null,"weight":0,"categories":[],"aliases":["/cli/learn/examples/housing-prices"],"title":null,"href":"/examples/housing-prices"}}},"mdxSourceWithNoJs":null,"noJsSplices":[[143,1423,")=>null;const YouTubeList=()=>null;const YouTube=()=>null;const Schema=()=>null;const Term=()=>null;"]]},"mdxExtracts":{"tableOfContents":[{"title":"Summary","slug":"summary","depth":2,"children":[]},{"title":"Steps","slug":"steps","depth":2,"children":[{"title":"Getting Started","slug":"getting-started","depth":3,"children":[]},{"title":"Root Datasets","slug":"root-datasets","depth":3,"children":[]},{"title":"Creating MapBox Account","slug":"creating-mapbox-account","depth":3,"children":[]},{"title":"Visualizing Housing Prices","slug":"visualizing-housing-prices","depth":3,"children":[]},{"title":"Spatial Joins","slug":"spatial-joins","depth":3,"children":[]}]}],"codeExamples":{}},"jsLinks":[],"dynamicCss":".mint-aspect-video {\n aspect-ratio: 16 / 9\n}\n.mint-w-full {\n width: 100%\n}\n.mint-rounded-xl {\n border-radius: 0.75rem\n}","subdomain":"kamu","siteName":"Kamu Docs","title":"Housing prices - Kamu Docs","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-15T04:13:50.283Z","gitLastModified":"2026-03-16T00:59:55.000Z","originalFileLocation":"examples/housing-prices.md"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"application-name\" content=\"Kamu Docs\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Housing prices - Kamu Docs\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Kamu Docs\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.kamu.dev/examples/housing-prices\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://kamu.mintlify.app/_mintlify/api/og/v2?division=Examples\u0026amp;title=Housing+prices\u0026amp;theme=4425de33767c8dc7c1d6072e\u0026amp;signature=14a728b6e70182c1000c5ec634181b3acd14001cb377fee817a09b0fc243fe8d\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Housing prices - Kamu Docs\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://kamu.mintlify.app/_mintlify/api/og/v2?division=Examples\u0026amp;title=Housing+prices\u0026amp;theme=4425de33767c8dc7c1d6072e\u0026amp;signature=14a728b6e70182c1000c5ec634181b3acd14001cb377fee817a09b0fc243fe8d\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/kamu/FxhmdHpAfy0cwcpV/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Kamu Docs\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#ec6e2a\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.kamu.dev/examples/housing-prices\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/examples/housing-prices.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.kamu.dev/#organization\",\"name\":\"Kamu Docs\",\"url\":\"https://docs.kamu.dev\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/kamu/j1tx5fgzyFHd1DYS/images/kamu-logo-light.svg?fit=max\u0026auto=format\u0026n=j1tx5fgzyFHd1DYS\u0026q=85\u0026s=a09261b617da6e1515dea3d28495f633\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.kamu.dev#website\",\"name\":\"Kamu Docs\",\"url\":\"https://docs.kamu.dev\",\"publisher\":{\"@id\":\"https://docs.kamu.dev/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.kamu.dev/examples/housing-prices#webpage\",\"url\":\"https://docs.kamu.dev/examples/housing-prices\",\"name\":\"Housing prices\",\"dateModified\":\"2026-03-16T00:59:55.000Z\",\"isPartOf\":{\"@id\":\"https://docs.kamu.dev#website\"},\"breadcrumb\":{\"@id\":\"https://docs.kamu.dev/examples/housing-prices#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.kamu.dev/examples/housing-prices#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Get Started\",\"item\":\"https://docs.kamu.dev/start/welcome\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Examples\",\"item\":\"https://docs.kamu.dev/examples/index\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Housing prices\",\"item\":\"https://docs.kamu.dev/examples/housing-prices\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.kamu.dev/examples/housing-prices#article\",\"headline\":\"Housing prices\",\"name\":\"Housing prices\",\"url\":\"https://docs.kamu.dev/examples/housing-prices\",\"mainEntityOfPage\":{\"@id\":\"https://docs.kamu.dev/examples/housing-prices#webpage\"},\"dateModified\":\"2026-03-16T00:59:55.000Z\",\"publisher\":{\"@id\":\"https://docs.kamu.dev/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.kamu.dev#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Kamu Docs\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Kamu Docs","nav":{"global":{"anchors":[]},"tabs":[{"tab":"Guides","icon":"person-chalkboard","groups":[{"group":"Get Started","pages":[{"title":"Welcome to Kamu!","sidebarTitle":"Welcome","icon":"hand-spock","mode":"wide","href":"/start/welcome"},{"title":"Frequently asked questions","sidebarTitle":"FAQ","icon":"circle-question","href":"/start/faq"},{"title":"First Steps","icon":"list-ol","href":"/start/first-steps"},{"title":"Learning Materials","icon":"person-chalkboard","mode":"wide","href":"/start/learning-materials"},{"title":"Online Tutorial","icon":"play","href":"/start/tutorial"},{"group":"Examples","icon":"book-open","root":{"title":"Examples","href":"/examples/index"},"pages":[{"title":"COVID-19 Daily Cases","href":"/examples/covid19"},{"title":"Currency Conversion","description":null,"href":"/examples/currency-conversion"},{"title":null,"href":"/examples/housing-prices"},{"description":null,"title":null,"href":"/examples/leaderboard"},{"title":"Overdue Order Shipments","href":"/examples/overdue-shipments"},{"title":null,"href":"/examples/stock-trading"},{"title":null,"href":"/examples/web3-data"}]}]},{"group":"Kamu CLI","pages":[{"title":"About","href":"/cli/about"},{"title":"Install","href":"/cli/install"},{"title":"Quick Start","href":"/cli/quick-start"},{"group":"Ingesting Data","root":{"title":"Ingesting Data","href":"/cli/ingest/index"},"pages":[{"title":"Input Formats","href":"/cli/ingest/input-formats"},{"title":"Polling Sources","href":"/cli/ingest/polling-source"},{"title":"Push Sources","href":"/cli/ingest/push-source"},{"title":"Merge Strategies","href":"/cli/ingest/merge-strategies"},{"title":"Blockchain Sources","href":"/cli/ingest/blockchain-source"}]},{"group":"Transforming Data","root":{"title":"Transforming Data","href":"/cli/transform/index"},"pages":[{"title":"Projections","icon":"wrench","href":"/cli/transform/projections"},{"title":"Retractions \u0026 Corrections","href":"/cli/transform/retractions-corrections"},{"title":"Streaming Aggregations","icon":"wrench","href":"/cli/transform/aggregations"},{"title":"Stream-to-Stream Joins","icon":"wrench","href":"/cli/transform/joins-s2s"},{"title":"Temporal Table Joins","icon":"wrench","href":"/cli/transform/joins-tt"},{"title":"Watermarks","icon":"wrench","href":"/cli/transform/watermarks"},{"title":"Geospatial Data","icon":"wrench","href":"/cli/transform/gis-data"}]},{"title":"Exploring Data","href":"/cli/explore"},{"group":"Sharing \u0026 Collaboration","root":{"title":"Sharing \u0026 Collaboration","href":"/cli/collab/index"},"pages":[{"title":"Repositories","href":"/cli/collab/repositories"},{"title":"Privacy and Permissions","icon":"wrench","href":"/cli/collab/privacy-and-permissions"},{"title":"Sharing datasets with IPFS","href":"/cli/collab/ipfs"},{"title":"Validity of Data","href":"/cli/collab/validity"},{"title":"Provenance","icon":"wrench","href":"/cli/collab/provenance"}]},{"group":"Dataset Evolution","icon":"wrench","pages":[{"title":"Schema Evolution","icon":"wrench","href":"/cli/evolve/schema"},{"title":"Root Dataset Evolution","icon":"wrench","href":"/cli/evolve/root"},{"title":"Derivative Dataset Evolution","icon":"wrench","href":"/cli/evolve/deriv"}]},{"group":"Handling Bad Data","icon":"wrench","pages":[{"title":"Retractions \u0026 Corrections","icon":"wrench","href":"/cli/bad-data/retractions-corrections"},{"title":"Bad Data on Ingestion","icon":"wrench","href":"/cli/bad-data/ingest-errors"},{"title":"Bad Data in Upstream Datasets","icon":"wrench","href":"/cli/bad-data/upstream"},{"title":"PII and Sensitive Data","icon":"wrench","href":"/cli/bad-data/pii"}]},{"title":"Troubleshooting","href":"/cli/troubleshooting"}]},{"group":"Kamu Node","pages":[{"title":"About","href":"/node/about"},{"title":"Quick Start","href":"/node/quick-start"},{"title":"Architecture","href":"/node/architecture"},{"group":"Deployment","pages":[{"title":"Deployment Manual","href":"/node/deploy/manual"},{"title":"Kubernetes Setup","icon":"wrench","href":"/node/deploy/k8s"},{"title":"Artifacts","href":"/node/deploy/artifacts"},{"title":"Auth","icon":"wrench","href":"/node/deploy/auth"},{"title":"Storage","href":"/node/deploy/storage"},{"title":"Capacity Planning","icon":"wrench","href":"/node/deploy/capacity"},{"title":"Security","icon":"wrench","href":"/node/deploy/security"},{"title":"Customization","icon":"wrench","href":"/node/deploy/customization"}]},{"group":"Operations","icon":"wrench","pages":[{"title":"Monitoring","icon":"wrench","href":"/node/operator/monitoring"},{"title":"Upgrades","icon":"wrench","href":"/node/operator/upgrades"},{"title":"Performance Tips","icon":"wrench","href":"/node/operator/performance"}]},{"title":"Verifiable Queries","href":"/node/commitments"},{"title":"Troubleshooting","icon":"wrench","href":"/node/troubleshoot"}]},{"group":"Kamu Web Platform","pages":[{"title":"About","href":"/platform/about"},{"title":"Accounts \u0026 Organizations","icon":"wrench","href":"/platform/accounts"},{"group":"Datasets","icon":"wrench","pages":[{"title":"Attachments","icon":"wrench","href":"/platform/datasets/attachments"},{"title":"Licenses","icon":"wrench","href":"/platform/datasets/licenses"}]},{"group":"Data Exploration","icon":"wrench","pages":[{"title":"Querying","icon":"wrench","href":"/platform/data/querying"},{"title":"Notebooks","icon":"wrench","href":"/platform/data/notebooks"}]},{"title":"Privacy","icon":"wrench","href":"/platform/privacy"},{"group":"Flow System","icon":"wrench","pages":[{"title":"Overview","icon":"wrench","href":"/platform/flows/overview"}]},{"group":"Administration","icon":"wrench","pages":[{"title":"Monitoring","icon":"wrench","href":"/platform/admin/monitoring"},{"title":"Tasks \u0026 Executors","icon":"wrench","href":"/platform/admin/tasks-executors"}]}]},{"group":"General","pages":[{"title":"Project Status","icon":"temperature-full","href":"/general/project-status"},{"title":"Supported Data Engines","icon":"database","href":"/general/supported-engines"},{"title":"Community","icon":"user-group","href":"/general/community"},{"title":"Contributing","icon":"heart","href":"/general/contrib"},{"title":"Licensing Terms","icon":"scroll","href":"/general/licensing"},{"title":"Terms of Service","icon":"scale-balanced","href":"/general/terms"},{"title":"Glossary","icon":"arrow-down-a-z","href":"/general/glossary"},{"icon":"pen","title":null,"href":"/general/typography"}]}]},{"tab":"Reference","icon":"book-open-cover","groups":[{"group":"Open Data Fabric","pages":[{"title":null,"href":"/odf/about"},{"group":"Specification","root":{"title":"Overview","href":"/odf/spec/overview"},"pages":[{"group":"Datasets","pages":[{"title":"Logical Structure","href":"/odf/spec/datasets/logical-structure"},{"title":"Identity","href":"/odf/spec/datasets/identity"},{"title":"Data Model","href":"/odf/spec/datasets/data-model"},{"title":"Data Schema","href":"/odf/spec/datasets/data-schema"},{"title":"Metadata Chain","href":"/odf/spec/datasets/metadata-chain"},{"title":"Data \u0026 Checkpoint Hashing","href":"/odf/spec/datasets/data-and-checkpoint-hashing"},{"title":"Storage Layout","href":"/odf/spec/datasets/storage-layout"},{"title":"Ingestion","href":"/odf/spec/datasets/ingestion"}]},{"group":"Transformations","pages":[{"title":"Processing Model","href":"/odf/spec/transformations/processing-model"},{"title":"Engine Contract","href":"/odf/spec/transformations/engine-contract"}]},{"group":"Exchange","pages":[{"title":"Transfer Protocols","href":"/odf/spec/exchange/transfer-protocols"},{"title":"Verifiable Batch Queries","href":"/odf/spec/exchange/verifiable-batch-queries"}]},{"group":"Automation","pages":[{"title":"Resource Framework","href":"/odf/spec/automation/resource-framework"},{"title":"Tasks and Flows","href":"/odf/spec/automation/tasks-and-flows"}]},{"group":"Auth \u0026 Privacy","pages":[{"title":"Authorization","href":"/odf/spec/auth-and-privacy/authorization"}]}]},{"title":"Schemas","href":"/odf/schemas"},{"group":"RFCs","root":{"title":"RFCs","href":"/odf/rfcs/index"},"pages":[{"title":"RFC-001: Record Offsets","href":"/odf/rfcs/001-record-offsets"},{"title":"RFC-002: Logical Data Digests","href":"/odf/rfcs/002-logical-data-hashes"},{"title":"RFC-003: Content Addressability","href":"/odf/rfcs/003-content-addressability"},{"title":"RFC-004: Metadata Extensibility","href":"/odf/rfcs/004-metadata-extensibility"},{"title":"RFC-005: New Annotation Metadata Events","href":"/odf/rfcs/005-dataset-annotations"},{"title":"RFC-006: Store Checkpoints as Files","href":"/odf/rfcs/006-checkpoints-as-files"},{"title":"RFC-007: Simple Transfer Protocol","href":"/odf/rfcs/007-simple-transfer-protocol"},{"title":"RFC-008: Smart Transfer Protocol","href":"/odf/rfcs/008-smart-transfer-protocol"},{"title":"RFC-009: Ingestion Source State","href":"/odf/rfcs/009-ingest-source-state"},{"title":"RFC-010: Data Schema in Metadata","href":"/odf/rfcs/010-data-schema-in-metadata"},{"title":"RFC-011: Push Ingest Sources","href":"/odf/rfcs/011-push-ingest-sources"},{"title":"RFC-012: Recommend `base16` encoding for textual representation of hashes and DIDs","href":"/odf/rfcs/012-recommend-base16-encoding"},{"title":"RFC-013: Enum representation in YAML encoding","href":"/odf/rfcs/013-yaml-enum-representation"},{"title":"RFC-014: Minimizing scanning for last offset and block","href":"/odf/rfcs/014-minimize-offset-scanning"},{"title":"RFC-015: Unified changelog stream schema","href":"/odf/rfcs/015-unified-changelog-stream-schema"},{"title":"RFC-016: ODF Schema Format","href":"/odf/rfcs/016-odf-schema"},{"title":"RFC-017: Large Files Linking","href":"/odf/rfcs/017-large-files-linking"},{"title":"RFC-018: Infrastructure-as-Code Resource Framework","href":"/odf/rfcs/018-iac-resource-framework"},{"title":"RFC-019: IaC Task and Flow System","href":"/odf/rfcs/019-iac-task-flow-system"},{"title":"RFC-020: Authorization Model","href":"/odf/rfcs/020-auth"},{"title":"RFC-021: ODF Spec Restructuring","href":"/odf/rfcs/021-spec-restructuring"},{"title":"RFC-022: Batch Query Commitments","href":"/odf/rfcs/022-batch-query-commitments"}]}]},{"group":"Kamu CLI","pages":[{"title":"Commands Reference","href":"/cli/commands"},{"title":"Config Reference","href":"/cli/config"}]},{"group":"Kamu Node","pages":[{"title":"Config Reference","href":"/node/config"}]}]},{"tab":"APIs","icon":"code","pages":[{"title":"Overview","href":"/api/overview"},{"title":"FlightSQL","href":"/api/flight-sql"},{"title":"GraphQL","href":"/api/graphql"},{"title":"JDBC","href":"/api/jdbc"},{"title":"Kafka","icon":"wrench","href":"/api/kafka"},{"title":"MQTT","href":"/api/mqtt"},{"title":"OData","href":"/api/odata"},{"title":"ODF","href":"/api/odf"},{"title":"PostgreSQL","icon":"wrench","href":"/api/postgres"},{"title":"REST","href":"/api/rest"},{"title":"Webhooks","href":"/api/webhooks"},{"title":"WebSocket","icon":"wrench","href":"/api/websocket"},{"title":"Blockchain Oracle","href":"/api/oracle"}]},{"tab":"Integrations","icon":"network-wired","pages":[{"title":"Overview","href":"/integrations/overview"},{"title":"Apache Superset","href":"/integrations/apache-superset"},{"title":"DBeaver","href":"/integrations/dbeaver"},{"title":"Generic ADBC Client","href":"/integrations/adbc"},{"title":"Generic JDBC Client","href":"/integrations/jdbc"},{"title":"Generic ODBC Client","tag":"WIP","href":"/integrations/odbc"},{"title":"PowerBI","href":"/integrations/powerbi"},{"title":"Python Scripts \u0026 Notebooks","href":"/integrations/python"},{"title":"Tableau","href":"/integrations/tableau"}]}]},"title":"Housing prices - Kamu Docs","buildId":"dpl_849ArpqvBiCczQiT1Y1stNGpbqHT","deploymentId":"dpl_849ArpqvBiCczQiT1Y1stNGpbqHT","dynamics":[],"chunks":[]}