Skip to content

Commit

Permalink
Merge branch 'development' of https://github.com/pydemic/health_board
Browse files Browse the repository at this point in the history
…into development
  • Loading branch information
laercios committed Dec 7, 2020
2 parents 47e6d67 + b298277 commit 9d80e78
Show file tree
Hide file tree
Showing 11 changed files with 339 additions and 141 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,169 @@
defmodule HealthBoardWeb.DashboardLive.CardData.IncidenceRateControlDiagram do
alias HealthBoard.Contexts

@spec fetch(map()) :: map()
def fetch(card_data) do
def fetch(%{filters: filters} = card_data) do
send(card_data.root_pid, {:exec_and_emit, &do_fetch/1, card_data, {:chart, :combo}})

card_data
|> Map.put(:view_data, %{event_pushed: true})
|> Map.put(:filters, Map.update!(filters, :morbidity_context, &Contexts.morbidity_name(&1)))
end

defp do_fetch(%{id: id, data: data, filters: filters}) do
%{morbidity_context: context, from_year: from_year, to_year: to_year} = filters
%{data_periods: data_periods, weekly_morbidities: weekly_cases, yearly_populations: yearly_populations} = data

weeks = Enum.to_list(1..53)

data_period = fetch_data_period(data_periods, context, from_year)

weekly_cases = Map.get(weekly_cases, context, [])
rates = fetch_rates(weekly_cases, yearly_populations)

{lower, middle, upper} = moving_average_boundaries(rates, weeks, data_period, to_year)

rates = Enum.filter(rates, &(&1.year == to_year))

%{
id: id,
labels: weeks,
labelString: "Semana",
datasets: [
%{
type: "line",
label: "Coeficiente de incidência na semana",
backgroundColor: "#445",
borderColor: "#445",
pointRadius: 2,
borderWidth: 3,
fill: false,
data: Enum.map(weeks, &find_rate_from_week(rates, &1))
},
%{
type: "line",
label: "Limite inferior do canal endêmico",
backgroundColor: "#6dac6d",
borderColor: "#6dac6d",
borderWidth: 2,
pointRadius: 1,
fill: false,
data: lower
},
%{
type: "line",
label: "Limite superior do canal endêmico",
backgroundColor: "#e47f7f",
borderColor: "#e47f7f",
borderWidth: 2,
pointRadius: 1,
fill: false,
data: upper
},
%{
type: "line",
label: "Índice endêmico",
backgroundColor: "#dbcb37",
borderColor: "#dbcb37",
borderWidth: 1,
pointRadius: 0,
fill: false,
data: middle
}
]
}
end

defp fetch_data_period(data_periods, context, from_year) do
data_context = Contexts.data_context!(:morbidity)

data_periods
|> Map.fetch!(data_context)
|> Map.get(context, [%{from_year: from_year, from_week: 1}])
|> Enum.at(0)
end

defp fetch_rates(weekly_cases, yearly_populations) do
population_per_year = Enum.group_by(yearly_populations, & &1.year, & &1.total)
Enum.map(weekly_cases, &fetch_rate(&1, population_per_year))
end

defp fetch_rate(%{year: year, week: week, total: cases}, population_per_year) do
[population] = Map.get(population_per_year, year, [0])

if population > 0 and cases > 0 do
%{year: year, week: week, cases: cases, rate: cases * 100_000 / population}
else
%{year: year, week: week, cases: cases, rate: 0.0}
end
end

defp moving_average_boundaries(rates, weeks, data_period, to_year) do
rates
|> weekly_rates(weeks, data_period, to_year)
|> displace_by(7)
|> Enum.zip()
|> Enum.map(&calculate_moving_average/1)
|> Enum.group_by(& &1.week, & &1.average)
|> Enum.map(&calculate_moving_average_quartile/1)
|> Enum.reverse()
|> Enum.reduce({[], [], []}, &ungroup_boundaries/2)
end

defp weekly_rates(rates, weeks, %{from_year: from_year, from_week: from_week}, to_year) do
for year <- from_year..to_year, week <- weeks do
if year < from_year or (year == from_year and week < from_week) do
nil
else
%{week: week, rate: rate} = Enum.find(rates, %{week: week, rate: 0.0}, &(&1.year == year and &1.week == week))
%{week: week, rate: rate}
end
end
|> Enum.reject(&is_nil/1)
end

defp displace_by(list, amount, displaced_lists \\ nil) do
if amount == 0 do
displaced_lists
else
if displaced_lists == nil do
displace_by(list, amount - 1, [list])
else
displace_by(list, amount - 1, [[nil | list] | displaced_lists])
end
end
end

defp calculate_moving_average(displaced_data) do
displaced_data
|> Tuple.to_list()
|> Enum.reverse()
|> Enum.reject(&is_nil/1)
|> calculate_average()
end

defp calculate_average([%{week: week} | _tail] = data) do
size = length(data)
%{week: week, average: Enum.reduce(data, 0.0, &(&1.rate + &2)) / size}
end

defp calculate_moving_average_quartile({_week, moving_averages}) do
{
Statistics.percentile(moving_averages, 25),
Statistics.percentile(moving_averages, 50),
Statistics.percentile(moving_averages, 75)
}
end

defp ungroup_boundaries({q1, q2, q3}, {l1, l2, l3}) do
{
[q1 | l1],
[q2 | l2],
[q3 | l3]
}
end

defp find_rate_from_week(rates, week) do
Enum.find_value(rates, 0.0, &if(&1.week == week, do: &1.rate, else: nil))
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ defmodule HealthBoardWeb.DashboardLive.DashboardData do
@spec assign(map) :: map
def assign(%{dashboard: dashboard, data: data, filters: filters, root_pid: root_pid}) do
dashboard.sections
|> Task.async_stream(&fetch_section_data(&1, data, filters, root_pid), timeout: 10_000)
|> Task.async_stream(&fetch_section_data(&1, data, filters, root_pid), timeout: 60_000)
|> Enum.reduce(%{}, fn {:ok, {k, v}}, map -> Map.put(map, k, v) end)
rescue
_error -> []
end

defp fetch_section_data(dashboard_section, data, filters, root_pid) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ defmodule HealthBoardWeb.DashboardLive.DashboardData.Analytic do
order_by: [asc: :context, asc: :year, asc: :week]
]
|> WeeklyDeaths.list_by()
|> Enum.map(&Map.take(&1, [:context, :location_id, :year, :total]))
|> Enum.map(&Map.take(&1, [:context, :location_id, :year, :week, :total]))
|> Enum.group_by(& &1.context)
end

Expand All @@ -131,7 +131,7 @@ defmodule HealthBoardWeb.DashboardLive.DashboardData.Analytic do
order_by: [asc: :context, asc: :year, asc: :week]
]
|> WeeklyMorbidities.list_by()
|> Enum.map(&Map.take(&1, [:context, :location_id, :year, :total]))
|> Enum.map(&Map.take(&1, [:context, :location_id, :year, :week, :total]))
|> Enum.group_by(& &1.context)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule HealthBoardWeb.DashboardLive.EventData do

defp build_chart_data(data, sub_type) do
case sub_type do
:combo -> %{}
:combo -> combo_chart_data(data)
:horizontal_bar -> %{}
:line -> %{}
:multiline -> multiline_chart_data(data)
Expand All @@ -20,6 +20,32 @@ defmodule HealthBoardWeb.DashboardLive.EventData do
end
end

defp combo_chart_data(%{id: id, datasets: datasets, labels: labels, labelString: label_string}) do
%{
id: id,
data: %{
type: "line",
data: %{
labels: labels,
datasets: datasets
},
options: %{
maintainAspectRatio: false,
scales: %{
xAxes: [
%{
scaleLabel: %{
display: true,
labelString: label_string
}
}
]
}
}
}
}
end

defp multiline_chart_data(%{id: id, datasets: datasets, labels: labels}) do
datasets =
datasets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ defmodule HealthBoardWeb.DashboardLive.SectionData do
@spec assign(map) :: map
def assign(%{section: %{cards: section_cards}, data: data, filters: filters, root_pid: root_pid}) do
section_cards
|> Task.async_stream(&fetch_card_data(&1, data, filters, root_pid), timeout: 10_000)
|> Task.async_stream(&fetch_card_data(&1, data, filters, root_pid), timeout: 60_000)
|> Enum.reduce(%{}, fn {:ok, {k, v}}, map -> Map.put(map, k, v) end)
rescue
_error -> []
end

defp fetch_card_data(section_card, data, filters, root_pid) do
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule HealthBoardWeb.DashboardLive.SectionData.ImmediateCompulsoryAnalyticControlDiagrams do
@data_keys ~w[data_periods weekly_deaths weekly_morbidities weekly_populations]a
@filter_keys ~w[morbidity_context]a
@data_keys ~w[data_periods weekly_deaths weekly_morbidities yearly_populations]a
@filter_keys ~w[from_year morbidity_context to_year]a

@spec fetch(map()) :: map()
def fetch(%{data: data, filters: filters} = section_data) do
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule HealthBoardWeb.DashboardLive.SectionData.WeeklyCompulsoryAnalyticControlDiagrams do
@data_keys ~w[data_periods weekly_deaths weekly_morbidities weekly_populations]a
@filter_keys ~w[morbidity_context]a
@data_keys ~w[data_periods weekly_deaths weekly_morbidities yearly_populations]a
@filter_keys ~w[from_year morbidity_context to_year]a

@spec fetch(map()) :: map()
def fetch(%{data: data, filters: filters} = section_data) do
Expand Down
Loading

0 comments on commit 9d80e78

Please sign in to comment.