diff --git a/src/components/side-panel/SidePanel.tsx b/src/components/side-panel/SidePanel.tsx
index 5cf30e7..88cba58 100644
--- a/src/components/side-panel/SidePanel.tsx
+++ b/src/components/side-panel/SidePanel.tsx
@@ -11,6 +11,8 @@ const SidePanel = (): JSX.Element => {
setChartProperties,
selectedFilename,
setSelectedFilename,
+ sparqlQuery,
+ setSparqlQuery,
}: ChartContextProps = useContext(ChartContext);
const isAMap = chartProperties[0].properties[0].value === "Map";
@@ -195,6 +197,22 @@ const SidePanel = (): JSX.Element => {
);
};
+ const getSparqlInput = () => {
+ return (
+
+ );
+ };
+
return (
{chartProperties.map((section: any, index: number) => {
@@ -222,8 +240,10 @@ const SidePanel = (): JSX.Element => {
}
})}
- {section.name === "chartTypes" && !isAMap
- ? getDataSelectionSection(section.name)
+ {section.name === "chartTypes"
+ ? isAMap
+ ? getSparqlInput()
+ : getDataSelectionSection(section.name)
: null}
);
diff --git a/src/components/side-panel/side-panel.css b/src/components/side-panel/side-panel.css
index d6920be..5d09d41 100644
--- a/src/components/side-panel/side-panel.css
+++ b/src/components/side-panel/side-panel.css
@@ -114,3 +114,16 @@
align-items: center;
margin-top: 0.5rem;
}
+
+#sparql-input {
+ width: 100%;
+ margin-top: 0.7rem;
+ padding: 0.2rem;
+ font-size: 0.8rem;
+ font-family: monospace;
+ border-style: solid;
+ background-color: whitesmoke;
+ outline: none;
+ overflow-y: auto;
+ resize: none;
+}
diff --git a/src/context/ChartContext.tsx b/src/context/ChartContext.tsx
index 8703dca..e4f2019 100644
--- a/src/context/ChartContext.tsx
+++ b/src/context/ChartContext.tsx
@@ -1,4 +1,4 @@
-import React, {Dispatch, SetStateAction} from "react";
+import React, { Dispatch, SetStateAction } from "react";
import {
ChartPropertySection,
DataSelection,
@@ -37,6 +37,9 @@ export interface ChartContextState {
setMapData: any,
geoJson: any,
setGeoJson: any,
+
+ sparqlQuery: string;
+ setSparqlQuery: Dispatch>;
}
export interface ChartContextProps {
@@ -70,6 +73,9 @@ export interface ChartContextProps {
importCsvData: (data: File | string, filename: string) => void;
importEeaData: (data: EeaData) => void;
+
+ sparqlQuery: string;
+ setSparqlQuery: Dispatch>;
}
const ChartContext = React.createContext(
diff --git a/src/context/ChartContextProvider.tsx b/src/context/ChartContextProvider.tsx
index bf7ac71..ab830f3 100644
--- a/src/context/ChartContextProvider.tsx
+++ b/src/context/ChartContextProvider.tsx
@@ -12,9 +12,11 @@ import {
TidyData,
ChartDataProvider
} from "./types";
-import { getMapData } from "../services/map-data/map-data-loader";
-import { getUkLaBoundaries } from "../services/map-data/uk-la-boundaries";
import { arrayColumn, getDistinctValues } from "../helper-functions/array-helpers";
+import { getMapData } from "../services/map-data/mapDataLoader";
+import { getGeoJson } from "../services/map-data/geoJsonLoader";
+import LOCAL_AUTHORITY_BOUNDARY_QUERY from "../services/map-data/geoJsonQueries";
+
import { NO_FILE_SELECTED_TEXT } from "../components/constants/Common-constants";
import updateChartDefinition from "../plotly/chartDefinition";
@@ -39,6 +41,7 @@ export function useChartContextState(): ChartContextState {
>([]);
const [mapData, setMapData] = useState([]);
const [geoJson, setGeoJson] = useState([]);
+ const [sparqlQuery, setSparqlQuery] = useState("");
return {
chartDefinition,
@@ -57,6 +60,8 @@ export function useChartContextState(): ChartContextState {
setMapData,
geoJson,
setGeoJson,
+ sparqlQuery,
+ setSparqlQuery,
};
}
@@ -201,6 +206,8 @@ export function useChartContext(state: ChartContextState): ChartContextProps {
setMapData,
geoJson,
setGeoJson,
+ sparqlQuery,
+ setSparqlQuery,
} = state;
const dimensionValue = dataSelection?.dimension || '';
@@ -229,16 +236,20 @@ export function useChartContext(state: ChartContextState): ChartContextProps {
availableDimensions = eeaDataAvailableDimensions;
}
- const loadMapData = useCallback(async () => {
- const mapData = await getMapData();
- const geoJson = await getUkLaBoundaries();
- setMapData(mapData);
- setGeoJson(geoJson);
- }, []);
-
useEffect(() => {
+ if (sparqlQuery === "") return;
+ const loadMapData = async () => {
+ try {
+ const mapData = await getMapData(sparqlQuery);
+ const geoJson = await getGeoJson(LOCAL_AUTHORITY_BOUNDARY_QUERY);
+ setGeoJson(geoJson);
+ setMapData(mapData);
+ } catch (e) {
+ console.error(e);
+ }
+ };
loadMapData();
- }, []);
+ }, [sparqlQuery]);
useEffect(() => {
// todo restore empty data state check - with but with eea/sparql data sources for maps and charts
@@ -286,6 +297,8 @@ export function useChartContext(state: ChartContextState): ChartContextProps {
setMapData,
geoJson,
setGeoJson,
+ sparqlQuery,
+ setSparqlQuery,
};
}
diff --git a/src/context/initialChartProperties.ts b/src/context/initialChartProperties.ts
index b66455e..e4e710c 100644
--- a/src/context/initialChartProperties.ts
+++ b/src/context/initialChartProperties.ts
@@ -74,7 +74,14 @@ const interactivitySection: ChartPropertySection = {
displayName: "Series tooltip",
type: "radio",
options: ["x+y", "none"],
- value: "none",
+ value: "x+y",
+ output: "svg",
+ },
+ {
+ name: "hoverInfoUnit",
+ displayName: "Hoverinfo unit",
+ type: "text",
+ value: "%",
output: "svg",
},
],
@@ -134,35 +141,35 @@ const chartDimensionsSection: ChartPropertySection = {
name: "height",
displayName: "Height(px)",
type: "text",
- value: "550",
+ value: "700",
output: "svg",
},
{
name: "marginLeft",
displayName: "Left margin(px)",
type: "text",
- value: "70",
+ value: "0",
output: "svg",
},
{
name: "marginRight",
displayName: "Right margin(px)",
type: "text",
- value: "70",
+ value: "0",
output: "svg",
},
{
name: "marginTop",
- displayName: "Bottom margin(px)",
+ displayName: "Top margin(px)",
type: "text",
- value: "70",
+ value: "0",
output: "svg",
},
{
name: "marginBottom",
displayName: "Bottom margin(px)",
type: "text",
- value: "70",
+ value: "0",
output: "svg",
},
],
@@ -203,6 +210,21 @@ const colorBarSection: ChartPropertySection = {
value: "25",
output: "svg",
},
+ {
+ name: "colorscale",
+ displayName: "Color scale",
+ type: "radio",
+ options: ["Sequential", "Diverging"],
+ value: "Sequential",
+ output: "svg",
+ },
+ {
+ name: "autocolorscale",
+ displayName: "Auto color scale",
+ type: "checkbox",
+ value: false,
+ output: "svg",
+ },
],
};
diff --git a/src/context/types.ts b/src/context/types.ts
index 137d4c7..0512947 100644
--- a/src/context/types.ts
+++ b/src/context/types.ts
@@ -33,7 +33,7 @@ interface EeaData {
}
// should be whatever shape of props react-plotly receives.
-type PlotlyChartDefinition = object;56
+type PlotlyChartDefinition = object;
interface ChartPropertySection {
name: string,
diff --git a/src/plotly/chartDefinition.ts b/src/plotly/chartDefinition.ts
index 811f620..905aa3e 100644
--- a/src/plotly/chartDefinition.ts
+++ b/src/plotly/chartDefinition.ts
@@ -1,6 +1,20 @@
import { getMapLayout, getChartLayout } from "./layout";
import config from "./config";
+const divergingColorScale = [
+ [0, "rgb(242, 108, 49)"],
+ [0.35, "rgb(242, 160, 49)"],
+ [0.5, "rgb(233, 212, 30)"],
+ [0.6, "rgb(202, 233, 30)"],
+ [0.7, "rgb(44, 182, 169)"],
+ [1, "rgb(36, 151, 140)"],
+];
+
+const sequentialColorScale = [
+ [0, "rgb(233, 212, 30)"],
+ [1, "rgb(36, 151, 140)"],
+];
+
import {
colors,
flattenChartProperties,
@@ -69,24 +83,21 @@ const getChartData = (chartType: any, chartProps: any, chartData: any) => {
};
const getMapData = (chartProps: any, mapData: any, geoJson: any) => {
- const data = [
+ let data: any = [
{
type: "choropleth",
locationmode: "geojson-id",
- locations: mapData.la_uri,
- z: mapData.emissions,
+ locations: mapData.geography_uri,
+ z: mapData.values,
text: mapData.label,
- hoverinfo: chartProps.interactivity,
- colorscale: [
- [0, "rgb(242, 108, 49)"],
- [0.35, "rgb(242, 160, 49)"],
- [0.5, "rgb(233, 212, 30)"],
- [0.6, "rgb(202, 233, 30)"],
- [0.7, "rgb(44, 182, 169)"],
- [1, "rgb(36, 151, 140)"],
- ],
+ colorscale:
+ chartProps.colorscale === "Diverging"
+ ? divergingColorScale
+ : sequentialColorScale,
+ autocolorscale: chartProps.autocolorscale,
featureidkey: "properties.geography_uri",
geojson: geoJson,
+ hoverinfo: chartProps.interactivity,
marker: {
line: {
color: "rgb(123,123,123)",
@@ -99,6 +110,15 @@ const getMapData = (chartProps: any, mapData: any, geoJson: any) => {
},
},
];
+
+ // if interactivity is enabled show hover text over map regions
+ // we use a custom hover template so that the geography_uri doesn't show up in the hover text
+ if (chartProps.interactivity === "x+y") {
+ const hovertemplate = {
+ hovertemplate: ` %{text}
%{z}${chartProps.hoverInfoUnit} `,
+ };
+ data = [{ ...data[0], ...hovertemplate }];
+ }
return data;
};
diff --git a/src/services/map-data/datasets.ts b/src/services/map-data/datasets.ts
deleted file mode 100644
index 9b24945..0000000
--- a/src/services/map-data/datasets.ts
+++ /dev/null
@@ -1,261 +0,0 @@
-import type { Dataset, DatasetInfo } from "./types";
-
-export const ONS_TRADE_IN_GOODS: Dataset = {
- id: "ons-trade-in-goods",
- uri: "http://gss-data.org.uk/data/gss_data/trade/ons-trade-in-goods",
-};
-
-export const ONS_TRADE_IN_GOODS_SEASONALLY: Dataset = {
- id: "ons-trade-in-goods",
- uri: "http://gss-data.org.uk/data/gss_data/trade/ons-uk-sa-trade-in-goods-catalog-entry",
-};
-
-export const ONS_TRADE_UK_TIME_SERIES: Dataset = {
- id: "ons-trade-in-goods",
- uri: "http://gss-data.org.uk/data/gss_data/trade/ons_mrets/uk-trade-time-series-current-prices-catalog-entry",
-};
-
-export const ONS_SA_TRADE_IN_GOODS: Dataset = {
- id: "ons-sa-trade-in-goods",
- uri: "http://gss-data.org.uk/data/gss_data/trade/ons-uk-sa-trade-in-goods",
-};
-export const DEFRA_EFFICIENT_WATER: Dataset = {
- id: "defra-efficient-water",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/defra-e8-efficient-use-of-water",
-};
-export const DEFRA_WATER_LEAKAGE: Dataset = {
- id: "defra-water-leakage",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/defra-uk-water-leakage",
-};
-export const DEFRA_WATER_CONSUMPTION: Dataset = {
- id: "defra-efficient-water",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/defra-e8-efficient-use-of-water-catalog-entry",
-};
-
-export const BEIS_GAS_EMISSIONS: Dataset = {
- id: "beis-gas-emissions",
- uri: "http://gss-data.org.uk/data/gss_data/energy/beis-final-uk-greenhouse-gas-emissions-national-statistics-1990-to-2019",
-};
-export const BEIS_GAS_EMISSIONS_PROVISIONAL: Dataset = {
- id: "beis-gas-emissions",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/beis-final-uk-greenhouse-gas-emissions-national-statistics",
-};
-export const DEFRA_CARBON_FOOTPRINT_SUMMARY: Dataset = {
- id: "defra-carbon-footprint-summary",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/defra-carbon-footprint-summary-final-demand-90-18",
-};
-export const MET_GROWING_SEASON: Dataset = {
- id: "met-growing-season",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/met-office-annual-growing-season-length-with-trends-actual",
-};
-export const MET_UK_MEAN_TEMP: Dataset = {
- id: "met-uk-meantemp",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/met-office-annual-mean-temp-with-trends-actual",
-};
-export const MET_UK_MEAN_TEMP_ANOMALY: Dataset = {
- id: "met-uk-meantemp-anomaly",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/met-office-annual-mean-temp-with-trends-anomaly",
-};
-export const ONS_ATMOSPHERIC_EMISSIONS_GREENHOUSE_GASSES_BY_INDUSTRY_AND_GAS: Dataset =
- {
- id: "ons-atmospheric-emissions-greenhouse-gases-by-industry-and-gas",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/ons-atmospheric-emissions-greenhouse-gases-by-industry-and-gas",
- };
-export const MET_UK_MEAN_RAIN1: Dataset = {
- id: "met-uk-meanrain",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/met-office-annual-mean-rainfall-with-trends-actual",
-};
-export const DEFRA_CARBON_FOOTPRINT_SUMMARY_SOURCE_REGION: Dataset = {
- id: "trade/defra-carbon-summary-region",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/defra-carbon-footprint-summary-source-region-90-18",
-};
-export const BEIS_LA_CARBON_EMISSIONS: Dataset = {
- id: "emissions/beis-la-carbon-emissions",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/beis-2005-to-2019-local-authority-carbon-dioxide-co2-emissions",
-};
-
-export const BEIS_ENERGY_TRENDS_EXTRACT: Dataset = {
- id: "drivers/beis-energy-trends-extract",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/beis-energy-trends-table-1-2-extract",
-};
-
-export const BEIS_ENERGY_INTENSITY_EXTRACT: Dataset = {
- id: "drivers/beis-energy-intensity-extract",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/beis-energy-intensity-extract",
-};
-
-export const ONS_ENERGY_USE_BY_FUEL_AND_INDUSTRY: Dataset = {
- id: "drivers/ons-energy-use-by-fuel-and-industry",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/ons-energy-use-fossil-fuels-by-fuel-type-and-industry",
-};
-
-export const ONS_EMISSIONS_BY_INDUSTRY_2020: Dataset = {
- id: "ons-emissions-by-industry-2020",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/ons-atmospheric-emissions-greenhouse-gases-by-industry-and-gas",
-};
-
-export const FORESTRY_RESEARCH_NEW_PLANTING: Dataset = {
- id: "adaptation/forestry_research_new_planting",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/forestry-research-forestry-statistics-2021-new-planting",
-};
-
-export const DEFRA_B3_STATE_OF_THE_WATER_ENVIRONMENT: Dataset = {
- id: "impacts/defra-b3-state-of-the-water-environment",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/defra-b3-state-of-the-water-environment",
-};
-
-export const DEFRA_POLLINATOR_SPECIES: Dataset = {
- id: "adaptation/defra-pollinator-species",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/defra-d7-species-supporting-ecosystem-functions",
-};
-
-export const FORESTRY_RESEARCH_FORESTRY_STATISTICS_2021_WOODLAND_AREA: Dataset =
- {
- id: "adaptation/forestry-research-forestry-statistics-2021-woodland-area",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/forestry-research-forestry-statistics-2021-woodland-area",
- };
-
-export const FOREST_RESEARCH_WOODLAND_AREA_LA: Dataset = {
- id: "adaptation/forest-research-woodland-area-la",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/forestry-research-woodland-area-local-authority",
-};
-
-export const DLUHC_ENERGY_EFFICIENCY_EXISTING_HOMES: Dataset = {
- id: "dluhc-energy-efficiency-existing-homes",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/mhclg-energy-efficiency-ratings-existing-homes",
-};
-
-export const DLUHC_ENERGY_EFFICIENCY_NEW_HOMES: Dataset = {
- id: "dluhc-energy-efficiency-new-homes",
- uri: "http://gss-data.org.uk/data/gss_data/climate-change/mhclg-energy-efficiency-ratings-new-homes",
-};
-
-export const MISC_ONS: Dataset = {
- id: "misc-ons",
- onPmd: false,
- datasetInfo: {
- title: "Unpublished",
- publisher: {
- uri: "https://www.gov.uk/government/organisations/office-for-national-statistics",
- label: "Office for National Statistics",
- },
- },
-};
-
-export const MISC_DEFRA: Dataset = {
- id: "misc-defra",
- onPmd: false,
- datasetInfo: {
- title: "Unpublished",
- publisher: {
- uri: "https://www.gov.uk/government/organisations/department-for-environment-food-rural-affairs",
- label: "Department of Agriculture, Environment & Rural Affairs",
- },
- },
-};
-
-export const MISC_BEIS: Dataset = {
- id: "misc-beis",
- onPmd: false,
- datasetInfo: {
- title: "Unpublished",
- publisher: {
- uri: "https://www.gov.uk/government/organisations/department-for-business-energy-and-industrial-strategy",
- label: "Department for Business, Energy & Industrial Strategy",
- },
- },
-};
-
-export const MISC_WELSH_WATER: Dataset = {
- id: "misc-welsh-water",
- onPmd: false,
- datasetInfo: {
- title: "Unpublished",
- publisher: {
- uri: "https://www.dwrcymru.com/",
- label: "Welsh Water",
- },
- },
-};
-
-export const MISC_NI_WATER: Dataset = {
- id: "misc-ni-water",
- onPmd: false,
- datasetInfo: {
- title: "Unpublished",
- publisher: {
- uri: "https://www.niwater.com/",
- label: "Northern Ireland Water",
- },
- },
-};
-
-export const MISC_SCOTTISH_WATER: Dataset = {
- id: "misc-scottish-water",
- onPmd: false,
- datasetInfo: {
- title: "Unpublished",
- publisher: {
- uri: "https://www.scottishwater.co.uk/",
- label: "Scottish Water",
- },
- },
-};
-
-export const datasets: Array = [
- ONS_TRADE_IN_GOODS,
- ONS_SA_TRADE_IN_GOODS,
- DEFRA_EFFICIENT_WATER,
- BEIS_GAS_EMISSIONS,
- MET_GROWING_SEASON,
- MET_UK_MEAN_TEMP,
- MET_UK_MEAN_TEMP_ANOMALY,
- ONS_ATMOSPHERIC_EMISSIONS_GREENHOUSE_GASSES_BY_INDUSTRY_AND_GAS,
- MET_UK_MEAN_RAIN1,
- DEFRA_CARBON_FOOTPRINT_SUMMARY_SOURCE_REGION,
- BEIS_LA_CARBON_EMISSIONS,
- BEIS_ENERGY_TRENDS_EXTRACT,
- BEIS_ENERGY_INTENSITY_EXTRACT,
- ONS_ENERGY_USE_BY_FUEL_AND_INDUSTRY,
- ONS_EMISSIONS_BY_INDUSTRY_2020,
- DEFRA_B3_STATE_OF_THE_WATER_ENVIRONMENT,
- FORESTRY_RESEARCH_NEW_PLANTING,
- BEIS_GAS_EMISSIONS_PROVISIONAL,
- DEFRA_CARBON_FOOTPRINT_SUMMARY,
- DEFRA_POLLINATOR_SPECIES,
- FORESTRY_RESEARCH_FORESTRY_STATISTICS_2021_WOODLAND_AREA,
- DLUHC_ENERGY_EFFICIENCY_EXISTING_HOMES,
- DLUHC_ENERGY_EFFICIENCY_NEW_HOMES,
- DEFRA_WATER_LEAKAGE,
- ONS_SA_TRADE_IN_GOODS,
- FOREST_RESEARCH_WOODLAND_AREA_LA,
- MISC_ONS,
- MISC_DEFRA,
- MISC_BEIS,
- MISC_WELSH_WATER,
- MISC_NI_WATER,
- MISC_SCOTTISH_WATER,
-];
-
-export async function fetchInfo(fetch: any, datasets: Array) {
- const infos = await Promise.all(
- datasets.map((ds) => {
- if (ds.onPmd == false) {
- return ds.datasetInfo;
- } else {
- return fetch(`/dataset/${ds.id}`);
- }
- }),
- );
- const dsInfo: any = new Map();
- for (let i = 0; i < datasets.length; i++) {
- if (infos[i] instanceof Response) {
- if (infos[i].ok) {
- dsInfo[datasets[i].id] = await infos[i].json();
- }
- } else {
- dsInfo[datasets[i].id] = await infos[i];
- }
- }
- return dsInfo;
-}
diff --git a/src/services/map-data/fetch-data.js b/src/services/map-data/fetch-data.js
deleted file mode 100644
index 2b1a5de..0000000
--- a/src/services/map-data/fetch-data.js
+++ /dev/null
@@ -1,163 +0,0 @@
-import { datasets } from "./datasets";
-
-const SPARQL_ENDPOINT = "https://staging.gss-data.org.uk/sparql";
-const PMD_BASEURL = "https://staging.gss-data.org.uk/";
-
-/**
- * @param {string} query
- */
-function sparql(query) {
- return fetch(SPARQL_ENDPOINT, {
- method: "POST",
- mode: "cors",
- headers: {
- "Content-Type": "application/sparql-query",
- Accept: "application/sparql-results+json",
- },
- body: query,
- }).then((response) => response.json());
-}
-
-function typedValue(v) {
- if (v.hasOwnProperty("datatype")) {
- if (v.datatype === "http://publishmydata.com/def/pmdgeo/geoJsonLiteral") {
- return JSON.parse(v.value);
- } else if (v.datatype.startsWith("http://www.w3.org/2001/XMLSchema#")) {
- const xsd = v.datatype.substring(
- "http://www.w3.org/2001/XMLSchema#".length,
- );
- if (xsd === "float" || xsd === "double") {
- return parseFloat(v.value);
- } else if (xsd === "integer") {
- return parseInt(v.value);
- } else if (xsd === "boolean") {
- return v.value === "true";
- } else if (
- xsd === "date" ||
- xsd === "dateTime" ||
- xsd === "dateTimeStamp"
- ) {
- return new Date(v.value);
- }
- }
- }
- return v.value;
-}
-
-function getValues(list) {
- return list.map((item) => {
- return Object.fromEntries(
- Object.entries(item).map(([key, value]) => [key, typedValue(value)]),
- );
- });
-}
-
-// convert a list of nested objects to a map of field-value arrays
-export function longify(list) {
- const map = {};
- for (let i = 0; i < list.length; ++i) {
- let entries = Object.entries(list[i]);
- entries.forEach(([key, value]) => {
- if (!map[key]) map[key] = [];
- map[key].push(value);
- });
- }
- return map;
-}
-
-export async function tidyResults(query) {
- let response = await sparql(query);
- let bindings = response.results.bindings;
- return longify(getValues(bindings));
-}
-
-export async function plotlyData(query, x, y, by, mode, type, additional) {
- let data = await tidyResults(query);
-
- let groups = [...new Set(data[by])];
- let result = [];
-
- for (let group of groups) {
- const x_vals = data[x].filter(
- (r, i) => data[by].map((g) => g === group)[i],
- );
- const y_vals = data[y].filter(
- (r, i) => data[by].map((g) => g === group)[i],
- );
- let series = {
- x: x_vals,
- y: y_vals,
- name: group,
- mode: mode,
- type: type,
- };
- if (additional.hasOwnProperty(group)) {
- series = { ...series, ...additional[group] };
- }
- result.push(series);
- }
- return result;
-}
-
-function pmdDatasetPage(record) {
- return PMD_BASEURL + "cube/about?uri=" + encodeURIComponent(record);
-}
-
-export async function datasetInfo(id) {
- const record_results = await sparql(`
-PREFIX pmdcat:
-SELECT ?record
-WHERE { ?record pmdcat:datasetContents <${id}#dataset> . }
-`);
- if (record_results.results.bindings.length === 1) {
- const record_uri = record_results.results.bindings[0].record.value;
- const response_json = await sparql(`
-PREFIX pmdcat:
-PREFIX rdfs:
-PREFIX skos:
-
-SELECT ?p ?o ?l ?a
-WHERE {
- <${record_uri}> ?p ?o .
- OPTIONAL { ?o rdfs:label ?l } .
- OPTIONAL { ?o skos:altLabel ?a }
-}`);
- const bindings = response_json.results.bindings;
- const info = Object.fromEntries(
- bindings.map((binding) => {
- const prop = binding.p.value;
- const key = prop.substring(
- Math.max(prop.lastIndexOf("/"), prop.lastIndexOf("#")) + 1,
- );
- let val = typedValue(binding.o);
- if (
- binding.hasOwnProperty("l") &&
- binding.l.hasOwnProperty("value") &&
- binding.l.value !== null
- ) {
- val = { uri: binding.o.value, label: binding.l.value };
- if (
- binding.hasOwnProperty("a") &&
- binding.a.hasOwnProperty("value") &&
- binding.a.value !== null
- ) {
- val["alt"] = binding.a.value;
- }
- }
- return [key, val];
- }),
- );
- return { ...info, record: record_uri, pmd: pmdDatasetPage(record_uri) };
- } else {
- return false;
- }
-}
-
-export async function datasetInfoFromPath(path) {
- const ds = datasets.find((ds) => ds.id === path);
- if (typeof ds === "undefined") {
- return false;
- } else {
- return await datasetInfo(ds.uri);
- }
-}
diff --git a/src/services/map-data/fetchData.js b/src/services/map-data/fetchData.js
new file mode 100644
index 0000000..012ae1a
--- /dev/null
+++ b/src/services/map-data/fetchData.js
@@ -0,0 +1,69 @@
+const SPARQL_ENDPOINT = "https://beta.gss-data.org.uk/sparql";
+
+/**
+ * @param {string} query
+ */
+function sparql(query) {
+ return fetch(SPARQL_ENDPOINT, {
+ method: "POST",
+ mode: "cors",
+ headers: {
+ "Content-Type": "application/sparql-query",
+ Accept: "application/sparql-results+json",
+ },
+ body: query,
+ }).then((response) => response.json());
+}
+
+function typedValue(v) {
+ if (v.hasOwnProperty("datatype")) {
+ if (v.datatype === "http://publishmydata.com/def/pmdgeo/geoJsonLiteral") {
+ return JSON.parse(v.value);
+ } else if (v.datatype.startsWith("http://www.w3.org/2001/XMLSchema#")) {
+ const xsd = v.datatype.substring(
+ "http://www.w3.org/2001/XMLSchema#".length,
+ );
+ if (xsd === "float" || xsd === "double") {
+ return parseFloat(v.value);
+ } else if (xsd === "integer") {
+ return parseInt(v.value);
+ } else if (xsd === "boolean") {
+ return v.value === "true";
+ } else if (
+ xsd === "date" ||
+ xsd === "dateTime" ||
+ xsd === "dateTimeStamp"
+ ) {
+ return new Date(v.value);
+ }
+ }
+ }
+ return v.value;
+}
+
+function getValues(list) {
+ return list.map((item) => {
+ return Object.fromEntries(
+ Object.entries(item).map(([key, value]) => [key, typedValue(value)]),
+ );
+ });
+}
+
+// convert a list of nested objects to a map of field-value arrays
+export function longify(list) {
+ const map = {};
+ for (let i = 0; i < list.length; ++i) {
+ let entries = Object.entries(list[i]);
+ entries.forEach(([key, value]) => {
+ if (!map[key]) map[key] = [];
+ map[key].push(value);
+ });
+ }
+ return map;
+}
+
+export async function tidyResults(query) {
+ let response = await sparql(query);
+ let bindings = response.results.bindings;
+ return longify(getValues(bindings));
+}
diff --git a/src/services/map-data/geoJsonLoader.ts b/src/services/map-data/geoJsonLoader.ts
new file mode 100644
index 0000000..20fd928
--- /dev/null
+++ b/src/services/map-data/geoJsonLoader.ts
@@ -0,0 +1,14 @@
+import { tidyResults } from "./fetchData";
+import rewind from "@turf/rewind";
+
+export const getGeoJson: any = async (query: string) => {
+ const data: any = await tidyResults(query);
+ data.boundary.forEach((b: any) => {
+ b.geometry = rewind(b.geometry, { reverse: true });
+ });
+
+ return {
+ type: "FeatureCollection",
+ features: data.boundary,
+ };
+};
diff --git a/src/services/map-data/geoJsonQueries.js b/src/services/map-data/geoJsonQueries.js
new file mode 100644
index 0000000..cb607c1
--- /dev/null
+++ b/src/services/map-data/geoJsonQueries.js
@@ -0,0 +1,27 @@
+const LOCAL_AUTHORITY_BOUNDARY_QUERY = `
+PREFIX statent:
+PREFIX statgeo:
+PREFIX geosparql:
+PREFIX pmdgeo:
+
+SELECT ?boundary
+WHERE {
+ GRAPH {
+ ?la_uri statent:code ?area_type .
+ }
+ GRAPH {
+ ?la_uri geosparql:hasGeometry [
+ pmdgeo:simplificationPercent 25 ;
+ pmdgeo:asGeoJSON ?boundary ] .
+ }
+ VALUES ?area_type {
+
+
+
+
+
+
+ }
+
+}`;
+export default LOCAL_AUTHORITY_BOUNDARY_QUERY;
diff --git a/src/services/map-data/map-data-loader.ts b/src/services/map-data/map-data-loader.ts
deleted file mode 100644
index 4402b1a..0000000
--- a/src/services/map-data/map-data-loader.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { tidyResults } from "./fetch-data";
-import { FOREST_RESEARCH_WOODLAND_AREA_QUERY } from "./sparql-queries";
-
-export const getMapData: any = async () => {
- const data: any = await tidyResults(FOREST_RESEARCH_WOODLAND_AREA_QUERY);
- return data;
-};
diff --git a/src/services/map-data/mapDataLoader.ts b/src/services/map-data/mapDataLoader.ts
new file mode 100644
index 0000000..23f54cc
--- /dev/null
+++ b/src/services/map-data/mapDataLoader.ts
@@ -0,0 +1,6 @@
+import { tidyResults } from "./fetchData";
+
+export const getMapData: any = async (query: string) => {
+ const data: any = await tidyResults(query);
+ return data;
+};
diff --git a/src/services/map-data/sparql-queries.js b/src/services/map-data/sparql-queries.js
deleted file mode 100644
index 41cb23b..0000000
--- a/src/services/map-data/sparql-queries.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import {
- FOREST_RESEARCH_WOODLAND_AREA_LA,
- FORESTRY_RESEARCH_NEW_PLANTING,
-} from "./datasets";
-
-const LOCAL_AUTHORITY_BOUNDARY_QUERY = `
-PREFIX statent:
-PREFIX statgeo:
-PREFIX geosparql:
-PREFIX pmdgeo:
-
-SELECT ?boundary
-WHERE {
- GRAPH {
- ?la_uri statent:code ?area_type .
- }
- GRAPH {
- ?la_uri geosparql:hasGeometry [
- pmdgeo:simplificationPercent 25 ;
- pmdgeo:asGeoJSON ?boundary ] .
- }
- VALUES ?area_type {
-
-
-
-
-
-
- }
-
-}`;
-
-const FOREST_RESEARCH_WOODLAND_AREA_QUERY = `
-PREFIX qb:
-PREFIX xsd:
-PREFIX geo:
-PREFIX data: <${FOREST_RESEARCH_WOODLAND_AREA_LA.uri}#>
-PREFIX dim: <${FOREST_RESEARCH_WOODLAND_AREA_LA.uri}#dimension/>
-PREFIX meas:
-
-SELECT ?la_uri ?label (SUM(xsd:float(?val)) as ?emissions)
-WHERE {
- ?obs qb:dataSet data:dataset ;
- dim:year ;
- dim:local-authority-area ?wrong_la_uri ;
- meas:woodland ?val ;
- ;
- .
-
- BIND (
- IRI(
- REPLACE(
- STR(?wrong_la_uri),
- "^.*/",
- "http://statistics.data.gov.uk/id/statistical-geography/"
- )
- ) AS ?la_uri )
- FILTER(?la_uri != )
-
- OPTIONAL { ?la_uri geo:officialname ?label }
-}
-GROUP BY ?la_uri ?label`;
-
-const FORESTRY_RESEARCH_NEW_PLANTING_QUERY = `
-PREFIX qb:
-PREFIX rdfs:
-PREFIX scovo:
-PREFIX sdmxa:
-PREFIX meas:
-PREFIX data: <${FORESTRY_RESEARCH_NEW_PLANTING.uri}#>
-PREFIX dim: <${FORESTRY_RESEARCH_NEW_PLANTING.uri}#dimension/>
-PREFIX def:
-
-SELECT * {
- {
- SELECT ?year ?type ?value
- WHERE {
- ?obs qb:dataSet data:dataset ;
- dim:year [ rdfs:label ?year ] ;
- qb:measureType [ rdfs:label ?type ] ;
- meas:new-broadleaves ?value;
- }
- }
- UNION
- {
- SELECT ?year ?type ?value
- WHERE {
- ?obs qb:dataSet data:dataset ;
- dim:year [ rdfs:label ?year ] ;
- qb:measureType [ rdfs:label ?type ] ;
- meas:new-conifers ?value;
- }
- }
-}
-ORDER BY ?year ?type
- `;
-
-export {
- LOCAL_AUTHORITY_BOUNDARY_QUERY,
- FOREST_RESEARCH_WOODLAND_AREA_QUERY,
- FORESTRY_RESEARCH_NEW_PLANTING_QUERY,
-};
diff --git a/src/services/map-data/uk-la-boundaries.ts b/src/services/map-data/uk-la-boundaries.ts
deleted file mode 100644
index b2ed59b..0000000
--- a/src/services/map-data/uk-la-boundaries.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { tidyResults } from "./fetch-data";
-import rewind from "@turf/rewind";
-import { LOCAL_AUTHORITY_BOUNDARY_QUERY } from "./sparql-queries";
-
-export const getUkLaBoundaries: any = async () => {
- const data: any = await tidyResults(LOCAL_AUTHORITY_BOUNDARY_QUERY);
- data.boundary.forEach((b: any) => {
- b.geometry = rewind(b.geometry, { reverse: true });
- });
-
- return {
- type: "FeatureCollection",
- features: data.boundary,
- };
-};