chg: [dashboard] Added COVID widgets to the default installation from widget-collections

- should be interesting enough for all at this point. We might remove it again once COVID-19 is finally gone from our lives
pull/5776/head
iglocska 2020-04-06 09:22:37 +02:00
parent ba921383ba
commit 78ad3cb368
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
3 changed files with 688 additions and 0 deletions

View File

@ -0,0 +1,305 @@
<?php
class CsseCovidMapWidget
{
public $title = 'CSSE Covid-19 map';
public $render = 'WorldMap';
public $width = 3;
public $height = 4;
public $params = array(
'event_info' => 'World map based on the countries with infections.',
'type' => 'Type of data used for the widget (confirmed, death, recovered).',
'logarithmic' => 'Use a log10 scale for the graph (set via 0/1).'
);
public $description = 'Widget mapping the countries showing confirmed cases of COVID-19.';
public $placeholder =
'{
"event_info": "%CSSE COVID-19 daily report%",
"type": "confirmed",
"logarithmic": 1
}';
public $countryCodes = array(
'Afghanistan' => 'AF',
'Albania' => 'AL',
'Algeria' => 'DZ',
'Angola' => 'AO',
'Argentina' => 'AR',
'Armenia' => 'AM',
'Australia' => 'AU',
'Austria' => 'AT',
'Azerbaijan' => 'AZ',
'Bahamas' => 'BS',
'Bangladesh' => 'BD',
'Belarus' => 'BY',
'Belgium' => 'BE',
'Belize' => 'BZ',
'Benin' => 'BJ',
'Bhutan' => 'BT',
'Bolivia' => 'BO',
'Bosnia and Herz.' => 'BA',
'Botswana' => 'BW',
'Brazil' => 'BR',
'Brunei' => 'BN',
'Bulgaria' => 'BG',
'Burkina Faso' => 'BF',
'Burundi' => 'BI',
'Cambodia' => 'KH',
'Cameroon' => 'CM',
'Canada' => 'CA',
'Central African Rep.' => 'CF',
'Chad' => 'TD',
'Chile' => 'CL',
'China' => 'CN',
'Colombia' => 'CO',
'Congo' => 'CG',
'Costa Rica' => 'CR',
'Croatia' => 'HR',
'Cuba' => 'CU',
'Cyprus' => 'CY',
'Czech Rep.' => 'CZ',
'Côte d\'Ivoire' => 'CI',
'Dem. Rep. Congo' => 'CD',
'Dem. Rep. Korea' => 'KP',
'Denmark' => 'DK',
'Djibouti' => 'DJ',
'Dominican Rep.' => 'DO',
'Ecuador' => 'EC',
'Egypt' => 'EG',
'El Salvador' => 'SV',
'Eq. Guinea' => 'GQ',
'Eritrea' => 'ER',
'Estonia' => 'EE',
'Ethiopia' => 'ET',
'Falkland Is.' => 'FK',
'Fiji' => 'FJ',
'Finland' => 'FI',
'Fr. S. Antarctic Lands' => 'TF',
'France' => 'FR',
'Gabon' => 'GA',
'Gambia' => 'GM',
'Georgia' => 'GE',
'Germany' => 'DE',
'Ghana' => 'GH',
'Greece' => 'GR',
'Greenland' => 'GL',
'Guatemala' => 'GT',
'Guinea' => 'GN',
'Guinea-Bissau' => 'GW',
'Guyana' => 'GY',
'Haiti' => 'HT',
'Honduras' => 'HN',
'Hungary' => 'HU',
'Iceland' => 'IS',
'India' => 'IN',
'Indonesia' => 'ID',
'Iran' => 'IR',
'Iraq' => 'IQ',
'Ireland' => 'IE',
'Israel' => 'IL',
'Italy' => 'IT',
'Jamaica' => 'JM',
'Japan' => 'JP',
'Jordan' => 'JO',
'Kazakhstan' => 'KZ',
'Kenya' => 'KE',
'Korea' => 'KR',
'Kuwait' => 'KW',
'Kyrgyzstan' => 'KG',
'Lao PDR' => 'LA',
'Latvia' => 'LV',
'Lebanon' => 'LB',
'Lesotho' => 'LS',
'Liberia' => 'LR',
'Libya' => 'LY',
'Lithuania' => 'LT',
'Luxembourg' => 'LU',
'Macedonia' => 'MK',
'Madagascar' => 'MG',
'Mainland China' => 'CN',
'Malawi' => 'MW',
'Malaysia' => 'MY',
'Mali' => 'ML',
'Mauritania' => 'MR',
'Mexico' => 'MX',
'Moldova' => 'MD',
'Mongolia' => 'MN',
'Montenegro' => 'ME',
'Morocco' => 'MA',
'Mozamb' => 'MZ',
'Myanmar' => 'MM',
'Namibia' => 'NA',
'Nepal' => 'NP',
'Netherlands' => 'NL',
'New Caledonia' => 'NC',
'New Zealand' => 'NZ',
'Nicaragua' => 'NI',
'Niger' => 'NE',
'Nigeria' => 'NG',
'Norway' => 'NO',
'Oman' => 'OM',
'Pakistan' => 'PK',
'Palestine' => 'PS',
'Panama' => 'PA',
'Papua New Guinea' => 'PG',
'Paraguay' => 'PY',
'Peru' => 'PE',
'Philippines' => 'PH',
'Poland' => 'PL',
'Portugal' => 'PT',
'Puerto Rico' => 'PR',
'Qatar' => 'QA',
'Romania' => 'RO',
'Russia' => 'RU',
'Rwanda' => 'RW',
'S. Sudan' => 'SS',
'Saudi Arabia' => 'SA',
'Senegal' => 'SN',
'Serbia' => 'RS',
'Sierra Leone' => 'SL',
'Slovakia' => 'SK',
'Slovenia' => 'SI',
'Solomon Is.' => 'SB',
'Somalia' => 'SO',
'South Africa' => 'ZA',
'Spain' => 'ES',
'Sri Lanka' => 'LK',
'Sudan' => 'SD',
'Suriname' => 'SR',
'Swaziland' => 'SZ',
'Sweden' => 'SE',
'Switzerland' => 'CH',
'Syria' => 'SY',
'Taiwan' => 'TW',
'Tajikistan' => 'TJ',
'Tanzania' => 'TZ',
'Thailand' => 'TH',
'Timor-Leste' => 'TL',
'Togo' => 'TG',
'Trinidad and Tobago' => 'TT',
'Tunisia' => 'TN',
'Turkey' => 'TR',
'Turkmenistan' => 'TM',
'Uganda' => 'UG',
'Ukraine' => 'UA',
'United Arab Emirates' => 'AE',
'United Kingdom' => 'GB',
'United States' => 'US',
'Uruguay' => 'UY',
'Uzbekistan' => 'UZ',
'Vanuatu' => 'VU',
'Venezuela' => 'VE',
'Vietnam' => 'VN',
'W. Sahara' => 'EH',
'Yemen' => 'YE',
'Zambia' => 'ZM',
'Zimbabwe' => 'ZW'
);
public $countryCodesReversed = array();
public function handler($user, $options = array())
{
$this->countryCodesReversed = array_flip($this->countryCodes);
$this->Event = ClassRegistry::init('Event');
$event_info_condition = empty($options['event_info']) ? '%CSSE COVID-19 daily report%' : $options['event_info'];
$params = array(
'eventinfo' => $event_info_condition,
'order' => 'date desc',
'limit' => 1,
'page' => 1
);
$eventIds = $this->Event->filterEventIds($user, $params);
$params['eventid'] = $eventIds;
$data = array();
if (empty($options['type'])) {
$options['type'] = 'confirmed';
}
if (!empty($eventIds)) {
$events = $this->Event->fetchEvent($user, $params);
$data = $this->__handleEvents($events, $options);
arsort($data);
}
$data = array('data' => $data);
if (!empty($options['type']) && $options['type'] === 'mortality') {
$data['output_decorator'] = 'percentage';
}
if (!empty($options['logarithmic'])) {
$data['logarithmic'] = array();
foreach ($data['data'] as $k => $v) {
if ($v == 0) {
$value = 0;
} else if ($v <= 1) {
$value = 0.2;
} else {
$value = log10($v);
}
$data['logarithmic'][$k] = $value;
}
}
$data['scope'] = Inflector::humanize($options['type']);
$data['colour_scale'] = json_encode(array('#F08080', '#8B0000'), true);
return $data;
}
private function __handleEvents($events, $options)
{
$data = array();
if (!empty($events)) {
foreach ($events as $event) {
if (!empty($event['Object'])) {
$data = $this->__handleObjects($data, $event['Object'], $options);
}
}
}
return $data;
}
private function __handleObjects($data, $objects, $options)
{
foreach ($objects as $object) {
if ($object['name'] === 'covid19-csse-daily-report') {
$temp = $this->__interpretObject($object);
$data = $this->__rearrangeResults($data, $temp, $options);
}
}
if ($options['type'] === 'mortality') {
foreach ($data as $k => $v) {
$data[$k] = round(100 * (empty($v['death']) ? 0 : $v['death']) / $v['confirmed'], 2);
}
}
return $data;
}
private function __rearrangeResults($data, $temp, $options)
{
$country = $temp['country-region'];
$type = $options['type'];
if (!empty($temp[$type])) {
$data[$country] = (empty($data[$country]) ? $temp[$type] : ($data[$country] + $temp[$type]));
}
return $data;
}
private function __interpretObject($object)
{
$temp = array();
$validFields = array('country-region', 'confirmed', 'death', 'recovered');
foreach ($object['Attribute'] as $attribute) {
if (in_array($attribute['object_relation'], $validFields)) {
if ($attribute['object_relation'] === 'country-region') {
if (!empty($this->countryCodes[$attribute['value']])) {
$temp[$attribute['object_relation']] = $this->countryCodes[$attribute['value']];
} elseif (isset($this->countryCodesReversed[$attribute['value']])) {
$temp[$attribute['object_relation']] = $attribute['value'];
} else {
$temp[$attribute['object_relation']] = 'XX';
}
} else {
$attribute['value'] = intval($attribute['value']);
$temp[$attribute['object_relation']] = $attribute['value'];
}
}
}
return $temp;
}
}

View File

@ -0,0 +1,201 @@
<?php
class CsseCovidTrendsWidget
{
public $title = 'CSSE Covid-19 trends';
public $render = 'MultiLineChart';
public $width = 4;
public $height = 5;
public $params = array(
'event_info' => 'Substring included in the info field of relevant CSSE COVID-19 events.',
'type' => 'Type of data used for the widget - confirmed (default), death, recovered, mortality.',
'insight' => 'Insight type - raw (default), growth, percent.',
'countries' => 'List of countries to be included (using the names used by the reports, such as Belgium, US, Germany).',
'timeframe' => 'Timeframe for events taken into account in days (going back from now, using the date field, default 10).'
);
public $description = 'Widget showing line charts for the evolution of the various case types.';
public $placeholder =
'{
"event_info": "%CSSE COVID-19 daily report%",
"type": "confirmed",
"insight": "growth",
"countries": ["Luxembourg", "Germany", "Belgium", "France"],
"timeframe": 20
}';
//public $cacheLifetime = 600;
public $autoRefreshDelay = false;
private $__countries = array();
public function handler($user, $options = array())
{
$this->Event = ClassRegistry::init('Event');
if (!isset($options['insight']) || !isset($this->__insightFunctions[$options['insight']])) {
$options['Insight'] = 'calculate_growth_rate';
}
if (empty($options['timeframe'])) {
$options['timeframe'] = 10;
}
if (empty($options['countries'])) {
$options['countries'] = array("Luxembourg", "Germany", "Belgium", "France");
}
if (empty($options['insight'])) {
$options['insight'] = 'raw';
}
$event_info_condition = empty($options['event_info']) ? '%CSSE COVID-19 daily report%' : $options['event_info'];
$params = array(
'eventinfo' => $event_info_condition,
'order' => 'date desc',
'date' => (empty($options['timeframe']) ? 10 : $options['timeframe']) . 'd'
);
$eventIds = $this->Event->filterEventIds($user, $params);
$eventIds = array_reverse(array_values($eventIds));
$data = array();
if (empty($options['type'])) {
$options['type'] = 'confirmed';
}
if (!empty($eventIds)) {
$previous = false;
foreach ($eventIds as $eventId) {
$params = array('eventid' => $eventId);
$event = $this->Event->fetchEvent($user, $params);
if (!empty($event)) {
$data[$event[0]['Event']['date']] = $this->__handleEvent($event[0], $options, $previous);
}
$previous = $data[$event[0]['Event']['date']];
}
}
$startDate = date('Y-m-d', strtotime('-' . intval($options['timeframe']) . ' days'));
//$data = call_user_func_array((array($this, $this->__insightFunctions[$options['Insight']]), array($startDate));
$data = array('data' => $data);
$data['insight'] = empty($options['insight']) ? 'raw' : $options['insight'];
foreach ($data['data'] as $date => $day) {
$data['data'][$date]['date'] = $date;
foreach ($this->__countries as $country => $temp) {
if (empty($data['data'][$date][$country][$data['insight']])) {
$data['data'][$date][$country][$data['insight']] = 0;
}
}
}
$data['data'] = array_values($data['data']);
$formulaData = array(
'insight' => array(
'raw' => '',
'growth' => 'daily increase in ',
'percent' => 'percentage wise daily increase in '
),
'type' => array(
'confirmed' => 'confirmed cases',
'death' => 'mortalities',
'recovered' => 'recoveries',
'mortality' => 'mortality rate'
)
);
$data['formula'] = sprintf(
'%s%s',
(isset($options['insight']) && !empty($formulaData[$options['insight']])) ?
$formulaData['insight'][$options['insight']] :
$formulaData['insight']['raw'],
(isset($options['type']) && !empty($formulaData['type'][$options['type']])) ?
$formulaData['type'][$options['type']] :
$formulaData['type']['confirmed']
);
$data['formula'] = ucfirst($data['formula']);
foreach ($data['data'] as &$day) {
foreach ($day as $key => &$countryData) {
if ($key !== 'date') {
$countryData = $countryData[$options['insight']];
}
}
}
return $data;
}
private function __handleEvent($event, $options, $previous)
{
$data = array();
if (!empty($event['Object'])) {
$data = $this->__handleObjects($data, $event['Object'], $options, $previous);
}
$data['date'] = $event['Event']['date'];
return $data;
}
private function __handleObjects($data, $objects, $options, $previous)
{
foreach ($objects as $object) {
if ($object['name'] === 'covid19-csse-daily-report') {
$temp = $this->__interpretObject($object, $previous);
$data = $this->__rearrangeResults($data, $temp, $options, $previous);
}
}
if ($options['type'] === 'mortality') {
foreach ($data as $k => $v) {
$data[$k]['mortality'] = round(100 * (empty($v['death']) ? 0 : $v['death']) / $v['confirmed'], 2);
}
}
if (!empty($options['insight']) && $options['insight'] !== 'raw') {
if ($options['insight'] == 'growth') {
foreach ($data as $k => &$countryData) {
foreach ($countryData as $type => &$value) {
if (empty($previous[$k][$type])) {
$previous[$k][$type] = 0;
}
$data[$k]['growth'] = $data[$k][$type] - $previous[$k][$type];
}
}
} else if ($options['insight'] == 'percent') {
foreach ($data as $k => &$countryData) {
foreach ($countryData as $type => &$value) {
if (empty($previous[$k][$type])) {
$previous[$k][$type] = $data[$k][$type];
}
$data[$k]['percent'] = ($data[$k][$type] - $previous[$k][$type]) / $previous[$k][$type];
}
}
}
} else {
foreach ($data as $k => &$countryData) {
$data[$k]['raw'] = $data[$k][$options['type']];
}
}
return $data;
}
private function __rearrangeResults($data, $temp, $options, $previous)
{
$country = $temp['country-region'];
if (!in_array($country, $options['countries'])) {
return $data;
}
$this->__countries[$country] = 1;
if ($options['type'] === 'mortality') {
foreach (array('confirmed', 'death') as $type) {
if (!empty($temp[$type])) {
$data[$country][$type] = (empty($data[$country][$type]) ? $temp[$type] : ($data[$country][$type] + $temp[$type]));
}
}
} else {
$type = $options['type'];
if (!empty($temp[$type])) {
$data[$country][$type] = (empty($data[$country][$type]) ? $temp[$type] : ($data[$country][$type] + $temp[$type]));
}
}
return $data;
}
private function __interpretObject($object, $previous)
{
$temp = array();
$validFields = array('country-region', 'confirmed', 'death', 'recovered');
foreach ($object['Attribute'] as $attribute) {
if (in_array($attribute['object_relation'], $validFields)) {
if ($attribute['object_relation'] !== 'country-region') {
$attribute['value'] = intval($attribute['value']);
}
$temp[$attribute['object_relation']] = $attribute['value'];
}
}
return $temp;
}
}

View File

@ -0,0 +1,182 @@
<?php
class CsseCovidWidget
{
public $title = 'CSSE Covid-19 data';
public $render = 'BarChart';
public $width = 3;
public $height = 4;
public $params = array(
'event_info' => 'Substring included in the info field of relevant CSSE COVID-19 events.',
'type' => 'Type of data used for the widget (confirmed, death, recovered, mortality).',
'logarithmic' => 'Use a log10 scale for the graph (set via 0/1).',
'relative' => 'Take the country\'s population size into account (count / 10M)'
);
public $description = 'Widget visualising the countries ranked by highest count in the chosen category.';
public $placeholder =
'{
"event_info": "%CSSE COVID-19 daily report%",
"type": "confirmed",
"logarithmic": 1,
"relative": 0
}';
public $__nameReplacements = array(
'US' => 'United States',
'Cote d\'Ivoire' => 'Ivory Coast',
'Holy See' => 'Vatican',
'Congo (Kinshasa)' => 'Democratic Republic of Congo',
'Taiwan*' => 'Taiwan',
'Korea, South' => 'South Korea'
);
private $__populationData = array();
public function handler($user, $options = array())
{
$this->Event = ClassRegistry::init('Event');
$event_info_condition = empty($options['event_info']) ? '%CSSE COVID-19 daily report%' : $options['event_info'];
$params = array(
'eventinfo' => $event_info_condition,
'order' => 'date desc',
'limit' => 1,
'page' => 1
);
$eventIds = $this->Event->filterEventIds($user, $params);
$params['eventid'] = $eventIds;
$data = array();
if (empty($options['type'])) {
$options['type'] = 'confirmed';
}
if (!empty($eventIds)) {
$events = $this->Event->fetchEvent($user, $params);
$data = $this->__handleEvents($events, $options);
arsort($data);
}
$data = array('data' => $data);
if (!empty($options['type']) && $options['type'] === 'mortality') {
$data['output_decorator'] = 'percentage';
}
if ($options['type'] !== 'mortality' && !empty($options['relative'])) {
$this->__getPopulationData();
if (!empty($this->__populationData)) {
foreach ($data['data'] as $country => $value) {
if (isset($this->__nameReplacements[$country])) {
$alias = $this->__nameReplacements[$country];
} else {
$alias = $country;
}
if (empty($this->__populationData[$alias])) {
unset($data['data'][$country]);
} else {
$pre = $data['data'][$country];
$data['data'][$country] = round(10000000 * $data['data'][$country] / $this->__populationData[$alias]);
}
}
}
arsort($data['data']);
}
if (!empty($options['logarithmic'])) {
$data['logarithmic'] = array();
foreach ($data['data'] as $k => $v) {
if ($v == 0) {
$value = 0;
} else if ($v <= 1) {
$value = 0.2;
} else {
$value = log10($v);
}
$data['logarithmic'][$k] = $value;
}
}
return $data;
}
private function __getPopulationData()
{
$this->Galaxy = ClassRegistry::init('Galaxy');
$galaxy = $this->Galaxy->find('first', array(
'recursive' => -1,
'contain' => array('GalaxyCluster' => array('GalaxyElement')),
'conditions' => array('Galaxy.name' => 'Country')
));
if (empty($galaxy)) {
return false;
}
foreach ($galaxy['GalaxyCluster'] as $cluster) {
foreach ($cluster['GalaxyElement'] as $element) {
if ($element['key'] === 'Population') {
$this->__populationData[$cluster['description']] = $element['value'];
}
}
}
return true;
}
private function __handleEvents($events, $options)
{
$data = array();
if (!empty($events)) {
foreach ($events as $event) {
if (!empty($event['Object'])) {
$data = $this->__handleObjects($data, $event['Object'], $options);
}
}
}
return $data;
}
private function __handleObjects($data, $objects, $options)
{
foreach ($objects as $object) {
if ($object['name'] === 'covid19-csse-daily-report') {
$temp = $this->__interpretObject($object);
$data = $this->__rearrangeResults($data, $temp, $options);
}
}
if ($options['type'] === 'mortality') {
foreach ($data as $k => $v) {
if (!isset($v['death']) || empty($v['confirmed'])) {
unset($data[$k]);
continue;
}
$data[$k] = round(100 * (empty($v['death']) ? 0 : $v['death']) / $v['confirmed'], 2);
}
}
return $data;
}
private function __rearrangeResults($data, $temp, $options)
{
$country = $temp['country-region'];
if ($options['type'] === 'mortality') {
foreach (array('confirmed', 'death') as $type) {
if (!empty($temp[$type])) {
$data[$country][$type] = (empty($data[$country][$type]) ? $temp[$type] : ($data[$country][$type] + $temp[$type]));
}
}
} else {
$type = $options['type'];
if (!empty($temp[$type])) {
$data[$country] = (empty($data[$country]) ? $temp[$type] : ($data[$country] + $temp[$type]));
}
}
return $data;
}
private function __interpretObject($object)
{
$temp = array();
$validFields = array('country-region', 'confirmed', 'death', 'recovered');
foreach ($object['Attribute'] as $attribute) {
if (in_array($attribute['object_relation'], $validFields)) {
if ($attribute['object_relation'] !== 'country-region') {
$attribute['value'] = intval($attribute['value']);
}
$temp[$attribute['object_relation']] = $attribute['value'];
}
}
return $temp;
}
}