GuiasExportar dados

Exportar dados: o formato .h5dcnvs

Quando exporta um conjunto de dados, designado por observação, do DataCNVS, obtém um ficheiro que pode efetivamente abrir em qualquer lugar, e não um bloco proprietário que só faz sentido dentro da nossa aplicação. Esta página explica o que contém o ficheiro, como abri-lo e apresenta exemplos práticos em Python e MATLAB.

Nesta página

O que obtém #

A exportação produz um único ficheiro com a extensão .h5dcnvs. Na base, trata-se de um ficheiro HDF5 totalmente normalizado; qualquer ferramenta compatível com HDF5 consegue abri-lo, mesmo sem saber nada sobre o DataCNVS. O que o torna um ficheiro .h5dcnvs é uma estrutura em árvore específica e autodescritiva no seu interior: cada valor está identificado com a respetiva função, unidades físicas e a variável e o tipo de grandeza que representa, pelo que o ficheiro se explica a si próprio, quer o abra num visualizador HDF5 genérico, quer escreva cinco linhas de Python.

Uma exportação contém uma observação, com:

  • os respetivos campos escalares (de valor único), por exemplo, o valor de referência de um forno ou o ID de uma amostra,
  • os respetivos campos de série (com valores em matriz), por exemplo, uma série de temperaturas ou medições de tensão,
  • a amostra a que pertence, caso exista,
  • e um catálogo das variáveis e dos tipos de grandeza referenciados por esses campos.

Apenas são exportados dados canónicos do DataCNVS: os mesmos valores processados e com unidades resolvidas que vê nos canvases da aplicação. Os dados em bruto, tal como foram carregados, nunca são incluídos.

Exportar a partir da aplicação #

Abra a página de uma observação e utilize o botão Transferir no canto superior direito. A exportação é executada como uma tarefa em segundo plano, pelo que a página apresenta o progresso enquanto o ficheiro está a ser criado; quando terminar, a transferência começa automaticamente. Atualmente, HDF5 é o único formato de exportação disponível, e a exportação é feita por observação: existe um ficheiro por exportação, correspondente à observação que está a visualizar.

Abrir o ficheiro #

Como .h5dcnvs é simplesmente HDF5, dispõe de uma ampla escolha de ferramentas:

FerramentaAdequada paraNotas
HDFViewPercorrer a árvore, os atributos e os valores sem escrever qualquer códigoInterface gráfica gratuita do The HDF Group; apresenta cada atributo e conjunto de dados exatamente como descrito abaixo
h5dump / h5lsInspeção rápida na linha de comandosIncluídas nas ferramentas de linha de comandos HDF5 padrão; h5dump -A file.h5dcnvs apresenta todos os atributos da árvore
Python (h5py, xarray, pandas)Análise com scripts, blocos de notasConsulte abaixo
MATLAB (h5info/h5read/h5readatt integrados)Análise com scripts, criação de gráficosNão requer qualquer toolbox; consulte abaixo
R (rhdf5)Análise com scriptsPacote Bioconductor; aplica-se o mesmo modelo de atributos/conjuntos de dados

Se outra ferramenta que utilize tiver uma opção genérica para "abrir ficheiro HDF5/NetCDF" e permitir percorrer grupos e atributos, funcionará; o DataCNVS não requer um plug-in específico do DataCNVS em lado algum. Aponte-a para qualquer conjunto de dados values/value e leia em conjunto os atributos units/long_name.

Estrutura do ficheiro #

A regra fundamental #

Os atributos contêm todos os elementos descritivos; os conjuntos de dados contêm apenas os valores propriamente ditos.

Tudo o que constitua metadados sobre uma medição, incluindo as unidades, a etiqueta, a variável a que corresponde e a observação a que pertence, é um atributo HDF5. Os únicos dois tipos de conjunto de dados HDF5 em todo o ficheiro são a matriz values de uma série e o value único de um escalar. Depois de compreender isto, é fácil prever como percorrer a árvore: os atributos indicam o que algo é e os conjuntos de dados fornecem os números.

Visão geral da estrutura #

/                                        (grupo raiz, atributos ao nível do ficheiro, ver abaixo)
├─ observations_summary                  (uma representação JSON de toda a árvore, para maior comodidade)
├─ catalog/
│   ├─ quantity_kinds/
│   │   └─ temperature/                  (um grupo por tipo de grandeza, com o nome da respetiva chave)
│   └─ variables/
│       └─ temperature/                  (um grupo por variável, com o nome da respetiva chave)
└─ observations/
    └─ obs_000001/
        ├─ sample/                       (presente apenas se a observação tiver uma amostra)
        ├─ scalars/
        │   └─ contextual_furnace_setpoint/
        │       └─ value                 (Conjunto de dados)
        ├─ series/
        │   ├─ index_time/
        │   │   └─ values                (Conjunto de dados)
        │   └─ dependent_temperature/
        │       └─ values                (Conjunto de dados)
        └─ series_groups/                (presente apenas quando as séries partilham um índice comum)
            └─ group_000001/

Os nomes dos grupos e dos campos são estáveis, determinísticos e legíveis. A mesma observação exportada duas vezes produz a mesma árvore, e o caminho HDF5 de um campo (por exemplo, observations/obs_000001/series/dependent_temperature) funciona também como a sua localização em linguagem corrente.

Atributos da raiz #

Um pequeno conjunto de atributos no grupo raiz do ficheiro descreve a exportação como um todo:

AtributoSignificado
formatSempre "datacnvs.interchange.hdf5", o que identifica este ficheiro como uma exportação do DataCNVS, e não apenas como um ficheiro HDF5 qualquer
format_versionVersão do formato do contentor (número inteiro)
generated_atData e hora em que a exportação foi gerada, em UTC segundo a norma ISO-8601
source_tenant_slugO espaço de trabalho a partir do qual os dados foram exportados
title, readmeUm título legível e um pequeno parágrafo que explica a árvore; leia-o primeiro se estiver a explorar um ficheiro pela primeira vez

Catálogo: variáveis e tipos de grandeza #

catalog/quantity_kinds/<key>/ e catalog/variables/<key>/ contêm os metadados partilhados a que os campos escalares e de série fazem referência, pelo que são escritos apenas uma vez, mesmo que vários campos utilizem a mesma variável. Um grupo de tipo de grandeza tem o seguinte aspeto:

catalog/quantity_kinds/temperature/
├─ @key             = "temperature"
├─ @label           = "Temperature"
├─ @canonical_units = "K"
├─ @units           = "K"          (duplicado, ao estilo CF, ver abaixo)
├─ @symbol          = "T"
└─ @common_units    = ["degC", "degF", "K"]

Um grupo de variável é semelhante e contém também @quantity_kind_key, que é a cadeia que deve procurar em catalog/quantity_kinds/ para resolver as respetivas unidades e definição.

A observação #

O grupo observations/obs_000001/ corresponde à observação que exportou, com obs_type, title, technique, notes, ingestion_status e created_at como atributos, além de um subgrupo sample/ caso esteja associada uma amostra.

No interior, cada campo escalar e de série tem o seu próprio grupo em scalars/ ou series/, com o nome de um slug legível (por exemplo, contextual_furnace_setpoint, dependent_temperature, index_time). Cada grupo de campos contém o mesmo vocabulário de atributos em dois estilos sobrepostos, apresentados lado a lado:

AtributoEstiloSignificado
unitsConvenção CFUnidades físicas, resolvidas a partir do tipo de grandeza (ou de units_override se o campo as substituir)
long_nameConvenção CFEtiqueta legível: o alias do campo, caso exista; caso contrário, o nome da variável
standard_nameCampo da convenção CFReutilizado para conter a chave de tipo de grandeza do DataCNVS; não é validado face ao verdadeiro vocabulário CF
roleDataCNVSA razão pela qual este campo existe na observação, por exemplo, dependent, contextual, index
dtypeDataCNVSO tipo de dados DataCNVS do valor; consulte abaixo a referência de tipos
variable_key, quantity_kind_keyDataCNVSChaves de consulta em catalog/variables/ e catalog/quantity_kinds/
alias, units_overrideDataCNVSPresentes apenas quando o campo substitui a etiqueta ou as unidades predefinidas da variável

Os nomes ao estilo CF (units, long_name, standard_name) existem porque são amplamente reconhecidos pelas ferramentas científicas HDF5/NetCDF genéricas, permitindo obter unidades e etiquetas legíveis sem qualquer plug-in específico do DataCNVS. Os nomes ao estilo DataCNVS existem para permitir consultas inequívocas e fáceis de utilizar em código. Ambos descrevem o mesmo campo; utilize o que melhor se adequar à sua ferramenta.

Os campos de série contêm ainda series_kind ("series" ou "index"), length e, se a série partilhar um índice comum com outras (por exemplo, um eixo temporal partilhado por várias curvas dependentes), series_group_ref, que aponta para uma entrada series_groups/ (consulte a secção seguinte).

Grupos de séries #

Quando duas ou mais séries da observação partilham um índice comum (na maioria dos casos, um eixo temporal ou de posição com várias medições dependentes representadas em função desse eixo), são associadas através de observations/obs_000001/series_groups/group_NNNNNN/. Este grupo não duplica quaisquer dados; limita-se a enumerar os caminhos dos membros e, apenas para facilitar a navegação, disponibiliza ligações simbólicas HDF5 para os verdadeiros conjuntos de dados values, para que um visualizador em árvore mostre visualmente a relação. O código deve resolver sempre a relação a partir do atributo series_group_ref, e não percorrendo as ligações.

Uma série sem o atributo series_group_ref simplesmente não tem um índice partilhado; por isso, considere os respetivos valores ordenados pela posição da linha (ponto 0, ponto 1, ponto 2, …).

observations_summary #

O conjunto de dados observations_summary ao nível da raiz contém as mesmas informações que toda a árvore, reformuladas num único documento JSON que inclui a observação, os respetivos campos e as entradas do catálogo com os seus caminhos HDF5. É uma comodidade para scripts que prefiram analisar um único bloco JSON em vez de percorrer a árvore de grupos, e é garantidamente uma representação estrita do que os atributos já indicam (nunca uma fonte de informações adicionais).

Referência de tipos de dados #

O atributo dtype de cada campo indica como o respetivo conjunto de dados value/values é armazenado fisicamente:

dtype do DataCNVSArmazenado comoNotas
stringTexto UTF-8
booleanbooleano
integerNúmero inteiro de 64 bits
number / numeric(p,s)Número de vírgula flutuante de 64 bits
dateTexto de data segundo a norma ISO-8601, por exemplo, "2026-06-01"
datetime / timestampNúmero inteiro de 64 bits em milissegundos desde a época Unix (UTC)Inclui também um atributo time_units = "epoch_ms_utc" como lembrete
json, list, struct, map, dictionaryTexto UTF-8 que contém o valor codificado em JSONInclui também encoding = "json"; analise a cadeia como JSON para recuperar o valor estruturado

As séries numéricas grandes são comprimidas com gzip e divididas em blocos; os valores pequenos e o texto são armazenados sem compressão. Este processo é transparente para todos os leitores abaixo: h5py, xarray e MATLAB descomprimem tudo automaticamente.

Trabalhar com exportações em Python #

A opção mais direta é h5py; não requer código específico do DataCNVS, apenas os nomes dos atributos documentados acima.

python
import datetime as dt
import json

import h5py

with h5py.File("furnace_run_14.h5dcnvs", "r") as f:
    print(f.attrs["title"])
    print(f.attrs["readme"])

    obs = f["observations/obs_000001"]
    print(obs.attrs["title"], "-", obs.attrs["technique"])

    # Um valor escalar, com as respetivas unidades.
    setpoint = obs["scalars/contextual_furnace_setpoint"]
    print(setpoint["value"][()], setpoint.attrs["units"])

    # Uma série e as respetivas unidades/etiqueta.
    temperature = obs["series/dependent_temperature"]
    values = temperature["values"][:]
    print(f"{len(values)} points, units={temperature.attrs['units']}")

    # Uma série de índices de data e hora é descodificada a partir de milissegundos desde a época.
    index_time = obs["series/index_time"]
    epoch_ms = index_time["values"][:]
    timestamps = [
        dt.datetime(1970, 1, 1, tzinfo=dt.timezone.utc) + dt.timedelta(milliseconds=int(t))
        for t in epoch_ms
    ]

    # Consulte o tipo de grandeza de um campo através do catálogo partilhado.
    qk_key = temperature.attrs["quantity_kind_key"]
    qk = f[f"catalog/quantity_kinds/{qk_key}"]
    print(qk.attrs["label"], qk.attrs["canonical_units"])

    # Um campo json/list/struct/map é descodificado com json.loads.
    # struct_field = obs["scalars/contextual_some_json_field"]
    # value = json.loads(struct_field["value"][()])

    # A árvore completa, reformulada como JSON, caso seja mais fácil trabalhar assim.
    summary = json.loads(f["observations_summary"][()])

Se preferir trabalhar com matrizes etiquetadas em vez de caminhos HDF5 em bruto, crie um xarray.Dataset a partir dos elementos acima (o próprio ficheiro não associa escalas de dimensão, pelo que terá de compor as etiquetas uma vez durante a leitura):

python
import h5py
import xarray as xr

with h5py.File("furnace_run_14.h5dcnvs", "r") as f:
    obs = f["observations/obs_000001"]
    time = obs["series/index_time/values"][:]
    temp_grp = obs["series/dependent_temperature"]
    temp = temp_grp["values"][:]
    units = temp_grp.attrs["units"]

ds = xr.Dataset(
    {"temperature": ("time", temp, {"units": units})},
    coords={"time": ("time", time, {"units": "epoch_ms_utc"})},
)
ds.temperature.plot()

Para trabalhar com dados tabulares, a matriz values de uma série é convertida diretamente numa coluna pandas.Series ou DataFrame: pandas.Series(temperature["values"][:]).

Trabalhar com exportações em MATLAB #

As funções HDF5 integradas no MATLAB (h5info, h5disp, h5read, h5readatt) não requerem qualquer toolbox e funcionam diretamente com ficheiros .h5dcnvs.

matlab
file = "furnace_run_14.h5dcnvs";

% Percorra a árvore completa, incluindo todos os atributos.
h5disp(file);

% Leia o título da observação.
obsTitle = h5readatt(file, "/observations/obs_000001", "title");

% Leia uma série e as respetivas unidades.
temperature = h5read(file, "/observations/obs_000001/series/dependent_temperature/values");
units = h5readatt(file, "/observations/obs_000001/series/dependent_temperature", "units");

% O índice temporal emparelhado é descodificado a partir de milissegundos desde a época (UTC).
epochMs = h5read(file, "/observations/obs_000001/series/index_time/values");
t = datetime(epochMs, "ConvertFrom", "epochtime", ...
    "TicksPerSecond", 1000, "Epoch", "1970-01-01", "TimeZone", "UTC");

% Um valor escalar, com as respetivas unidades.
setpoint = h5read(file, "/observations/obs_000001/scalars/contextual_furnace_setpoint/value");
setpointUnits = h5readatt(file, "/observations/obs_000001/scalars/contextual_furnace_setpoint", "units");

plot(t, temperature);
xlabel("Time");
ylabel(sprintf("Temperature (%s)", units));
title(sprintf("%s — setpoint %.1f %s", obsTitle, setpoint, setpointUnits));

Notas para utilizadores do MATLAB:

  • Os campos de texto de comprimento variável (etiquetas, valores codificados em JSON, cadeias de datas ISO) são devolvidos por h5read/h5readatt como uma string do MATLAB ou uma matriz de células de vetores de carateres, consoante o conjunto de dados ou atributo subjacente seja escalar ou tenha valores em matriz; envolva os valores únicos em string(...) se precisar de uma tipagem uniforme entre campos.
  • Um valor json/list/struct/map/dictionary é lido como texto JSON; descodifique-o com jsondecode(...).
  • h5info(file, "/observations/obs_000001") fornece a mesma lista de atributos/conjuntos de dados que h5disp apresenta, mas como uma struct que pode percorrer de forma programática em vez de a ler na consola.

Limites e retenção #

  • A exportação é feita por observação: um ficheiro, uma observação.
  • Apenas são exportados dados canónicos (processados), nunca dados em bruto tal como foram carregados.
  • As ligações de transferência expiram 7 dias após a conclusão da exportação; os dados subjacentes da observação não são alterados, pelo que pode simplesmente voltar a exportá-los.

Pretende outro formato? #

Atualmente, HDF5 é o único formato de exportação. Se o seu fluxo de trabalho exigir outra opção, como um CSV simples, outro formato de intercâmbio ou o formato nativo de uma ferramenta específica, contacte-nos.

Fale com a equipa do DataCNVS