RSS logo RSS logo
  • Home
  • About the Project
  • Taxonomy
  • Methodology

Poverty Data Gaps

This data explorer has been produced as part of the Royal Statistical Society and Centre for Public Data’s research into poverty data gaps in the UK, funded by the Joseph Rowntree Foundation Insight Infrastructure team.

We intend for the explorer to be a living tool that will help those at the forefront of anti-poverty research and intervention share data gaps they encounter in the course of their work. To that end, we ask interested individuals and organisations to fill out our form below, where they can tell us about specific issues they’ve had with the datasets they use for poverty research.

Each row in the explorer represents one data gap. Information about each gap is given in the columns:

  • Name: a headline statement of what the data gap is.
  • Type of Data Gap: one or more categories assigned to the data gap following a gaps taxonomy. See the Taxonomy page for more information about the categories.
  • Data Sources: the data source(s) to which the gap pertains. Where the gap pertains to a lack of data or non-existent data, this is marked as “non-existent”.
  • Topics: one or more topic areas relevant to poverty to which the gap relates.
  • Link: further detail about the gap, including a link to the relevant source (where applicable).

You can find more information about the gaps, including links to the source where the gap was identified, a quote from that source, and the research questions it was trying to answer (where applicable), by clicking on the “Details” button for each gap. The “Reports” tab organises the gaps by the sources that were used when collating them.

We encourage anyone who makes use of data relating to poverty in the UK to submit information about gaps they have encountered. Please do so by completing this form:

Add a new data gap

viewof sources = {
  const options = sources_opts.map(d => d[Object.keys(d)[0]]);
  const container = document.createElement("div");
  container.classList.add("filter-name");
  
  const label = document.createElement("label");
  label.textContent = "Data sources:";
  label.style.cssText = "display: block; margin-bottom: 4px; font-weight: 500;";
  
  const selectedContainer = document.createElement("div");
  selectedContainer.style.cssText = "display: flex; flex-wrap: wrap; gap: 6px; min-height: 38px; padding: 6px; border: 1px solid #ccc; border-radius: 4px; margin-bottom: 8px; background: white; align-items: center;";
  
  const buttonWrapper = document.createElement("div");
  buttonWrapper.style.cssText = "position: relative; width: 100%;";
  
  const dropdownButton = document.createElement("button");
  dropdownButton.textContent = "Select sources...";
  dropdownButton.style.cssText = "width: 100%; padding: 8px 12px; text-align: left; background: white; border: 1px solid #ccc; border-radius: 4px; cursor: pointer; color: #333; display: block;";
  
  const dropdownMenu = document.createElement("div");
  dropdownMenu.style.cssText = "display: none; position: fixed; max-height: 200px; overflow-y: auto; background: white; border: 1px solid #ccc; border-radius: 4px; z-index: 1000; box-shadow: 0 2px 8px rgba(0,0,0,0.1); box-sizing: border-box;";
  
  let selected = [];
  
  const updateView = () => {
    selectedContainer.innerHTML = "";
    selected.forEach(item => {
      const tag = document.createElement("span");
      tag.style.cssText = "display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; background: #e3f2fd; border-radius: 3px; font-size: 13px; color: #333;";
      tag.innerHTML = `${item} <span style="cursor: pointer; font-weight: bold;">×</span>`;
      tag.querySelector("span").onclick = () => {
        selected = selected.filter(s => s !== item);
        updateView();
        container.value = selected;
        container.dispatchEvent(new CustomEvent("input"));
      };
      selectedContainer.appendChild(tag);
    });
    
    if (selected.length === 0) {
      const placeholder = document.createElement("span");
      placeholder.textContent = "No sources selected (showing all data)";
      placeholder.style.cssText = "color: #999; font-style: italic;";
      selectedContainer.appendChild(placeholder);
    }
  };
  
  options.forEach(option => {
    const item = document.createElement("div");
    item.textContent = option;
    item.style.cssText = "padding: 8px 12px; cursor: pointer; user-select: none; color: #333;";
    item.onmouseenter = () => item.style.background = "#f0f0f0";
    item.onmouseleave = () => item.style.background = selected.includes(option) ? "#e3f2fd" : "white";
    item.onclick = () => {
      if (selected.includes(option)) {
        selected = selected.filter(s => s !== option);
      } else {
        selected.push(option);
      }
      updateView();
      container.value = selected;
      container.dispatchEvent(new CustomEvent("input"));
    };
    dropdownMenu.appendChild(item);
  });
  
  dropdownButton.onclick = () => {
    const isVisible = dropdownMenu.style.display === "block";
    if (isVisible) {
      dropdownMenu.style.display = "none";
    } else {
      const rect = dropdownButton.getBoundingClientRect();
      dropdownMenu.style.top = `${rect.bottom + 2}px`;
      dropdownMenu.style.left = `${rect.left}px`;
      dropdownMenu.style.width = `${rect.width}px`;
      dropdownMenu.style.display = "block";
    }
  };
  
  document.addEventListener("click", (e) => {
    if (!container.contains(e.target) && !dropdownMenu.contains(e.target)) {
      dropdownMenu.style.display = "none";
    }
  });
  
  container.appendChild(label);
  container.appendChild(selectedContainer);
  buttonWrapper.appendChild(dropdownButton);
  container.appendChild(buttonWrapper);
  document.body.appendChild(dropdownMenu);
  
  updateView();
  container.value = selected;
  return container;
}
viewof types = {
  const options = types_opts.map(d => d[Object.keys(d)[0]]);
  const container = document.createElement("div");
  container.classList.add("filter-name");
  
  const label = document.createElement("label");
  label.textContent = "Type of data gap:";
  label.style.cssText = "display: block; margin-bottom: 4px; font-weight: 500;";
  
  const selectedContainer = document.createElement("div");
  selectedContainer.style.cssText = "display: flex; flex-wrap: wrap; gap: 6px; min-height: 38px; padding: 6px; border: 1px solid #ccc; border-radius: 4px; margin-bottom: 8px; background: white; align-items: center;";
  
  const buttonWrapper = document.createElement("div");
  buttonWrapper.style.cssText = "position: relative; width: 100%;";
  
  const dropdownButton = document.createElement("button");
  dropdownButton.textContent = "Select types of gap...";
  dropdownButton.style.cssText = "width: 100%; padding: 8px 12px; text-align: left; background: white; border: 1px solid #ccc; border-radius: 4px; cursor: pointer; color: #333; display: block;";
  
  const dropdownMenu = document.createElement("div");
  dropdownMenu.style.cssText = "display: none; position: fixed; max-height: 200px; overflow-y: auto; background: white; border: 1px solid #ccc; border-radius: 4px; z-index: 1000; box-shadow: 0 2px 8px rgba(0,0,0,0.1); box-sizing: border-box;";
  
  let selected = [];
  
  const updateView = () => {
    selectedContainer.innerHTML = "";
    selected.forEach(item => {
      const tag = document.createElement("span");
      tag.style.cssText = "display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; background: #e3f2fd; border-radius: 3px; font-size: 13px; color: #333;";
      tag.innerHTML = `${item} <span style="cursor: pointer; font-weight: bold;">×</span>`;
      tag.querySelector("span").onclick = () => {
        selected = selected.filter(s => s !== item);
        updateView();
        container.value = selected;
        container.dispatchEvent(new CustomEvent("input"));
      };
      selectedContainer.appendChild(tag);
    });
    
    if (selected.length === 0) {
      const placeholder = document.createElement("span");
      placeholder.textContent = "No gap types selected (showing all data)";
      placeholder.style.cssText = "color: #999; font-style: italic;";
      selectedContainer.appendChild(placeholder);
    }
  };
  
  options.forEach(option => {
    const item = document.createElement("div");
    item.textContent = option;
    item.style.cssText = "padding: 8px 12px; cursor: pointer; user-select: none; color: #333;";
    item.onmouseenter = () => item.style.background = "#f0f0f0";
    item.onmouseleave = () => item.style.background = selected.includes(option) ? "#e3f2fd" : "white";
    item.onclick = () => {
      if (selected.includes(option)) {
        selected = selected.filter(s => s !== option);
      } else {
        selected.push(option);
      }
      updateView();
      container.value = selected;
      container.dispatchEvent(new CustomEvent("input"));
    };
    dropdownMenu.appendChild(item);
  });
  
  dropdownButton.onclick = () => {
    const isVisible = dropdownMenu.style.display === "block";
    if (isVisible) {
      dropdownMenu.style.display = "none";
    } else {
      const rect = dropdownButton.getBoundingClientRect();
      dropdownMenu.style.top = `${rect.bottom + 2}px`;
      dropdownMenu.style.left = `${rect.left}px`;
      dropdownMenu.style.width = `${rect.width}px`;
      dropdownMenu.style.display = "block";
    }
  };
  
  document.addEventListener("click", (e) => {
    if (!container.contains(e.target) && !dropdownMenu.contains(e.target)) {
      dropdownMenu.style.display = "none";
    }
  });
  
  container.appendChild(label);
  container.appendChild(selectedContainer);
  buttonWrapper.appendChild(dropdownButton);
  container.appendChild(buttonWrapper);
  document.body.appendChild(dropdownMenu);
  
  updateView();
  container.value = selected;
  return container;
}
viewof topics = {
  const options = topics_opts.map(d => d[Object.keys(d)[0]]);
  const container = document.createElement("div");
  container.classList.add("filter-name");
  
  const label = document.createElement("label");
  label.textContent = "Topics:";
  label.style.cssText = "display: block; margin-bottom: 4px; font-weight: 500;";
  
  const selectedContainer = document.createElement("div");
  selectedContainer.style.cssText = "display: flex; flex-wrap: wrap; gap: 6px; min-height: 38px; padding: 6px; border: 1px solid #ccc; border-radius: 4px; margin-bottom: 8px; background: white; align-items: center;";
  
  const buttonWrapper = document.createElement("div");
  buttonWrapper.style.cssText = "position: relative; width: 100%;";
  
  const dropdownButton = document.createElement("button");
  dropdownButton.textContent = "Select topics...";
  dropdownButton.style.cssText = "width: 100%; padding: 8px 12px; text-align: left; background: white; border: 1px solid #ccc; border-radius: 4px; cursor: pointer; color: #333; display: block;";
  
  const dropdownMenu = document.createElement("div");
  dropdownMenu.style.cssText = "display: none; position: fixed; max-height: 200px; overflow-y: auto; background: white; border: 1px solid #ccc; border-radius: 4px; z-index: 1000; box-shadow: 0 2px 8px rgba(0,0,0,0.1); box-sizing: border-box;";
  
  let selected = [];
  
  const updateView = () => {
    selectedContainer.innerHTML = "";
    selected.forEach(item => {
      const tag = document.createElement("span");
      tag.style.cssText = "display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; background: #e3f2fd; border-radius: 3px; font-size: 13px; color: #333;";
      tag.innerHTML = `${item} <span style="cursor: pointer; font-weight: bold;">×</span>`;
      tag.querySelector("span").onclick = () => {
        selected = selected.filter(s => s !== item);
        updateView();
        container.value = selected;
        container.dispatchEvent(new CustomEvent("input"));
      };
      selectedContainer.appendChild(tag);
    });
    
    if (selected.length === 0) {
      const placeholder = document.createElement("span");
      placeholder.textContent = "No topics selected (showing all data)";
      placeholder.style.cssText = "color: #999; font-style: italic;";
      selectedContainer.appendChild(placeholder);
    }
  };
  
  options.forEach(option => {
    const item = document.createElement("div");
    item.textContent = option;
    item.style.cssText = "padding: 8px 12px; cursor: pointer; user-select: none; color: #333;";
    item.onmouseenter = () => item.style.background = "#f0f0f0";
    item.onmouseleave = () => item.style.background = selected.includes(option) ? "#e3f2fd" : "white";
    item.onclick = () => {
      if (selected.includes(option)) {
        selected = selected.filter(s => s !== option);
      } else {
        selected.push(option);
      }
      updateView();
      container.value = selected;
      container.dispatchEvent(new CustomEvent("input"));
    };
    dropdownMenu.appendChild(item);
  });
  
  dropdownButton.onclick = () => {
    const isVisible = dropdownMenu.style.display === "block";
    if (isVisible) {
      dropdownMenu.style.display = "none";
    } else {
      const rect = dropdownButton.getBoundingClientRect();
      dropdownMenu.style.top = `${rect.bottom + 2}px`;
      dropdownMenu.style.left = `${rect.left}px`;
      dropdownMenu.style.width = `${rect.width}px`;
      dropdownMenu.style.display = "block";
    }
  };
  
  document.addEventListener("click", (e) => {
    if (!container.contains(e.target) && !dropdownMenu.contains(e.target)) {
      dropdownMenu.style.display = "none";
    }
  });
  
  container.appendChild(label);
  container.appendChild(selectedContainer);
  buttonWrapper.appendChild(dropdownButton);
  container.appendChild(buttonWrapper);
  document.body.appendChild(dropdownMenu);
  
  updateView();
  container.value = selected;
  return container;
}
  • Data gaps
  • Reports
modal = html`<div id="modal-overlay">
  <div id="modal-content">
    <button id="modal-close">X</button>
    <div id="modal-body"></div>
  </div>
</div>`

// Helper functions for modal
function showModal(rowData) {
  const overlay = document.getElementById('modal-overlay');
  const modalBody = document.getElementById('modal-body');
  
  modalBody.innerHTML = `
    <h2>${rowData.Name}</h2>
    
    <div style="margin-bottom: 1rem;">
      <strong>Headline finding:</strong> ${rowData.Headline || 'No description available'}
    </div>
    
    <div style="margin-bottom: 1rem;">
      <strong>Research Questions:</strong> ${rowData.Questions || 'No description available'}
    </div>
    
    <div style="margin-bottom: 1rem;">
      <strong>Impact:</strong> ${rowData.Impact || 'No description available'}
    </div>
    
    <div style="margin-bottom: 1rem;">
      <strong>Sources:</strong> ${rowData.Sources || 'No description available'}
    </div>
    
    <div style="margin-bottom: 1rem;">
      <strong>Topics:</strong> ${rowData.Topics_Text || 'No description available'}
    </div>
    
    <div style="margin-bottom: 1rem;">
      <strong>Types of Gap:</strong> ${rowData.Type || 'No description available'}
    </div>
    
    <div style="background: #f5f5f5; padding: 1rem; border-radius: 4px;">
      <strong>${rowData.Report}</strong>
      <p>${rowData.Author || 'No author available'} (${rowData.Date}) </p>
      <a href=${rowData.URL} target=_blank>View Report</a>
    </div>
    
  `;
  
  overlay.style.display = 'flex';
}

function hideModal() {
  const overlay = document.getElementById('modal-overlay');
  if (overlay) overlay.style.display = 'none';
}

// Set up close handlers after modal is rendered
{
  setTimeout(() => {
    const closeBtn = document.getElementById('modal-close');
    const overlay = document.getElementById('modal-overlay');
    
    if (closeBtn) {
      closeBtn.addEventListener('click', hideModal);
    }
    
    if (overlay) {
      overlay.addEventListener('click', (e) => {
        if (e.target.id === 'modal-overlay') hideModal();
      });
    }
  }, 100);
}
viewof gaps_table = Inputs.table(filtered_gaps, {
  columns: ["Name", "Type", "Sources", "Topics", "Link"], 
  header: {
    Type: "Type of Data Gap",
  },
  sort: false,
  format: {
    Link: (testValue, row_index) => {
      const div = document.createElement('div');
      div.innerHTML = testValue;
      
      const button = div.querySelector('button');
      if (button) {
        button.addEventListener('click', () => {
          const rowData = filtered_gaps[row_index];
          showModal(rowData);
        });
      }
      
      return div;
    }
  },
  rows: 20
})
modal2 = html`<div id="modal-overlay2">
  <div id="modal-content2">
    <button id="modal-close2">X</button>
    <div id="modal-body2"></div>
  </div>
</div>`

// Helper functions for modal
function showReportsModal(rowData) {
  const overlay2 = document.getElementById('modal-overlay2');
  const modalBody2 = document.getElementById('modal-body2');
  
  modalBody2.innerHTML = `
    <h2>${rowData.Title}</h2>
    
    <div style="margin-bottom: 1rem;">
      ${rowData.Author} (${rowData.Date})
    </div>

    <div style="background: #f5f5f5; padding: 1rem; border-radius: 4px;">
      ${rowData.GapText}
    </div>

    
  `;
  
  overlay2.style.display = 'flex';
}

function hideReportsModal() {
  const overlay2 = document.getElementById('modal-overlay2');
  if (overlay2) overlay2.style.display = 'none';
}

// Set up close handlers after modal is rendered
{
  setTimeout(() => {
    const closeBtn2 = document.getElementById('modal-close2');
    const overlay2 = document.getElementById('modal-overlay2');
    
    if (closeBtn2) {
      closeBtn2.addEventListener('click', hideReportsModal);
    }
    
    if (overlay2) {
      overlay2.addEventListener('click', (e) => {
        if (e.target.id === 'modal-overlay2') hideReportsModal();
      });
    }
  }, 100);
}
viewof reports_table = Inputs.table(filtered_reports, {
  columns: ["Title", "Author", "Date", "URL", "Link"], 
  sort: false,
  format: {
    Link: (testValue, row_index) => {
      const div = document.createElement('div');
      div.innerHTML = testValue;
      
      const button = div.querySelector('button');
      if (button) {
        button.addEventListener('click', () => {
          const rowData = filtered_reports[row_index];
          showReportsModal(rowData);
        });
      }
      
      return div;
    },
    URL: Test => {
      const div = document.createElement('div');
      div.innerHTML = Test;
      return div;
    }
  },
  rows: 20
})
data_gaps = FileAttachment("data/data_gaps_table.csv").csv({ typed: true })
data_reports = FileAttachment("data/reports_table.csv")
  .csv({ typed: true })
  .then(data => data.map(d => ({ ...d, Date: String(d.Date) })))
sources_opts = FileAttachment("data/sources_opts.csv").csv({ typed: true })
types_opts = FileAttachment("data/types_opts.csv").csv({ typed: true })
topics_opts = FileAttachment("data/topics_opts.csv").csv({ typed: true })
filtered_gaps = data_gaps.filter(function(x) {
  if (sources.length > 0 && !sources.some(s => x.Sources.includes(s))) return false;
  if (types.length > 0 && !types.some(t => x.Type.includes(t))) return false;
  if (topics.length > 0 && !topics.some(topic => x.Topics.includes(topic))) return false;
  return true;
})
filtered_reports = data_reports.filter(function(x) {
  if (sources.length > 0 && !sources.some(s => x.Sources.includes(s))) return false;
  if (types.length > 0 && !types.some(t => x.Type.includes(t))) return false;
  if (topics.length > 0 && !topics.some(topic => x.Topics.includes(topic))) return false;
  return true;
})

 
  • © Copyright 2026 The Royal Statistical Society. Registered charity in England and Wales. No.306096.