├── data.json ├── datachile ├── client.py ├── exception.py ├── __init__.pyc ├── __init__.py ├── download.py └── chilecube.py ├── datachile.egg-info ├── zip-safe ├── dependency_links.txt ├── top_level.txt ├── requires.txt ├── SOURCES.txt └── PKG-INFO ├── setup.cfg ├── .gitignore ├── test ├── _get_comunas.py ├── _get_measures.py ├── _get_drilldowns.py └── _get.py ├── setup.py ├── test.py ├── LICENSE.txt └── README.md /data.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /datachile/client.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /datachile.egg-info/zip-safe: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /datachile.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /datachile.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | datachile 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md -------------------------------------------------------------------------------- /datachile.egg-info/requires.txt: -------------------------------------------------------------------------------- 1 | mondrian-rest 2 | numpy 3 | requests 4 | -------------------------------------------------------------------------------- /datachile/exception.py: -------------------------------------------------------------------------------- 1 | class InvalidParamException(Exception): 2 | pass -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /dist 3 | /datachile.egg-info 4 | /.vscode 5 | /datachile/__pycache__ -------------------------------------------------------------------------------- /datachile/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datachile/datachile-python-client/HEAD/datachile/__init__.pyc -------------------------------------------------------------------------------- /test/_get_comunas.py: -------------------------------------------------------------------------------- 1 | from datachile import ChileCube 2 | 3 | client = ChileCube() 4 | query = client.get_comunas() 5 | 6 | print(query) -------------------------------------------------------------------------------- /test/_get_measures.py: -------------------------------------------------------------------------------- 1 | from datachile import ChileCube 2 | 3 | client = ChileCube() 4 | cube_id = "election_participation" 5 | 6 | ms = client.get_measures(cube_id) 7 | 8 | print(ms) -------------------------------------------------------------------------------- /test/_get_drilldowns.py: -------------------------------------------------------------------------------- 1 | from datachile import ChileCube 2 | 3 | client = ChileCube() 4 | cube_id = "election_participation" 5 | 6 | dd = client.get_drilldowns(cube_id) 7 | 8 | print(dd) -------------------------------------------------------------------------------- /datachile/__init__.py: -------------------------------------------------------------------------------- 1 | from mondrian_rest import Cube, MondrianClient 2 | from mondrian_rest import Aggregation 3 | from mondrian_rest import Identifier 4 | 5 | from datachile.chilecube import ChileCube -------------------------------------------------------------------------------- /datachile.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | README.md 2 | setup.cfg 3 | setup.py 4 | datachile/__init__.py 5 | datachile/chilecube.py 6 | datachile/client.py 7 | datachile/download.py 8 | datachile/exception.py 9 | datachile.egg-info/PKG-INFO 10 | datachile.egg-info/SOURCES.txt 11 | datachile.egg-info/dependency_links.txt 12 | datachile.egg-info/requires.txt 13 | datachile.egg-info/top_level.txt 14 | datachile.egg-info/zip-safe -------------------------------------------------------------------------------- /datachile.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.1 2 | Name: datachile 3 | Version: 0.0.8 4 | Summary: Python client for manage DataChile API 5 | Home-page: http://github.com/datachile/datachile-python-client 6 | Author: Carlos Navarrete - Datawheel LLC 7 | Author-email: cnavarreteliz@gmail.com 8 | License: MIT 9 | Download-URL: https://github.com/datachile/datachile-python-client/archive/0.0.8.tar.gz 10 | Description-Content-Type: UNKNOWN 11 | Description: UNKNOWN 12 | Keywords: python,mondrian,olap,api 13 | Platform: UNKNOWN 14 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='datachile', 5 | version='0.0.11', 6 | description='Python client for manage DataChile API', 7 | url='http://github.com/datachile/datachile-python-client', 8 | download_url='https://github.com/datachile/datachile-python-client/archive/0.0.11.tar.gz', 9 | author='Carlos Navarrete - Datawheel LLC', 10 | author_email='cnavarreteliz@gmail.com', 11 | license='MIT', 12 | packages=['datachile'], 13 | install_requires=[ 14 | 'mondrian-rest', 15 | 'numpy', 16 | 'requests' 17 | ], 18 | keywords = ['python', 'mondrian', 'olap', 'api'], 19 | zip_safe=True 20 | ) 21 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | from datachile import ChileCube 2 | 3 | client = ChileCube() 4 | 5 | x = client.get_all([ 6 | [ 7 | "casen_household", 8 | { 9 | "drilldowns": [ 10 | ["Geography", "Geography", "Region"], 11 | ["Walls Material", "Walls Material", "Walls Material"] 12 | ], 13 | "measures": ["Expansion Factor Comuna"] 14 | } 15 | ], 16 | [ 17 | "crimes", 18 | { 19 | "drilldowns": [ 20 | ["Geography", "Geography", "Region"], 21 | ["Crime", "Crime", "Crime Group"] 22 | ], 23 | "measures": ["Number of records"] 24 | } 25 | ] 26 | ]) 27 | 28 | print(x) 29 | 30 | '''from json import dumps 31 | file = open("data.json", "w") 32 | file.write(dumps(query1["data"])) 33 | file.close()''' -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2018 Carlos Navarrete 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /test/_get.py: -------------------------------------------------------------------------------- 1 | from datachile import ChileCube 2 | 3 | client = ChileCube() 4 | 5 | # Health System by Year and Region in 2014 6 | query1 = client.get( 7 | "casen_health_system", 8 | { 9 | "drilldowns": [ 10 | ["Date", "Date", "Year"], 11 | ["Geography", "Geography", "Region"], 12 | ["Health System", "Health System", "Health System"] 13 | ], 14 | "measures": ["FOB US"], 15 | "cuts": [ 16 | { 17 | "drilldown": ["Date", "Date", "Year"], 18 | "values": [2014] 19 | } 20 | ], 21 | "parents": True 22 | } 23 | ) 24 | 25 | # Exports from Chile in 2012-2014, divided in Year and Destination Country 26 | query2 = client.get( 27 | "exports", 28 | { 29 | "drilldowns": [ 30 | ["Date", "Date", "Year"], 31 | ["Destination Country", "Country", "Country"] 32 | ], 33 | "measures": ["FOB US"], 34 | "cuts": [ 35 | { 36 | "drilldown": ["Date", "Date", "Year"], 37 | "values": [2012, 2013, 2014] 38 | } 39 | ], 40 | "parents": True 41 | } 42 | ) 43 | 44 | 45 | print(query1) 46 | print(query2) -------------------------------------------------------------------------------- /datachile/download.py: -------------------------------------------------------------------------------- 1 | class Download(object): 2 | def __init__(self, data): 3 | self._data = data 4 | 5 | def xml(self, line_padding=""): 6 | result_list = list() 7 | 8 | json_obj_type = type(self._data) 9 | 10 | if json_obj_type is list: 11 | for sub_elem in json_obj: 12 | result_list.append(json2xml(sub_elem, line_padding)) 13 | 14 | return "\n".join(result_list) 15 | 16 | if json_obj_type is dict: 17 | for tag_name in self._data: 18 | sub_obj = self._data[tag_name] 19 | result_list.append("%s<%s>" % (line_padding, tag_name)) 20 | result_list.append(json2xml(sub_obj, "\t" + line_padding)) 21 | result_list.append("%s" % (line_padding, tag_name)) 22 | 23 | return "\n".join(result_list) 24 | 25 | return "%s%s" % (line_padding, self._data) 26 | 27 | def csv(self, data, delimiter=","): 28 | import json 29 | import csv 30 | 31 | #output = json.loads(data) 32 | output = data["data"] 33 | # open a file for writing 34 | employ_data = open('tmp.csv', 'w', encoding='utf8') 35 | 36 | # create the csv writer object 37 | csvwriter = csv.writer(employ_data, delimiter=delimiter) 38 | count = 0 39 | 40 | for emp in output: 41 | 42 | if count == 0: 43 | header = emp.keys() 44 | csvwriter.writerow(header) 45 | count += 1 46 | csvwriter.writerow(emp.values()) 47 | employ_data.close() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DataChile Python Client 2 | `DataChile Python Client` is a Python 3 library to access the DataChile API. This library enables you to use public data from differents sources in your Python applications. 3 | 4 | # Install 5 | Install from PyPI, using pip: 6 | 7 | `pip install datachile` 8 | 9 | # Simple Demo 10 | Interact with the API: 11 | 12 | * Get all datasets availables in DataChile 13 | 14 | ```Python 15 | from datachile import ChileCube 16 | 17 | client = ChileCube() 18 | query = client.get_cubes() 19 | 20 | print(query) 21 | ``` 22 | 23 | * Get drilldowns availables from "Election Participation" dataset. 24 | ```Python 25 | from datachile import ChileCube 26 | 27 | client = ChileCube() 28 | cube = "election_participation" 29 | 30 | dd = client.get_drilldowns(cube) 31 | ms = client.get_measures(cube) 32 | 33 | print(dd) 34 | print(ms) 35 | ``` 36 | 37 | * Get exports from Chile in 2012-2014, divided in Year and Destination Country 38 | ```Python 39 | from datachile import ChileCube 40 | 41 | client = ChileCube() 42 | 43 | query = client.get( 44 | "exports", 45 | { 46 | "drilldowns": [ 47 | ["Date", "Year"], 48 | ["Destination Country", "Country", "Country"] 49 | ], 50 | "measures": ["FOB US"], 51 | "cuts": [ 52 | { 53 | "drilldown": ["Date", "Year"], 54 | "values": [2012, 2013, 2014] 55 | } 56 | ], 57 | "parents": True 58 | } 59 | ) 60 | 61 | print(query) 62 | ``` 63 | 64 | # Documentation 65 | Please refer to our Wiki documentation for more information or [Datachile API Documentation Website](https://datachile.io/about/api). 66 | 67 | # Development 68 | 69 | ## Contributing 70 | Long-term discussion and bug reports are maintained via GitHub Issues. Code review is done via GitHub Pull Requests. 71 | 72 | # License 73 | The MIT License (MIT) 74 | 75 | Copyright (c) 2018 Carlos Navarrete & Datawheel LLC 76 | 77 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 78 | 79 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 80 | 81 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 82 | -------------------------------------------------------------------------------- /datachile/chilecube.py: -------------------------------------------------------------------------------- 1 | from mondrian_rest import Cube, MondrianClient 2 | from datachile import client 3 | from .exception import InvalidParamException 4 | 5 | API_BASE = "https://chilecube.datachile.io" 6 | 7 | 8 | class ChileCube(object): 9 | def __init__(self): 10 | self.client = MondrianClient(API_BASE) 11 | 12 | def get_cube(self, cube_id): 13 | cube = self.client.get_cube(cube_id) 14 | return { 15 | "name": cube.name, 16 | "dimensions": cube.dimensions, 17 | "measures": cube.measures, 18 | "annotations": cube.annotations 19 | } 20 | 21 | def get_cubes(self): 22 | return [{ 23 | "name": cube.name, 24 | "dimensions": cube.dimensions, 25 | "measures": cube.measures, 26 | "annotations": cube.annotations 27 | } for cube in self.client.get_cubes()] 28 | 29 | def get_drilldowns(self, cube_id): 30 | cube = self.client.get_cube(cube_id) 31 | 32 | dd = [] 33 | 34 | for dimension in cube.dimensions: 35 | for hierarchy in dimension["hierarchies"]: 36 | for level in hierarchy["levels"][1:]: 37 | dd.append({ 38 | "dimension": 39 | dimension["name"], 40 | "hierarchy": 41 | hierarchy["name"], 42 | "level": 43 | level["name"], 44 | "drilldown": 45 | [dimension["name"], hierarchy["name"], level["name"]], 46 | "mdx": level["full_name"] 47 | }) 48 | 49 | return dd 50 | 51 | def get_measures(self, cube_id): 52 | cube = self.client.get_cube(cube_id) 53 | return [ms for ms in cube.measures] 54 | 55 | def get_members(self, cube_id, dimension, level): 56 | return self.client.get_members(cube_id, dimension, level) 57 | 58 | def get_regiones(self): 59 | return [{ 60 | "region_id": comuna["key"], 61 | "region": comuna["name"] 62 | } for region in self.client.get_members( 63 | "exports", "Geography", "Region")["members"]] 64 | 65 | def get_comunas(self): 66 | return [{ 67 | "comuna_id": comuna["key"], 68 | "comuna": comuna["name"], 69 | "region_id": comuna["ancestors"][0]["key"], 70 | "region": comuna["ancestors"][0]["name"] 71 | } for comuna in self.client.get_members( 72 | "exports", "Geography", "Comuna")["members"]] 73 | 74 | def get(self, cube_id, params={}, df=False, lang="en"): 75 | cube = self.client.get_cube(cube_id) 76 | 77 | if "drilldowns" not in params: 78 | raise InvalidParamException("At least one drilldown is missing") 79 | 80 | if "measures" not in params: 81 | raise InvalidParamException("At least one measure is missing") 82 | 83 | obj = { 84 | "caption": 85 | lang, 86 | "drilldown": [{ 87 | "full_name": ".".join("[{}]".format(x) for x in dd) 88 | } for dd in params["drilldowns"]], 89 | "cut": [], 90 | "measures": [{ 91 | "name": item 92 | } for item in params["measures"]] 93 | } 94 | 95 | if "cuts" in params: 96 | for cut in params["cuts"]: 97 | dd = ".".join("[{}]".format(x) for x in cut["drilldown"]) 98 | output = [] 99 | for value in cut["values"]: 100 | output.append("{}.&[{}]".format(dd, value)) 101 | output = ",".join(output) 102 | output = "{" + output + "}" 103 | obj["cut"].append(output) 104 | 105 | if "parents" in params: 106 | obj["parents"] = params["parents"] 107 | 108 | agg = self.client.get_aggregation(cube, obj) 109 | 110 | q = agg.tidy 111 | 112 | data = [] 113 | n_axes = len(q["axes"]) 114 | for item in q["data"]: 115 | obj = {} 116 | for i, dd in enumerate(q["axes"]): 117 | obj["ID " + dd["level"]] = int(item[i]["key"]) 118 | obj[dd["level"]] = item[i]["caption"] 119 | for i, ms in enumerate(q["measures"]): 120 | obj[ms["caption"]] = item[n_axes + i] if item[n_axes 121 | + i] else 0 122 | data.append(obj) 123 | 124 | q["data"] = data 125 | q["count"] = len(data) 126 | 127 | if df: 128 | from pandas import DataFrame 129 | return DataFrame(data=q["data"]) 130 | 131 | return q 132 | 133 | def get_all(self, queries): 134 | merged = [] 135 | n_queries = len(queries) 136 | 137 | q = {key: None for key in list(range(n_queries))} 138 | 139 | for key, query in enumerate(queries): 140 | q[key] = self.get( *query, df=False ) 141 | merged += list(q[key]["data"][0].keys()) 142 | 143 | unique_keys = list( 144 | set([x for x in merged if merged.count(x) > 1 and x[:3] == "ID "]) 145 | ) 146 | 147 | result = [] 148 | 149 | def condition_generator(keys, item1, item2): 150 | for key in keys: 151 | if item1[key] != item2[key]: 152 | return False 153 | 154 | return True 155 | 156 | i = 0 157 | for item1 in q[i]["data"]: 158 | for item2 in q[i + 1]["data"]: 159 | if condition_generator(unique_keys, item1, item2): 160 | item = {**item1, **item2} 161 | result.append(item) 162 | break 163 | 164 | return result 165 | --------------------------------------------------------------------------------