API Documentation
Guides
Use Measure Data from a Specific Report (Grouped by Population)

Using Measure Data from a Specific Report (Grouped by Population)

This guide explains the process of searching for reports and their measures, fetching desired data and rendering the chart in a React component.

Searching for Reports

First, we need find the Report we'd like to use. Let's use the GetReports GraphQL query to list all Reports grouped by Report Type.

query GetReports {
  reportTypes_A {
    reportTypeId
    name
    reports(order: { releaseDate: DESC }) {
      reportId
      name
      releaseDate
    }
  }
}

Using the Playground, we can run the query and get the response:

{
  "data": {
    "reportTypes_A": [
      {
        "reportTypeId": 1,
        "name": "Annual",
        "reports": [
          {
            "reportId": 276,
            "name": "2023 Annual",
            "releaseDate": 2023
          }
        ]
      },
      {
        "reportTypeId": 2,
        "name": "Senior",
        "reports": [
          {
            "reportId": 277,
            "name": "2024 Senior",
            "releaseDate": 2024
          }
        ]
      },
      {
        "reportTypeId": 3,
        "name": "HWC",
        "reports": [
          {
            "reportId": 275,
            "name": "2023 HWC",
            "releaseDate": 2023
          }
        ]
      }
    ]
  }
}

The data.reportTypes_A and data.reportTypes_A.reports array has been truncated for brevity. The actual response contains more data points.

Getting Report Measures

Once we've identified the Report of interest, we retrieve all Report Measure data for that Report using the GetReportMeasures GraphQL query.

Measure data is nested within reportMeasures with a new field called endDate. This is the date that measure data will be filtered by to only use data from the specified Report.

query GetReportMeasures {
  report_A(editionId: 276) {
    reportId
    name
    releaseDate
    reportMeasures {
      endDate
      measure {
        measureId
        name
        description
        unitType
        format
      }
    }
  }
}

Using the Playground, we can run the query and get the response:

{
  "data": {
    "report_A": {
      "reportId": 276,
      "name": "2023 Annual",
      "releaseDate": 2023,
      "reportMeasures": [
        {
          "endDate": "2022-01-01T00:00:00.000Z",
          "measure": {
            "measureId": "147",
            "name": "Air Pollution",
            "description": "Average exposure of the general public to particulate matter of 2.5 microns or less, measured in micrograms per cubic meter",
            "unitType": "Micrograms of fine particles per cubic meter",
            "format": "Numeric"
          }
        },
        {
          "endDate": "2022-01-01T00:00:00.000Z",
          "measure": {
            "measureId": "171",
            "name": "Smoking",
            "description": "Percentage of adults who reported smoking at least 100 cigarettes in their lifetime and currently smoke daily or some days",
            "unitType": "Percentage of adults",
            "format": "Percent"
          }
        },
        {
          "endDate": "2022-01-01T00:00:00.000Z",
          "measure": {
            "measureId": "173",
            "name": "Obesity",
            "description": "Percentage of adults who have a body mass index of 30.0 or higher based on reported height and weight ",
            "unitType": "Percentage of adults",
            "format": "Percent"
          }
        }
      ]
    }
  }
}

The data.report_A.reportMeasures array has been truncated for brevity. The actual response contains more data points.

Getting Measure Population Data

Once we have identified the measure of interest, we retrieve the detailed data for that measure using the GetMeasurePopulationData GraphQL query.

Instead of fetching all data points, we're getting grouped data points for each population at the national level (state = "ALL").

Note that the datum endDate is included to compare against the Report Measure endDate from the previous step.

query GetMeasurePopulationData {
  measure_A(metricId: 171) {
    measureId
    name
    description
    unitType
    format
    source {
      name
    }
    subpopulations {
      name
      population {
        name
        populationCategory {
          name
        }
      }
      data(where: { state: { in: ["ALL"] } }) {
        endDate
        dateLabel
        value
      }
    }
  }
}

Using the Playground, we can run the query and get the response:

{
  "data": {
    "measure_A": {
      "measureId": "171",
      "name": "Smoking",
      "description": "Percentage of adults who reported smoking at least 100 cigarettes in their lifetime and currently smoke daily or some days",
      "unitType": "Percentage of adults",
      "format": "Percent",
      "source": {
        "name": "CDC, Behavioral Risk Factor Surveillance System"
      },
      "subpopulations": [
        {
          "name": "Smoking - College Grad",
          "population": {
            "name": "College Grad",
            "populationCategory": {
              "name": "Education"
            }
          },
          "data": [
            {
              "endDate": "2012-01-01T00:00:00.000Z",
              "dateLabel": "2012",
              "value": 7.8
            },
            {
              "endDate": "2013-01-01T00:00:00.000Z",
              "dateLabel": "2013",
              "value": 7.6
            }
          ]
        }
      ]
    }
  }
}

The data.measure_A.data array has been truncated for brevity. The actual response contains more data points.

Setting up GraphQL Data Fetching

We create a utility function to fetch data from the GraphQL API. This function sends a GraphQL query to the API and returns the response.

util/graphql.ts
export type GraphQLResponse<T> = {
  data?: T;
  errors?: { message: string }[];
};
 
export const fetchGraphqlClient = async <T>({
  method = "POST",
  body,
}: RequestInit): Promise<GraphQLResponse<T>> => {
  const headers: HeadersInit = {
    "Content-Type": "application/json",
    "X-Api-Key": process.env.AHR_API_KEY
  };
 
  const response = await fetch("https://api.americashealthrankings.org/graphql", {
    method,
    headers,
    body,
  }).then((data) => data.json());
 
  return response as GraphQLResponse<T>;
};

Fetching Chart Data

We then create a utility function fetchChartData to fetch the measure data using a GraphQL client. This function sends a GraphQL query to get the filtered measure data and returns the response.

fetch.ts
import { fetchGraphqlClient } from "util/graphql";
 
export const fetchChartData = async () => {
  return await fetchGraphqlClient<any>({
    body: JSON.stringify({
      query: `query GetMeasurePopulationData {
  measure_A(metricId: 171) {
    measureId
    name
    description
    unitType
    format
    source {
      name
    }
    subpopulations {
      name
      population {
        name
        populationCategory {
          name
        }
      }
      data(where: { state: { in: ["ALL"]}}) {
        endDate
        dateLabel
        value
      }
    }
  }
}`,
    }),
  });
};

Rendering the Chart

Finally, we use the fetched data to render a list of all available Population Categories and a pie chart in our React component. The DynamicPieChart component uses the useState and useEffect hooks to manage and fetch the data. We use the recharts library to create a pie chart, displaying the Population data based on the selected Population Category.

npm install recharts
DynamicPieChart.tsx
import React, { useEffect, useState } from "react";
import { PieChart, Pie, ResponsiveContainer, Cell, Text } from "recharts";
import { fetchChartData } from "./fetch";
 
type ChartData = {
  name: string;
  description: string;
  source: string;
  year: string;
  unitType: string;
  format: string;
  data: {
    [key: string]: {
      population: string;
      percent: number;
    }[];
  };
};
 
const RADIAN = Math.PI / 180;
const colors = ["#1490ff", "#43A6FF", "#72BCFF", "#A1D3FF"];
const reportMeasureEndDate = "2022-01-01T00:00:00.000Z";
 
const DynamicPieChart = () => {
  const [populationCategory, setPopulationCategory] =
    useState<string>("Education");
  const [chartData, setChartData] = useState<ChartData | null>(null);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
 
  useEffect(() => {
    const getChartData = async () => {
      try {
        const measure = await fetchChartData().then(
          (res) => res.data?.measure_A,
        );
        const data = {};
        let dateLabel = "";
 
        measure.subpopulations.forEach((subpopulation) => {
          const populationCategory =
            subpopulation?.population?.populationCategory?.name;
 
          if (!data[populationCategory]) {
            data[populationCategory] = [];
          }
 
          const reportMeasureData = subpopulation?.data.find((datum) => {
            return datum.endDate === reportMeasureEndDate;
          });
 
          if (!!reportMeasureData) {
            data[populationCategory].push({
              population: subpopulation?.population?.name,
              percent: reportMeasureData?.value,
            });
 
            if (!dateLabel) {
              dateLabel = reportMeasureData?.dateLabel;
            }
          }
        });
 
        const formattedData = {
          name: measure?.name,
          description: measure?.description,
          source: measure?.source.name,
          year: dateLabel,
          unitType: measure?.unitType,
          format: measure?.format,
          data,
        };
        setChartData(formattedData);
      } catch (error) {
        console.error(error);
        setError("An error occurred while fetching the chart data.");
      } finally {
        setLoading(false);
      }
    };
 
    getChartData();
  }, []);
 
  const renderPopulationCategories = () => {
    return Object.keys(chartData?.data || {}).map((pg, i) => {
      return (
        <p
          key={`population-category-${i}`}
          onClick={() => {
            setPopulationCategory(pg);
          }}
          className={`${pg === populationCategory ? "nx-border-primary-500" : "nx-cursor-pointer"} nx-border nx-rounded-lg nx-p-2`}
          style={{
            borderWidth: pg === populationCategory ? "2px" : "1px",
          }}
        >
          {pg}
        </p>
      );
    });
  };
 
  if (loading) {
    return <div>Loading...</div>;
  }
 
  if (error) {
    return <div>Error: {error}</div>;
  }
 
  return (
    <figure>
      <figcaption className="nx-mt-2 nx-mb-2">
        <hgroup>
          <h3 className="nx-text-2xl nx-font-bold">{chartData?.name}</h3>
          <h4 className="nx-text-md">{chartData?.description}</h4>
        </hgroup>
        <cite>
          America’s Health Rankings analysis of {chartData?.source}, United
          Health Foundation, AmericasHealthRankings.org, accessed{" "}
          {chartData?.year}.
        </cite>
      </figcaption>
      <div
        className="nx-w-full nx-py-4"
        style={{ display: "grid", gridTemplateColumns: "1fr 4fr", gap: "8px" }}
      >
        <div className="nx-col-span-1 nx-flex nx-flex-col nx-gap-1">
          {renderPopulationCategories()}
        </div>
        <div className="nx-col-span-4">
          <ResponsiveContainer>
            <PieChart>
              <Pie
                label={renderCustomizedLabel}
                labelLine={false}
                nameKey={"population"}
                dataKey="percent"
                data={chartData?.data[populationCategory]}
                fill="#000000"
              >
                {chartData?.data[populationCategory].map((_, index) => (
                  <Cell
                    key={`cell-${index}`}
                    fill={colors[index % colors.length]}
                  />
                ))}
              </Pie>
            </PieChart>
          </ResponsiveContainer>
        </div>
      </div>
    </figure>
  );
};
 
const renderCustomizedLabel = ({
  cx,
  cy,
  midAngle,
  innerRadius,
  outerRadius,
  percent,
  name,
}) => {
  const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
  const x = cx + radius * Math.cos(-midAngle * RADIAN);
  const y = cy + radius * Math.sin(-midAngle * RADIAN);
  const textX = cx + (outerRadius + 20) * Math.cos(-midAngle * RADIAN);
  const textY = cy + (outerRadius + 20) * Math.sin(-midAngle * RADIAN);
 
  return (
    <>
      <Text
        x={textX}
        y={textY}
        fill="black"
        textAnchor={x > cx ? "start" : "end"}
        dominantBaseline="central"
        width={150}
      >
        {name}
      </Text>
      <Text
        x={x}
        y={y}
        fill="white"
        textAnchor="middle"
        dominantBaseline="central"
        fontSize={18}
      >
        {`${percent.toFixed(1)}%`}
      </Text>
    </>
  );
};
 
export default DynamicPieChart;

Chart Component

Loading...