-
+ {maxValue !== 0 ? (
+
+ ) : (
+
+ {titleElement(category, years)}
+
+
+ {category} data in {years} is unavailable for all states.
+
+
+
+ )}
@@ -213,5 +206,16 @@ const EQIPTotalMap = ({ statePerformance, allStates }: { statePerformance: any;
);
};
-
+const titleElement = (attribute, year): JSX.Element => {
+ return (
+
+
+ {attribute} Benefits from {year}
+ {" "}
+
+ In any state that appears in grey, there is no available data
+
+
+ );
+};
export default EQIPTotalMap;
diff --git a/src/components/eqip/EQIPTotalTable.tsx b/src/components/eqip/EQIPTotalTable.tsx
index b58a2ceb..e00c7cc8 100644
--- a/src/components/eqip/EQIPTotalTable.tsx
+++ b/src/components/eqip/EQIPTotalTable.tsx
@@ -6,6 +6,7 @@ import "../../styles/table.css";
const Styles = styled.div`
padding: 1rem;
+ margin-left: ${window.innerWidth <= 1440 ? "480px" : "auto"};
table {
border-spacing: 0;
diff --git a/src/components/shared/DrawLegend.tsx b/src/components/shared/DrawLegend.tsx
index 742e0713..7a4486ef 100644
--- a/src/components/shared/DrawLegend.tsx
+++ b/src/components/shared/DrawLegend.tsx
@@ -3,6 +3,7 @@ import * as d3 from "d3";
import { Box, Typography } from "@mui/material";
import { ShortFormat } from "./ConvertionFormats";
import "../../styles/drawLegend.css";
+
/**
* Keys in legendConfig.json must match the 'searchKey' variable in DrawLegend.tsx file.
* If there's any changes in legendConfig.json, please re-check and update the 'searchKey' variable here.
@@ -47,7 +48,6 @@ export default function DrawLegend({
const customScale = colorScale.domain();
cut_points.push(Math.min(...programData));
cut_points = cut_points.concat(customScale);
-
const legendRectX: number[] = [];
if (Math.min(...programData) !== Infinity && Math.max(...programData) !== Infinity) {
baseSVG.selectAll("text").remove();
@@ -68,108 +68,121 @@ export default function DrawLegend({
data_distribution.push(
programData.filter((d) => d >= cut_points[cut_points.length - 1]).length / programData.length
);
- // Leave following part as the backup of solution 2.
- // data_distribution.push(
- // programData
- // .filter((d) => d >= cut_points[cut_points.length - 1])
- // .reduce((accumulator, currentValue) => accumulator + currentValue, 0) /
- // programData.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
- // );
const svgWidth = baseSVG.attr("width") - margin * 2;
- baseSVG
- .selectAll(null)
- .data(data_distribution)
- .enter()
- .append("rect")
- .attr("class", "legendRect")
- .attr("id", (d) => `legendRect${d}`)
- .attr("x", (d, i) => {
- if (i === 0) {
- return margin;
- }
- const sum = data_distribution.slice(0, i).reduce((acc, curr) => acc + curr, 0);
- return margin + svgWidth * sum;
- })
- .attr("y", () => {
- return 20;
- })
- .attr("width", (d) => {
- return d * svgWidth;
- })
- .attr("height", 10)
- .style("fill", (d, i) => prepColor[i]);
- cut_points = cut_points.concat(Math.max(...programData));
- baseSVG
- .selectAll(".legendRect")
- .nodes()
- .forEach((d) => {
- legendRectX.push(Number(d3.select(d).attr("x")));
- });
- const last =
- legendRectX[legendRectX.length - 1] + data_distribution[data_distribution.length - 1] * svgWidth;
- legendRectX.push(last);
- if (window.innerWidth > 1679) {
+ // No need to show color length if there are less than five colors (i.e. not enough data points or label is not correctly identified)
+ if (!data_distribution.includes(0)) {
baseSVG
.selectAll(null)
- .data(legendRectX)
+ .data(data_distribution)
.enter()
- .append("text")
- .attr("class", "legendText")
- .attr("id", (d) => `legendText${d}`)
- .attr("y", 50)
+ .append("rect")
+ .attr("class", "legendRect")
+ .attr("id", (d) => `legendRect${d}`)
.attr("x", (d, i) => {
- return i === 0 ? d : d - margin / 4;
- })
- .text((d, i) => {
- if (isRatio) {
- return `${Math.round(cut_points[i] * 100)}%`;
- }
- if (i === 0 && !notDollar) {
- const res = ShortFormat(Math.round(cut_points[i]), i);
- return res.indexOf("-") < 0 ? `$${res}` : `-$${res.substring(1)}`;
+ if (i === 0) {
+ return margin;
}
- return ShortFormat(Math.round(cut_points[i]), i);
- });
- } else {
- baseSVG
- .selectAll(null)
- .data(legendRectX)
- .enter()
- .append("text")
- .attr("class", "legendText")
- .attr("id", (d) => `legendText${d}`)
- .attr("y", (d, i) => {
- return i % 2 === 0 ? 50 : 10;
+ const sum = data_distribution.slice(0, i).reduce((acc, curr) => acc + curr, 0);
+ return margin + svgWidth * sum;
})
- .attr("x", (d, i) => {
- return i === 0 ? d : d - margin / 4;
+ .attr("y", () => {
+ return 20;
})
- .text((d, i) => {
- if (isRatio) {
- return `${Math.round(cut_points[i] * 100)}%`;
- }
- if (i === 0 && !notDollar) {
- const res = ShortFormat(Math.round(cut_points[i]), i);
- return res.indexOf("-") < 0 ? `$${res}` : `-$${res.substring(1)}`;
- }
- return ShortFormat(Math.round(cut_points[i]), i);
+ .attr("width", (d) => {
+ return d * svgWidth;
+ })
+ .attr("height", 10)
+ .style("fill", (d, i) => prepColor[i]);
+ cut_points = cut_points.concat(Math.max(...programData));
+ baseSVG
+ .selectAll(".legendRect")
+ .nodes()
+ .forEach((d) => {
+ legendRectX.push(Number(d3.select(d).attr("x")));
});
- }
- if (emptyState.length !== 0) {
+ const last =
+ legendRectX[legendRectX.length - 1] +
+ data_distribution[data_distribution.length - 1] * svgWidth;
+ legendRectX.push(last);
+ if (window.innerWidth > 1679) {
+ baseSVG
+ .selectAll(null)
+ .data(legendRectX)
+ .enter()
+ .append("text")
+ .attr("class", "legendText")
+ .attr("id", (d) => `legendText${d}`)
+ .attr("y", 50)
+ .attr("x", (d, i) => {
+ return i === 0 ? d : d - margin / 4;
+ })
+ .text((d, i) => {
+ if (isRatio) {
+ return `${Math.round(cut_points[i] * 100)}%`;
+ }
+ if (i === 0 && !notDollar) {
+ const res = ShortFormat(Math.round(cut_points[i]), i);
+ return res.indexOf("-") < 0 ? `$${res}` : `-$${res.substring(1)}`;
+ }
+ return ShortFormat(Math.round(cut_points[i]), i);
+ });
+ } else {
+ baseSVG
+ .selectAll(null)
+ .data(legendRectX)
+ .enter()
+ .append("text")
+ .attr("class", "legendText")
+ .attr("id", (d) => `legendText${d}`)
+ .attr("y", (d, i) => {
+ return i % 2 === 0 ? 50 : 10;
+ })
+ .attr("x", (d, i) => {
+ return i === 0 ? d : d - margin / 4;
+ })
+ .text((d, i) => {
+ if (isRatio) {
+ return `${Math.round(cut_points[i] * 100)}%`;
+ }
+ if (i === 0 && !notDollar) {
+ const res = ShortFormat(Math.round(cut_points[i]), i);
+ return res.indexOf("-") < 0 ? `$${res}` : `-$${res.substring(1)}`;
+ }
+ return ShortFormat(Math.round(cut_points[i]), i);
+ });
+ }
+ if (emptyState.length !== 0) {
+ const middleText = baseSVG
+ .append("text")
+ .attr("class", "legendTextSide")
+ .attr("x", -1000)
+ .attr("y", -1000)
+ .text(`${emptyState.join(", ")}'s data is not available`);
+ const middleBox = middleText.node().getBBox();
+ middleText.remove();
+ baseSVG
+ .append("text")
+ .attr("class", "legendTextSide")
+ .attr("x", (svgWidth + margin * 2) / 2 - middleBox.width / 2)
+ .attr("y", 80)
+ .text(`${emptyState.join(", ")}'s data is not available`);
+ }
+ } else {
+ baseSVG.attr("height", 40);
const middleText = baseSVG
.append("text")
.attr("class", "legendTextSide")
.attr("x", -1000)
.attr("y", -1000)
- .text(`${emptyState.join(", ")}'s data is not available`);
+ .text("There isn't sufficient data to display the legend");
const middleBox = middleText.node().getBBox();
middleText.remove();
baseSVG
.append("text")
.attr("class", "legendTextSide")
.attr("x", (svgWidth + margin * 2) / 2 - middleBox.width / 2)
- .attr("y", 80)
- .text(`${emptyState.join(", ")}'s data is not available`);
+ .attr("y", 16)
+ .text("There isn't sufficient data to display the legend");
}
}
}
diff --git a/src/components/shared/NavSearchBar.tsx b/src/components/shared/NavSearchBar.tsx
index a9b768ab..6a27915c 100644
--- a/src/components/shared/NavSearchBar.tsx
+++ b/src/components/shared/NavSearchBar.tsx
@@ -17,7 +17,7 @@ export default function NavSearchBar({
borderLeft: 0,
borderRight: 0,
borderColor: brColor,
- padding: 1,
+ margin: 1,
backgroundColor: bkColor
}}
>
diff --git a/src/main.tsx b/src/main.tsx
index cf749636..4c198db2 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -3,6 +3,7 @@ import { Routes, Route, useLocation } from "react-router-dom";
import LandingPage from "./pages/LandingPage";
import EQIPPage from "./pages/EQIPPage";
import CSPPage from "./pages/CSPPage";
+import CRPPage from "./pages/CRPPage";
import SNAPPage from "./pages/SNAPPage";
import TitleIPage from "./pages/TitleIPage";
import CropInsurancePage from "./pages/CropInsurancePage";
@@ -23,6 +24,7 @@ export default function Main(): JSX.Element {
} />
} />
} />
+
} />
} />
} />
} />
diff --git a/src/pages/CRPPage.tsx b/src/pages/CRPPage.tsx
new file mode 100644
index 00000000..57d1085c
--- /dev/null
+++ b/src/pages/CRPPage.tsx
@@ -0,0 +1,380 @@
+import Box from "@mui/material/Box";
+import * as React from "react";
+import { createTheme, ThemeProvider, Typography } from "@mui/material";
+import NavBar from "../components/NavBar";
+import Drawer from "../components/ProgramDrawer";
+import SemiDonutChart from "../components/SemiDonutChart";
+import DataTable from "../components/crp/CRPTotalTable";
+import CRPTotalMap from "../components/crp/CRPTotalMap";
+import CategoryTable from "../components/crp/CategoryTable";
+import CategoryMap from "../components/crp/CategoryMap";
+import { config } from "../app.config";
+import { convertAllState, getJsonDataFromUrl } from "../utils/apiutil";
+import NavSearchBar from "../components/shared/NavSearchBar";
+
+export default function CRPPage(): JSX.Element {
+ const year = "2018-2022";
+ const attribute = "paymentInDollars";
+ const [checked, setChecked] = React.useState(0);
+
+ const [stateDistributionData, setStateDistributionData] = React.useState({});
+ const [stateCodesData, setStateCodesData] = React.useState({});
+ const [stateCodesArray, setStateCodesArray] = React.useState({});
+ const [allStatesData, setAllStatesData] = React.useState([]);
+ const [totalChartData, setTotalChartData] = React.useState([{}]);
+ const [subChartData, setSubChartData] = React.useState([{}]);
+ const [zeroCategories, setZeroCategories] = React.useState([]);
+ const [totalCrp, setTotalCrp] = React.useState(0);
+ const [totalSub, setTotalSub] = React.useState(0);
+
+ const defaultTheme = createTheme();
+ const zeroCategory = [];
+ let totalCRPPaymentInDollars = 0;
+ let generalSignUpPaymentInDollars = 0;
+ let continuousSingUpPaymentInDollars = 0;
+ let crepPaymentInDollars = 0;
+ let nocCrepPaymentInDollars = 0;
+ let wetlandPaymentInDollars = 0;
+ let grasslandPyamentInDollars = 0;
+
+ React.useEffect(() => {
+ const allstates_url = `${config.apiUrl}/states`;
+ getJsonDataFromUrl(allstates_url).then((response) => {
+ setAllStatesData(response);
+ });
+
+ const statecode_url = `${config.apiUrl}/statecodes`;
+ getJsonDataFromUrl(statecode_url).then((response) => {
+ setStateCodesArray(response);
+ const converted_json = convertAllState(response);
+ setStateCodesData(converted_json);
+ });
+
+ const statedistribution_url = `${config.apiUrl}/programs/conservation/crp/state-distribution`;
+ getJsonDataFromUrl(statedistribution_url).then((response) => {
+ setStateDistributionData(response);
+ });
+
+ const chartData_url = `${config.apiUrl}/programs/conservation/crp/subprograms`;
+ getJsonDataFromUrl(chartData_url).then((response) => {
+ processData(response);
+ });
+ }, []);
+
+ const processData = (chartData) => {
+ if (chartData.programs === undefined) return;
+
+ const cur1 = chartData.programs.find((s) => s.programName === "Total CRP");
+ const cur2 = chartData.programs.find((s) => s.programName === "Total General Sign-Up");
+ const cur3 = chartData.programs.find((s) => s.programName === "Total Continuous");
+ let cur4;
+ let cur5;
+ let cur6;
+ const cur7 = chartData.programs.find((s) => s.programName === "Grassland");
+ const subCurs = cur3.subPrograms;
+
+ if (subCurs !== undefined) {
+ subCurs.forEach((value) => {
+ if (value.programName === "CREP Only") {
+ cur4 = value;
+ } else if (value.programName === "Continuous Non-CREP") {
+ cur5 = value;
+ } else if (value.programName === "Farmable Wetland") {
+ cur6 = value;
+ }
+ });
+
+ totalCRPPaymentInDollars = cur1.paymentInDollars;
+ setTotalCrp(totalCRPPaymentInDollars);
+ if (totalCRPPaymentInDollars === 0) zeroCategory.push("Total CRP");
+ generalSignUpPaymentInDollars = cur2.paymentInDollars;
+ if (generalSignUpPaymentInDollars === 0) zeroCategory.push("Total General Sign-Up");
+ continuousSingUpPaymentInDollars = cur3.paymentInDollars;
+ if (continuousSingUpPaymentInDollars === 0) zeroCategory.push("Total Continuous");
+ setTotalSub(continuousSingUpPaymentInDollars);
+ crepPaymentInDollars = cur4.paymentInDollars;
+ if (crepPaymentInDollars === 0) zeroCategory.push("CREP Only");
+ nocCrepPaymentInDollars = cur5.paymentInDollars;
+ if (nocCrepPaymentInDollars === 0) zeroCategory.push("Continuous Non-CREP");
+ wetlandPaymentInDollars = cur6.paymentInDollars;
+ if (wetlandPaymentInDollars === 0) zeroCategory.push("Farmable Wetland");
+ grasslandPyamentInDollars = cur7.paymentInDollars;
+ if (grasslandPyamentInDollars === 0) zeroCategory.push("Grassland");
+
+ setZeroCategories(zeroCategory);
+
+ setTotalChartData([
+ { name: "Total General Sign-Up", value: generalSignUpPaymentInDollars, color: "#2F7164" },
+ { name: "Total Continuous", value: continuousSingUpPaymentInDollars, color: "#869397" },
+ { name: "Grassland", value: grasslandPyamentInDollars, color: "#9CBAB4" }
+ ]);
+
+ setSubChartData([
+ { name: "CREP Only", value: crepPaymentInDollars, color: "#2F7164" },
+ { name: "Continuous Non-CREP", value: nocCrepPaymentInDollars, color: "#869397" },
+ { name: "Farmable Wetland", value: wetlandPaymentInDollars, color: "#9CBAB4" }
+ ]);
+ }
+ };
+
+ return (
+
+ {Object.keys(stateCodesData).length > 0 &&
+ Object.keys(allStatesData).length > 0 &&
+ Object.keys(stateDistributionData).length > 0 ? (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CRP: Category of Practice Performance
+
+
+
+
+
+
+ CRP: Category of Practice Performance
+
+
+
+ 2 && checked < 6 ? "block" : "none"
+ }}
+ >
+
+
+ CRP Total Continuous: Sub-Category of Practice Performance
+
+
+
+
+
+ CRP provides annual rental payments to landowners in return for conservation practices
+ that remove the acres from production and implements conservation cover (e.g., grasses
+ and/or trees). CRP contracts are for 10 or 15 years and enrolled land can be an entire
+ field or portions of a field (e.g., grass waterways or buffers). CRP spending will be
+ visualized using the following categories.
+
+
+
+
+
+
+
+
+
+
+ 2 && checked < 6 ? "block" : "none" }}>
+
+
+
+
+
+
+ Overall Performance of States
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ) : (
+ Loading data...
+ )}
+
+ );
+}
diff --git a/src/pages/EQIPPage.tsx b/src/pages/EQIPPage.tsx
index 1c67bc3f..dc35e581 100644
--- a/src/pages/EQIPPage.tsx
+++ b/src/pages/EQIPPage.tsx
@@ -28,6 +28,7 @@ export default function EQIPPage(): JSX.Element {
let comprehensiveNutrientMgtTotal = 0;
let resourceConservingCropRotationTotal = 0;
let soilHealthTotal = 0;
+ const zeroCategory = [];
// connect to api endpoint
const [statePerformance, setStatePerformance] = React.useState({});
@@ -37,6 +38,7 @@ export default function EQIPPage(): JSX.Element {
const [sixBChartData, setSixBChartData] = React.useState([{}]);
const [aTotal, setATotal] = React.useState(0);
const [bTotal, setBTotal] = React.useState(0);
+ const [zeroCategories, setZeroCategories] = React.useState([]);
React.useEffect(() => {
const state_perf_url = `${config.apiUrl}/programs/conservation/eqip/state-distribution`;
@@ -90,18 +92,30 @@ export default function EQIPPage(): JSX.Element {
const soilHealthCur = BCur.find((s) => s.practiceCategoryName === "Soil health");
structuralTotal += Number(structuralCur.totalPaymentInDollars);
+ if (structuralTotal === 0) zeroCategory.push("Structural");
landManagementTotal += Number(landManagementCur.totalPaymentInDollars);
+ if (landManagementTotal === 0) zeroCategory.push("Land management");
vegetativeTotal += Number(vegetativeCur.totalPaymentInDollars);
+ if (vegetativeTotal === 0) zeroCategory.push("Vegetative");
forestManagementTotal += Number(forestManagementCur.totalPaymentInDollars);
+ if (forestManagementTotal === 0) zeroCategory.push("Forest management");
soilRemediationTotal += Number(soilRemediationCur.totalPaymentInDollars);
+ if (soilRemediationTotal === 0) zeroCategory.push("Soil remediation");
other6ATotal += Number(other6ACur.totalPaymentInDollars);
+ if (other6ATotal === 0) zeroCategory.push("Other improvement");
soilTestingTotal += Number(soilTestingCur.totalPaymentInDollars);
+ if (soilTestingTotal === 0) zeroCategory.push("Soil testing");
otherPlanningTotal += Number(otherPlanningCur.totalPaymentInDollars);
+ if (otherPlanningTotal === 0) zeroCategory.push("Other planning");
conservationPlanningAssessmentTotal += Number(conservationPlanningAssessmentCur.totalPaymentInDollars);
+ if (conservationPlanningAssessmentTotal === 0) zeroCategory.push("Conservation planning assessment");
comprehensiveNutrientMgtTotal += Number(comprehensiveNutrientMgtCur.totalPaymentInDollars);
+ if (comprehensiveNutrientMgtTotal === 0) zeroCategory.push("Comprehensive Nutrient Mgt.");
resourceConservingCropRotationTotal += Number(resourceConservingCropRotationCur.totalPaymentInDollars);
+ if (resourceConservingCropRotationTotal === 0) zeroCategory.push("Resource-conserving crop rotation");
soilHealthTotal += Number(soilHealthCur.totalPaymentInDollars);
+ if (soilHealthTotal === 0) zeroCategory.push("Soil health");
setSixAChartData([
{ name: "Structural", value: structuralTotal, color: "#2F7164" },
@@ -127,6 +141,8 @@ export default function EQIPPage(): JSX.Element {
{ name: "6 (A)", value: sixATotal, color: "#2F7164" },
{ name: "6 (B)", value: sixBTotal, color: "#9CBAB4" }
]);
+
+ setZeroCategories(zeroCategory);
};
return (
@@ -140,7 +156,7 @@ export default function EQIPPage(): JSX.Element {
subtext="Environmental Quality Incentives Program (EQIP)"
/>
-
+
{
+ let ans = "";
+ Object.keys(stateRecord).forEach((key) => {
+ const match = key.match(/^(.*?)(?=\s*InDollars)/);
+ const extractedKey = match ? match[1] : key;
+ if (extractedKey === attribute) {
+ ans = key;
+ }
+ });
+ return ans;
+};
diff --git a/src/utils/legendConfig.json b/src/utils/legendConfig.json
index 72937b00..edd6c2f5 100644
--- a/src/utils/legendConfig.json
+++ b/src/utils/legendConfig.json
@@ -2,14 +2,16 @@
"18-22 All Programs Total": [5000000000, 10000000000, 30000000000, 40000000000],
"Crop Insurance Total":[0, 500000000, 1000000000, 5000000000],
"totalNetFarmerBenefit": [0, 500000000, 1000000000, 5000000000],
- "Title I Total":[100000000, 500000000, 1000000000, 2000000000],
+ "Title I Total":[50000000, 100000000, 500000000, 1000000000],
"Total Commodities Programs": [100000000, 500000000, 1000000000, 2000000000],
"Title II Total":[100000000, 500000000, 1000000000, 2000000000],
"SNAP Total": [1000000000, 5000000000, 10000000000, 20000000000],
+
"Agriculture Risk Coverage (ARC)": [10000000, 50000000, 100000000, 500000000],
"Agriculture Risk Coverage County Option (ARC-CO)": [50000000, 100000000, 250000000, 500000000],
"Agriculture Risk Coverage Individual Coverage (ARC-IC)": [5000000, 10000000, 25000000, 50000000],
"Price Loss Coverage (PLC)":[50000000, 100000000, 500000000, 1000000000],
+
"totalIndemnities":[10000000, 100000000, 1000000000, 5000000000],
"totalPremium":[10000000, 100000000, 1000000000, 5000000000],
"totalPremiumSubsidy": [5000000, 100000000, 500000000, 1000000000],
@@ -17,6 +19,47 @@
"totalPoliciesEarningPremium": [1000, 10000, 100000, 500000],
"averageLiabilities":[50000000, 1000000000, 5000000000, 10000000000],
"lossRatio":[0.5, 0.75, 1, 1.5],
- "averageInsuredAreaInAcres":[10000, 5000000, 10000000, 20000000]
+ "averageInsuredAreaInAcres":[10000, 5000000, 10000000, 20000000],
+
+ "Total EQIP": [10000000, 50000000, 100000000, 200000000],
+ "Land management": [1000000, 10000000, 30000000, 50000000],
+ "Forest management": [500000, 1000000, 3000000,10000000],
+ "Structural":[10000000, 50000000, 80000000, 100000000],
+ "Soil remediation":[100000, 500000, 1000000, 5000000],
+ "Vegetative":[1000000, 5000000, 10000000, 20000000],
+ "Other improvement":[100000, 1000000, 5000000, 10000000],
+ "Soil testing":[100, 500, 1000, 3000],
+ "Other planning":[10000, 100000, 500000, 1000000],
+ "Conservation planning assessment":[5000, 100000, 500000, 1000000],
+ "Resource-conserving crop rotation":[500, 1000, 5000, 10000],
+ "Soil health":[10000, 100000, 500000, 1000000],
+ "Comprehensive Nutrient Mgt.":[1000, 10000, 100000, 1000000],
+
+ "Total CSP": [10000000, 50000000, 100000000, 200000000],
+ "2018 Practices": [1000000, 5000000, 10000000, 80000000],
+ "2014 Eligible Land": [5000000, 10000000, 80000000, 150000000],
+ "Forest management-CSP": [100000, 500000, 1000000, 10000000],
+ "Land management-CSP": [10000, 1000000, 5000000, 10000000],
+ "Existing activity payments": [100000, 1000000, 3000000, 5000000],
+ "Vegetative-CSP": [500000, 1000000, 5000000, 10000000],
+ "Other improvement-CSP": [5000, 1000000, 5000000, 10000000],
+ "Soil remediation": [100000, 500000, 1000000, 3000000],
+ "Structural-CSP": [50000, 100000, 500000, 1000000],
+ "Bundles": [50000, 100000, 300000, 800000],
+ "Soil testing-CSP": [100000, 500000, 1000000, 10000000],
+ "Cropland": [1000000, 10000000, 100000000, 200000000],
+ "Non-industrial private forestland": [500000, 1000000, 3000000, 8000000],
+ "Pastureland": [1000000, 5000000, 8000000, 10000000],
+ "Grassland": [5000, 100000, 400000, 8000000],
+ "Other: supplemental, adjustment & other": [500000, 1000000, 5000000, 10000000],
+ "Rangeland": [100000, 5000000, 10000000, 30000000],
+
+ "Total CRP": [100000, 10000000, 100000000, 500000000],
+ "Total General Sign-Up":[10000, 100000, 10000000, 100000000],
+ "Total Continuous Sign-Up":[10000, 100000, 100000000, 1000000000],
+ "CREP Only":[100000, 10000000, 50000000, 80000000],
+ "Continuous Non-CREP":[10000, 100000, 100000000, 200000000],
+ "Farmable Wetland":[10000, 100000, 500000, 10000000],
+ "Grassland-CRP":[10000, 100000, 500000, 10000000]
}