diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0701fe3722503406ff178143a7fcd3d1f0e8968b..4ff9b7edf9bc36823916ec121ea2834da902790f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,9 +15,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 - The daily statistics data component was converted to Vue.
 - Time span controls were converted to use Vue.
 - Select-actions component converted to Vue.
+- The hydrograph data table is now a Vue component and can be sorted by time.
+- Parameter selection list now has the option to graph a second parameter
 
 ### Fixed
 - Parameter codes with multiple methods will now show statistical data for each method available.
+- The hydrograph legend and time span shortcuts will now correctly display for calculated temperature parameter codes.
 
 ## [1.2.0](https://github.com/usgs/waterdataui/compare/waterdataui-1.1.0...waterdataui-1.2.0) - 2022-06-10
 ### Added
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/selectors/legend-data.js b/assets/src/scripts/monitoring-location/components/hydrograph/selectors/legend-data.js
index 7c3ed29d46f45ea916c78dfba2ad5331e2f7905c..945313a998ebcf7dddac0b71a6b69adf3abf0029 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/selectors/legend-data.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/selectors/legend-data.js
@@ -43,8 +43,8 @@ const getLegendDisplay = createSelector(
     (showCompare, showMedian, thresholds, medianSeries, currentClasses, compareClasses, showFloodLevels,
      floodLevels, gwLevelKinds, primaryParameter) => {
         const parameterCode = primaryParameter ? primaryParameter.parameterCode : null;
-        const hasIVData = config.ivPeriodOfRecord && parameterCode ? parameterCode in config.ivPeriodOfRecord : false;
-        const hasGWLevelsData = config.gwPeriodOfRecord && parameterCode ? parameterCode in config.gwPeriodOfRecord : false;
+        const hasIVData = config.ivPeriodOfRecord && parameterCode ? parameterCode.replace(config.CALCULATED_TEMPERATURE_VARIABLE_CODE, '') in config.ivPeriodOfRecord : false;
+        const hasGWLevelsData = config.gwPeriodOfRecord && parameterCode ? parameterCode.replace(config.CALCULATED_TEMPERATURE_VARIABLE_CODE, '') in config.gwPeriodOfRecord : false;
         return {
             primaryIV: hasIVData ? currentClasses : undefined,
             compareIV: hasIVData && showCompare ? compareClasses : undefined,
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/selectors/legend-data.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/selectors/legend-data.test.js
index 933ca67413a59738a50be00145202daeeed37a19..c1f802a0357e3f406a9341ad6956350ecc528ee2 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/selectors/legend-data.test.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/selectors/legend-data.test.js
@@ -6,7 +6,8 @@ import {getLegendMarkerRows} from './legend-data';
 
 describe('monitoring-location/components/hydrograph/selectors/legend-data', () => {
     config.ivPeriodOfRecord = {
-        '72019': {}
+        '72019': {},
+        '00010': {}
     };
     config.gwPeriodOfRecord = {
         '72019': {}
@@ -100,6 +101,23 @@ describe('monitoring-location/components/hydrograph/selectors/legend-data', () =
         }
     };
 
+    const TEST_STATE_TEMPERATURE = {
+        ...TEST_STATE,
+        hydrographState: {
+            selectedParameterCode: '00010F',
+            showCompareIVData: false,
+            showMedianData: false,
+            selectedIVMethodID: '90649'
+        },
+        primaryIVData: {
+            ...TEST_PRIMARY_IV_DATA,
+            parameter: {
+                parameterCode: '00010F',
+                unit: 'F'
+            }
+        }
+    };
+
     describe('getLegendMarkerRows', () => {
         beforeAll(() => {
             Object.defineProperty(window, 'matchMedia', {
@@ -140,6 +158,16 @@ describe('monitoring-location/components/hydrograph/selectors/legend-data', () =
             expect(gwRow[2].type).toEqual(circleMarker);
         });
 
+        it('Should return markers for primary IV with a caculated temperature parameter code', () => {
+            const markerRows = getLegendMarkerRows(TEST_STATE_TEMPERATURE);
+            expect(markerRows).toHaveLength(2);
+            const currentRow = markerRows[0];
+            expect(currentRow).toHaveLength(3);
+            expect(currentRow[0].type).toEqual(textOnlyMarker);
+            expect(currentRow[1].type).toEqual(lineMarker);
+            expect(currentRow[2].type).toEqual(rectangleMarker);
+        });
+
         it('Should return markers for primary and compare when compare is visible', () => {
             const markerRows = getLegendMarkerRows({
                 ...TEST_STATE,
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/data-table.vue b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/data-table.vue
index f6c7000c00b926bcd0c2f4b633b42a6bec22ed95..aade0a8784142cc81b003d8b1fefe16db6691b95 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/data-table.vue
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/data-table.vue
@@ -1,46 +1,26 @@
 <template>
   <div id="iv-hydrograph-data-table-container">
     <div
-      v-show="currentIVData.length"
+      v-show="currentIVData.IVData.length"
       id="iv-table-container"
     >
-      <table class="usa-table">
-        <caption>Instantaneous value data</caption>
-        <thead>
-          <tr>
-            <th
-              v-for="column in ivColumnHeadings"
-              :key="column"
-              scope="col"
-            >
-              {{ column }}
-            </th>
-          </tr>
-        </thead>
-        <tbody class="list" />
-      </table>
-      <ul class="pagination" />
+      <PaginatedTable
+        :data-set="currentIVData.IVData"
+        :headers="ivColumnHeadings"
+        :key-order="ivValueNames"
+        :title="`${currentIVData.name} -- instantaneous value data`"
+      />
     </div>
     <div
-      v-show="currentGWData.length"
+      v-show="currentGWData.GWData.length"
       id="gw-table-container"
     >
-      <table class="usa-table">
-        <caption>Field visit data</caption>
-        <thead>
-          <tr>
-            <th
-              v-for="column in gwColumnHeadings"
-              :key="column"
-              scope="col"
-            >
-              {{ column }}
-            </th>
-          </tr>
-        </thead>
-        <tbody class="list" />
-      </table>
-      <ul class="pagination" />
+      <PaginatedTable
+        :data-set="currentGWData.GWData"
+        :headers="gwColumnHeadings"
+        :key-order="gwValueNames"
+        :title="`${currentGWData.name} -- field visit data`"
+      />
     </div>
 
     <button
@@ -76,12 +56,9 @@
 </template>
 
 <script>
-import Pagination from 'list.js/src/pagination.js'; /* eslint no-unused-vars: off */
-import List from 'list.js';
 import {useState} from 'redux-connect-vue';
-import {ref, inject, onMounted} from 'vue';
-
-import {listen} from 'ui/lib/d3-redux';
+import {ref} from 'vue';
+import {createSelector} from 'reselect';
 
 import config from 'ui/config.js';
 
@@ -89,75 +66,62 @@ import {getIVTableData} from '../selectors/iv-data';
 import {getGroundwaterLevelsTableData} from '../selectors/discrete-data';
 
 import DownloadData from './download-data.vue';
+import PaginatedTable from './paginated-table.vue';
 
 export default {
   name: 'DataTable',
   components: {
-    DownloadData
+    DownloadData,
+    PaginatedTable
   },
   setup() {
     const downloadIcon = `${config.STATIC_URL}img/sprite.svg#file_download`;
     const showDownloadContainer = ref(false);
-    const CONTAINER_ID = {
-      iv: 'iv-table-container',
-      gw: 'gw-table-container'
-    };
     const COLUMN_HEADINGS = {
-      iv: ['Parameter', 'Time', 'Result', 'Approval', 'Masks'],
-      gw: ['Parameter', 'Time', 'Result', 'Accuracy', 'Approval', 'Qualifiers']
+      iv: ['Time', 'Result', 'Approval', 'Masks'],
+      gw: ['Time', 'Result', 'Accuracy', 'Approval', 'Qualifiers']
     };
     const VALUE_NAMES = {
-      iv: ['parameterName', 'dateTime', 'result', 'approvals', 'masks'],
-      gw: ['parameterName', 'dateTime', 'result', 'resultAccuracy', 'approvals', 'qualifiers']
+      iv: ['dateTime', 'result', 'approvals', 'masks'],
+      gw: ['dateTime', 'result', 'resultAccuracy', 'approvals', 'qualifiers']
     };
 
-    const state = useState({
-      currentIVData: getIVTableData('primary'),
-      currentGWData: getGroundwaterLevelsTableData
-    });
-    let dataLists = {
-      iv: null,
-      gw: null
-    };
-    const reduxStore = inject('store');
-
-    const updateDataTable = function(dataKind, data) {
-      if (dataLists[dataKind]) {
-        dataLists[dataKind].clear();
-        dataLists[dataKind].add(data);
-      } else {
-        const items = VALUE_NAMES[dataKind].reduce(function(total, propName, index) {
-          if (index === 0) {
-            return `${total}<th scope="row" class="${propName}"></th>`;
-          } else {
-            return `${total}<td class="${propName}"></td>`;
-          }
-        }, '');
-        const options = {
-          valueNames: VALUE_NAMES[dataKind],
-          item: `<tr>${items}</tr>`,
-          page: 16,
-          pagination: [{
-            left: 1,
-            innerWindow: 2,
-            right: 1,
-            item: '<li><a class="page" href="javascript:;"></a></li>'
-          }]
-        };
-        dataLists[dataKind] = new List(CONTAINER_ID[dataKind], options, data);
+    const filter = function(object, keys) {
+      let result = {}, key;
+
+      for (key in object) {
+        if (Object.prototype.hasOwnProperty.call(object, key) && keys.includes(key)) {
+          result[key] = object[key];
+        }
       }
+      return result;
     };
 
-    const updateIVDataTable = function(data) {
-      updateDataTable('iv', data);
-    };
-    const updateGWDataTable = function(data) {
-      updateDataTable('gw', data);
-    };
+    const getIVData = createSelector(
+      getIVTableData('primary'),
+      (data) => {
+
+        return {
+          IVData: data.map(object => filter(object, VALUE_NAMES.iv)),
+          name: data.length ? data[0].parameterName : ''
+          };
+      }
+    );
 
-    onMounted(() => {
-      listen(reduxStore, getIVTableData('primary'), updateIVDataTable);
-      listen(reduxStore, getGroundwaterLevelsTableData, updateGWDataTable);
+    const getGWData = createSelector(
+      getGroundwaterLevelsTableData,
+      (data) => {
+
+        return {
+          GWData: data.map(object => filter(object, VALUE_NAMES.gw)),
+          name: data.length ? data[0].parameterName : ''
+          };
+      }
+    );
+
+    const state = useState({
+      currentIVData: getIVData,
+      currentGWData: getGWData
     });
 
     const toggleDownloadContainer = function() {
@@ -170,7 +134,9 @@ export default {
       showDownloadContainer,
       toggleDownloadContainer,
       ivColumnHeadings: COLUMN_HEADINGS.iv,
-      gwColumnHeadings: COLUMN_HEADINGS.gw
+      gwColumnHeadings: COLUMN_HEADINGS.gw,
+      ivValueNames: VALUE_NAMES.iv,
+      gwValueNames: VALUE_NAMES.gw
     };
   }
 };
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/graph-controls.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/graph-controls.test.js
index 8074124233725accc6c25085124e2e47a569c9ba..1c617728c6cd05b5bcb26959b2611dbf40bd4ea4 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/graph-controls.test.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/graph-controls.test.js
@@ -20,7 +20,8 @@ import GraphControls from './graph-controls.vue';
 describe('monitoring-location/components/hydrograph/components/graph-controls', () => {
     utils.mediaQuery = jest.fn().mockReturnValue(true);
     config.ivPeriodOfRecord = {
-        '72019': {}
+        '72019': {},
+        '00010': {}
     };
 
     let restoreConsole;
@@ -133,6 +134,38 @@ describe('monitoring-location/components/hydrograph/components/graph-controls',
         expect(wrapper.findAll('.usa-checkbox')[0].find('input').attributes('disabled')).toBeDefined();
     });
 
+    it('expect that compare is enabled if a calulated temp parameter code is selected', async() => {
+        store = configureStore({
+            hydrographData: {
+                currentTimeRange: TEST_CURRENT_TIME_RANGE
+            },
+            hydrographState: {
+                showCompareIVData: false,
+                selectedTimeSpan: 'P7D',
+                showMedianData: false,
+                selectedParameterCode: '00010F'
+            }
+        });
+
+        wrapper = mount(GraphControls, {
+            global: {
+                plugins: [
+                    [ReduxConnectVue, {
+                        store,
+                        mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
+                        mapStateToPropsFactory: createStructuredSelector
+                    }]
+                ],
+                provide: {
+                    store: store,
+                    siteno: '12345678'
+                }
+            }
+        });
+
+        expect(wrapper.findAll('.usa-checkbox')[0].find('input').attributes('disabled')).not.toBeDefined();
+    });
+
     it('expect that clicking the median updates the store', async() => {
         const medianInput = wrapper.findAll('.usa-checkbox')[1].find('input');
         medianInput.element.checked = true;
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/graph-controls.vue b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/graph-controls.vue
index 1ed7376dc9d3d5079ef299fc7b36dd6e6ca461e0..17d54673600f61a792b953f87e3b29f4fb0a847f 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/graph-controls.vue
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/graph-controls.vue
@@ -44,7 +44,7 @@ export default {
 
   setup() {
     const hasIVData = function(parameterCode) {
-      return config.ivPeriodOfRecord && parameterCode in config.ivPeriodOfRecord;
+      return config.ivPeriodOfRecord && parameterCode.replace(config.CALCULATED_TEMPERATURE_VARIABLE_CODE, '') in config.ivPeriodOfRecord;
     };
 
     const ALLOW_COMPARE_FOR_DURATIONS = config.IV_SHORTCUT_BUTTONS.map(button => button.timeSpan);
@@ -104,6 +104,7 @@ export default {
         showDataIndicators(false, reduxStore);
       }
     }
+
     return {
       ...state,
       selectCompare,
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/paginated-table.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/paginated-table.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..df64b1f159eeb90fd28c9a15d080e57ddc727f31
--- /dev/null
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/paginated-table.test.js
@@ -0,0 +1,202 @@
+import {mount} from '@vue/test-utils';
+
+import PaginatedTable from './paginated-table.vue';
+
+describe('monitoring-location/components/hydrograph/components/data-table.vue', () => {
+    let wrapper;
+    const TEST_DATASET = [
+        {
+            time: '12:00',
+            value: '3',
+            notes: 'sth 456'
+        },
+        {
+            time: '12:15',
+            value: '453',
+            notes: 'sth 1'
+        },
+        {
+            time: '12:30',
+            value: '123',
+            notes: 'sth 2'
+        },
+        {
+            time: '12:45',
+            value: '35',
+            notes: 'sth 3'
+        },
+        {
+            time: '13:00',
+            value: '33',
+            notes: 'sth 4'
+        },
+        {
+            time: '13:15',
+            value: '1003',
+            notes: 'sth 5'
+        },
+        {
+            time: '13:30',
+            value: '103',
+            notes: 'sth 6'
+        },
+        {
+            time: '13:45',
+            value: '2',
+            notes: 'sth 7'
+        },
+        {
+            time: '14:00',
+            value: '300',
+            notes: 'sth 8'
+        },
+        {
+            time: '14:15',
+            value: '30',
+            notes: 'sth 9'
+        }
+    ];
+
+    it('Draws the table', () => {
+        wrapper = mount(PaginatedTable, {
+            props: {
+                dataSet: TEST_DATASET,
+                headers: ['Time', 'Result', 'Notes'],
+                rowsPerPage: 2,
+                title: 'Test Title',
+                keyOrder: ['time', 'value', 'notes']
+            }
+        });
+        const headers = wrapper.findAll('th');
+        const rows = wrapper.findAll('tbody tr');
+        expect(wrapper.find('caption').text()).toBe('Test Title');
+
+        expect(headers).toHaveLength(3);
+        expect(headers[0].text()).toBe('Time');
+        expect(headers[1].text()).toBe('Result');
+        expect(headers[2].text()).toBe('Notes');
+
+        expect(rows).toHaveLength(2);
+        expect(rows[0].findAll('td')).toHaveLength(3);
+        expect(rows[0].findAll('td')[0].text()).toBe('14:15');
+        expect(rows[0].findAll('td')[1].text()).toBe('30');
+        expect(rows[0].findAll('td')[2].text()).toBe('sth 9');
+
+        expect(rows[1].findAll('td')).toHaveLength(3);
+        expect(rows[1].findAll('td')[0].text()).toBe('14:00');
+        expect(rows[1].findAll('td')[1].text()).toBe('300');
+        expect(rows[1].findAll('td')[2].text()).toBe('sth 8');
+
+        expect(wrapper.findAll('nav')).toHaveLength(1);
+    });
+
+    it('Shows the pagination buttons', () => {
+        wrapper = mount(PaginatedTable, {
+            props: {
+                dataSet: TEST_DATASET,
+                headers: ['Time', 'Result', 'Notes'],
+                rowsPerPage: 2,
+                title: 'Test Title',
+                keyOrder: ['time', 'value', 'notes']
+            }
+        });
+
+        const pageButtons = wrapper.findAll('ul li');
+        expect(pageButtons).toHaveLength(4);
+        expect(pageButtons[0].text()).toBe('1');
+        expect(pageButtons[1].text()).toBe('2');
+        expect(pageButtons[2].text()).toBe('...');
+        expect(pageButtons[3].text()).toBe('5');
+    });
+
+    it('Changes the table when a page button is clicked', async() => {
+        wrapper = mount(PaginatedTable, {
+            props: {
+                dataSet: TEST_DATASET,
+                headers: ['Time', 'Result', 'Notes'],
+                rowsPerPage: 2,
+                title: 'Test Title',
+                keyOrder: ['time', 'value', 'notes']
+            }
+        });
+        const pageButtons = wrapper.findAll('ul li a');
+        pageButtons[1].trigger('click');
+        await wrapper.vm.$nextTick();
+        const rows = wrapper.findAll('tbody tr');
+
+        expect(rows[0].findAll('td')).toHaveLength(3);
+        expect(rows[0].findAll('td')[0].text()).toBe('13:45');
+        expect(rows[0].findAll('td')[1].text()).toBe('2');
+        expect(rows[0].findAll('td')[2].text()).toBe('sth 7');
+
+        expect(rows[1].findAll('td')).toHaveLength(3);
+        expect(rows[1].findAll('td')[0].text()).toBe('13:30');
+        expect(rows[1].findAll('td')[1].text()).toBe('103');
+        expect(rows[1].findAll('td')[2].text()).toBe('sth 6');
+    });
+
+    it('Updates page buttons when page is changed', async() => {
+        wrapper = mount(PaginatedTable, {
+            props: {
+                dataSet: TEST_DATASET,
+                headers: ['Time', 'Result', 'Notes'],
+                rowsPerPage: 2,
+                title: 'Test Title',
+                keyOrder: ['time', 'value', 'notes']
+            }
+        });
+
+        let pageButtons = wrapper.findAll('ul li');
+        expect(pageButtons).toHaveLength(4);
+        expect(pageButtons[0].text()).toBe('1');
+        expect(pageButtons[1].text()).toBe('2');
+        expect(pageButtons[2].text()).toBe('...');
+        expect(pageButtons[3].text()).toBe('5');
+
+        wrapper.findAll('ul li a')[1].trigger('click');
+        await wrapper.vm.$nextTick();
+        pageButtons = wrapper.findAll('ul li');
+
+        expect(pageButtons).toHaveLength(5);
+        expect(pageButtons[0].text()).toBe('1');
+        expect(pageButtons[1].text()).toBe('2');
+        expect(pageButtons[2].text()).toBe('3');
+        expect(pageButtons[3].text()).toBe('...');
+        expect(pageButtons[4].text()).toBe('5');
+
+        wrapper.findAll('ul li a')[0].trigger('click');
+        await wrapper.vm.$nextTick();
+        pageButtons = wrapper.findAll('ul li');
+
+        expect(pageButtons).toHaveLength(4);
+        expect(pageButtons[0].text()).toBe('1');
+        expect(pageButtons[1].text()).toBe('2');
+        expect(pageButtons[2].text()).toBe('...');
+        expect(pageButtons[3].text()).toBe('5');
+    });
+
+    it('Sorts the table when the sort button is clicked', async() => {
+        wrapper = mount(PaginatedTable, {
+            props: {
+                dataSet: TEST_DATASET,
+                headers: ['Time', 'Result', 'Notes'],
+                rowsPerPage: 2,
+                title: 'Test Title',
+                keyOrder: ['time', 'value', 'notes']
+            }
+        });
+        const rows = wrapper.findAll('tbody tr');
+        wrapper.find('svg').trigger('click');
+        await wrapper.vm.$nextTick();
+
+        expect(rows[0].findAll('td')).toHaveLength(3);
+        expect(rows[0].findAll('td')[0].text()).toBe('12:00');
+        expect(rows[0].findAll('td')[1].text()).toBe('3');
+        expect(rows[0].findAll('td')[2].text()).toBe('sth 456');
+
+        expect(rows[1].findAll('td')).toHaveLength(3);
+        expect(rows[1].findAll('td')[0].text()).toBe('12:15');
+        expect(rows[1].findAll('td')[1].text()).toBe('453');
+        expect(rows[1].findAll('td')[2].text()).toBe('sth 1');
+    });
+});
\ No newline at end of file
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/paginated-table.vue b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/paginated-table.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6ef917c1317be91638e10f292bf806d0ebb87d47
--- /dev/null
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/paginated-table.vue
@@ -0,0 +1,216 @@
+<template>
+  <table class="usa-table">
+    <!-- eslint-disable vue/no-v-html -->
+    <caption v-html="myTitle" />
+    <!--eslint-enable-->
+    <thead>
+      <tr>
+        <th
+          v-for="column in myHeaders"
+          :key="column"
+          scope="col"
+        >
+          {{ column }}
+          <a href="javascript:void(0);">
+            <svg
+              v-if="column === 'Time'"
+              class="usa-icon sort"
+              aria-hidden="true"
+              role="img"
+              @click="sortOrder === 'desc' ? sortOrder = 'asce' : sortOrder = 'desc'"
+            >
+              <use :xlink:href="sortIconURL" />
+            </svg>
+          </a>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr
+        v-for="(dataObject, index) in pagedArray[page-1]"
+        :key="index"
+      >
+        <td
+          v-for="key in myKeyOrder"
+          :key="key"
+          :data-sort-value="key === 'dateTime' ? dataObject[key] : null"
+        >
+          {{ dataObject[key] }}
+        </td>
+      </tr>
+    </tbody>
+    <nav class="usa-pagination">
+      <ul class="usa-pagination__list">
+        <li class="usa-pagination__item usa-pagination__page-no">
+          <a
+            :href="`${page === 1 ? '' : 'javascript:void(0);'}` || null"
+            :class="`usa-pagination__button ${page === 1 ? 'usa-current' : ''}`"
+            aria-label="Page 1"
+            @click="page=1"
+          >
+            {{ 1 }}
+          </a>
+        </li>
+        <li
+          v-if="page > 3"
+          class="usa-pagination__item usa-pagination__overflow"
+        >
+          <span>...</span>
+        </li>
+        <li
+          v-if="3 <= page && page <= data.length"
+          class="usa-pagination__item usa-pagination__page-no"
+        >
+          <a
+            class="usa-pagination__button"
+            :aria-label="`Page ${page - 1}`"
+            href="javascript:void(0);"
+            @click="page=page - 1"
+          >
+            {{ page - 1 }}
+          </a>
+        </li>
+        <li
+          v-if="1 < page && page < data.length"
+          class="usa-pagination__item usa-pagination__page-no"
+        >
+          <a
+            class="usa-pagination__button usa-current"
+            :aria-label="`Page ${page}`"
+          >
+            {{ page }}
+          </a>
+        </li>
+        <li
+          v-if="1 <= page && page < (data.length - 1)"
+          class="usa-pagination__item usa-pagination__page-no"
+        >
+          <a
+            class="usa-pagination__button"
+            :aria-label="`Page ${page + 1}`"
+            href="javascript:void(0);"
+            @click="page=page + 1"
+          >
+            {{ page + 1 }}
+          </a>
+        </li>
+        <li
+          v-if="page < data.length - 2"
+          class="usa-pagination__item usa-pagination__overflow"
+        >
+          <span>...</span>
+        </li>
+        <li
+          class="usa-pagination__item usa-pagination__page-no"
+        >
+          <a
+            :href="`${page === data.length ? '' : 'javascript:void(0);'}` || null"
+            :class="`usa-pagination__button ${page === data.length ? 'usa-current' : ''}`"
+            :aria-label="`Last page, page ${data.length}`"
+            @click="page=data.length"
+          >
+            {{ data.length }}
+          </a>
+        </li>
+      </ul>
+    </nav>
+  </table>
+</template>
+
+<script>
+import config from 'ui/config.js';
+import {ref, toRefs, computed} from 'vue';
+
+/*
+ * @vue-prop {Array of Objects} dataSet - array of objects to be displayed
+ * @vue-prop {Array of Strings} headers - array of column headers
+ * @vue-prop {Number} rowsPerPage
+ * @vue-prop {String} title
+ * @vue-prop {Array of Strings} keyOrder - array of keys found in dataSet        
+ */
+export default {
+  name: 'PaginatedTable',
+  props: {
+    dataSet: {
+      type: Array,
+      required: true
+    },
+    headers: {
+      type: Array,
+      required: true
+    },
+    rowsPerPage: {
+      type: Number,
+      default: 16
+    },
+    title: {
+      type: String,
+      required: true
+    },
+    keyOrder: {
+      type: Array,
+      required: true
+    }
+  },
+
+  setup(props) {
+    const sortIconURL = `${config.STATIC_URL}img/sprite.svg#sort_arrow`;
+    const trackedData = toRefs(props).dataSet;
+    const trackedPagesPerRow = toRefs(props).rowsPerPage;
+    const trackedKeyOrder = toRefs(props).keyOrder;
+    const page = ref(1);
+    const sortOrder = ref('desc');
+    const sortTarget = ref(trackedKeyOrder.value[0]);
+
+    Array.prototype.objectSort = function(sortParameter) {
+      function compare(a, b) {
+        function isNumeric(num) {
+          return !isNaN(num);
+        }
+
+        let left = isNumeric(a[sortParameter]) ? +a[sortParameter] : a[sortParameter];
+        let right = isNumeric(b[sortParameter]) ? +b[sortParameter] : b[sortParameter];
+
+        if (left < right) {
+          return -1;
+        }
+        if (left > right) {
+          return 1;
+        }
+        return 0;
+      }
+      this.sort(compare);
+    };
+
+    const pagedArray = computed(() => {
+      let array = [];
+      let dataCopy = [...trackedData.value];
+      switch (sortOrder.value) {
+        case 'desc':
+          dataCopy.objectSort(sortTarget.value);
+          dataCopy.reverse();
+          break;
+        case 'asce':
+          dataCopy.objectSort(sortTarget.value);
+          break;
+      }
+      for (let i = 0; i < dataCopy.length; i += trackedPagesPerRow.value) {
+        array.push(dataCopy.slice(i, i + trackedPagesPerRow.value));
+      }
+      return array;
+    });
+    
+    return {
+      sortIconURL,
+      pagedArray,
+      data: pagedArray,
+      page,
+      myHeaders: toRefs(props).headers,
+      myTitle: toRefs(props).title,
+      myKeyOrder: toRefs(props).keyOrder,
+      sortOrder,
+      mySortTarget: sortTarget.value
+    };
+  }
+};
+</script>
\ No newline at end of file
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/parameter-selection.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/parameter-selection.test.js
index 4d74ce6dc592431b1963f576ef4d857652a9fa10..12565ea8c022f94619a618586ee07e4f77b83adf 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/parameter-selection.test.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/parameter-selection.test.js
@@ -1,5 +1,4 @@
 import {enableFetchMocks, disableFetchMocks} from 'jest-fetch-mock';
-import mockConsole from 'jest-mock-console';
 import {bindActionCreators} from 'redux';
 import ReduxConnectVue from 'redux-connect-vue';
 import {createStructuredSelector} from 'reselect';
@@ -17,6 +16,8 @@ import {TEST_PRIMARY_IV_DATA, TEST_HYDROGRAPH_PARAMETERS} from '../mock-hydrogra
 import MethodPicker from './method-picker.vue';
 import ParameterSelection from './parameter-selection.vue';
 import ParameterSelectionExpansionControl from './parameter-selection-expansion-control.vue';
+import SecondaryParameterControls from './secondary-parameter-controls.vue';
+
 
 describe('monitoring-location/components/hydrograph/vue-components/parameter-selection', () => {
     utils.mediaQuery = jest.fn().mockReturnValue(true);
@@ -47,6 +48,9 @@ describe('monitoring-location/components/hydrograph/vue-components/parameter-sel
         }
     };
 
+    config.SENSOR_THINGS_ENDPOINT = 'https://fake-sensor-things-endpoint';
+    config.IV_DATA_ENDPOINT = 'https://fake-iv-data-endpoint';
+
     const TEST_STATE = {
         hydrographData: {
             primaryIVData: TEST_PRIMARY_IV_DATA
@@ -59,15 +63,12 @@ describe('monitoring-location/components/hydrograph/vue-components/parameter-sel
         }
     };
 
-    let restoreConsole;
     beforeAll(() => {
         enableFetchMocks();
-        restoreConsole = mockConsole();
     });
 
     afterAll(() => {
         disableFetchMocks();
-        restoreConsole();
     });
 
     let retrieveHydrographDataSpy;
@@ -148,7 +149,7 @@ describe('monitoring-location/components/hydrograph/vue-components/parameter-sel
             .toBe('1980-03-31 to 2020-04-01');
 
         const expansionControls = wrapper.findAllComponents(ParameterSelectionExpansionControl);
-        expect(expansionControls).toHaveLength(4);
+        expect(expansionControls).toHaveLength(5);
         expect(expansionControls.find(control => control.props('parameterCode') === '62016')).toBeUndefined();
 
         const expansionControlOne = periodOfRecordContainers[0].findComponent(ParameterSelectionExpansionControl);
@@ -162,6 +163,8 @@ describe('monitoring-location/components/hydrograph/vue-components/parameter-sel
     });
 
     it('Expects that clicking on a row selects that parameter and closes any open row and opens that parameter\'s row', async() => {
+        fetch.mockResponse(JSON.stringify({}));
+
         const parameterRowContainers = wrapper.findAll('.parameter-row-container');
         await parameterRowContainers[0].find('.parameter-row-info-container').trigger('click');
 
@@ -172,6 +175,8 @@ describe('monitoring-location/components/hydrograph/vue-components/parameter-sel
     });
 
     it('Expects that clicking on a row updates the selected parameter code in the state and fetches new hydrograph data', async() => {
+        fetch.mockResponse(JSON.stringify({}));
+
         const parameterRowContainers = wrapper.findAll('.parameter-row-container');
         await parameterRowContainers[0].find('.parameter-row-info-container').trigger('click');
 
@@ -182,7 +187,7 @@ describe('monitoring-location/components/hydrograph/vue-components/parameter-sel
 
     it('Expects the expansion container to be only shown for the expanded row on', () => {
         const expansionContainers = wrapper.findAll('.expansion-container-row');
-        expect(expansionContainers).toHaveLength(4);
+        expect(expansionContainers).toHaveLength(5);
         expect(expansionContainers[0].isVisible()).toBe(false);
         expect(expansionContainers[1].isVisible()).toBe(true);
         expect(expansionContainers[2].isVisible()).toBe(false);
@@ -205,13 +210,6 @@ describe('monitoring-location/components/hydrograph/vue-components/parameter-sel
         expect(gwlevelsMethodPicker.attributes('sortedivmethods')).toBeDefined();
     });
 
-    it('Expects that clicking the expansion toggle in the selected row hides the expansion container', async() => {
-        const selectedExpansionToggle = wrapper.find('.selected').findComponent(ParameterSelectionExpansionControl);
-        await selectedExpansionToggle.vm.$emit('toggleExpansionRow', '72019', false);
-
-        expect(wrapper.find('#expansion-row-72019').isVisible()).toBe(false);
-    });
-
     it('Expects that clicking on a hidden expansion toggle shows the expansion container but does not change the selection', async() => {
         const expansionToggles = wrapper.findAllComponents(ParameterSelectionExpansionControl);
         await expansionToggles[0].vm.$emit('toggleExpansionRow', '00060', true);
@@ -223,10 +221,131 @@ describe('monitoring-location/components/hydrograph/vue-components/parameter-sel
         expect(parameterRows[1].classes()).toContain('selected');
     });
 
+
+    it('Expects that clicking the expansion toggle in the selected row hides the expansion container', async() => {
+        const selectedExpansionToggle = wrapper.find('.selected').findComponent(ParameterSelectionExpansionControl);
+        await selectedExpansionToggle.vm.$emit('toggleExpansionRow', '72019', false);
+
+        expect(wrapper.find('#expansion-row-72019').isVisible()).toBe(false);
+    });
+
     it('Expects that updated the selected method updates the store', async() => {
         const gwLevelMethodPicker = wrapper.find('#expansion-row-72019').findComponent(MethodPicker);
         await gwLevelMethodPicker.vm.$emit('selectMethod', '252055');
 
         expect(store.getState().hydrographState.selectedIVMethodID).toBe('252055');
     });
+
+    it('Expects that the second parameter selection component will show only on selected parameter row with the correct props', () => {
+        const parameterList =  [
+            {
+                'actionValue': {
+                    'secondaryParameterCode': '00060'
+                },
+                'checked': false,
+                'id': 'second-parameter-radio-button-00060',
+                'label': 'Discharge, cubic feet per second'
+            },
+            {
+                'actionValue': {
+                    'secondaryParameterCode': '62610'
+                },
+                'checked': false,
+                'id': 'second-parameter-radio-button-62610',
+                'label': 'Groundwater level above NGVD 1929, feet'
+            },
+            {
+                'actionValue': {
+                    'secondaryParameterCode': '00010'
+                },
+                'checked': false,
+                'id': 'second-parameter-radio-button-00010',
+                'label': 'Temperature, water, degrees Celsius'
+            },
+            {
+                'actionValue': {
+                    'secondaryParameterCode': '00010F'
+                },
+                'checked': false,
+                'id': 'second-parameter-radio-button-00010F',
+                'label': 'Temperature, water, degrees Fahrenheit'
+            }
+        ];
+
+        expect(wrapper.findAllComponents(SecondaryParameterControls)).toHaveLength(1);
+        const secondaryParameterControl = wrapper.findComponent(SecondaryParameterControls);
+        expect(secondaryParameterControl.props().parameterList).toStrictEqual(parameterList);
+    });
+
+    it('Expects that selecting a new parameter row will change the location of the second parameter selection component', async() => {
+        fetch.mockResponse(JSON.stringify({}));
+
+        const rowContainers = wrapper.findAll('.parameter-row-container');
+        expect(rowContainers).toHaveLength(5);
+        const rowForParameter00060 = rowContainers[0];
+        const rowForParameter72019 = rowContainers[1];
+
+        expect(rowForParameter00060.classes()).not.toContain('selected');
+        expect(rowForParameter00060.html()).not.toContain('secondary-parameter-controls-stub');
+        expect(rowForParameter72019.classes()).toContain('selected');
+        expect(rowForParameter72019.html()).toContain('secondary-parameter-controls-stub');
+
+        await rowForParameter00060.find('.parameter-row-info-container').trigger('click');
+        expect(rowForParameter00060.classes()).toContain('selected');
+        expect(rowForParameter00060.html()).toContain('secondary-parameter-controls-stub');
+        expect(rowForParameter72019.classes()).not.toContain('selected');
+        expect(rowForParameter72019.html()).not.toContain('secondary-parameter-controls-stub');
+    });
+
+    it('Expects that when SecondaryParameterControls emit a radio button event the parameter list changes', async() => {
+        fetch.mockResponse(JSON.stringify({}));
+
+        const parameterList = [
+            {
+                'actionValue': {
+                    'secondaryParameterCode': '72019'
+                },
+                'checked': false,
+                'id': 'second-parameter-radio-button-72019',
+                'label': 'Depth to water level, feet below land surface'
+            },
+            {
+                'actionValue': {
+                    'secondaryParameterCode': '62610'
+                },
+                'checked': true,
+                'id': 'second-parameter-radio-button-62610',
+                'label': 'Groundwater level above NGVD 1929, feet'
+            },
+            {
+                'actionValue': {
+                    'secondaryParameterCode': '00010'
+                },
+                'checked': false,
+                'id': 'second-parameter-radio-button-00010',
+                'label': 'Temperature, water, degrees Celsius'
+            },
+            {
+                'actionValue': {
+                    'secondaryParameterCode': '00010F'
+                },
+                'checked': false,
+                'id': 'second-parameter-radio-button-00010F',
+                'label': 'Temperature, water, degrees Fahrenheit'
+            }
+        ];
+
+        const rowContainers = wrapper.findAll('.parameter-row-container');
+        expect(rowContainers).toHaveLength(5);
+        const rowForParameter00060 = rowContainers[0];
+        const rowForParameter72019 = rowContainers[1];
+        expect(rowForParameter72019.classes()).toContain('selected');
+
+        expect(wrapper.findAllComponents(SecondaryParameterControls)).toHaveLength(1);
+        await wrapper.findComponent(SecondaryParameterControls).vm.$emit('checkedRadioButton', {'secondaryParameterCode': '62610'});
+        await rowForParameter00060.find('.parameter-row-info-container').trigger('click');
+
+        const secondaryParameterControl = wrapper.findComponent(SecondaryParameterControls);
+        expect(secondaryParameterControl.props().parameterList).toStrictEqual(parameterList);
+    });
 });
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/parameter-selection.vue b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/parameter-selection.vue
index 85ea87cc3c9b0f64381e84e07db37b4587bc9bfb..265a6ce829ea443d0492efc16000d12d31183e93 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/parameter-selection.vue
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/parameter-selection.vue
@@ -22,7 +22,6 @@
               {{ parameter.periodOfRecord.begin_date }} to {{ parameter.periodOfRecord.end_date }}
             </div>
             <ParameterSelectionExpansionControl
-              v-if="parameter.waterAlert.hasWaterAlert"
               :parameter-code="parameter.parameterCode"
               :is-expanded="parameter.parameterCode === expandedParameterCode"
               :id-for-expansion-row="`expansion-row-${parameter.parameterCode}`"
@@ -47,7 +46,6 @@
           </div>
         </div>
         <div
-          v-if="parameter.waterAlert.hasWaterAlert || (sortedIvMethods && parameter.parameterCode === sortedIvMethods.parameterCode && sortedIvMethods.length > 1)"
           v-show="parameter.parameterCode === expandedParameterCode"
           :id="`expansion-row-${parameter.parameterCode}`"
           class="expansion-container-row"
@@ -69,6 +67,15 @@
             :sorted-iv-methods="sortedIvMethods"
             @selectMethod="updateSelectedMethod"
           />
+
+          <SecondaryParameterControls
+            v-if="parameter.parameterCode === expandedParameterCode"
+            :parameter-list="secondaryParameterButtonList"
+            :is-show-second-parameter-options-checked="isShowSecondParameterOptionsChecked"
+            @checkedCheckBox="setCheckBoxStatus"
+            @checkedRadioButton="setRadioButtonStatus"
+            @disableEnableMedianAndCompare="disableEnableMedianAndCompare"
+          />
         </div>
       </div>
     </div>
@@ -78,7 +85,7 @@
 <script>
 import {useActions, useState} from 'redux-connect-vue';
 import {createSelector} from 'reselect';
-import {inject, ref} from 'vue';
+import {inject, ref, computed} from 'vue';
 
 import config from 'ui/config';
 
@@ -94,12 +101,14 @@ import {showDataIndicators} from '../data-indicator';
 
 import MethodPicker from './method-picker.vue';
 import ParameterSelectionExpansionControl from './parameter-selection-expansion-control.vue';
+import SecondaryParameterControls from './secondary-parameter-controls.vue';
 
 export default {
   name: 'ParameterSelection',
   components: {
     MethodPicker,
-    ParameterSelectionExpansionControl
+    ParameterSelectionExpansionControl,
+    SecondaryParameterControls
   },
   setup() {
     const reduxStore = inject('store');
@@ -109,19 +118,20 @@ export default {
     const expandedParameterCode = ref(getSelectedParameterCode(reduxStore.getState()));
 
     const getAvailableParameterData = createSelector(
-      getAvailableParameters,
-      (parameters) => {
-        return parameters.map((parameter) => {
-          const parameterForWaterAlertUrl = parameter.parameterCode.includes(config.CALCULATED_TEMPERATURE_VARIABLE_CODE) ?
-            parameter.parameterCode.replace(config.CALCULATED_TEMPERATURE_VARIABLE_CODE) : parameter.parameterCode;
-          return {
-            ...parameter,
-            waterAlertUrl: parameter.waterAlert.hasWaterAlert ?
-              `${config.WATERALERT_SUBSCRIPTION}/?site_no=${siteno}&parm=${parameterForWaterAlertUrl}` : ''
-          };
-        });
-      }
+        getAvailableParameters,
+        (parameters) => {
+          return parameters.map((parameter) => {
+            const parameterForWaterAlertUrl = parameter.parameterCode.includes(config.CALCULATED_TEMPERATURE_VARIABLE_CODE) ?
+                parameter.parameterCode.replace(config.CALCULATED_TEMPERATURE_VARIABLE_CODE) : parameter.parameterCode;
+            return {
+              ...parameter,
+              waterAlertUrl: parameter.waterAlert.hasWaterAlert ?
+                  `${config.WATERALERT_SUBSCRIPTION}/?site_no=${siteno}&parm=${parameterForWaterAlertUrl}` : ''
+            };
+          });
+        }
     );
+
     const state = useState({
       parameters: getAvailableParameterData,
       sortedIvMethods: getSortedIVMethods,
@@ -134,23 +144,71 @@ export default {
       retrieveHydrographData
     });
 
+    // Second parameter selection code
+    const selectedSecondaryParameter = ref('');
+    const showSecondParameterList = ref(false);
+
+    const isShowSecondParameterOptionsChecked = ref(false);
+    const setCheckBoxStatus = function() {
+      isShowSecondParameterOptionsChecked.value = !isShowSecondParameterOptionsChecked.value;
+    };
+
+    let parameterCodeOfSecondaryRadioButton = '';
+    const setRadioButtonStatus = function(buttonData) {
+      parameterCodeOfSecondaryRadioButton = buttonData.secondaryParameterCode;
+    };
+
+    const secondaryParameterButtonList = computed(() => {
+      const radioButtonList = [];
+      state.parameters.value.forEach((parameter) => {
+        if (parameter.parameterCode !== expandedParameterCode.value) {
+          const buttonDetail = {
+            id: `second-parameter-radio-button-${parameter.parameterCode}`,
+            label: parameter.description,
+            checked: parameterCodeOfSecondaryRadioButton === parameter.parameterCode,
+            actionValue: {
+              secondaryParameterCode: parameter.parameterCode
+            }
+          };
+          radioButtonList.push(buttonDetail);
+        }
+      });
+
+      return radioButtonList;
+    });
+
+    // TODO: when graph-controls and parameter-selection are part of the same app, use Vue to control elements
+    const compareToLastYearCheckBox = document.querySelector('#iv-compare-timeseries-checkbox');
+    const medianCheckBox = document.querySelector('#iv-median-timeseries-checkbox');
+    const disableEnableMedianAndCompare = function(isEnabled) {
+      compareToLastYearCheckBox.disabled = isEnabled;
+      medianCheckBox.disabled = isEnabled;
+    };
+
+    // Primary parameter selection code
     function toggleExpansionRow(parameterCode, expandRow) {
-        expandedParameterCode.value = expandRow ? parameterCode : '';
+      expandedParameterCode.value = expandRow ? parameterCode : '';
     }
 
     function selectParameter(parameterCode) {
+      if (parameterCodeOfSecondaryRadioButton === expandedParameterCode.value) {
+        isShowSecondParameterOptionsChecked.value = false;
+        // TODO: Hide second parameter visibility -- perhaps as part of WDFN-732
+        console.log(`Primary button clicked, ${parameterCode}, is same as secondary selection. Remove second parameter from graph`);
+      }
+
       actions.setSelectedParameterCode(parameterCode);
       expandedParameterCode.value = parameterCode;
 
       showDataIndicators(true, reduxStore);
       actions.retrieveHydrographData(siteno, agencyCode, getInputsForRetrieval(reduxStore.getState()), true)
-        .then(() => {
-          const sortedMethods = getSortedIVMethods(reduxStore.getState());
+          .then(() => {
+            const sortedMethods = getSortedIVMethods(reduxStore.getState());
             if (sortedMethods && sortedMethods.methods.length) {
               actions.setSelectedIVMethodID(sortedMethods.methods[0].methodID);
             }
             showDataIndicators(false, reduxStore);
-        });
+          });
     }
 
     function updateSelectedMethod(methodId) {
@@ -160,7 +218,14 @@ export default {
     return {
       ...state,
       expandedParameterCode,
+      disableEnableMedianAndCompare,
+      isShowSecondParameterOptionsChecked,
+      secondaryParameterButtonList,
       selectParameter,
+      selectedSecondaryParameter,
+      setCheckBoxStatus,
+      setRadioButtonStatus,
+      showSecondParameterList,
       toggleExpansionRow,
       updateSelectedMethod
     };
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/secondary-parameter-controls.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/secondary-parameter-controls.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ceb186a8e1fb7c1a91b0c571b8e7f5848afeecb
--- /dev/null
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/secondary-parameter-controls.test.js
@@ -0,0 +1,148 @@
+import {shallowMount} from '@vue/test-utils';
+
+import USWDSCheckbox from 'ui/uswds-components/checkbox.vue';
+import USWDSRadioButtonSet from 'ui/uswds-components/radio-button-set.vue';
+
+import SecondaryParameterControls from './secondary-parameter-controls.vue';
+import ReduxConnectVue from 'redux-connect-vue';
+import {bindActionCreators} from 'redux';
+import {createStructuredSelector} from 'reselect';
+import {TEST_HYDROGRAPH_PARAMETERS, TEST_PRIMARY_IV_DATA} from '../mock-hydrograph-state';
+import {configureStore} from 'ml/store';
+
+
+
+describe('monitoring-location/components/hydrograph/vue-components/secondary-parameter-controls', () => {
+    const parameterList =  [
+        {
+            'actionValue': {
+                'secondaryParameterCode': '00060'
+            },
+            'checked': false,
+            'id': 'second-parameter-radio-button-00060',
+            'label': 'Discharge, cubic feet per second'
+        },
+        {
+            'actionValue': {
+                'secondaryParameterCode': '62610'
+            },
+            'checked': false,
+            'id': 'second-parameter-radio-button-62610',
+            'label': 'Groundwater level above NGVD 1929, feet'
+        }
+    ];
+
+    let wrapper;
+    let store;
+
+    const TEST_STATE = {
+        hydrographData: {
+            primaryIVData: TEST_PRIMARY_IV_DATA
+        },
+        hydrographParameters: TEST_HYDROGRAPH_PARAMETERS,
+        hydrographState: {
+            selectedTimeSpan: 'P7D',
+            selectedParameterCode: '72019',
+            selectedIVMethodID: '90649'
+        }
+    };
+
+    describe('tests with check box checked', () => {
+        beforeEach(() => {
+            store = configureStore(TEST_STATE);
+            wrapper = shallowMount(SecondaryParameterControls, {
+                global: {
+                    plugins: [
+                        [ReduxConnectVue, {
+                            store,
+                            mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
+                            mapStateToPropsFactory: createStructuredSelector
+                        }]
+                    ],
+                    provide: {
+                        store: store
+                    }
+                },
+                props: {
+                    parameterList: parameterList,
+                    isShowSecondParameterOptionsChecked: true
+                }
+            });
+        });
+
+        it('expects radio buttons will show if checkbox checked', () => {
+            expect(wrapper.findAllComponents(USWDSCheckbox)).toHaveLength(1);
+            expect(wrapper.findAllComponents(USWDSRadioButtonSet)).toHaveLength(1);
+        });
+
+        it('expects radio buttons will have correct props', () => {
+            expect(wrapper.findAllComponents(USWDSCheckbox)).toHaveLength(1);
+            expect(wrapper.findAllComponents(USWDSRadioButtonSet)).toHaveLength(1);
+
+            const radioButtonSet = wrapper.findComponent(USWDSRadioButtonSet);
+            expect(radioButtonSet.props('buttonList')).toBe(parameterList);
+            expect(radioButtonSet.props('buttonSetName')).toBe('second-parameter-radio-button-set');
+            expect(radioButtonSet.props('legendText')).toBe('Available secondary data types');
+        });
+
+        it('expects unchecking check box will emit correct events and payload', async() => {
+            const checkboxComponent = wrapper.findComponent(USWDSCheckbox);
+            await checkboxComponent.vm.$emit('toggleCheckbox');
+
+            expect(wrapper.emitted().disableEnableMedianAndCompare[0][0]).toBe( false);
+            expect(wrapper.emitted().checkedRadioButton[0][0]).toStrictEqual({
+                secondaryParameterCode: ''
+            });
+            expect(wrapper.emitted().checkedCheckBox[0][0]).not.toBeTruthy();
+        });
+
+        it('expects clicking a radio button will emit the correct event', async() => {
+            const radioButtonSetComponent = wrapper.findComponent(USWDSRadioButtonSet);
+
+            await radioButtonSetComponent.vm.$emit('updateValue', {
+                'secondaryParameterCode': '62610'
+            });
+
+            expect(wrapper.emitted().disableEnableMedianAndCompare[0][0]).toBe( true);
+            expect(wrapper.emitted().checkedRadioButton[0][0]).toStrictEqual( {'secondaryParameterCode': '62610'});
+        });
+    });
+
+    describe('tests with check box not checked', () => {
+        beforeEach(() => {
+            store = configureStore(TEST_STATE);
+            wrapper = shallowMount(SecondaryParameterControls, {
+                global: {
+                    plugins: [
+                        [ReduxConnectVue, {
+                            store,
+                            mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
+                            mapStateToPropsFactory: createStructuredSelector
+                        }]
+                    ],
+                    provide: {
+                        store: store
+                    }
+                },
+                props: {
+                    parameterList: parameterList,
+                    isShowSecondParameterOptionsChecked: false
+                }
+            });
+        });
+
+        it('Expects radio buttons will not show if checkbox not checked', () => {
+            expect(wrapper.findAllComponents(USWDSCheckbox)).toHaveLength(1);
+            expect(wrapper.findAllComponents(USWDSRadioButtonSet)).toHaveLength(0);
+        });
+
+        it('expects checking check box will emit correct events and payload', async() => {
+            const checkboxComponent = wrapper.findComponent(USWDSCheckbox);
+
+            await checkboxComponent.vm.$emit('toggleCheckbox');
+            expect(wrapper.emitted('disableEnableMedianAndCompare')).not.toBeTruthy();
+            expect(wrapper.emitted('checkedRadioButton')).not.toBeTruthy();
+            expect(wrapper.emitted().checkedCheckBox[0][0]).toBe(true);
+        });
+    });
+});
\ No newline at end of file
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/secondary-parameter-controls.vue b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/secondary-parameter-controls.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a45a637fa644c1e4a763512c8c341da9a947e909
--- /dev/null
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/secondary-parameter-controls.vue
@@ -0,0 +1,93 @@
+<template>
+  <div>
+    <USWDSCheckbox
+      id="checkbox-show-second-parameter"
+      label="Select data to graph on second x-axis"
+      name="second-parameter-checkbox"
+      value="graphSecondParameter"
+      :is-checked="isShowSecondParameterOptionsChecked"
+      @toggleCheckbox="showSecondParameterOptions"
+    />
+
+    <USWDSRadioButtonSet
+      v-if="isShowSecondParameterOptionsChecked"
+      button-set-name="second-parameter-radio-button-set"
+      legend-text="Available secondary data types"
+      :button-list="parameterList"
+      @updateValue="graphSecondParameter"
+    />
+  </div>
+</template>
+
+<script>
+import {ref} from 'vue';
+
+import {useActions} from 'redux-connect-vue';
+import {setCompareDataVisibility, setMedianDataVisibility} from 'ml/store/hydrograph-state';
+
+import USWDSCheckbox from 'ui/uswds-components/checkbox.vue';
+import USWDSRadioButtonSet from 'ui/uswds-components/radio-button-set.vue';
+
+
+export default {
+  name: 'SecondaryParameterControls',
+  components: {
+    USWDSCheckbox,
+    USWDSRadioButtonSet
+  },
+  props: {
+    parameterList: {
+      type: Object,
+      required: true
+    },
+    isShowSecondParameterOptionsChecked: {
+      type: Boolean,
+      required: true
+    }
+  },
+  setup(props, {emit}) {
+    const actions = useActions({
+      setCompareDataVisibility,
+      setMedianDataVisibility
+    });
+
+    const showSecondParameterList = ref(false);
+
+    const showSecondParameterOptions = function() {
+      showSecondParameterList.value = !showSecondParameterList.value;
+      const isBoxChecked =  !props.isShowSecondParameterOptionsChecked;
+
+      if (!isBoxChecked) {
+        emit('disableEnableMedianAndCompare', false);
+        emit('checkedRadioButton', {
+          secondaryParameterCode: ''
+        });
+        // TODO: Hide second parameter visibility -- perhaps as part of WDFN-732
+        console.log('check box unchecked: clear any second parameter data from graph ');
+      }
+
+      emit('checkedCheckBox', isBoxChecked);
+    };
+
+    const disableCompareAndMedianButtons = function() {
+      actions.setCompareDataVisibility(false);
+      actions.setMedianDataVisibility(false);
+      emit('disableEnableMedianAndCompare', true);
+    };
+
+    const graphSecondParameter = function(buttonData) {
+      disableCompareAndMedianButtons();
+      emit('checkedRadioButton', buttonData);
+      // TODO: Add data to state -- part of WDFN-735
+      // TODO: Graph data on hydrograph -- part of WDFN-735
+      console.log(`Radio button, ${buttonData.secondaryParameterCode} clicked: fetch data and then run graphing code using secondary parameter ${buttonData.secondaryParameterCode}`);
+     };
+
+    return {
+      showSecondParameterList,
+      showSecondParameterOptions,
+      graphSecondParameter
+    };
+  }
+};
+</script>
\ No newline at end of file
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/statistics-table.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/statistics-table.test.js
index b35e4b402c54cb2b6ae94f347709254200c55a4e..c7730945bb9e4397360fb69a44951db2fcebd185 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/statistics-table.test.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/statistics-table.test.js
@@ -1,5 +1,3 @@
-import {enableFetchMocks, disableFetchMocks} from 'jest-fetch-mock';
-import mockConsole from 'jest-mock-console';
 import {bindActionCreators} from 'redux';
 import ReduxConnectVue from 'redux-connect-vue';
 import {createStructuredSelector} from 'reselect';
@@ -7,25 +5,14 @@ import {mount} from '@vue/test-utils';
 
 import {configureStore} from 'ml/store';
 
-import StatisticsTableApp from './statistics-table.vue';
+import StatisticsTable from './statistics-table.vue';
 import {TEST_STATS_DATA} from '../mock-hydrograph-state';
 
 describe('monitoring-location/components/hydrograph/statistics', () => {
 
-    describe('Cases with data available', () => {
-        let restoreConsole;
-        var store;
-        var wrapper;
-        
-        beforeAll(() => {
-            enableFetchMocks();
-            restoreConsole = mockConsole();
-        });
-
-        afterAll(() => {
-            disableFetchMocks();
-            restoreConsole();
-        });
+    describe('Cases with multiple methods available', () => {
+        let store;
+        let wrapper;
 
         beforeEach(() => {
             jest.useFakeTimers('modern');
@@ -54,7 +41,7 @@ describe('monitoring-location/components/hydrograph/statistics', () => {
                 }
             });
 
-            wrapper = mount(StatisticsTableApp, {
+            wrapper = mount(StatisticsTable, {
                 global: {
                     plugins: [
                         [ReduxConnectVue, {
@@ -84,7 +71,89 @@ describe('monitoring-location/components/hydrograph/statistics', () => {
         });
 
         it('Expects the table to have headers', () => {
-            let tableHeaders = wrapper.find('thead').find('tr').findAll('tr > th');
+            const tableHeaders = wrapper.find('thead').find('tr').findAll('tr > th');
+            expect(tableHeaders).toHaveLength(6);
+            expect(tableHeaders[0].text()).toBe('Lowest Value (2006)');
+            expect(tableHeaders[1].text()).toBe('25th Percentile');
+            expect(tableHeaders[2].text()).toBe('Median');
+            expect(tableHeaders[3].text()).toBe('75th Percentile');
+            expect(tableHeaders[4].text()).toBe('Mean');
+            expect(tableHeaders[5].text()).toBe('Highest Value (2020)');
+        });
+
+        it('Expects the table to have data in it', () => {
+            const tableHeaders = wrapper.find('tbody').find('tr').findAll('tr > th');
+            expect(tableHeaders).toHaveLength(6);
+            expect(tableHeaders[0].text()).toBe('550.5');
+            expect(tableHeaders[1].text()).toBe('1000');
+            expect(tableHeaders[2].text()).toBe('160');
+            expect(tableHeaders[3].text()).toBe('2240');
+            expect(tableHeaders[4].text()).toBe('1530');
+            expect(tableHeaders[5].text()).toBe('2730');
+        });
+    });
+
+    describe('Cases with one method available', () => {
+        let store;
+        let wrapper;
+
+        beforeEach(() => {
+            jest.useFakeTimers('modern');
+            jest.setSystemTime(new Date(2020, 0, 1));
+
+            store = configureStore({
+                hydrographData: {
+                    statisticsData: {'153885' : TEST_STATS_DATA['153885']},
+                    primaryIVData: {
+                        parameter: {
+                            parameterCode: '153885',
+                            name: 'Test Name'
+                        },
+                        values: {}
+                    }
+                },
+                hydrographParameters: {
+                    '153885': {
+                        parameterCode: '153885',
+                        name: 'Test Name',
+                        latestValue: '25.9'
+                    }
+                },
+                hydrographState: {
+                    selectedParameterCode: '153885'
+                }
+            });
+
+            wrapper = mount(StatisticsTable, {
+                global: {
+                    plugins: [
+                        [ReduxConnectVue, {
+                            store,
+                            mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
+                            mapStateToPropsFactory: createStructuredSelector
+                        }]
+                    ]
+                }
+            });
+        });
+
+        afterEach(() => {
+            jest.useRealTimers();
+        });
+
+        it('Displays the accordion', () => {
+            expect(wrapper.find('.stats-accordion').isVisible()).toBe(true);
+        });
+
+        it('Creates multiple tables', () => {
+            const captions = wrapper.findAll('caption');
+            expect(wrapper.findAll('#daily-stats-tables div')).toHaveLength(1);
+            expect(captions).toHaveLength(1);
+            expect(captions[0].text()).toContain('Test Name (Method1)');
+        });
+
+        it('Expects the table to have headers', () => {
+            const tableHeaders = wrapper.find('thead').find('tr').findAll('tr > th');
             expect(tableHeaders).toHaveLength(7);
             expect(tableHeaders[0].text()).toBe('Latest Value');
             expect(tableHeaders[1].text()).toBe('Lowest Value (2006)');
@@ -96,33 +165,22 @@ describe('monitoring-location/components/hydrograph/statistics', () => {
         });
 
         it('Expects the table to have data in it', () => {
-            let tableHeaders = wrapper.find('tbody').find('tr').findAll('tr > th');
+            const tableHeaders = wrapper.find('tbody').find('tr').findAll('tr > th');
             expect(tableHeaders).toHaveLength(7);
             expect(tableHeaders[0].text()).toBe('25.9');
-            expect(tableHeaders[1].text()).toBe('550.5');
-            expect(tableHeaders[2].text()).toBe('1000');
-            expect(tableHeaders[3].text()).toBe('160');
-            expect(tableHeaders[4].text()).toBe('2240');
-            expect(tableHeaders[5].text()).toBe('1530');
-            expect(tableHeaders[6].text()).toBe('2730');
+            expect(tableHeaders[1].text()).toBe('55.5');
+            expect(tableHeaders[2].text()).toBe('100');
+            expect(tableHeaders[3].text()).toBe('16');
+            expect(tableHeaders[4].text()).toBe('224');
+            expect(tableHeaders[5].text()).toBe('153');
+            expect(tableHeaders[6].text()).toBe('273');
         });
 
     });
 
     describe('Cases with no stats data available', () => {
-        let restoreConsole;
-        var store;
-        var wrapper;
-        
-        beforeAll(() => {
-            enableFetchMocks();
-            restoreConsole = mockConsole();
-        });
-
-        afterAll(() => {
-            disableFetchMocks();
-            restoreConsole();
-        });
+        let store;
+        let wrapper;
 
         beforeEach(() => {
             jest.useFakeTimers('modern');
@@ -142,7 +200,7 @@ describe('monitoring-location/components/hydrograph/statistics', () => {
                 }
             });
 
-            wrapper = mount(StatisticsTableApp, {
+            wrapper = mount(StatisticsTable, {
                 global: {
                     plugins: [
                         [ReduxConnectVue, {
@@ -165,19 +223,8 @@ describe('monitoring-location/components/hydrograph/statistics', () => {
     });
 
     describe('Cases with no latest value available', () => {
-        let restoreConsole;
-        var store;
-        var wrapper;
-        
-        beforeAll(() => {
-            enableFetchMocks();
-            restoreConsole = mockConsole();
-        });
-
-        afterAll(() => {
-            disableFetchMocks();
-            restoreConsole();
-        });
+        let store;
+        let wrapper;
 
         beforeEach(() => {
             jest.useFakeTimers('modern');
@@ -196,7 +243,7 @@ describe('monitoring-location/components/hydrograph/statistics', () => {
                 }
             });
 
-            wrapper = mount(StatisticsTableApp, {
+            wrapper = mount(StatisticsTable, {
                 global: {
                     plugins: [
                         [ReduxConnectVue, {
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/statistics-table.vue b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/statistics-table.vue
index fc8d6706a4b8f1f2b25218eba42983da9558f6b9..6f5d1fadd6c1b7606592f5a0db255856df270fe1 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/statistics-table.vue
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/statistics-table.vue
@@ -73,6 +73,7 @@ import {getDailyStatistics} from 'ml/components/hydrograph/selectors/statistics'
 import {latestSelectedParameterValue} from 'ml/selectors/hydrograph-parameters-selector';
 
 export default {
+  name: 'StatisticsTable',
   setup() {
     const COLUMN_HEADINGS = ['Latest Value', 'Lowest Value', '25th Percentile', 'Median', '75th Percentile', 'Mean', 'Highest Value'];
     const DATA_HEADINGS = ['min_va', 'p25_va', 'p50_va', 'p75_va', 'mean_va', 'max_va'];
@@ -86,14 +87,16 @@ export default {
           return [];
         }
 
+        const isOnlyOneMethod = dailyStatsObjectArray.length === 1;
+
         return dailyStatsObjectArray.map(dailyStatsObject => {
           let columnHeadings = [...COLUMN_HEADINGS];
           let dailyStatsArray = DATA_HEADINGS.map((key) => dailyStatsObject[key]);
           columnHeadings[1] = `${COLUMN_HEADINGS[1]} (${dailyStatsObject['min_va_yr']})`;
           columnHeadings[6] = `${COLUMN_HEADINGS[6]} (${dailyStatsObject['max_va_yr']})`;
           return {
-            tableData: [latestValue, ...dailyStatsArray],
-            columnHeadings: columnHeadings,
+            tableData: isOnlyOneMethod ? [latestValue, ...dailyStatsArray] : dailyStatsArray,
+            columnHeadings: isOnlyOneMethod ? columnHeadings : columnHeadings.slice(1),
             yearCount: dailyStatsObject['count_nu'],
             location_description: dailyStatsObject['loc_web_ds']
           };
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/time-span-shortcuts.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/time-span-shortcuts.test.js
index 8c86b215dc749de59fb1447a2f258dd0865a5cba..6fe1374a5c593f2a063f84dcae028a440a11939f 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/time-span-shortcuts.test.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/time-span-shortcuts.test.js
@@ -122,6 +122,54 @@ describe('monitoring-location/components/hydrograph/components/graph-controls',
         expect(labels[2].text()).toBe('1 year');
     });
 
+    it('Expects to render the shortcut radio buttons and check the 7 day radio button with a calculated temperature parameter code', () => {
+        store = configureStore({
+            hydrographState: {
+                showCompareIVData: false,
+                selectedTimeSpan: 'P7D',
+                showMedianData: false,
+                selectedParameterCode: '00010F'
+            }
+        });
+
+        wrapper = mount(TimeSpanShortcuts, {
+            global: {
+                plugins: [
+                    [ReduxConnectVue, {
+                        store,
+                        mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
+                        mapStateToPropsFactory: createStructuredSelector
+                    }]
+                ],
+                provide: {
+                    store: store,
+                    siteno: '11112222',
+                    agencyCd: 'USGS'
+                }
+            }
+        });
+
+        const radio7Day = wrapper.find('#P7D-input');
+        const radio30Day = wrapper.find('#P30D-input');
+        const radio1Year = wrapper.find('#P365D-input');
+        const labels = wrapper.findAll('.usa-radio__label');
+
+        expect(wrapper.findAll('.iv-button-container')).toHaveLength(1);
+        expect(wrapper.findAll('.gw-button-container')).toHaveLength(0);
+
+        expect(radio7Day.attributes('value')).toBe('P7D');
+        expect(radio7Day.element.checked).toBe(true);
+        expect(labels[0].text()).toBe('7 days');
+
+        expect(radio30Day.attributes('value')).toBe('P30D');
+        expect(radio30Day.element.checked).toBe(false);
+        expect(labels[1].text()).toBe('30 days');
+
+        expect(radio1Year.attributes('value')).toBe('P365D');
+        expect(radio1Year.element.checked).toBe(false);
+        expect(labels[2].text()).toBe('1 year');
+    });
+
     it('Expects that if the selectedTimeSpan is changed to a days before that is not a shortcut, they are all unset', async() => {
         store.dispatch(setSelectedTimeSpan('P45D'));
         await wrapper.vm.$nextTick();
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/time-span-shortcuts.vue b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/time-span-shortcuts.vue
index 2fb202f9b20a0c22df93d6e092be7df7ecaed3cd..af2babd7aac3ac38615640a8c73c44165bfd0fce 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/time-span-shortcuts.vue
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/time-span-shortcuts.vue
@@ -76,14 +76,14 @@ export default {
     const hasIVData = createSelector(
       getSelectedParameterCode,
       (parameterCode) => {
-        return config.ivPeriodOfRecord && parameterCode in config.ivPeriodOfRecord;
+        return config.ivPeriodOfRecord && parameterCode.replace(config.CALCULATED_TEMPERATURE_VARIABLE_CODE, '') in config.ivPeriodOfRecord;
       }
     );
 
     const hasGWData = createSelector(
       getSelectedParameterCode,
       (parameterCode) => {
-        return config.gwPeriodOfRecord && parameterCode in config.gwPeriodOfRecord;
+        return config.gwPeriodOfRecord && parameterCode.replace(config.CALCULATED_TEMPERATURE_VARIABLE_CODE, '') in config.gwPeriodOfRecord;
       }
     );
     
diff --git a/assets/src/scripts/monitoring-location/store/hydrograph-data.js b/assets/src/scripts/monitoring-location/store/hydrograph-data.js
index 4990f577500c080b6d9a4495887ca1f36b811817..30a6be974d33b91aa0d7afb7be61efb0c89fe711 100644
--- a/assets/src/scripts/monitoring-location/store/hydrograph-data.js
+++ b/assets/src/scripts/monitoring-location/store/hydrograph-data.js
@@ -130,7 +130,7 @@ const retrieveIVData = function(siteno, dataKind, {parameterCode, period, startT
                     parameter = getConvertedTemperatureParameter(parameter);
                 }
 
-                // The 'code' for no data value come from the web service as a number but the point values come
+                // The 'code' for no data value comes from the web service as a number, but the point values come
                 // as strings, so convert it to a string like the point values and let JavaScript compare them.
                 const noDataValue = tsData.variable.noDataValue.toString();
 
@@ -254,7 +254,7 @@ export const retrieveStatistics = function(siteno, parameterCode) {
 /**
  * Removes the unneeded data from Sensor Things and returns only the essential information for thresholds
  * @param {Object} properties - Complex object containing threshold data along with unneeded data returned from Sensor Things
- * @return {Object} A well organised object containg threshold information
+ * @return {Object} A well organised object containing threshold information
  */
 const cleanThresholdData = function(properties) {
     const THRESHOLD_CODES = ['Operational limit - low-Public', 'Operational limit - high-Public'];
diff --git a/assets/src/scripts/uswds-components/radio-button-set.test.js b/assets/src/scripts/uswds-components/radio-button-set.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..fbdebc46cc726903c9f232efbcccc2da998d43d5
--- /dev/null
+++ b/assets/src/scripts/uswds-components/radio-button-set.test.js
@@ -0,0 +1,86 @@
+import {shallowMount} from '@vue/test-utils';
+
+import RadioButtonSet from './radio-button-set.vue';
+
+describe('components/radio-button-set', () => {
+    it('expects the buttons will match the props passed in', () => {
+        const buttonList = [
+            {
+                id: 'button-one',
+                label: 'Button one - choose me!',
+                checked: true,
+                actionValue: 'button one clicked'
+            },
+            {
+                id: 'button-two',
+                label: 'Button two - no, choose me!',
+                checked: false,
+                actionValue: 'button two clicked'
+            }
+        ];
+
+        const wrapper = shallowMount(RadioButtonSet, {
+            props: {
+                'buttonSetName': 'test-set',
+                'buttonList': buttonList,
+                'legendText': 'A set of radio buttons'
+            }
+        });
+
+        expect(wrapper.findAll('.usa-radio')).toHaveLength(2);
+        const buttonOne = wrapper.findAll('.usa-radio').at(0);
+        const buttonTwo = wrapper.findAll('.usa-radio').at(1);
+        expect(buttonOne.attributes('checked')).valueOf(true);
+        expect(buttonTwo.attributes('checked')).valueOf(false);
+
+        expect(wrapper.findAll('input')).toHaveLength(2);
+        const buttonInputOne = wrapper.findAll('input')[0];
+        const buttonInputTwo = wrapper.findAll('input')[1];
+        expect(buttonInputOne.attributes('id')).valueOf('button-one');
+        expect(buttonInputTwo.attributes('id')).valueOf('button-two');
+        expect(buttonInputOne.attributes('name')).valueOf('test-set');
+        expect(buttonInputTwo.attributes('name')).valueOf('test-set');
+
+        expect(wrapper.findAll('legend')).toHaveLength(1);
+        expect(wrapper.findAll('legend')[0].text()).toBe('A set of radio buttons');
+    });
+
+    it('expects the buttons will emit the correct events', async() => {
+        const buttonList = [
+            {
+                id: 'button-one',
+                label: 'Button one - choose me!',
+                checked: true,
+                actionValue: 'button one clicked'
+            },
+            {
+                id: 'button-two',
+                label: 'Button two - no, choose me!',
+                checked: false,
+                actionValue: 'button two clicked'
+            }
+        ];
+
+        const wrapper = shallowMount(RadioButtonSet, {
+            props: {
+                'buttonSetName': 'test-set',
+                'buttonList': buttonList,
+                'legendText': 'A set of radio buttons'
+            }
+        });
+
+        expect(wrapper.findAll('input')).toHaveLength(2);
+
+        const buttonOne = wrapper.findAll('input')[0];
+        const buttonTwo = wrapper.findAll('input')[1];
+
+        await buttonOne.trigger('click');
+        await wrapper.vm.$nextTick();
+        expect(wrapper.emitted().updateValue).toBeTruthy();
+        expect(wrapper.emitted().updateValue).toEqual([['button one clicked']]);
+
+        await buttonTwo.trigger('click');
+        await wrapper.vm.$nextTick();
+        expect(wrapper.emitted().updateValue).toEqual([['button one clicked'], ['button two clicked']]);
+    });
+});
diff --git a/assets/src/scripts/uswds-components/radio-button-set.vue b/assets/src/scripts/uswds-components/radio-button-set.vue
new file mode 100644
index 0000000000000000000000000000000000000000..78867b1e75fd613791abda61a3321f47190d14c3
--- /dev/null
+++ b/assets/src/scripts/uswds-components/radio-button-set.vue
@@ -0,0 +1,72 @@
+<template>
+  <div class="radio-button-set">
+    <fieldset class="usa-fieldset">
+      <legend class="usa-legend">
+        {{ legendText }}
+      </legend>
+      <div
+        v-for="item in buttonList"
+        :key="item.id"
+        class="usa-radio"
+      >
+        <input
+          :id="item.id"
+          class="usa-radio__input"
+          type="radio"
+          :name="buttonSetName"
+          :checked="item.checked"
+          @click="updateValue(item.actionValue)"
+        >
+        <label
+          class="usa-radio__label"
+          :for="item.id"
+        >
+          {{ item.label }}
+        </label>
+      </div>
+    </fieldset>
+  </div>
+</template>
+
+<script>
+/*
+* Renders a generic radio button set
+* @vue-prop {String} buttonSetName - must be unique for each set
+* @vue-prop {Array} buttonList - an array of objects with details about each button in the set
+*   each button object must contain the following values:
+*    {
+*         id: {String} unique to each button,
+*         label: {String} the label for the button,
+*         checked: {Boolean} if the button is checked at start (only use true on one button),
+*         actionValue: {String} Value that the clicked button will return to the parent component
+*    }
+* @vue-prop {String} legendText - The text which will be put into the legend text
+* @vue-event updateValue - passes the actionValue of the radio button clicked
+*/
+export default {
+  name: 'RadioButtonSet',
+  props: {
+    buttonSetName: {
+      type: String,
+      required: true
+    },
+    buttonList: {
+      type: Array,
+      required: true
+    },
+    legendText: {
+      type: String,
+      default: ''
+    }
+  },
+  setup(props, {emit}) {
+    const updateValue = function(value) {
+      emit('updateValue', value);
+    };
+
+    return {
+      updateValue
+    };
+  }
+};
+</script>
diff --git a/assets/src/styles/monitoring-location.scss b/assets/src/styles/monitoring-location.scss
index c45594af0b4c1d9b821e7db5b4ba04beccb8aa55..c11a8fcd9e12499f79d947a8bfae55f30e943384 100644
--- a/assets/src/styles/monitoring-location.scss
+++ b/assets/src/styles/monitoring-location.scss
@@ -26,6 +26,7 @@
 @forward 'usa-select';
 @forward 'usa-tag';
 @forward 'usa-tooltip';
+@forward 'usa-pagination';
 
 @use './components/dv-hydrograph';
 @use './components/hydrograph/app';
diff --git a/assets/src/styles/partials/_parameter-list.scss b/assets/src/styles/partials/_parameter-list.scss
index 9731e34e5ecee5e00bd319356cbe61c9b7f31ae0..25a740c3ad3e54242341331c4df2a22326af7574 100644
--- a/assets/src/styles/partials/_parameter-list.scss
+++ b/assets/src/styles/partials/_parameter-list.scss
@@ -29,6 +29,12 @@ $row-border-color: 'black';
       }
     }
 
+    .parameter-row-container.selected {
+      .usa-checkbox {
+        background-color: variables.$selected;
+      }
+    }
+
     .parameter-row-container {
       cursor: pointer;
       @include uswds.u-border-bottom(1px, $row-border-color);
diff --git a/wdfn-server/waterdata/services/sifta.py b/wdfn-server/waterdata/services/sifta.py
index 068c88d068dfeeaabcdd4c1544111159d30d831c..7830c71206e94116b089fc1adb005a0da561ea93 100644
--- a/wdfn-server/waterdata/services/sifta.py
+++ b/wdfn-server/waterdata/services/sifta.py
@@ -35,5 +35,5 @@ async def get_cooperators(session, site_no):
             else:
                 return False, resp_json.get('Customers', [])
     except (ServerDisconnectedError, ClientConnectorError) as err:
-        app.logger.error(f'Sifta server to ${site_no} failed with error: ${repr(err)}')
+        app.logger.error(f'Sifta server to {site_no} failed with error: {repr(err)}')
         return True, []