Working on expanded pages and data processing.

This commit is contained in:
Joshua Bemenderfer
2021-12-29 22:03:12 -05:00
parent bac61fe227
commit b8cca082ed
241 changed files with 793 additions and 970346 deletions

5
src/components/Card.vue Normal file
View File

@@ -0,0 +1,5 @@
<template>
<div class="bg-white shadow rounded-lg p-4 lg:p-8 max-w-none prose lg:prose-base prose-headings:font-light prose-headings:text-indigo-900 prose-h1:mb-0">
<slot></slot>
</div>
</template>

View File

@@ -0,0 +1,21 @@
<template></template>
<script setup>
import { onMounted, watch } from 'vue'
const { parameters, data, watcher, refresher } = defineProps({
parameters: Object,
data: Object,
watcher: Function,
refresher: Function
})
console.log(parameters, data, watcher, refresher)
async function refreshData(parameters) {
data.value = await refresher(parameters)
}
watch(watcher, () => refreshData(parameters))
onMounted(() => refreshData(parameters))
</script>

View File

@@ -0,0 +1,190 @@
<template>
<div class='flex flex-wrap bg-white shadow rounded-lg p-4 space-x-6 lg:px-6 lg:py-0 lg:fixed lg:z-50 lg:top-0 lg:right-0 lg:left-96 lg:h-16 lg:shadow-none lg:flex-nowrap lg:!mt-0'>
<label class='w-full flex items-center lg:inline-flex lg:w-auto'>
County
<select v-model="parameters.county" class='ml-4 flex-1'>
<option v-for='county of counties' :key='county' :value='county'>{{county}}</option>
</select>
</label>
<label class='w-full flex items-center lg:inline-flex lg:w-auto'>
Start
<input type='date' v-model='parameters.start' class='ml-4 flex-1'/>
</label>
<label class='w-full flex items-center lg:inline-flex lg:w-auto'>
End
<input type='date' v-model='parameters.end' class='ml-4 flex-1'/>
</label>
</div>
</template>
<script setup lang='ts'>
import { ref, inject } from 'vue'
const parameters = inject('parameters')
const counties = [
'All',
'Appling',
'Atkinson',
'Bacon',
'Baker',
'Baldwin',
'Banks',
'Barrow',
'Bartow',
'Ben Hill',
'Berrien',
'Bibb',
'Bleckley',
'Brantley',
'Brooks',
'Bryan',
'Bulloch',
'Burke',
'Butts',
'Calhoun',
'Camden',
'Candler',
'Carroll',
'Catoosa',
'Charlton',
'Chatham',
'Chattahoochee',
'Chattooga',
'Cherokee',
'Clarke',
'Clay',
'Clayton',
'Clinch',
'Cobb',
'Coffee',
'Colquitt',
'Columbia',
'Cook',
'Coweta',
'Crawford',
'Crisp',
'Dade',
'Dawson',
'Decatur',
'DeKalb',
'Dodge',
'Dooly',
'Dougherty',
'Douglas',
'Early',
'Echols',
'Effingham',
'Elbert',
'Emanuel',
'Evans',
'Fannin',
'Fayette',
'Floyd',
'Forsyth',
'Franklin',
'Fulton',
'Gilmer',
'Glascock',
'Glynn',
'Gordon',
'Grady',
'Greene',
'Gwinnett',
'Habersham',
'Hall',
'Hancock',
'Haralson',
'Harris',
'Hart',
'Heard',
'Henry',
'Houston',
'Irwin',
'Jackson',
'Jasper',
'Jeff Davis',
'Jefferson',
'Jenkins',
'Johnson',
'Jones',
'Lamar',
'Lanier',
'Laurens',
'Lee',
'Liberty',
'Lincoln',
'Long',
'Lowndes',
'Lumpkin',
'Macon',
'Madison',
'Marion',
'McDuffie',
'McIntosh',
'Meriwether',
'Miller',
'Mitchell',
'Monroe',
'Montgomery',
'Morgan',
'Murray',
'Muscogee',
'Newton',
'Oconee',
'Oglethorpe',
'Paulding',
'Peach',
'Pickens',
'Pierce',
'Pike',
'Polk',
'Pulaski',
'Putnam',
'Quitman',
'Rabun',
'Randolph',
'Richmond',
'Rockdale',
'Schley',
'Screven',
'Seminole',
'Spalding',
'Stephens',
'Stewart',
'Sumter',
'Talbot',
'Taliaferro',
'Tattnall',
'Taylor',
'Telfair',
'Terrell',
'Thomas',
'Tift',
'Toombs',
'Towns',
'Treutlen',
'Troup',
'Turner',
'Twiggs',
'Union',
'Unknown',
'Upson',
'Walker',
'Walton',
'Ware',
'Warren',
'Washington',
'Wayne',
'Webster',
'Wheeler',
'White',
'Whitfield',
'Wilcox',
'Wilkes',
'Wilkinson',
'Worth'
]
</script>

View File

@@ -1,85 +0,0 @@
<template>
<label>
Counties
<select v-model="selectedCounty">
<option v-for="county of counties" :key="county" :value="county">{{county}}</option>
</select>
</label>
<label>
Statistic
<select v-model="selectedStat">
<option v-for="(func, stat) of statistics" :key="stat" :value="stat">{{stat}}</option>
</select>
</label>
<br>
<label>
Start
<input type="date" v-model="selectedStartDate"/>
</label>
<label>
End
<input type="date" v-model="selectedEndDate"/>
</label>
<br>
<JSCharting v-if="data.length" :options="chartOptions"></JSCharting>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import Papa from 'papaparse'
let data = ref([])
let selectedCounty = ref('Georgia')
let selectedStat = ref('Positive PCR Tests')
let selectedStartDate = ref('2021-01-01')
let selectedEndDate = ref('2021-12-31')
const counties = computed(() => {
return Array.from(new Set(data.value.map(r => r.county)))
})
const statistics = {
'PCR Tests Performed': r => r['ALL PCR tests performed'],
'Positive PCR Tests': r => r['All PCR positive tests'],
'PCR+Antigen Tests Performed': r => parseInt(r['ALL PCR tests performed']) + parseInt(r['Antigen Tests Performed']),
'Antigen Tests Performed': r => r['Antigen Tests Performed'],
'Positive Antigen Tests': r => r['Antigen Positive Tests'],
'Positive PCR & Antigen Tests': r => parseInt(r['All PCR positive tests']) + parseInt(r['Antigen Positive Tests']),
'7-day Percent Positive': r => r['7 day percent positive'],
'14-day Percent Positive': r => r['14 day percent positive'],
}
const colors = ['#f5f3ff','#ede9fe','#ddd6fe','#c4b5fd','#a78bfa','#8b5cf6','#7c3aed','#6d28d9','#5b21b6','#4c1d95']
const chartOptions = computed(() => {
return {
type: 'calendar solid',
palette: { colors },
data: data.value
.filter(r => {
return r.county == selectedCounty.value
&& r.report_date >= selectedStartDate.value
&& r.report_date <= selectedEndDate.value
})
.map(r => ([
`${r.report_date} 12:00:00`,
+statistics[selectedStat.value](r)
]))
}
})
async function getData() {
const csv = await fetch('/data/2021-12-28/pcr_antigen.csv').then(res => res.text())
return Papa.parse(csv, {
header: true
}).data
}
onMounted(async () => {
data.value = await getData()
})
</script>

View File

@@ -0,0 +1,28 @@
<template>
<JSCharting v-if="data" :options="chartOptions"></JSCharting>
</template>
<script setup>
import { computed, inject } from 'vue'
import { colors, col } from './util.js'
const parameters = inject('parameters')
const data = inject('data')
const chartOptions = computed(() => {
if (!data.value) return
return {
type: 'calendar solid',
palette: { colors },
data: data.value.rows
.filter(r => {
return col(data, r, 'report_date') >= parameters.start && col(data, r, 'report_date') <= parameters.end
})
.map(r => ([
`${col(data, r, 'report_date')} 12:00:00`,
col(data, r, parameters.column)
]))
}
})
</script>

View File

@@ -0,0 +1,7 @@
export const colors = ['#f5f3ff','#ede9fe','#ddd6fe','#c4b5fd','#a78bfa','#8b5cf6','#7c3aed','#6d28d9','#5b21b6','#4c1d95']
export function col(data, row, column) {
const index = data.value.headers.indexOf(column)
if (index === -1) return null
return row[index]
}

View File

@@ -1,37 +1,37 @@
<template>
<ul class="space-y-2 pb-2">
<li>
<a href="/" class="text-base text-violet-900 font-bold flex flex-col rounded-lg p-2 px-3 hover:bg-violet-100 group">
<router-link :to="{path: '/'}" class="text-base text-violet-900 font-bold flex flex-col rounded-lg p-2 px-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
Introduction
</a>
</router-link>
</li>
<li>
<span class="flex font-bold px-3 py-1 text-violet-900">What is the statewide trend in...</span>
<ul class="space-y-1 py-2 ml-3">
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/state/testing/'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 hover:bg-violet-800 text-white">
<icon-mdi-test-tube class="mr-2"></icon-mdi-test-tube> testing?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-percent-outline class="mr-2"></icon-mdi-percent-outline> test positivity?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-virus-outline class="mr-2"></icon-mdi-virus-outline> cases?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-hospital-box-outline class="mr-2"></icon-mdi-hospital-box-outline> hospitalizations?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-grave-stone class="mr-2"></icon-mdi-grave-stone> deaths?
</a>
</router-link>
</li>
</ul>
</li>
@@ -39,24 +39,24 @@
<span class="flex font-bold px-3 py-1 text-violet-900">Which counties have the...</span>
<ul class="space-y-1 py-2 ml-3">
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-percent-outline class="mr-2"></icon-mdi-percent-outline> highest positivity rate?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-virus-outline class="mr-2"></icon-mdi-virus-outline> most cases by population?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-hospital-box-outline class="mr-2"></icon-mdi-hospital-box-outline> most hospitalizations by population?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-grave-stone class="mr-2"></icon-mdi-grave-stone> most deaths by population?
</a>
</router-link>
</li>
</ul>
</li>
@@ -64,49 +64,24 @@
<span class="flex font-bold px-3 py-1 text-violet-900">Who is most at-risk...</span>
<ul class="space-y-1 py-2 ml-3">
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-human-cane class="mr-2"></icon-mdi-human-cane> by age?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-gender-male-female class="mr-2"></icon-mdi-gender-male-female> by gender?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-mdi-web class="mr-2"></icon-mdi-web> by ethnicity?
</a>
</router-link>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<router-link :to="{path: '/cases'}" class="text-base rounded-lg flex items-center p-2 mr-3 hover:bg-violet-100 group" active-class="bg-violet-800 text-white hover:bg-violet-800">
<icon-healthicons-clinical-f-outline class="mr-2"></icon-healthicons-clinical-f-outline> by health condition?
</a>
</li>
</ul>
</li>
<li>
<span class="flex font-bold px-3 py-1 text-violet-900">Who is most at-risk...</span>
<ul class="space-y-1 py-2 ml-3">
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<icon-mdi-human-cane class="mr-2"></icon-mdi-human-cane> by age?
</a>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<icon-mdi-gender-male-female class="mr-2"></icon-mdi-gender-male-female> by gender?
</a>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<icon-mdi-web class="mr-2"></icon-mdi-web> by ethnicity?
</a>
</li>
<li>
<a href="/cases" class="text-base text-gray-900 rounded-lg flex items-center p-2 hover:bg-violet-100 group">
<icon-healthicons-clinical-f-outline class="mr-2"></icon-healthicons-clinical-f-outline> by health condition?
</a>
</router-link>
</li>
</ul>
</li>

View File

@@ -34,12 +34,8 @@
</aside>
<main class="w-full min-h-full relative overflow-y-auto mt-16 shadow-inner bg-violet-100 rounded-t-xl">
<div class="p-2 lg:p-6">
<div class="w-full space-y-2 lg:space-y-4 flex flex-col h-full">
<div class="bg-white shadow rounded-lg p-4 lg:p-8">
<article class="max-w-none prose lg:prose-base prose-headings:font-light prose-headings:text-indigo-900">
<slot></slot>
</article>
</div>
<article class="w-full space-y-2 lg:space-y-4 flex flex-col h-full">
<slot></slot>
<div class="flex-1"></div>
<div class="bg-white font-light shadow rounded-lg p-4 lg:p-8 flex flex-wrap items-center justify-between">
<p>
@@ -51,7 +47,7 @@
<li class="text-center"><a href="/contact" class="font-normal text-violet-900 hover:bg-violet-100 rounded-lg p-2 px-3 block">Contact</a></li>
</ul>
</div>
</div>
</article>
</div>
</main>
</div>

View File

@@ -2,7 +2,3 @@
title: Introduction
---
# Introduction
Example stats/day calendar chart
<CasesPerDay></CasesPerDay>

View File

@@ -0,0 +1,24 @@
<template><slot></slot></template>
<script setup>
import { onMounted, reactive, ref, watch, provide } from 'vue'
const parameters = reactive({
county: 'All',
start: '2021-01-01',
end: '2021-12-12',
test: () => 'test'
})
const data = ref(null)
provide('parameters', parameters)
provide('data', data)
async function refreshData() {
data.value = await fetch(`/data/testing-trend/${parameters.county}.json`).then(res => res.json())
}
watch(() => parameters.county, () => refreshData())
onMounted(() => refreshData())
</script>

View File

@@ -0,0 +1,30 @@
---
title: What is the statewide trend in testing?
---
import DataSetup from './DataSetup.vue'
<Card>
# What is the statewide trend in testing?
## What is this report useful for?
The number of new cases reported doesn't always directly indicate how rapidly the disease is spreading.
By checking how many people are getting tested, you can get an idea of whether the current case load indicates major community spread or
if there is just a significant number of people getting tested for one reason or another.
**For example:**<br/>
If you get **10** positive results from **100** tests, the disease is probably spreading more widely than would be indicated if there were **50** positive results from **1,000** tests.
This discrepancy is often apparent on Mondays, where tests and cases from over the weekend might wind up in Monday's report.
See also: "<RouterLink to={{path: '/state/test-positivity/'}}>What is the statewide trend in test positivity?</RouterLink>" for a direct comparison of test-to-case rates.
</Card>
<DataSetup client:load>
<SliceSelector></SliceSelector>
<Card>
## Number of PCR Tests Performed Each Day
<TestingTrend column="pcr_performed" ></TestingTrend>
</Card>
</DataSetup>