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:
| Ferramenta | Adequada para | Notas |
|---|---|---|
| HDFView | Percorrer a árvore, os atributos e os valores sem escrever qualquer código | Interface gráfica gratuita do The HDF Group; apresenta cada atributo e conjunto de dados exatamente como descrito abaixo |
h5dump / h5ls | Inspeção rápida na linha de comandos | Incluí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 notas | Consulte abaixo |
| MATLAB (h5info/h5read/h5readatt integrados) | Análise com scripts, criação de gráficos | Não requer qualquer toolbox; consulte abaixo |
| R (rhdf5) | Análise com scripts | Pacote 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:
| Atributo | Significado |
|---|---|
format | Sempre "datacnvs.interchange.hdf5", o que identifica este ficheiro como uma exportação do DataCNVS, e não apenas como um ficheiro HDF5 qualquer |
format_version | Versão do formato do contentor (número inteiro) |
generated_at | Data e hora em que a exportação foi gerada, em UTC segundo a norma ISO-8601 |
source_tenant_slug | O espaço de trabalho a partir do qual os dados foram exportados |
title, readme | Um 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:
| Atributo | Estilo | Significado |
|---|---|---|
units | Convenção CF | Unidades físicas, resolvidas a partir do tipo de grandeza (ou de units_override se o campo as substituir) |
long_name | Convenção CF | Etiqueta legível: o alias do campo, caso exista; caso contrário, o nome da variável |
standard_name | Campo da convenção CF | Reutilizado para conter a chave de tipo de grandeza do DataCNVS; não é validado face ao verdadeiro vocabulário CF |
role | DataCNVS | A razão pela qual este campo existe na observação, por exemplo, dependent, contextual, index |
dtype | DataCNVS | O tipo de dados DataCNVS do valor; consulte abaixo a referência de tipos |
variable_key, quantity_kind_key | DataCNVS | Chaves de consulta em catalog/variables/ e catalog/quantity_kinds/ |
alias, units_override | DataCNVS | Presentes 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 DataCNVS | Armazenado como | Notas |
|---|---|---|
string | Texto UTF-8 | |
boolean | booleano | |
integer | Número inteiro de 64 bits | |
number / numeric(p,s) | Número de vírgula flutuante de 64 bits | |
date | Texto de data segundo a norma ISO-8601, por exemplo, "2026-06-01" | |
datetime / timestamp | Nú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, dictionary | Texto UTF-8 que contém o valor codificado em JSON | Inclui 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.
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):
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.
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/h5readattcomo 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 emstring(...)se precisar de uma tipagem uniforme entre campos. - Um valor
json/list/struct/map/dictionaryé lido como texto JSON; descodifique-o comjsondecode(...). h5info(file, "/observations/obs_000001")fornece a mesma lista de atributos/conjuntos de dados queh5dispapresenta, 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