Repository files navigation

Table Builder IO

table_builder_io defines a minimal API for reading CSVs downloaded from ABS TableBuilder without manual editing of the raw data.

It serves to avoid/ replace bespoke ways of preparing table builder data e.g.

  • Cleaning the header and footer data manually
  • Trying to be clever with magic arguments to pandas read_csv skipheader and skipfooter that may or may not need to be adjusted every time
  • Realising your magic arguments to skipheader and skipfooter are only part of the problem when you have defined wafers and resort to manually cleaning CSVs
  • Hacky flattening of row level index labels and column labels into a single set of column headers that definitely works every time

Installation

The recommendation is to install table_builder_io with pip,

python -m pip install table_builder_io

Dependencies

Besides python itself, the only dependency for table_builder_io is pandas. It has been tested on pandas 1.1.x but does not use any special functionality, so may work on older versions as well. The light requirements mean that pip installing into a conda environment after pandas has already been installed should be relatively safe.

Developer install

To install for local development in your virtual environemnt tool of choice, active the environment then,

git clone git@github.com:vlc/table_builder_io.git
cd table_builder_io
python -m pip install -e .

table_builder_io requires python >=3.6 as it uses f-strings and standard library type hints. It has been explicitly tested on Python 3.6, 3.8 and 3.10.

Example

Lets say you have a table builder file that looks something like this

Australian Bureau of Statistics"2016 Census - Counting Persons, Place of Enumeration (MB)"
"SEXP Sex and FMGF - 1 Digit Level by STATE"
"Counting: Persons Location on Census Night"
Filters:
"Default Summation","Persons Location on Census Night","STATE","New South Wales","Victoria","Queensland","South Australia","Western Australia","Tasmania","Northern Territory","Australian Capital Territory","Other Territories","Total","SEXP Sex","FMGF - 1 Digit Level","Male","Couple family with grandchildren",20710,12307,14166,4066,7151,1435,1926,702,10,62463,,"Lone grandparent",10617,6127,6351,2085,3369,671,1486,302,13,31019,,"Not applicable",3692904,2892405,2362975,817562,1250871,244515,132578,196526,2853,11593188,"Female","Couple family with grandchildren",19712,11688,13790,3723,7000,1364,1820,723,10,59827,,"Lone grandparent",15730,9441,9534,3135,5042,961,1827,462,13,46152,,"Not applicable",3805273,3014087,2437722,844224,1244420,255233,119476,201935,2410,11924766,"Total","Couple family with grandchildren",40422,23999,27950,7780,14154,2793,3742,1423,21,122290,,"Lone grandparent",26351,15572,15892,5219,8409,1629,3317,761,27,77165,,"Not applicable",7498170,5906487,4800703,1661786,2495294,499744,252053,398458,5265,23517955,"Data Source: Census of Population and Housing, 2016, TableBuilder""INFO","Cells in this table have been randomly adjusted to avoid the release of confidential data. No reliance should be placed on small cells.""Copyright Commonwealth of Australia, 2018, see abs.gov.au/copyright""ABS data licensed under Creative Commons, see abs.gov.au/ccby"

table_builder_io (for now) defines a single public class TableBuilderReader which is used like so

In[1]: fromtable_builder_ioimportTableBuilderReaderIn[2]: reader=TableBuilderReader.from_file("test/mini_testfile.csv")
In[3]: df=reader.read_table(as_index=True)
In[4]: df.iloc[:, :4].head()
Out[4]:
STATENewSouthWalesVictoriaQueenslandSouthAustraliaSEXPSexFMGF-1DigitLevelMaleCouplefamilywithgrandchildren2071012307141664066Lonegrandparent10617612763512085Notapplicable369290428924052362975817562FemaleCouplefamilywithgrandchildren1971211688137903723Lonegrandparent15730944195343135# Or alternatively as a flat dataframeIn[5]: df2=reader.read(as_index=False)
In[6]: df2.iloc[:, :6].head()
Out[6]:
SEXPSexFMGF-1DigitLevelNewSouthWalesVictoriaQueenslandSouthAustralia0MaleCouplefamilywithgrandchildren20710123071416640661MaleLonegrandparent106176127635120852MaleNotapplicable3692904289240523629758175623FemaleCouplefamilywithgrandchildren19712116881379037234FemaleLonegrandparent15730944195343135Int[7]: reader.read_header_metadata() Out[7]:
HeaderInfo(authority='Australian Bureau of Statistics',
dataset='2016 Census - Counting Persons, Place of Enumeration (MB)',
variables='SEXP Sex and FMGF - 1 Digit Level by STATE',
counting='Persons Location on Census Night',
filters='',
summation='Persons Location on Census Night')

For more examples, see Examples on Github

Supported Formats

Currently should support

  • CSVs with multilevel / hierarchical row headers (as in the example above)
  • CSVs with multilevel / hierarchical row headers (e.g. the transpose of the above data)
  • Wafers: TableBuilderReader.read returns a Dict[str, pd.DataFrame] where the keys are the wafer names if wafers are found
  • Currently only intending to support CSV format from Table Builder

In theory easy to add

  • Support for datasets with filters
  • support for NVS TableBuilder headers/ footers
  • extraction of header/ footer metadata in a retrievable way
  • Standard utils after loading the table into memory

Performance

  • Not a super optimised implementation, need to be able to read everything into memory

  • File is scanned twice - once to look for header/ footer/ wafers and then to read the csvs

  • First scan is python, second scan is pandas csv reader (c engine)

  • So maybe not the best if you have data sizes near the cell limit

  • Internals are still messy because I haven't cleaned them up yet, waiting since I expect stuff to break

Acknowledgements

About

Read ABS Table Builder files painlessly in python

Resources

Stars

2 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Table Builder IO

table_builder_io defines a minimal API for reading CSVs downloaded from ABS TableBuilder without manual editing of the raw data.

It serves to avoid/ replace bespoke ways of preparing table builder data e.g.

  • Cleaning the header and footer data manually
  • Trying to be clever with magic arguments to pandas read_csv skipheader and skipfooter that may or may not need to be adjusted every time
  • Realising your magic arguments to skipheader and skipfooter are only part of the problem when you have defined wafers and resort to manually cleaning CSVs
  • Hacky flattening of row level index labels and column labels into a single set of column headers that definitely works every time

Installation

The recommendation is to install table_builder_io with pip,

python -m pip install table_builder_io

Dependencies

Besides python itself, the only dependency for table_builder_io is pandas. It has been tested on pandas 1.1.x but does not use any special functionality, so may work on older versions as well. The light requirements mean that pip installing into a conda environment after pandas has already been installed should be relatively safe.

Developer install

To install for local development in your virtual environemnt tool of choice, active the environment then,

git clone git@github.com:vlc/table_builder_io.git
cd table_builder_io
python -m pip install -e .

table_builder_io requires python >=3.6 as it uses f-strings and standard library type hints. It has been explicitly tested on Python 3.6, 3.8 and 3.10.

Example

Lets say you have a table builder file that looks something like this

Australian Bureau of Statistics"2016 Census - Counting Persons, Place of Enumeration (MB)"
"SEXP Sex and FMGF - 1 Digit Level by STATE"
"Counting: Persons Location on Census Night"
Filters:
"Default Summation","Persons Location on Census Night","STATE","New South Wales","Victoria","Queensland","South Australia","Western Australia","Tasmania","Northern Territory","Australian Capital Territory","Other Territories","Total","SEXP Sex","FMGF - 1 Digit Level","Male","Couple family with grandchildren",20710,12307,14166,4066,7151,1435,1926,702,10,62463,,"Lone grandparent",10617,6127,6351,2085,3369,671,1486,302,13,31019,,"Not applicable",3692904,2892405,2362975,817562,1250871,244515,132578,196526,2853,11593188,"Female","Couple family with grandchildren",19712,11688,13790,3723,7000,1364,1820,723,10,59827,,"Lone grandparent",15730,9441,9534,3135,5042,961,1827,462,13,46152,,"Not applicable",3805273,3014087,2437722,844224,1244420,255233,119476,201935,2410,11924766,"Total","Couple family with grandchildren",40422,23999,27950,7780,14154,2793,3742,1423,21,122290,,"Lone grandparent",26351,15572,15892,5219,8409,1629,3317,761,27,77165,,"Not applicable",7498170,5906487,4800703,1661786,2495294,499744,252053,398458,5265,23517955,"Data Source: Census of Population and Housing, 2016, TableBuilder""INFO","Cells in this table have been randomly adjusted to avoid the release of confidential data. No reliance should be placed on small cells.""Copyright Commonwealth of Australia, 2018, see abs.gov.au/copyright""ABS data licensed under Creative Commons, see abs.gov.au/ccby"

table_builder_io (for now) defines a single public class TableBuilderReader which is used like so

In[1]: fromtable_builder_ioimportTableBuilderReaderIn[2]: reader=TableBuilderReader.from_file("test/mini_testfile.csv")
In[3]: df=reader.read_table(as_index=True)
In[4]: df.iloc[:, :4].head()
Out[4]:
STATENewSouthWalesVictoriaQueenslandSouthAustraliaSEXPSexFMGF-1DigitLevelMaleCouplefamilywithgrandchildren2071012307141664066Lonegrandparent10617612763512085Notapplicable369290428924052362975817562FemaleCouplefamilywithgrandchildren1971211688137903723Lonegrandparent15730944195343135# Or alternatively as a flat dataframeIn[5]: df2=reader.read(as_index=False)
In[6]: df2.iloc[:, :6].head()
Out[6]:
SEXPSexFMGF-1DigitLevelNewSouthWalesVictoriaQueenslandSouthAustralia0MaleCouplefamilywithgrandchildren20710123071416640661MaleLonegrandparent106176127635120852MaleNotapplicable3692904289240523629758175623FemaleCouplefamilywithgrandchildren19712116881379037234FemaleLonegrandparent15730944195343135Int[7]: reader.read_header_metadata() Out[7]:
HeaderInfo(authority='Australian Bureau of Statistics',
dataset='2016 Census - Counting Persons, Place of Enumeration (MB)',
variables='SEXP Sex and FMGF - 1 Digit Level by STATE',
counting='Persons Location on Census Night',
filters='',
summation='Persons Location on Census Night')

For more examples, see Examples on Github

Supported Formats

Currently should support

  • CSVs with multilevel / hierarchical row headers (as in the example above)
  • CSVs with multilevel / hierarchical row headers (e.g. the transpose of the above data)
  • Wafers: TableBuilderReader.read returns a Dict[str, pd.DataFrame] where the keys are the wafer names if wafers are found
  • Currently only intending to support CSV format from Table Builder

In theory easy to add

  • Support for datasets with filters
  • support for NVS TableBuilder headers/ footers
  • extraction of header/ footer metadata in a retrievable way
  • Standard utils after loading the table into memory

Performance

  • Not a super optimised implementation, need to be able to read everything into memory

  • File is scanned twice - once to look for header/ footer/ wafers and then to read the csvs

  • First scan is python, second scan is pandas csv reader (c engine)

  • So maybe not the best if you have data sizes near the cell limit

  • Internals are still messy because I haven't cleaned them up yet, waiting since I expect stuff to break

Acknowledgements

About

Read ABS Table Builder files painlessly in python

Resources

Stars

2 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Table Builder IO

table_builder_io defines a minimal API for reading CSVs downloaded from ABS TableBuilder without manual editing of the raw data.

It serves to avoid/ replace bespoke ways of preparing table builder data e.g.

  • Cleaning the header and footer data manually
  • Trying to be clever with magic arguments to pandas read_csv skipheader and skipfooter that may or may not need to be adjusted every time
  • Realising your magic arguments to skipheader and skipfooter are only part of the problem when you have defined wafers and resort to manually cleaning CSVs
  • Hacky flattening of row level index labels and column labels into a single set of column headers that definitely works every time

Installation

The recommendation is to install table_builder_io with pip,

python -m pip install table_builder_io

Dependencies

Besides python itself, the only dependency for table_builder_io is pandas. It has been tested on pandas 1.1.x but does not use any special functionality, so may work on older versions as well. The light requirements mean that pip installing into a conda environment after pandas has already been installed should be relatively safe.

Developer install

To install for local development in your virtual environemnt tool of choice, active the environment then,

git clone git@github.com:vlc/table_builder_io.git
cd table_builder_io
python -m pip install -e .

table_builder_io requires python >=3.6 as it uses f-strings and standard library type hints. It has been explicitly tested on Python 3.6, 3.8 and 3.10.

Example

Lets say you have a table builder file that looks something like this

Australian Bureau of Statistics"2016 Census - Counting Persons, Place of Enumeration (MB)"
"SEXP Sex and FMGF - 1 Digit Level by STATE"
"Counting: Persons Location on Census Night"
Filters:
"Default Summation","Persons Location on Census Night","STATE","New South Wales","Victoria","Queensland","South Australia","Western Australia","Tasmania","Northern Territory","Australian Capital Territory","Other Territories","Total","SEXP Sex","FMGF - 1 Digit Level","Male","Couple family with grandchildren",20710,12307,14166,4066,7151,1435,1926,702,10,62463,,"Lone grandparent",10617,6127,6351,2085,3369,671,1486,302,13,31019,,"Not applicable",3692904,2892405,2362975,817562,1250871,244515,132578,196526,2853,11593188,"Female","Couple family with grandchildren",19712,11688,13790,3723,7000,1364,1820,723,10,59827,,"Lone grandparent",15730,9441,9534,3135,5042,961,1827,462,13,46152,,"Not applicable",3805273,3014087,2437722,844224,1244420,255233,119476,201935,2410,11924766,"Total","Couple family with grandchildren",40422,23999,27950,7780,14154,2793,3742,1423,21,122290,,"Lone grandparent",26351,15572,15892,5219,8409,1629,3317,761,27,77165,,"Not applicable",7498170,5906487,4800703,1661786,2495294,499744,252053,398458,5265,23517955,"Data Source: Census of Population and Housing, 2016, TableBuilder""INFO","Cells in this table have been randomly adjusted to avoid the release of confidential data. No reliance should be placed on small cells.""Copyright Commonwealth of Australia, 2018, see abs.gov.au/copyright""ABS data licensed under Creative Commons, see abs.gov.au/ccby"

table_builder_io (for now) defines a single public class TableBuilderReader which is used like so

In[1]: fromtable_builder_ioimportTableBuilderReaderIn[2]: reader=TableBuilderReader.from_file("test/mini_testfile.csv")
In[3]: df=reader.read_table(as_index=True)
In[4]: df.iloc[:, :4].head()
Out[4]:
STATENewSouthWalesVictoriaQueenslandSouthAustraliaSEXPSexFMGF-1DigitLevelMaleCouplefamilywithgrandchildren2071012307141664066Lonegrandparent10617612763512085Notapplicable369290428924052362975817562FemaleCouplefamilywithgrandchildren1971211688137903723Lonegrandparent15730944195343135# Or alternatively as a flat dataframeIn[5]: df2=reader.read(as_index=False)
In[6]: df2.iloc[:, :6].head()
Out[6]:
SEXPSexFMGF-1DigitLevelNewSouthWalesVictoriaQueenslandSouthAustralia0MaleCouplefamilywithgrandchildren20710123071416640661MaleLonegrandparent106176127635120852MaleNotapplicable3692904289240523629758175623FemaleCouplefamilywithgrandchildren19712116881379037234FemaleLonegrandparent15730944195343135Int[7]: reader.read_header_metadata() Out[7]:
HeaderInfo(authority='Australian Bureau of Statistics',
dataset='2016 Census - Counting Persons, Place of Enumeration (MB)',
variables='SEXP Sex and FMGF - 1 Digit Level by STATE',
counting='Persons Location on Census Night',
filters='',
summation='Persons Location on Census Night')

For more examples, see Examples on Github

Supported Formats

Currently should support

  • CSVs with multilevel / hierarchical row headers (as in the example above)
  • CSVs with multilevel / hierarchical row headers (e.g. the transpose of the above data)
  • Wafers: TableBuilderReader.read returns a Dict[str, pd.DataFrame] where the keys are the wafer names if wafers are found
  • Currently only intending to support CSV format from Table Builder

In theory easy to add

  • Support for datasets with filters
  • support for NVS TableBuilder headers/ footers
  • extraction of header/ footer metadata in a retrievable way
  • Standard utils after loading the table into memory

Performance

  • Not a super optimised implementation, need to be able to read everything into memory

  • File is scanned twice - once to look for header/ footer/ wafers and then to read the csvs

  • First scan is python, second scan is pandas csv reader (c engine)

  • So maybe not the best if you have data sizes near the cell limit

  • Internals are still messy because I haven't cleaned them up yet, waiting since I expect stuff to break

Acknowledgements

About

Read ABS Table Builder files painlessly in python

Resources

Stars

2 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Table Builder IO

table_builder_io defines a minimal API for reading CSVs downloaded from ABS TableBuilder without manual editing of the raw data.

It serves to avoid/ replace bespoke ways of preparing table builder data e.g.

  • Cleaning the header and footer data manually
  • Trying to be clever with magic arguments to pandas read_csv skipheader and skipfooter that may or may not need to be adjusted every time
  • Realising your magic arguments to skipheader and skipfooter are only part of the problem when you have defined wafers and resort to manually cleaning CSVs
  • Hacky flattening of row level index labels and column labels into a single set of column headers that definitely works every time

Installation

The recommendation is to install table_builder_io with pip,

python -m pip install table_builder_io

Dependencies

Besides python itself, the only dependency for table_builder_io is pandas. It has been tested on pandas 1.1.x but does not use any special functionality, so may work on older versions as well. The light requirements mean that pip installing into a conda environment after pandas has already been installed should be relatively safe.

Developer install

To install for local development in your virtual environemnt tool of choice, active the environment then,

git clone git@github.com:vlc/table_builder_io.git
cd table_builder_io
python -m pip install -e .

table_builder_io requires python >=3.6 as it uses f-strings and standard library type hints. It has been explicitly tested on Python 3.6, 3.8 and 3.10.

Example

Lets say you have a table builder file that looks something like this

Australian Bureau of Statistics"2016 Census - Counting Persons, Place of Enumeration (MB)"
"SEXP Sex and FMGF - 1 Digit Level by STATE"
"Counting: Persons Location on Census Night"
Filters:
"Default Summation","Persons Location on Census Night","STATE","New South Wales","Victoria","Queensland","South Australia","Western Australia","Tasmania","Northern Territory","Australian Capital Territory","Other Territories","Total","SEXP Sex","FMGF - 1 Digit Level","Male","Couple family with grandchildren",20710,12307,14166,4066,7151,1435,1926,702,10,62463,,"Lone grandparent",10617,6127,6351,2085,3369,671,1486,302,13,31019,,"Not applicable",3692904,2892405,2362975,817562,1250871,244515,132578,196526,2853,11593188,"Female","Couple family with grandchildren",19712,11688,13790,3723,7000,1364,1820,723,10,59827,,"Lone grandparent",15730,9441,9534,3135,5042,961,1827,462,13,46152,,"Not applicable",3805273,3014087,2437722,844224,1244420,255233,119476,201935,2410,11924766,"Total","Couple family with grandchildren",40422,23999,27950,7780,14154,2793,3742,1423,21,122290,,"Lone grandparent",26351,15572,15892,5219,8409,1629,3317,761,27,77165,,"Not applicable",7498170,5906487,4800703,1661786,2495294,499744,252053,398458,5265,23517955,"Data Source: Census of Population and Housing, 2016, TableBuilder""INFO","Cells in this table have been randomly adjusted to avoid the release of confidential data. No reliance should be placed on small cells.""Copyright Commonwealth of Australia, 2018, see abs.gov.au/copyright""ABS data licensed under Creative Commons, see abs.gov.au/ccby"

table_builder_io (for now) defines a single public class TableBuilderReader which is used like so

In[1]: fromtable_builder_ioimportTableBuilderReaderIn[2]: reader=TableBuilderReader.from_file("test/mini_testfile.csv")
In[3]: df=reader.read_table(as_index=True)
In[4]: df.iloc[:, :4].head()
Out[4]:
STATENewSouthWalesVictoriaQueenslandSouthAustraliaSEXPSexFMGF-1DigitLevelMaleCouplefamilywithgrandchildren2071012307141664066Lonegrandparent10617612763512085Notapplicable369290428924052362975817562FemaleCouplefamilywithgrandchildren1971211688137903723Lonegrandparent15730944195343135# Or alternatively as a flat dataframeIn[5]: df2=reader.read(as_index=False)
In[6]: df2.iloc[:, :6].head()
Out[6]:
SEXPSexFMGF-1DigitLevelNewSouthWalesVictoriaQueenslandSouthAustralia0MaleCouplefamilywithgrandchildren20710123071416640661MaleLonegrandparent106176127635120852MaleNotapplicable3692904289240523629758175623FemaleCouplefamilywithgrandchildren19712116881379037234FemaleLonegrandparent15730944195343135Int[7]: reader.read_header_metadata() Out[7]:
HeaderInfo(authority='Australian Bureau of Statistics',
dataset='2016 Census - Counting Persons, Place of Enumeration (MB)',
variables='SEXP Sex and FMGF - 1 Digit Level by STATE',
counting='Persons Location on Census Night',
filters='',
summation='Persons Location on Census Night')

For more examples, see Examples on Github

Supported Formats

Currently should support

  • CSVs with multilevel / hierarchical row headers (as in the example above)
  • CSVs with multilevel / hierarchical row headers (e.g. the transpose of the above data)
  • Wafers: TableBuilderReader.read returns a Dict[str, pd.DataFrame] where the keys are the wafer names if wafers are found
  • Currently only intending to support CSV format from Table Builder

In theory easy to add

  • Support for datasets with filters
  • support for NVS TableBuilder headers/ footers
  • extraction of header/ footer metadata in a retrievable way
  • Standard utils after loading the table into memory

Performance

  • Not a super optimised implementation, need to be able to read everything into memory

  • File is scanned twice - once to look for header/ footer/ wafers and then to read the csvs

  • First scan is python, second scan is pandas csv reader (c engine)

  • So maybe not the best if you have data sizes near the cell limit

  • Internals are still messy because I haven't cleaned them up yet, waiting since I expect stuff to break

Acknowledgements

About

Read ABS Table Builder files painlessly in python

Resources

Stars

2 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Table Builder IO

table_builder_io defines a minimal API for reading CSVs downloaded from ABS TableBuilder without manual editing of the raw data.

It serves to avoid/ replace bespoke ways of preparing table builder data e.g.

  • Cleaning the header and footer data manually
  • Trying to be clever with magic arguments to pandas read_csv skipheader and skipfooter that may or may not need to be adjusted every time
  • Realising your magic arguments to skipheader and skipfooter are only part of the problem when you have defined wafers and resort to manually cleaning CSVs
  • Hacky flattening of row level index labels and column labels into a single set of column headers that definitely works every time

Installation

The recommendation is to install table_builder_io with pip,

python -m pip install table_builder_io

Dependencies

Besides python itself, the only dependency for table_builder_io is pandas. It has been tested on pandas 1.1.x but does not use any special functionality, so may work on older versions as well. The light requirements mean that pip installing into a conda environment after pandas has already been installed should be relatively safe.

Developer install

To install for local development in your virtual environemnt tool of choice, active the environment then,

git clone git@github.com:vlc/table_builder_io.git
cd table_builder_io
python -m pip install -e .

table_builder_io requires python >=3.6 as it uses f-strings and standard library type hints. It has been explicitly tested on Python 3.6, 3.8 and 3.10.

Example

Lets say you have a table builder file that looks something like this

Australian Bureau of Statistics"2016 Census - Counting Persons, Place of Enumeration (MB)"
"SEXP Sex and FMGF - 1 Digit Level by STATE"
"Counting: Persons Location on Census Night"
Filters:
"Default Summation","Persons Location on Census Night","STATE","New South Wales","Victoria","Queensland","South Australia","Western Australia","Tasmania","Northern Territory","Australian Capital Territory","Other Territories","Total","SEXP Sex","FMGF - 1 Digit Level","Male","Couple family with grandchildren",20710,12307,14166,4066,7151,1435,1926,702,10,62463,,"Lone grandparent",10617,6127,6351,2085,3369,671,1486,302,13,31019,,"Not applicable",3692904,2892405,2362975,817562,1250871,244515,132578,196526,2853,11593188,"Female","Couple family with grandchildren",19712,11688,13790,3723,7000,1364,1820,723,10,59827,,"Lone grandparent",15730,9441,9534,3135,5042,961,1827,462,13,46152,,"Not applicable",3805273,3014087,2437722,844224,1244420,255233,119476,201935,2410,11924766,"Total","Couple family with grandchildren",40422,23999,27950,7780,14154,2793,3742,1423,21,122290,,"Lone grandparent",26351,15572,15892,5219,8409,1629,3317,761,27,77165,,"Not applicable",7498170,5906487,4800703,1661786,2495294,499744,252053,398458,5265,23517955,"Data Source: Census of Population and Housing, 2016, TableBuilder""INFO","Cells in this table have been randomly adjusted to avoid the release of confidential data. No reliance should be placed on small cells.""Copyright Commonwealth of Australia, 2018, see abs.gov.au/copyright""ABS data licensed under Creative Commons, see abs.gov.au/ccby"

table_builder_io (for now) defines a single public class TableBuilderReader which is used like so

In[1]: fromtable_builder_ioimportTableBuilderReaderIn[2]: reader=TableBuilderReader.from_file("test/mini_testfile.csv")
In[3]: df=reader.read_table(as_index=True)
In[4]: df.iloc[:, :4].head()
Out[4]:
STATENewSouthWalesVictoriaQueenslandSouthAustraliaSEXPSexFMGF-1DigitLevelMaleCouplefamilywithgrandchildren2071012307141664066Lonegrandparent10617612763512085Notapplicable369290428924052362975817562FemaleCouplefamilywithgrandchildren1971211688137903723Lonegrandparent15730944195343135# Or alternatively as a flat dataframeIn[5]: df2=reader.read(as_index=False)
In[6]: df2.iloc[:, :6].head()
Out[6]:
SEXPSexFMGF-1DigitLevelNewSouthWalesVictoriaQueenslandSouthAustralia0MaleCouplefamilywithgrandchildren20710123071416640661MaleLonegrandparent106176127635120852MaleNotapplicable3692904289240523629758175623FemaleCouplefamilywithgrandchildren19712116881379037234FemaleLonegrandparent15730944195343135Int[7]: reader.read_header_metadata() Out[7]:
HeaderInfo(authority='Australian Bureau of Statistics',
dataset='2016 Census - Counting Persons, Place of Enumeration (MB)',
variables='SEXP Sex and FMGF - 1 Digit Level by STATE',
counting='Persons Location on Census Night',
filters='',
summation='Persons Location on Census Night')

For more examples, see Examples on Github

Supported Formats

Currently should support

  • CSVs with multilevel / hierarchical row headers (as in the example above)
  • CSVs with multilevel / hierarchical row headers (e.g. the transpose of the above data)
  • Wafers: TableBuilderReader.read returns a Dict[str, pd.DataFrame] where the keys are the wafer names if wafers are found
  • Currently only intending to support CSV format from Table Builder

In theory easy to add

  • Support for datasets with filters
  • support for NVS TableBuilder headers/ footers
  • extraction of header/ footer metadata in a retrievable way
  • Standard utils after loading the table into memory

Performance

  • Not a super optimised implementation, need to be able to read everything into memory

  • File is scanned twice - once to look for header/ footer/ wafers and then to read the csvs

  • First scan is python, second scan is pandas csv reader (c engine)

  • So maybe not the best if you have data sizes near the cell limit

  • Internals are still messy because I haven't cleaned them up yet, waiting since I expect stuff to break

Acknowledgements

About

Read ABS Table Builder files painlessly in python

Resources

Stars

2 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Table Builder IO

table_builder_io defines a minimal API for reading CSVs downloaded from ABS TableBuilder without manual editing of the raw data.

It serves to avoid/ replace bespoke ways of preparing table builder data e.g.

  • Cleaning the header and footer data manually
  • Trying to be clever with magic arguments to pandas read_csv skipheader and skipfooter that may or may not need to be adjusted every time
  • Realising your magic arguments to skipheader and skipfooter are only part of the problem when you have defined wafers and resort to manually cleaning CSVs
  • Hacky flattening of row level index labels and column labels into a single set of column headers that definitely works every time

Installation

The recommendation is to install table_builder_io with pip,

python -m pip install table_builder_io

Dependencies

Besides python itself, the only dependency for table_builder_io is pandas. It has been tested on pandas 1.1.x but does not use any special functionality, so may work on older versions as well. The light requirements mean that pip installing into a conda environment after pandas has already been installed should be relatively safe.

Developer install

To install for local development in your virtual environemnt tool of choice, active the environment then,

git clone git@github.com:vlc/table_builder_io.git
cd table_builder_io
python -m pip install -e .

table_builder_io requires python >=3.6 as it uses f-strings and standard library type hints. It has been explicitly tested on Python 3.6, 3.8 and 3.10.

Example

Lets say you have a table builder file that looks something like this

Australian Bureau of Statistics"2016 Census - Counting Persons, Place of Enumeration (MB)"
"SEXP Sex and FMGF - 1 Digit Level by STATE"
"Counting: Persons Location on Census Night"
Filters:
"Default Summation","Persons Location on Census Night","STATE","New South Wales","Victoria","Queensland","South Australia","Western Australia","Tasmania","Northern Territory","Australian Capital Territory","Other Territories","Total","SEXP Sex","FMGF - 1 Digit Level","Male","Couple family with grandchildren",20710,12307,14166,4066,7151,1435,1926,702,10,62463,,"Lone grandparent",10617,6127,6351,2085,3369,671,1486,302,13,31019,,"Not applicable",3692904,2892405,2362975,817562,1250871,244515,132578,196526,2853,11593188,"Female","Couple family with grandchildren",19712,11688,13790,3723,7000,1364,1820,723,10,59827,,"Lone grandparent",15730,9441,9534,3135,5042,961,1827,462,13,46152,,"Not applicable",3805273,3014087,2437722,844224,1244420,255233,119476,201935,2410,11924766,"Total","Couple family with grandchildren",40422,23999,27950,7780,14154,2793,3742,1423,21,122290,,"Lone grandparent",26351,15572,15892,5219,8409,1629,3317,761,27,77165,,"Not applicable",7498170,5906487,4800703,1661786,2495294,499744,252053,398458,5265,23517955,"Data Source: Census of Population and Housing, 2016, TableBuilder""INFO","Cells in this table have been randomly adjusted to avoid the release of confidential data. No reliance should be placed on small cells.""Copyright Commonwealth of Australia, 2018, see abs.gov.au/copyright""ABS data licensed under Creative Commons, see abs.gov.au/ccby"

table_builder_io (for now) defines a single public class TableBuilderReader which is used like so

In[1]: fromtable_builder_ioimportTableBuilderReaderIn[2]: reader=TableBuilderReader.from_file("test/mini_testfile.csv")
In[3]: df=reader.read_table(as_index=True)
In[4]: df.iloc[:, :4].head()
Out[4]:
STATENewSouthWalesVictoriaQueenslandSouthAustraliaSEXPSexFMGF-1DigitLevelMaleCouplefamilywithgrandchildren2071012307141664066Lonegrandparent10617612763512085Notapplicable369290428924052362975817562FemaleCouplefamilywithgrandchildren1971211688137903723Lonegrandparent15730944195343135# Or alternatively as a flat dataframeIn[5]: df2=reader.read(as_index=False)
In[6]: df2.iloc[:, :6].head()
Out[6]:
SEXPSexFMGF-1DigitLevelNewSouthWalesVictoriaQueenslandSouthAustralia0MaleCouplefamilywithgrandchildren20710123071416640661MaleLonegrandparent106176127635120852MaleNotapplicable3692904289240523629758175623FemaleCouplefamilywithgrandchildren19712116881379037234FemaleLonegrandparent15730944195343135Int[7]: reader.read_header_metadata() Out[7]:
HeaderInfo(authority='Australian Bureau of Statistics',
dataset='2016 Census - Counting Persons, Place of Enumeration (MB)',
variables='SEXP Sex and FMGF - 1 Digit Level by STATE',
counting='Persons Location on Census Night',
filters='',
summation='Persons Location on Census Night')

For more examples, see Examples on Github

Supported Formats

Currently should support

  • CSVs with multilevel / hierarchical row headers (as in the example above)
  • CSVs with multilevel / hierarchical row headers (e.g. the transpose of the above data)
  • Wafers: TableBuilderReader.read returns a Dict[str, pd.DataFrame] where the keys are the wafer names if wafers are found
  • Currently only intending to support CSV format from Table Builder

In theory easy to add

  • Support for datasets with filters
  • support for NVS TableBuilder headers/ footers
  • extraction of header/ footer metadata in a retrievable way
  • Standard utils after loading the table into memory

Performance

  • Not a super optimised implementation, need to be able to read everything into memory

  • File is scanned twice - once to look for header/ footer/ wafers and then to read the csvs

  • First scan is python, second scan is pandas csv reader (c engine)

  • So maybe not the best if you have data sizes near the cell limit

  • Internals are still messy because I haven't cleaned them up yet, waiting since I expect stuff to break

Acknowledgements

About

Read ABS Table Builder files painlessly in python

Resources

Stars

2 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Table Builder IO

table_builder_io defines a minimal API for reading CSVs downloaded from ABS TableBuilder without manual editing of the raw data.

It serves to avoid/ replace bespoke ways of preparing table builder data e.g.

  • Cleaning the header and footer data manually
  • Trying to be clever with magic arguments to pandas read_csv skipheader and skipfooter that may or may not need to be adjusted every time
  • Realising your magic arguments to skipheader and skipfooter are only part of the problem when you have defined wafers and resort to manually cleaning CSVs
  • Hacky flattening of row level index labels and column labels into a single set of column headers that definitely works every time

Installation

The recommendation is to install table_builder_io with pip,

python -m pip install table_builder_io

Dependencies

Besides python itself, the only dependency for table_builder_io is pandas. It has been tested on pandas 1.1.x but does not use any special functionality, so may work on older versions as well. The light requirements mean that pip installing into a conda environment after pandas has already been installed should be relatively safe.

Developer install

To install for local development in your virtual environemnt tool of choice, active the environment then,

git clone git@github.com:vlc/table_builder_io.git
cd table_builder_io
python -m pip install -e .

table_builder_io requires python >=3.6 as it uses f-strings and standard library type hints. It has been explicitly tested on Python 3.6, 3.8 and 3.10.

Example

Lets say you have a table builder file that looks something like this

Australian Bureau of Statistics"2016 Census - Counting Persons, Place of Enumeration (MB)"
"SEXP Sex and FMGF - 1 Digit Level by STATE"
"Counting: Persons Location on Census Night"
Filters:
"Default Summation","Persons Location on Census Night","STATE","New South Wales","Victoria","Queensland","South Australia","Western Australia","Tasmania","Northern Territory","Australian Capital Territory","Other Territories","Total","SEXP Sex","FMGF - 1 Digit Level","Male","Couple family with grandchildren",20710,12307,14166,4066,7151,1435,1926,702,10,62463,,"Lone grandparent",10617,6127,6351,2085,3369,671,1486,302,13,31019,,"Not applicable",3692904,2892405,2362975,817562,1250871,244515,132578,196526,2853,11593188,"Female","Couple family with grandchildren",19712,11688,13790,3723,7000,1364,1820,723,10,59827,,"Lone grandparent",15730,9441,9534,3135,5042,961,1827,462,13,46152,,"Not applicable",3805273,3014087,2437722,844224,1244420,255233,119476,201935,2410,11924766,"Total","Couple family with grandchildren",40422,23999,27950,7780,14154,2793,3742,1423,21,122290,,"Lone grandparent",26351,15572,15892,5219,8409,1629,3317,761,27,77165,,"Not applicable",7498170,5906487,4800703,1661786,2495294,499744,252053,398458,5265,23517955,"Data Source: Census of Population and Housing, 2016, TableBuilder""INFO","Cells in this table have been randomly adjusted to avoid the release of confidential data. No reliance should be placed on small cells.""Copyright Commonwealth of Australia, 2018, see abs.gov.au/copyright""ABS data licensed under Creative Commons, see abs.gov.au/ccby"

table_builder_io (for now) defines a single public class TableBuilderReader which is used like so

In[1]: fromtable_builder_ioimportTableBuilderReaderIn[2]: reader=TableBuilderReader.from_file("test/mini_testfile.csv")
In[3]: df=reader.read_table(as_index=True)
In[4]: df.iloc[:, :4].head()
Out[4]:
STATENewSouthWalesVictoriaQueenslandSouthAustraliaSEXPSexFMGF-1DigitLevelMaleCouplefamilywithgrandchildren2071012307141664066Lonegrandparent10617612763512085Notapplicable369290428924052362975817562FemaleCouplefamilywithgrandchildren1971211688137903723Lonegrandparent15730944195343135# Or alternatively as a flat dataframeIn[5]: df2=reader.read(as_index=False)
In[6]: df2.iloc[:, :6].head()
Out[6]:
SEXPSexFMGF-1DigitLevelNewSouthWalesVictoriaQueenslandSouthAustralia0MaleCouplefamilywithgrandchildren20710123071416640661MaleLonegrandparent106176127635120852MaleNotapplicable3692904289240523629758175623FemaleCouplefamilywithgrandchildren19712116881379037234FemaleLonegrandparent15730944195343135Int[7]: reader.read_header_metadata() Out[7]:
HeaderInfo(authority='Australian Bureau of Statistics',
dataset='2016 Census - Counting Persons, Place of Enumeration (MB)',
variables='SEXP Sex and FMGF - 1 Digit Level by STATE',
counting='Persons Location on Census Night',
filters='',
summation='Persons Location on Census Night')

For more examples, see Examples on Github

Supported Formats

Currently should support

  • CSVs with multilevel / hierarchical row headers (as in the example above)
  • CSVs with multilevel / hierarchical row headers (e.g. the transpose of the above data)
  • Wafers: TableBuilderReader.read returns a Dict[str, pd.DataFrame] where the keys are the wafer names if wafers are found
  • Currently only intending to support CSV format from Table Builder

In theory easy to add

  • Support for datasets with filters
  • support for NVS TableBuilder headers/ footers
  • extraction of header/ footer metadata in a retrievable way
  • Standard utils after loading the table into memory

Performance

  • Not a super optimised implementation, need to be able to read everything into memory

  • File is scanned twice - once to look for header/ footer/ wafers and then to read the csvs

  • First scan is python, second scan is pandas csv reader (c engine)

  • So maybe not the best if you have data sizes near the cell limit

  • Internals are still messy because I haven't cleaned them up yet, waiting since I expect stuff to break

Acknowledgements

About

Read ABS Table Builder files painlessly in python

Resources

Stars

2 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Table Builder IO

table_builder_io defines a minimal API for reading CSVs downloaded from ABS TableBuilder without manual editing of the raw data.

It serves to avoid/ replace bespoke ways of preparing table builder data e.g.

  • Cleaning the header and footer data manually
  • Trying to be clever with magic arguments to pandas read_csv skipheader and skipfooter that may or may not need to be adjusted every time
  • Realising your magic arguments to skipheader and skipfooter are only part of the problem when you have defined wafers and resort to manually cleaning CSVs
  • Hacky flattening of row level index labels and column labels into a single set of column headers that definitely works every time

Installation

The recommendation is to install table_builder_io with pip,

python -m pip install table_builder_io

Dependencies

Besides python itself, the only dependency for table_builder_io is pandas. It has been tested on pandas 1.1.x but does not use any special functionality, so may work on older versions as well. The light requirements mean that pip installing into a conda environment after pandas has already been installed should be relatively safe.

Developer install

To install for local development in your virtual environemnt tool of choice, active the environment then,

git clone git@github.com:vlc/table_builder_io.git
cd table_builder_io
python -m pip install -e .

table_builder_io requires python >=3.6 as it uses f-strings and standard library type hints. It has been explicitly tested on Python 3.6, 3.8 and 3.10.

Example

Lets say you have a table builder file that looks something like this

Australian Bureau of Statistics"2016 Census - Counting Persons, Place of Enumeration (MB)"
"SEXP Sex and FMGF - 1 Digit Level by STATE"
"Counting: Persons Location on Census Night"
Filters:
"Default Summation","Persons Location on Census Night","STATE","New South Wales","Victoria","Queensland","South Australia","Western Australia","Tasmania","Northern Territory","Australian Capital Territory","Other Territories","Total","SEXP Sex","FMGF - 1 Digit Level","Male","Couple family with grandchildren",20710,12307,14166,4066,7151,1435,1926,702,10,62463,,"Lone grandparent",10617,6127,6351,2085,3369,671,1486,302,13,31019,,"Not applicable",3692904,2892405,2362975,817562,1250871,244515,132578,196526,2853,11593188,"Female","Couple family with grandchildren",19712,11688,13790,3723,7000,1364,1820,723,10,59827,,"Lone grandparent",15730,9441,9534,3135,5042,961,1827,462,13,46152,,"Not applicable",3805273,3014087,2437722,844224,1244420,255233,119476,201935,2410,11924766,"Total","Couple family with grandchildren",40422,23999,27950,7780,14154,2793,3742,1423,21,122290,,"Lone grandparent",26351,15572,15892,5219,8409,1629,3317,761,27,77165,,"Not applicable",7498170,5906487,4800703,1661786,2495294,499744,252053,398458,5265,23517955,"Data Source: Census of Population and Housing, 2016, TableBuilder""INFO","Cells in this table have been randomly adjusted to avoid the release of confidential data. No reliance should be placed on small cells.""Copyright Commonwealth of Australia, 2018, see abs.gov.au/copyright""ABS data licensed under Creative Commons, see abs.gov.au/ccby"

table_builder_io (for now) defines a single public class TableBuilderReader which is used like so

In[1]: fromtable_builder_ioimportTableBuilderReaderIn[2]: reader=TableBuilderReader.from_file("test/mini_testfile.csv")
In[3]: df=reader.read_table(as_index=True)
In[4]: df.iloc[:, :4].head()
Out[4]:
STATENewSouthWalesVictoriaQueenslandSouthAustraliaSEXPSexFMGF-1DigitLevelMaleCouplefamilywithgrandchildren2071012307141664066Lonegrandparent10617612763512085Notapplicable369290428924052362975817562FemaleCouplefamilywithgrandchildren1971211688137903723Lonegrandparent15730944195343135# Or alternatively as a flat dataframeIn[5]: df2=reader.read(as_index=False)
In[6]: df2.iloc[:, :6].head()
Out[6]:
SEXPSexFMGF-1DigitLevelNewSouthWalesVictoriaQueenslandSouthAustralia0MaleCouplefamilywithgrandchildren20710123071416640661MaleLonegrandparent106176127635120852MaleNotapplicable3692904289240523629758175623FemaleCouplefamilywithgrandchildren19712116881379037234FemaleLonegrandparent15730944195343135Int[7]: reader.read_header_metadata() Out[7]:
HeaderInfo(authority='Australian Bureau of Statistics',
dataset='2016 Census - Counting Persons, Place of Enumeration (MB)',
variables='SEXP Sex and FMGF - 1 Digit Level by STATE',
counting='Persons Location on Census Night',
filters='',
summation='Persons Location on Census Night')

For more examples, see Examples on Github

Supported Formats

Currently should support

  • CSVs with multilevel / hierarchical row headers (as in the example above)
  • CSVs with multilevel / hierarchical row headers (e.g. the transpose of the above data)
  • Wafers: TableBuilderReader.read returns a Dict[str, pd.DataFrame] where the keys are the wafer names if wafers are found
  • Currently only intending to support CSV format from Table Builder

In theory easy to add

  • Support for datasets with filters
  • support for NVS TableBuilder headers/ footers
  • extraction of header/ footer metadata in a retrievable way
  • Standard utils after loading the table into memory

Performance

  • Not a super optimised implementation, need to be able to read everything into memory

  • File is scanned twice - once to look for header/ footer/ wafers and then to read the csvs

  • First scan is python, second scan is pandas csv reader (c engine)

  • So maybe not the best if you have data sizes near the cell limit

  • Internals are still messy because I haven't cleaned them up yet, waiting since I expect stuff to break

Acknowledgements

About

Read ABS Table Builder files painlessly in python

Resources

Stars

2 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages