Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Consolidações: Mato Grosso do Sul

books/ms/consolidations.livemd

Consolidações: Mato Grosso do Sul

Informações Gerais

> Lembre-se de ativar o runtime para Mix Standalone com o caminho para /data

Objetivo deste book consiste em gerar consolidações dos seguintes indicadores do linkage do estado de Mato Grosso do Sul.

Dimensões

Por situação de vacinação

  • n/a - Desconsiderando a vacinação
  • no_vaccine - Considerando apenas quem não foi vacinado
  • partial_vaccine - Considerando apenas quem foi vacinado uma vez para vacinas de 2 doses
  • full_vaccine- Considerando apenas quem foi vacinado com a quantidade esperada de doses da vacina
  • guarded - Considerando full_vaccine com, ao menos, 14 dias depois da data dos primeiros sintomas

Faixas etárias

  • 18-29 - Considerando na idade entre 18 e 29 anos
  • 30-39 - Considerando na idade entre 30 e 39 anos
  • 40-49 - Considerando na idade entre 40 e 49 anos
  • 50-59 - Considerando na idade entre 50 e 59 anos
  • 60-69 - Considerando na idade entre 60 e 69 anos
  • 70-79 - Considerando na idade entre 70 e 79 anos
  • 80+ - Considerando na idade de 80 anos ou maior

Consolidações e-SUS VE

  • esus_ve_cases - Casos sintomáticos do e-SUS VE:
    • esus_ve_cases (faixas etárias, situação de vacinação n/a)
    • esus_ve_cases_no_vaccine (faixas etárias)
    • esus_ve_cases_partial_vaccine (faixas etárias)
    • esus_ve_cases_full_vaccine (faixas etárias)
    • esus_ve_cases_guarded (faixas etárias)

Consolidações SIPNI

  • sipni - Vacinações (SIPNI):
    • sipni_partial_vaccine (faixas etárias)
    • sipni_full_vaccine (faixas etárias)

Consolidações SIVEP

  • sivep_cases - Casos do SIVEP:

    • sivep_cases (faixas etárias, situação de vacinação n/a)
    • sivep_cases_no_vaccine (faixas etárias)
    • sivep_cases_partial_vaccine (faixas etárias)
    • sivep_cases_full_vaccine (faixas etárias)
    • sivep_cases_guarded (faixas etárias)
  • sivep_hospitalizations - Internações (SIVEP):

    • sivep_hospitalizations (faixas etárias, situação de vacinação n/a)
    • sivep_hospitalizations_no_vaccine (faixas etárias)
    • sivep_hospitalizations_partial_vaccine (faixas etárias)
    • sivep_hospitalizations_full_vaccine (faixas etárias)
    • sivep_hospitalizations_guarded (faixas etárias)
  • sivep_deaths - Óbitos (SIVEP):

    • sivep_deaths (faixas etárias, situação de vacinação n/a)
    • sivep_deaths_no_vaccine (faixas etárias)
    • sivep_deaths_partial_vaccine (faixas etárias)
    • sivep_deaths_full_vaccine (faixas etárias)
    • sivep_deaths_guarded (faixas etárias)

Entrada

Saída

Identificação dos caminhos

get_input_path = fn context ->
  "Caminho para #{context}: "
  |> IO.gets()
  |> String.trim()
  |> Path.expand(__DIR__)
  |> tap(&unless(File.exists?(&1), do: raise("Caminho #{&1} não existe.")))
end

get_destination_path = fn context ->
  "Caminho para #{context}: "
  |> IO.gets()
  |> String.trim()
  |> Path.expand(__DIR__)
  |> tap(&File.mkdir_p!(&1))
end

paths = %{
  input: %{
    linkage: get_input_path.("o linkage")
  },
  output: get_destination_path.("o diretório de resultados")
}

Definição de funções e variáveis

create_ets = fn ets_table ->
  try do
    :ets.new(ets_table, [:set, :public, :named_table])
  rescue
    _error -> :ets.delete_all_objects(ets_table)
  end
end

create_ets.(:cities)
city_name = &:ets.lookup_element(:cities, &1, 2)

"sandbox/input/ms_cities_names.csv"
|> Path.expand(__DIR__)
|> File.read!()
|> NimbleCSV.RFC4180.parse_string()
|> Enum.map(fn [k, v] -> {String.to_integer(k), v} end)
|> then(&[{50, "Mato Grosso do Sul"} | &1])
|> then(&:ets.insert(:cities, &1))

add_state = fn ets_table, state, date, age_index, default ->
  :ets.update_counter(ets_table, {state, date}, {age_index + 1, 1}, default)
end

add_both = fn ets_table, state, city, date, age_index, default_state, default_city ->
  :ets.update_counter(ets_table, {state, date}, {age_index + 1, 1}, default_state)
  :ets.update_counter(ets_table, {city, date}, {age_index + 1, 1}, default_city)
end

header = ~w(location date age_15_29 age_30_39 age_40_49 age_50_59 age_60_69 age_70_79 age_80_plus)

wrap = fn ets_table ->
  fn _input_path, output_path ->
    ets_table
    |> :ets.tab2list()
    |> Enum.map(fn values ->
      [{city, date} | values] = Tuple.to_list(values)
      [city, date | values]
    end)
    |> Enum.sort(&amp;(Enum.at(&amp;1, 1) <= Enum.at(&amp;2, 1)))
    |> Enum.sort(&amp;(List.first(&amp;1) <= List.first(&amp;2)))
    |> then(&amp;[header | &amp;1])
    |> NimbleCSV.RFC4180.dump_to_iodata()
    |> then(&amp;File.write(output_path, &amp;1))
  end
end

keys = ~w(15_29 30_39 40_49 50_59 60_69 70_79 80+)

show_plot = fn context, city, data ->
  [title: city_name.(city), width: 150, height: 150]
  |> VegaLite.new()
  |> VegaLite.data_from_values(data)
  |> VegaLite.mark(:line)
  |> VegaLite.transform(fold: keys)
  |> VegaLite.encode_field(:x, "data", type: :temporal)
  |> VegaLite.encode_field(:y, "value", type: :quantitative, title: context)
  |> VegaLite.encode_field(:color, "key", type: :nominal, title: "Faixa etária")
end

show_plots = fn title, context, path ->
  [title: title]
  |> VegaLite.new()
  |> VegaLite.concat(
    path
    |> File.read!()
    |> NimbleCSV.RFC4180.parse_string()
    |> Enum.map(fn [city, date | data] ->
      keys
      |> Enum.zip(Enum.map(data, &amp;String.to_integer/1))
      |> then(&amp;[{"localidade", String.to_integer(city)}, {"data", date} | &amp;1])
      |> Enum.into(%{})
    end)
    |> Enum.group_by(&amp; &amp;1["localidade"])
    |> Enum.sort(fn {k1, _}, {k2, _} -> k1 <= k2 end)
    |> Enum.map(fn {city, data} -> show_plot.(context, city, data) end)
  )
end

show_ets = fn ets_table ->
  ets_table
  |> Kino.ETS.new()
  |> Kino.render()
end

show_table = fn path ->
  path
  |> File.read!()
  |> NimbleCSV.RFC4180.parse_string()
  |> Enum.map(fn [city, date | line] ->
    keys
    |> Enum.zip(line)
    |> Enum.map(fn {k, v} -> {k, String.to_integer(v)} end)
    |> then(&amp;[{"localidade", city}, {"data", date} | &amp;1])
  end)
  |> Kino.DataTable.new()
end

force? = false

:ok

esus_ve_cases

# force? = true

esus_ve =
  :esus_ve
  |> Phi.Pipe.new(paths.input.linkage)
  |> Phi.Pipe.run(
    :cases,
    fn input_path, output_path ->
      create_ets.(:na)
      create_ets.(:no_vaccine)
      create_ets.(:partial_vaccine)
      create_ets.(:full_vaccine)
      create_ets.(:guarded)

      paths.input.linkage
      |> File.stream!(read_ahead: 100_000)
      |> NimbleCSV.RFC4180.parse_stream()
      |> Flow.from_enumerable()
      |> Flow.map(fn [_, city, age_index, date, _, vaccination_date, _, _, _, is_full_vaccination] ->
        age_index = String.to_integer(age_index)

        default_state = {{50, date}, 0, 0, 0, 0, 0, 0, 0}

        add =
          if city != "" do
            default_city = {{city, date}, 0, 0, 0, 0, 0, 0, 0}

            &amp;add_both.(
              &amp;1,
              50,
              String.to_integer(city),
              date,
              age_index,
              default_state,
              default_city
            )
          else
            &amp;add_state.(&amp;1, 50, date, age_index, default_state)
          end

        if date != "" do
          add.(:na)

          if is_full_vaccination == "1" do
            add.(:full_vaccine)

            date
            |> Date.from_iso8601!()
            |> Date.diff(Date.from_iso8601!(vaccination_date))
            |> then(&amp;(&amp;1 > 14))
            |> if(do: add.(:guarded))
          else
            if is_full_vaccination == "0" do
              add.(:partial_vaccine)
            else
              add.(:no_vaccine)
            end
          end
        end
      end)
      |> Flow.run()

      wrap.(:na).(input_path, output_path)
    end,
    result_dir: paths.output,
    force?: force?
  )
  |> Phi.Pipe.run(:cases_no_vaccine, wrap.(:no_vaccine), force?: force?)
  |> Phi.Pipe.run(:cases_partial_vaccine, wrap.(:partial_vaccine), force?: force?)
  |> Phi.Pipe.run(:cases_full_vaccine, wrap.(:full_vaccine), force?: force?)
  |> Phi.Pipe.run(:cases_guarded, wrap.(:guarded), force?: force?)
show_plots.(
  "e-SUS VE: Casos sintomáticos ocorridos após 15 dias da data de vacinação completa",
  "Casos",
  esus_ve.path
)

sipni

# force? = true

sipni =
  :sipni
  |> Phi.Pipe.new(paths.input.linkage)
  |> Phi.Pipe.run(
    :partial_vaccine,
    fn input_path, output_path ->
      create_ets.(:partial_vaccine)
      create_ets.(:full_vaccine)

      paths.input.linkage
      |> File.stream!(read_ahead: 100_000)
      |> NimbleCSV.RFC4180.parse_stream()
      |> Flow.from_enumerable()
      |> Flow.map(fn [_, city, age_index, _, _, date, _, _, _, is_full_vaccination] ->
        age_index = String.to_integer(age_index)
        default_state = {{50, date}, 0, 0, 0, 0, 0, 0, 0}

        add =
          if city != "" do
            default_city = {{city, date}, 0, 0, 0, 0, 0, 0, 0}

            &amp;add_both.(
              &amp;1,
              50,
              String.to_integer(city),
              date,
              age_index,
              default_state,
              default_city
            )
          else
            &amp;add_state.(&amp;1, 50, date, age_index, default_state)
          end

        if is_full_vaccination == "1" do
          add.(:full_vaccine)
        else
          if is_full_vaccination == "0" do
            add.(:partial_vaccine)
          end
        end
      end)
      |> Flow.run()

      wrap.(:partial_vaccine).(input_path, output_path)
    end,
    result_dir: paths.output,
    force?: force?
  )
  |> Phi.Pipe.run(:full_vaccine, wrap.(:full_vaccine), force?: force?)
show_plots.(
  "SIPNI: Vacinações completas (1 com a Janssen ou 2 de outro laboratório)",
  "Vacinações",
  sipni.path
)

sivep_cases

# force? = true

sivep =
  :sivep
  |> Phi.Pipe.new(paths.input.linkage)
  |> Phi.Pipe.run(
    :cases,
    fn input_path, output_path ->
      create_ets.(:na)
      create_ets.(:no_vaccine)
      create_ets.(:partial_vaccine)
      create_ets.(:full_vaccine)
      create_ets.(:guarded)

      paths.input.linkage
      |> File.stream!(read_ahead: 100_000)
      |> NimbleCSV.RFC4180.parse_stream()
      |> Flow.from_enumerable()
      |> Flow.map(fn [
                       _,
                       city,
                       age_index,
                       _,
                       date,
                       vaccination_date,
                       is_case,
                       _,
                       _,
                       is_full_vaccination
                     ] ->
        age_index = String.to_integer(age_index)
        default_state = {{50, date}, 0, 0, 0, 0, 0, 0, 0}

        add =
          if city != "" do
            default_city = {{city, date}, 0, 0, 0, 0, 0, 0, 0}

            &amp;add_both.(
              &amp;1,
              50,
              String.to_integer(city),
              date,
              age_index,
              default_state,
              default_city
            )
          else
            &amp;add_state.(&amp;1, 50, date, age_index, default_state)
          end

        if date != "" and is_case == "1" do
          add.(:na)

          if is_full_vaccination == "1" do
            add.(:full_vaccine)

            date
            |> Date.from_iso8601!()
            |> Date.diff(Date.from_iso8601!(vaccination_date))
            |> then(&amp;(&amp;1 > 14))
            |> if(do: add.(:guarded))
          else
            if is_full_vaccination == "0" do
              add.(:partial_vaccine)
            else
              add.(:no_vaccine)
            end
          end
        end
      end)
      |> Flow.run()

      wrap.(:na).(input_path, output_path)
    end,
    result_dir: paths.output,
    force?: force?
  )
  |> Phi.Pipe.run(:cases_no_vaccine, wrap.(:no_vaccine), force?: force?)
  |> Phi.Pipe.run(:cases_partial_vaccine, wrap.(:partial_vaccine), force?: force?)
  |> Phi.Pipe.run(:cases_full_vaccine, wrap.(:full_vaccine), force?: force?)
  |> Phi.Pipe.run(:cases_guarded, wrap.(:guarded), force?: force?)
show_plots.(
  "SIVEP: Casos ocorridos após 15 dias da data de vacinação completa",
  "Casos",
  sivep.path
)

sivep_hospitalizations

# force? = true

sivep =
  sivep
  |> Phi.Pipe.run(
    :hospitalizations,
    fn input_path, output_path ->
      create_ets.(:na)
      create_ets.(:no_vaccine)
      create_ets.(:partial_vaccine)
      create_ets.(:full_vaccine)
      create_ets.(:guarded)

      paths.input.linkage
      |> File.stream!(read_ahead: 100_000)
      |> NimbleCSV.RFC4180.parse_stream()
      |> Flow.from_enumerable()
      |> Flow.map(fn [
                       _,
                       city,
                       age_index,
                       _,
                       date,
                       vaccination_date,
                       _,
                       is_hospitalization,
                       _,
                       is_full_vaccination
                     ] ->
        age_index = String.to_integer(age_index)
        default_state = {{50, date}, 0, 0, 0, 0, 0, 0, 0}

        add =
          if city != "" do
            default_city = {{city, date}, 0, 0, 0, 0, 0, 0, 0}

            &amp;add_both.(
              &amp;1,
              50,
              String.to_integer(city),
              date,
              age_index,
              default_state,
              default_city
            )
          else
            &amp;add_state.(&amp;1, 50, date, age_index, default_state)
          end

        if date != "" and is_hospitalization == "1" do
          add.(:na)

          if is_full_vaccination == "1" do
            add.(:full_vaccine)

            date
            |> Date.from_iso8601!()
            |> Date.diff(Date.from_iso8601!(vaccination_date))
            |> then(&amp;(&amp;1 > 14))
            |> if(do: add.(:guarded))
          else
            if is_full_vaccination == "0" do
              add.(:partial_vaccine)
            else
              add.(:no_vaccine)
            end
          end
        end
      end)
      |> Flow.run()

      wrap.(:na).(input_path, output_path)
    end,
    force?: force?
  )
  |> Phi.Pipe.run(:hospitalizations_no_vaccine, wrap.(:no_vaccine), force?: force?)
  |> Phi.Pipe.run(:hospitalizations_partial_vaccine, wrap.(:partial_vaccine), force?: force?)
  |> Phi.Pipe.run(:hospitalizations_full_vaccine, wrap.(:full_vaccine), force?: force?)
  |> Phi.Pipe.run(:hospitalizations_guarded, wrap.(:guarded), force?: force?)
show_plots.(
  "SIVEP: Internações ocorridas após 15 dias da data de vacinação completa",
  "Casos",
  sivep.path
)

sivep_deaths

# force? = true

sivep =
  sivep
  |> Phi.Pipe.run(
    :deaths,
    fn input_path, output_path ->
      create_ets.(:na)
      create_ets.(:no_vaccine)
      create_ets.(:partial_vaccine)
      create_ets.(:full_vaccine)
      create_ets.(:guarded)

      paths.input.linkage
      |> File.stream!(read_ahead: 100_000)
      |> NimbleCSV.RFC4180.parse_stream()
      |> Flow.from_enumerable()
      |> Flow.map(fn [
                       _,
                       city,
                       age_index,
                       _,
                       date,
                       vaccination_date,
                       _,
                       _,
                       is_death,
                       is_full_vaccination
                     ] ->
        age_index = String.to_integer(age_index)
        default_state = {{50, date}, 0, 0, 0, 0, 0, 0, 0}

        add =
          if city != "" do
            default_city = {{city, date}, 0, 0, 0, 0, 0, 0, 0}

            &amp;add_both.(
              &amp;1,
              50,
              String.to_integer(city),
              date,
              age_index,
              default_state,
              default_city
            )
          else
            &amp;add_state.(&amp;1, 50, date, age_index, default_state)
          end

        if date != "" and is_death == "1" do
          add.(:na)

          if is_full_vaccination == "1" do
            add.(:full_vaccine)

            date
            |> Date.from_iso8601!()
            |> Date.diff(Date.from_iso8601!(vaccination_date))
            |> then(&amp;(&amp;1 > 14))
            |> if(do: add.(:guarded))
          else
            if is_full_vaccination == "0" do
              add.(:partial_vaccine)
            else
              add.(:no_vaccine)
            end
          end
        end
      end)
      |> Flow.run()

      wrap.(:na).(input_path, output_path)
    end,
    result_dir: paths.output,
    force?: force?
  )
  |> Phi.Pipe.run(:deaths_no_vaccine, wrap.(:no_vaccine), force?: force?)
  |> Phi.Pipe.run(:deaths_partial_vaccine, wrap.(:partial_vaccine), force?: force?)
  |> Phi.Pipe.run(:deaths_full_vaccine, wrap.(:full_vaccine), force?: force?)
  |> Phi.Pipe.run(:deaths_guarded, wrap.(:guarded), force?: force?)
show_plots.(
  "SIVEP: Óbitos ocorridos após 15 dias da data de vacinação completa",
  "Óbitos",
  sivep.path
)

Zip

path = "sandbox/results" |> Path.expand(__DIR__)

path
|> File.ls!()
|> Enum.filter(&amp;(String.first(&amp;1) == "0"))
|> Enum.map(&amp;String.to_charlist/1)
|> then(
  &amp;:zip.create(
    path |> Path.join("processamento.zip") |> String.to_charlist(),
    &amp;1,
    cwd: String.to_charlist(path)
  )
)