Tools for documentation-aware data reading, writing, and analysis
Project description
metacsv - Tools for documentation-aware data reading, writing, and analysis
See the full documentation at ReadTheDocs
Overview
MetaCSV provides tools to read in CSV data with a yaml-compliant header directly into a pandas Series, DataFrame, or Panel or an xarray DataArray or Dataset.
Data specification
Data can be specified using a yaml-formatted header, with the YAML start-mark string (---) above and the YAML end-mark string (...) below the yaml block. Only one yaml block is allowed. If the doc-separation string is not the first (non-whitespace) line in the file, all of the file’s contents will be interpreted by the csv reader. The yaml data can have arbitrary complexity.
>>> import metacsv, numpy as np
>>> import StringIO as io # import io for python 3
>>> doc = io.StringIO('''
... ---
... author: A Person
... date: 2000-12-31
... variables:
... pop:
... name: Population
... unit: millions
... gdp:
... name: Product
... unit: 2005 $Bn
... ...
... region,year,pop,gdp
... USA,2010,309.3,13599.3
... USA,2011,311.7,13817.0
... CAN,2010,34.0,1240.0
... CAN,2011,34.3,1276.7
... ''')
Using MetaCSV-formatted files in python
Read MetaCSV-formatted data into python using pandas-like syntax:
>>> df = metacsv.read_csv(doc, index_col=[0,1])
>>> df # doctest: +NORMALIZE_WHITESPACE
<metacsv.core.containers.DataFrame (4, 2)>
pop gdp
region year
USA 2010 309.3 13599.3
2011 311.7 13817.0
CAN 2010 34.0 1240.0
2011 34.3 1276.7
<BLANKLINE>
Variables
gdp:
name Product
unit 2005 $Bn
pop:
name Population
unit millions
Attributes
author: A Person
date: 2000-12-31
These properties can be transferred from one data container to another:
>>> np.random.seed(1)
>>> s = metacsv.Series(np.random.random(6))
>>> s
<metacsv.core.containers.Series (6L,)>
0 0.417022
1 0.720324
2 0.000114
3 0.302333
4 0.146756
5 0.092339
dtype: float64
>>> s.attrs = df.attrs
>>> s
<metacsv.core.containers.Series (6L,)>
0 0.417022
1 0.720324
2 0.000114
3 0.302333
4 0.146756
5 0.092339
dtype: float64
<BLANKLINE>
Attributes
author: A Person
date: 2000-12-31
All MetaCSV attributes, including the attrs Attribute object, can be copied, assigned to new objects, and deleted. Since these attributes are largely unstable across normal pandas data processing, it is recommended that attributes be copied before data work is attempted and then reassigned before IO conversions.
Exporting MetaCSV data to other formats
CSV
A MetaCSV Series or DataFrame can be written as a yaml-prefixed CSV using the same to_csv syntax as it’s pandas counterpart:
>>> df.attrs['new attribute'] = 'changed in python!'
>>> df.to_csv('my_new_data.csv')
The resulting csv will include a yaml-formatted header with the original metadata updated to include attr[‘new attribute’].,
pandas
The coordinates and MetaCSV attributes can be easily stripped from a MetaCSV Container:
>>> df.to_pandas() # doctest: +NORMALIZE_WHITESPACE
pop gdp
region year
USA 2010 309.3 13599.3
2011 311.7 13817.0
CAN 2010 34.0 1240.0
2011 34.3 1276.7
xarray/netCDF
xArray provides a pandas-like interface to operating on indexed ndarray data. It is modeled on the netCDF data storage format used frequently in climate science, but is useful for many applications with higher-order data.
>>> ds = df.to_xarray()
>>> ds
<xarray.Dataset>
Dimensions: (region: 2, year: 2)
Coordinates:
* region (region) object 'USA' 'CAN'
* year (year) int64 2010 2011
Data variables:
pop (region, year) float64 309.3 311.7 34.0 34.3
gdp (region, year) float64 1.36e+04 1.382e+04 1.24e+03 1.277e+03
Attributes:
author: A Person
date: 2000-12-31
new attribute: changed in python!
>>> ds.to_netcdf('my_netcdf_data.nc')
Pickling
Pickling works just like pandas.
>>> df.to_pickle('my_metacsv_pickle.pkl')
>>> metacsv.read_pickle('my_metacsv_pickle.pkl')
<metacsv.core.containers.DataFrame (4, 2)>
pop gdp
region year
USA 2010 309.3 13599.3
2011 311.7 13817.0
CAN 2010 34.0 1240.0
2011 34.3 1276.7
Variables
gdp: OrderedDict([('name', 'Product'), ('unit', '2005 $Bn')])
pop: OrderedDict([('name', 'Population'), ('unit', 'millions')])
Attributes
author: A Person
date: 2000-12-31
new attribute: changed in python!
Others
Currently, MetaCSV only supports conversion to CSV and to netCDF through the xarray module. However, feel free to suggest additional features and to contribute your own!
Conversion to other types on the fly
Special conversion utilities allow you to convert any metacsv, pandas, or xarray container or a CSV filepath into any other type in this group.
All of these conversion utilities are also methods on metacsv containers.
to_csv
to_csv allows you to write any container or csv file to a metacsv-formatted csv file. Keyword arguments attrs, coords, and variables will be attached to the data before it is written. Any conflicts in these attributes will be updated with the arguments to this function
>>> import pandas as pd, numpy as np, xarray as xr, metacsv
>>> df = pd.DataFrame(np.random.random((3,4)), columns=list('abcd'))
>>> df
a b c d
0 0.558083 0.665184 0.226173 0.339905
1 0.541712 0.835804 0.326078 0.179103
2 0.332869 0.435573 0.904612 0.823884
>>> metacsv.to_csv(df, 'mycsv.csv', attrs={'author': 'my name', 'date': '2015-12-31'})
>>>
>>> df2 = metacsv.read_csv('mycsv.csv', index_col=[0])
>>> df2
<metacsv.core.containers.DataFrame (3, 4)>
a b c d
0 0.558083 0.665184 0.226173 0.339905
1 0.541712 0.835804 0.326078 0.179103
2 0.332869 0.435573 0.904612 0.823884
Attributes
author: my name
date: 2015-12-31
new attribute: changed in python!
>>> metacsv.to_csv(df2, 'mycsv.csv', attrs={'author': 'new name'})
>>>
>>> metacsv.read_csv('mycsv.csv', index_col=[0])
<metacsv.core.containers.DataFrame (3, 4)>
a b c d
0 0.558083 0.665184 0.226173 0.339905
1 0.541712 0.835804 0.326078 0.179103
2 0.332869 0.435573 0.904612 0.823884
Attributes
author: new name
date: 2015-12-31
new attribute: changed in python!
to_header
to_header allows you to write the special attributes directly to a metacsv-formatted header file. The special attributes may be individually specified or taken from a metacsv container. The header_file argument to both read_csv and to_csv allow the creation of special header files which allow you to separate the metacsv-formatted header from the data if desired.
For example, say you have a table to read into pandas
>>> import metacsv, pandas as pd
>>> pd.DataFrame(
[['x',1,2,3],['y',4,5,6],['z',7,8,9]], columns=['index','a','b','c']).to_csv('mycsv.csv', index=None)
>>> metacsv.read_csv('mycsv.csv')
<metacsv.core.containers.DataFrame (3, 4)>
index a b c
0 x 1 2 3
1 y 4 5 6
2 z 7 8 9
A separate header file can be created and used which can then be read in with the data:
>>> metacsv.to_header('mycsv.header', attrs={'author': 'me'}, coords='index')
>>> metacsv.read_csv('mycsv.csv', header_file='mycsv.header')
<metacsv.core.containers.DataFrame (3, 3)>
a b c
index
x 1 2 3
y 4 5 6
z 7 8 9
Coordinates
* index (index) object x, y, z
Attributes
author: me
to_xarray
to_xarray returns any container or csv file as an xarray container. Table data (CSV files and DataFrames) will create xarray.Dataset objects, while Series objects will create xarray.DataArray objects. Keyword arguments attrs, coords, and variables will be attached to the data before it is written. Any conflicts in these attributes will be updated with the arguments to this function.
to_dataarray
to_dataarray returns any container or csv file as an xarray.DataArray. Table data (CSV files and DataFrames) will be stacked, with columns re-arranged as new xarray.Coordinates. Keyword arguments attrs, coords, and variables will be attached to the data before it is written. Any conflicts in these attributes will be updated with the arguments to this function.
to_dataset
to_dataarray returns any container or csv file as an xarray.DataArray. Table data (CSV files and DataFrames) will be stacked, with columns re-arranged as new xarray.Coordinates. Keyword arguments attrs, coords, and variables will be attached to the data before it is written. Any conflicts in these attributes will be updated with the arguments to this function.
to_pandas
to_pandas strips special attributes and returns an ordinary Series or DataFrame object.
to_netcdf
to_netcdf first converts a container or csv file to an xarray.Dataset using the to_dataset function, then writes the dataset to file with the xarray ds.to_netcdf method.
>>> metacsv.to_netcdf('mycsv.csv', 'mycsv.nc', header_file='mycsv.header')
>>> import xarray as xr
>>> xr.open_dataset('mycsv.nc')
<xarray.Dataset>
Dimensions: (index: 3)
Coordinates:
* index (index) |S1 'x' 'y' 'z'
Data variables:
a (index) int64 1 4 7
b (index) int64 2 5 8
c (index) int64 3 6 9
Attributes:
author: me
Special attributes
The coords and variables attributes are keywords and are not simply passed to the MetaCSV object’s attrs attribute.
Variables
Variables are attributes which apply to speicific columns or data variables. In MetaCSV containers, variables are displayed as a separate set of attributes. On conversion to xarray, these attributes are assigned to variable-specific attrs:
>>> ds = df.to_xarray()
>>> ds
<xarray.Dataset>
Dimensions: (index: 4)
Coordinates:
* index (index) int64 0 1 2 3
Data variables:
region (index) object 'USA' 'USA' 'CAN' 'CAN'
year (index) int64 2010 2011 2010 2011
pop (index) float64 309.3 311.7 34.0 34.3
gdp (index) float64 1.36e+04 1.382e+04 1.24e+03 1.277e+03
Attributes:
date: 2000-12-31
author: A Person
>>> ds.pop
<xarray.DataArray 'pop' (index: 4)>
array([ 309.3, 311.7, 34. , 34.3])
Coordinates:
* index (index) int64 0 1 2 3
Attributes:
name: Population
unit: millions
Note that at present, variables are not persistent across slicing operations.
parse_vars
Variables have a special argument to read_csv: parse_vars allows parsing of one-line variable definitions in the format var: description [unit]:
>>> doc = io.StringIO('''
---
author: A Person
date: 2000-12-31
variables:
pop: Population [millions]
gdp: Product [2005 $Bn]
...
region,year,pop,gdp
USA,2010,309.3,13599.3
USA,2011,311.7,13817.0
CAN,2010,34.0,1240.0
CAN,2011,34.3,1276.7
''')
>>> metacsv.read_csv(doc, index_col=0, parse_vars=True)
<metacsv.core.containers.DataFrame (4, 3)>
year pop gdp
region
USA 2010 309.3 13599.3
USA 2011 311.7 13817.0
CAN 2010 34.0 1240.0
CAN 2011 34.3 1276.7
Variables
gdp: {u'description': 'Product', u'unit': '2005 $Bn'}
pop: {u'description': 'Population', u'unit': 'millions'}
Attributes
date: 2000-12-31
author: A Person
Coordinates
The conceptual foundation of coordinates is taken from xarray, where data is treated as an ndarray rather than a table. If you plan to only work with the pandas-like features of metacsv, you do not really need coordinates.
That said, specifying the coords attribute in a csv results in automatic index handling:
>>> doc = io.StringIO('''
---
author: A Person
date: 2000-12-31
variables:
pop:
name: Population
unit: millions
gdp:
name: Product
unit: 2005 $Bn
coords:
- region
- year
...
region,year,pop,gdp
USA,2010,309.3,13599.3
USA,2011,311.7,13817.0
CAN,2010,34.0,1240.0
CAN,2011,34.3,1276.7
''')
>>> df = metacsv.read_csv(doc)
>>> df
<metacsv.core.containers.DataFrame (4, 2)>
pop gdp
region year
USA 2010 309.3 13599.3
2011 311.7 13817.0
CAN 2010 34.0 1240.0
2011 34.3 1276.7
Coordinates
* region (region) object CAN, USA
* year (year) int64 2010, 2011
Variables
gdp: OrderedDict([('name', 'Product'), ('unit', '2005 $Bn')])
pop: OrderedDict([('name', 'Population'), ('unit', 'millions')])
Attributes
date: 2000-12-31
author: A Person
Coordinates become especially useful, however, when moving to xarray objects or netCDF files. The DataFrame above will have no trouble, as region and year are orthoganal:
>>> df.to_xarray()
<xarray.Dataset>
Dimensions: (region: 2, year: 2)
Coordinates:
* region (region) object 'USA' 'CAN'
* year (year) int64 2010 2011
Data variables:
pop (region, year) float64 309.3 311.7 34.0 34.3
gdp (region, year) float64 1.36e+04 1.382e+04 1.24e+03 1.277e+03
Attributes:
date: 2000-12-31
author: A Person
This becomes more complicated when columns in the index are not independent and cannot be thought of as orthogonal. In this case, you can specify coords as a dict-like attribute either in the CSV header or as an argument to the conversion method:
doc = io.StringIO('''
---
coords:
region:
regname: 'region'
continent: 'region'
year:
...
region,regname,continent,year,pop,gdp
USA,United States,North America,2010,309.3,13599.3
USA,United States,North America,2011,311.7,13817.0
CAN,Canada,North America,2010,34.0,1240.0
CAN,Canada,North America,2011,34.3,1276.7
''')
>>> metacsv.to_xarray(doc)
<xarray.Dataset>
Dimensions: (region: 2, year: 2)
Coordinates:
* region (region) object 'USA' 'CAN'
* year (year) int64 2010 2011
regname (region) object 'United States' 'Canada'
continent (region) object 'North America' 'North America'
Data variables:
pop (region, year) float64 309.3 311.7 34.0 34.3
gdp (region, year) float64 1.36e+04 1.382e+04 1.24e+03 1.277e+03
Note that the resulting Dataset is not indexed by the cartesian product of all four coordinates, but only by the base coordinates, indicated by the *. Without first setting the coords attribute this way, the resulting data would have NaN values corresponding to (USA, Canada) and (CAN, United States).
TODO
Allow automatic coersion of xarray.Dataset and xarray.DataArray objects to MetaCSV containers.
Extend metacsv functionality to Panel objects
Make coords and attrs persistent across slicing operations (try df['pop'].to_xarray() from above example and watch it fail…)
Improve hooks between pandas and metacsv:
update coord names on df.index.names assignment
update coords on stack/unstack
update coords on
Improve parser to automatically strip trailing commas and other excel relics
Enable read_csv(engine='C')… this currently does not work.
Handle attributes indexed by coord/variable names –> assign to coord/variable-specific attrs
Let’s start an issue tracker and get rid of this section!
Should we rethink “special attribute,” naming e.g. coords? Maybe these should have some special prefix like _coords when included in yaml headers to avoid confusion with other generic attributes…
Allow attribute assertions (e.g. version='>1.6.0') in read_csv call
Improve test coverage
Improve documentation & build readthedocs page
Feature Requests
Create syntax for multi-csv –> Panel or combining using filename regex
Eventually? allow for on-disk manipulation of many/large files with dask/xarray
Eventually? add xml, SQL, other structured syntax language conversions
Changelog
Here you can find the recent changes to MetaCSV..
version dev
released Ongoing
Updated CHANGES.
version 0.0.1
released 2016-05-04
First release on PyPi.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file MetaCSV-0.1.1.tar.gz
.
File metadata
- Download URL: MetaCSV-0.1.1.tar.gz
- Upload date:
- Size: 26.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.7.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | b946952189ca6b1016409091d78b42b6b17a4a303d5b0ed36174c72a16527925 |
|
MD5 | 6d033dd5b4eb1a39ababee58ecca8f4a |
|
BLAKE2b-256 | 62ce36d01f4150f7ad7d9f3cbe09aa67df660ecb77bd524183a4e045bd1d7bac |
File details
Details for the file MetaCSV-0.1.1-py2.py3-none-any.whl
.
File metadata
- Download URL: MetaCSV-0.1.1-py2.py3-none-any.whl
- Upload date:
- Size: 27.8 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.7.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e7eeab0cc7330ad8fb9a2bf353c3b9f2dd1f24556c9ea73923fd5125a3bb9ef0 |
|
MD5 | d15fa9b494e48bbe52c240bbc52a10bb |
|
BLAKE2b-256 | b48848299b7ad9251c0c6ac7c8736d34e50daa288f5930cce61cec1080bdf5c2 |