├── LICENSE ├── README.md ├── api ├── annotator │ └── m_table_annotation.py ├── lookup │ └── m_mtabes.py └── utilities │ └── m_iw.py ├── data └── semtab │ ├── 0A2WQW7B.csv │ ├── 2T_10.zip │ ├── atable.zip │ ├── atable_2.zip │ ├── atable_3.zip │ ├── mytables.zip │ └── tables.zip ├── docs ├── mtab.md └── mtabes.md ├── interface ├── static │ ├── images │ │ ├── MTabESSemTab2T.png │ │ ├── MTabESSemTabR1.png │ │ ├── MTabESSemTabR2.png │ │ ├── MTabESSemTabR3.png │ │ ├── MTabESSemTabR4.png │ │ ├── logo_mtab_1.png │ │ ├── logo_mtab_2.png │ │ ├── logo_mtab_3.png │ │ ├── logo_mtab_4.png │ │ └── mtab_pic.png │ └── others │ │ ├── mytables.json │ │ └── mytables.zip └── templates │ └── md.html ├── requirements.txt ├── results.zip ├── run_2t.py └── static ├── images ├── MTabESSemTab2T.png ├── MTabESSemTabR1.png ├── MTabESSemTabR2.png ├── MTabESSemTabR3.png ├── MTabESSemTabR4.png ├── logo_mtab_1.png ├── logo_mtab_2.png ├── logo_mtab_3.png ├── logo_mtab_4.png ├── mtab_pic.png ├── semtab2019.png ├── semtab2020.png └── semtab2021.png └── others ├── 0AJSJYAL.xltx ├── mytables.json ├── mytables.zip ├── mytables_ntar.json ├── mytables_ntar.zip └── semtab2021 ├── biotable └── .gitkeep └── hardtable └── .gitkeep /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Phuc Nguyen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MTab 2 | 3 | --- 4 | 5 | MTab: Entity Search and Table Annotation with Knowledge Graphs (Wikidata, Wikipedia and DBpedia) 6 | 7 | ### Demo 8 | - Demo (Teaser): https://youtu.be/sr-zxH5JUjw 9 | - Demonstration Video: https://youtu.be/0ibTWeObWaA 10 | - Entity Search: https://mtab.kgraph.jp/mtabes 11 | - Table Annotation: https://mtab.kgraph.jp/mtab 12 | 13 | 14 | ### API usage 15 | - Entity Search: [MTabES](docs/mtabes.md) 16 | - Request Example: [entity search](api/lookup/m_mtabes.py) 17 | - Table Annotation: [MTab](docs/mtab.md) 18 | - Request Example: [table annotation](api/annotator/m_table_annotation.py) 19 | - Running Table Annotation on Tough Tables (2T) dataset: 20 | - Running Scripts: [run 2t](https://github.com/phucty/mtab_tool/blob/master/run_2t.py) 21 | 22 | ### Source code: 23 | - Development code: https://github.com/phucty/mtab_dev 24 | 25 | ### Other works: 26 | - [MTab4D](https://github.com/phucty/mtab4dbpedia): Table Annotation with DBpedia 27 | - [WikiDB](https://github.com/phucty/wikidb): Build a DB (key-value store - LMDB style) from Wikidata dump, offline access Wikidata, fast boolean search 28 | 29 | ### References 30 | - Phuc Nguyen, Ikuya Yamada, Natthawut Kertkeidkachorn, Ryutaro Ichise, Hideaki Takeda, SemTab 2021: Tabular Data Annotation with MTab Tool. [[video](https://www.youtube.com/watch?v=j-l3poE0Ktc)] 31 | 32 | - Phuc Nguyen, Ikuya Yamada, Natthawut Kertkeidkachorn, Ryutaro Ichise, Hideaki Takeda, Demonstration of MTab: Tabular Data Annotation with Knowledge Graphs. [[video](https://youtu.be/0ibTWeObWaA)] 33 | 34 | - Phuc Nguyen, Hideaki Takeda, MTab: Tabular Data Annotation, NII Open House June 2021. [[video](https://youtu.be/1ByffPp2alg?t=3269)] 35 | 36 | - Phuc Nguyen, Ikuya Yamada, Hideaki Takeda, [MTabES: Entity Search with Keyword Search, Fuzzy Search, and Entity Popularities](https://drive.google.com/file/d/10Tl0Qd5gxFSiCsnSjJbvRSUiDXW-Kifn/view?usp=sharing), In The 35th Annual Conference of the Japanese Society for Artificial Intelligence (JSAI), 2021. [[video](https://drive.google.com/file/d/1gYSP619HcMT-sE6iD3LiQeRtZw9UZTWQ/view?usp=sharing)] 37 | 38 | 39 | - Phuc Nguyen, Ikuya Yamada, Natthawut Kertkeidkachorn, Ryutaro Ichise, Hideaki Takeda, [MTab4Wikidata at SemTab 2020: Tabular Data Annotation with Wikidata](http://ceur-ws.org/Vol-2775/paper9.pdf), In SemTab@ISWC, 2020. [[video](https://drive.google.com/file/d/1vz-6nkc9t6MQZYzgg-PZNLs-9TT86wRD/view?usp=sharing)] 40 | 41 | 42 | - Phuc Nguyen, Natthawut Kertkeidkachorn, Ryutaro Ichise, Hideaki Takeda [MTab: Matching Tabular Data to Knowledge Graph using Probability Models](http://ceur-ws.org/Vol-2553/paper2.pdf), In SemTab@ISWC, 2019, [[slides](http://www.cs.ox.ac.uk/isg/challenges/sem-tab/2019/slides/MTab.pptx)] 43 | 44 | 45 | ### Awards: 46 | 47 | - 1st prize at SemTab 2021 (usability track). [Results](https://www.cs.ox.ac.uk/isg/challenges/sem-tab/2021/index.html#results) 48 | 49 | MTab 50 | 51 | - 1st prize at SemTab 2020 (tabular data to Wikidata matching). [Results](http://www.cs.ox.ac.uk/isg/challenges/sem-tab/2020/results.html) 52 | MTab 53 | 54 | - 1st prize at SemTab 2019 (tabular data to DBpedia matching). [Results](http://www.cs.ox.ac.uk/isg/challenges/sem-tab/2019/results.html) 55 | MTab 56 | 57 | ### Citing 58 | 59 | If you find MTab tool useful in your work, and you want to cite our work, please use the following referencee: 60 | ``` 61 | @inproceedings{2021_mtab4wikidata, 62 | author = {Phuc Nguyen and 63 | Ikuya Yamada and 64 | Natthawut Kertkeidkachorn and 65 | Ryutaro Ichise and 66 | Hideaki Takeda}, 67 | title = {SemTab 2021: Tabular Data Annotation with MTab Tool}, 68 | booktitle = {SemTab@ISWC 2021}, 69 | series = {{CEUR} Workshop Proceedings}, 70 | volume = {3103}, 71 | pages = {92--101}, 72 | publisher = {CEUR-WS.org}, 73 | year = {2021}, 74 | url = {http://ceur-ws.org/Vol-3103/paper8.pdf}, 75 | } 76 | ``` 77 | 78 | 79 | ### Contact 80 | Phuc Nguyen (`phucnt@nii.ac.jp`) 81 | -------------------------------------------------------------------------------- /api/annotator/m_table_annotation.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from collections import defaultdict 4 | from contextlib import closing 5 | from datetime import timedelta 6 | from time import time, sleep 7 | from multiprocessing import Pool 8 | 9 | import requests 10 | from requests.packages.urllib3.util.retry import Retry 11 | from requests.adapters import HTTPAdapter 12 | from tqdm import tqdm 13 | 14 | from api.utilities import m_iw 15 | 16 | # Request config 17 | LIMIT_TIME_OUT = 7200 # 2h: 7200 - 24h: 86400 -3days:259200 18 | LIMIT_RETRIES = 3 19 | 20 | 21 | class MTab(object): 22 | def __init__(self): 23 | self.F_MTAB = "https://mtab.app/api/v1.1/mtab" 24 | # self.F_MTAB = "http://localhost:5000/api/v1.1/mtab" 25 | 26 | self.session = requests.Session() 27 | retries = Retry( 28 | total=LIMIT_RETRIES, 29 | backoff_factor=1, 30 | status_forcelist=[500, 502, 503, 504], 31 | ) 32 | self.session.mount("https://", HTTPAdapter(max_retries=retries)) 33 | self.session.mount("http://", HTTPAdapter(max_retries=retries)) 34 | 35 | def _request(self, func_name, query_args, retries=3, message=""): 36 | responds = defaultdict() 37 | if retries == 0: 38 | print(message) 39 | return responds 40 | try: 41 | # _responds = requests.post(func_name, json=query_args, timeout=self.TIME_OUT) 42 | _responds = self.session.post( 43 | func_name, json=query_args, timeout=LIMIT_TIME_OUT 44 | ) 45 | if _responds.status_code == 200: 46 | responds = _responds.json() 47 | if not responds or ( 48 | responds.get("status") == "Error" and not responds.get("message") 49 | ): 50 | sleep(300) 51 | return self._request( 52 | func_name, 53 | query_args, 54 | retries - 1, 55 | message=f"Error: Retry {retries-1}", 56 | ) 57 | except Exception as message: 58 | if func_name == self.F_MTAB and query_args.get("table_name"): 59 | args_info = func_name + ": " + query_args.get("table_name") 60 | else: 61 | args_info = func_name 62 | sleep(300) 63 | return self._request( 64 | func_name, query_args, retries - 1, message=f"\n{message} - {args_info}" 65 | ) 66 | return responds 67 | 68 | def get_table_annotation( 69 | self, 70 | table_content, 71 | table_name="", 72 | predict_target=False, 73 | tar_cea=None, 74 | tar_cta=None, 75 | tar_cpa=None, 76 | search_mode="a", 77 | search_limit=50, 78 | debug=False, 79 | ): 80 | query_args = { 81 | "table_name": table_name, 82 | "table": table_content, 83 | "predict_target": predict_target, 84 | "tar_cea": tar_cea, 85 | "tar_cta": tar_cta, 86 | "tar_cpa": tar_cpa, 87 | "search_mode": search_mode, 88 | "search_limit": search_limit, 89 | "debug": debug, 90 | } 91 | responds = self._request(self.F_MTAB, query_args) 92 | return responds 93 | 94 | 95 | def example_table_annotation(): 96 | mtab_api = MTab() 97 | 98 | # Table file 99 | dir_table = "/Users/phucnguyen/Downloads/0AJSJYAL.xltx" 100 | # dir_table = f"/Users/phucnguyen/git/dprofile/data/tables/wikitable_1.xlsx" 101 | table_name = os.path.splitext(os.path.basename(dir_table))[0] 102 | table_content = m_iw.load_table(dir_table) 103 | 104 | # Run 1: Let MTab predict annotation targets 105 | responds_auto = mtab_api.get_table_annotation( 106 | table_content, 107 | table_name=table_name, 108 | predict_target=True, # Set this is True 109 | search_mode="a", # Using aggregation search 110 | search_limit=100, # candidate entity generation limit 111 | debug=True, # return all candidates, and their confidence scores in CEA tasks 112 | ) 113 | 114 | print(json.dumps(responds_auto, indent=2)) 115 | 116 | # Run 2: provide annotation targets 117 | 118 | # Annotation targets 119 | # tar_cea = [ 120 | # [1, 0], 121 | # [2, 0], 122 | # [3, 0], 123 | # [4, 0], 124 | # [5, 0], 125 | # [6, 0], 126 | # [7, 0], 127 | # [8, 0], 128 | # [9, 0], 129 | # [10, 0], 130 | # ] 131 | # tar_cta = [0] 132 | # tar_cpa = [[0, 1], [0, 2]] 133 | # 134 | # responds = mtab_api.get_table_annotation( 135 | # table_content, 136 | # table_name=table_name, 137 | # tar_cea=tar_cea, 138 | # tar_cta=tar_cta, 139 | # tar_cpa=tar_cpa, 140 | # search_mode="a", 141 | # ) 142 | # print(responds) 143 | 144 | 145 | if __name__ == "__main__": 146 | example_table_annotation() 147 | -------------------------------------------------------------------------------- /api/lookup/m_mtabes.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from time import time 3 | from requests.packages.urllib3.util.retry import Retry 4 | from requests.adapters import HTTPAdapter 5 | 6 | 7 | class MTabES(object): 8 | def __init__(self): 9 | self.URL = "https://mtab.app/api/v1/search" 10 | self.session = requests.Session() 11 | retries = Retry(total=5, 12 | backoff_factor=1, 13 | status_forcelist=[500, 502, 503, 504]) 14 | self.session.mount('https://', HTTPAdapter(max_retries=retries)) 15 | self.session.mount('http://', HTTPAdapter(max_retries=retries)) 16 | 17 | def get(self, query_value, limit=20, mode="a", lang="en", expensive=0, info=0): 18 | query_args = { 19 | "q": query_value, 20 | "limit": limit, 21 | "m": mode, 22 | "lang": lang, 23 | "info": info, 24 | "expensive": expensive 25 | } 26 | start = time() 27 | responds = [] 28 | if not query_value: 29 | return [], time() - start 30 | try: 31 | # tmp_responds = requests.get(self.URL, params=query_args) 32 | tmp_responds = self.session.get(self.URL, params=query_args) 33 | if tmp_responds.status_code == 200: 34 | tmp_responds = tmp_responds.json() 35 | if tmp_responds.get("hits"): 36 | if info: 37 | responds = [[r["id"], r["score"], r["label"], r["des"]] for r in tmp_responds["hits"]] 38 | else: 39 | responds = [[r["id"], r["score"]] for r in tmp_responds["hits"]] 40 | except Exception as message: 41 | print(f"\n{message}\n{str(query_args)}") 42 | run_time = time() - start 43 | return responds, run_time 44 | 45 | 46 | if __name__ == "__main__": 47 | mtab_es = MTabES() 48 | queries = [ 49 | "Sweden", 50 | "TV-Browser", 51 | "hideaki takeda", 52 | "HIdeki Tedaka", 53 | "2MASS J10540655-0031018", 54 | "Tokyo", 55 | "武田英明", 56 | "Град Скопјее", 57 | "Préfecture de Kanagawa", 58 | "Paulys Realenzyklopädie der klassischen Altertumswissenschaft", 59 | "La gran bretaña", 60 | "제주 유나이티드 FC", 61 | "অ্যাটলেটিকো ডি কলকাতা", 62 | "Nguyễn Ái Quốc", 63 | "ホー・チ・ミン", 64 | ] 65 | modes = ["a"] # "a", "b", "f" 66 | lang_opts = ["en"] # "en", "all" 67 | expensive_opts = [0] # 0, 1 68 | info = 1 # get entity information 69 | for query in queries: 70 | for mode in modes: 71 | for lang in lang_opts: 72 | for expensive in expensive_opts: 73 | responds, run_time = mtab_es.get(query, limit=20, mode=mode, lang=lang, expensive=expensive, info=info) 74 | print(f"\n[{lang}|{mode}|{expensive}] About {len(responds)} results in {run_time:.4f} seconds | {query}") 75 | 76 | if info: 77 | for i, (r, s, l, d) in enumerate(responds[:3]): 78 | print(f"{i + 1:2}. {s:.4f} - {r}[{l}] - {d}") 79 | else: 80 | for i, (r, s) in enumerate(responds[:3]): 81 | print(f"{i+1:2}. {s:.4f} - {r}[]") 82 | 83 | 84 | # Responds 85 | # [en|a|0] About 20 results in 0.3921 seconds | Sweden 86 | # 1. 0.2856 - Q34[Sweden] - sovereign state in northern Europe 87 | # 2. 0.2831 - Q424644[Sweden] - Wikimedia disambiguation page 88 | # 3. 0.2830 - Q37437749[Sweden] - family name 89 | # 90 | # [en|a|0] About 20 results in 0.1395 seconds | TV-Browser 91 | # 1. 0.5289 - Q1715028[TV-Browser] - electronic program guide (tv, radio) 92 | # 2. 0.1183 - Q399128[Browser] - Wikimedia disambiguation page 93 | # 3. 0.1183 - Q11334456[Browser] - None 94 | # 95 | # [en|a|0] About 20 results in 0.0937 seconds | hideaki takeda 96 | # 1. 0.6209 - Q2330082[Hideaki Takeda] - Japanese association football player 97 | # 2. 0.6209 - Q57886243[Hideaki Takeda] - informatics researcher, National Institute of Informatics, Japan 98 | # 3. 0.1058 - Q15719495[Hideaki] - male given name 99 | # 100 | # [en|a|0] About 20 results in 0.0650 seconds | HIdeki Tedaka 101 | # 1. 0.4108 - Q4924099[Hideki Todaka] - Japanese boxer 102 | # 2. 0.2360 - Q5752358[Hideki] - male given name 103 | # 3. 0.2359 - Q52319792[Hideki] - Japanese mangaka 104 | # 105 | # [en|a|0] About 20 results in 0.2180 seconds | 2MASS J10540655-0031018 106 | # 1. 0.4934 - Q222120[2MASS J00540655-0031018] - brown dwarf 107 | # 2. 0.2285 - Q87130330[TYC 4151-458-1] - None 108 | # 3. 0.0419 - Q89756929[TYC 5033-427-1] - None 109 | # 110 | # [en|a|0] About 20 results in 0.2050 seconds | Tokyo 111 | # 1. 0.2843 - Q1490[Tokyo] - capital and most populous prefecture of Japan 112 | # 2. 0.2833 - Q396867[Tokyo] - Wikimedia disambiguation page 113 | # 3. 0.2833 - Q65120889[Tokyo] - None 114 | # 115 | # [en|a|0] About 20 results in 0.2326 seconds | 武田英明 116 | # 1. 0.3100 - Q2330082[Hideaki Takeda] - Japanese association football player 117 | # 2. 0.3100 - Q57886243[Hideaki Takeda] - informatics researcher, National Institute of Informatics, Japan 118 | # 3. 0.0857 - Q433473[Hideaki Yanagida] - Japanese sport wrestler 119 | # 120 | # [en|a|0] About 20 results in 0.1653 seconds | Град Скопјее 121 | # 1. 0.4790 - Q2575820[Greater Skopje] - administrative division within the Republic of Macedonia constituted of 10 municipalities 122 | # 2. 0.0783 - Q515[city] - large permanent human settlement 123 | # 3. 0.0775 - Q1500094[grad] - place name element meaning 'town' 124 | # 125 | # [en|a|0] About 14 results in 0.3231 seconds | Préfecture de Kanagawa 126 | # 1. 0.4818 - Q127513[Kanagawa Prefecture] - prefecture of Japan 127 | # 2. 0.1015 - Q161454[Kagawa Prefecture] - prefecture of Japan 128 | # 3. 0.0771 - Q22800853[Q22800853] - Wikimedia template 129 | # 130 | # [en|a|0] About 20 results in 0.1574 seconds | Paulys Realenzyklopädie der klassischen Altertumswissenschaft 131 | # 1. 0.4548 - Q1138524[Paulys Realenzyklopädie der klassischen Altertumswissenschaft] - extensive and comprehensive German encyclopedia of classical scholarship 132 | # 2. 0.0009 - Q19250471[Mesembria (Pauly-Wissowa)] - cross-reference in Paulys Realencyclopädie der classischen Altertumswissenschaft (RE) 133 | # 3. 0.0005 - Q47459707[Paulys Realencyclopädie der classischen Altertumswissenschaft] - document published in 1997 134 | # 135 | # [en|a|0] About 19 results in 0.1409 seconds | La gran bretaña 136 | # 1. 0.5792 - Q2841[Bogota] - capital city of Colombia 137 | # 2. 0.0804 - Q145[United Kingdom] - country in Western Europe 138 | # 3. 0.0776 - Q23666[Great Britain] - island in the North Atlantic off the north-west coast of continental Europe 139 | # 140 | # [en|a|0] About 15 results in 0.1555 seconds | 제주 유나이티드 FC 141 | # 1. 0.4472 - Q482617[Jeju United FC] - football club in South Korea 142 | # 2. 0.0873 - Q12223270[Template:Jeju United FC] - Wikimedia template 143 | # 3. 0.0321 - Q8565398[Category:Jeju United FC] - Wikimedia category 144 | # 145 | # [en|a|0] About 20 results in 0.1284 seconds | অ্যাটলেটিকো ডি কলকাতা 146 | # 1. 0.5787 - Q16836329[ATK] - association football club 147 | # 2. 0.0771 - Q22003383[D.D Bhawalkar] - Indian Optical Physicist 148 | # 3. 0.0105 - Q14221200[North Kolkata] - Northern parts and some suburbs of the city of joy kolkata 149 | # 150 | # [en|a|0] About 20 results in 0.1098 seconds | Nguyễn Ái Quốc 151 | # 1. 0.4461 - Q36014[Ho Chi Minh] - Vietnamese communist leader and Chairman of the Workers' Party of Vietnam (1890-1969) 152 | # 2. 0.4455 - Q12901199[Q12901199] - None 153 | # 3. 0.4455 - Q10742909[Q10742909] - None 154 | # 155 | # [en|a|0] About 20 results in 0.0746 seconds | ホー・チ・ミン 156 | # 1. 0.4446 - Q36014[Ho Chi Minh] - Vietnamese communist leader and Chairman of the Workers' Party of Vietnam (1890-1969) 157 | # 2. 0.0967 - Q874234[Ho Chi Minh Mausoleum] - None 158 | # 3. 0.0771 - Q7410171[Category:Ho Chi Minh] - Wikimedia category 159 | -------------------------------------------------------------------------------- /api/utilities/m_iw.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import fnmatch 3 | import os 4 | import pandas 5 | import numpy as np 6 | import petl as petl 7 | 8 | 9 | def create_dir(file_dir): 10 | """Create a directory 11 | 12 | Args: 13 | file_dir (str): file directory 14 | """ 15 | folder_dir = os.path.dirname(file_dir) 16 | if not os.path.exists(folder_dir): 17 | os.makedirs(folder_dir) 18 | 19 | 20 | def load_object_csv(file_name, encoding="utf8"): 21 | content = [] 22 | if os.path.exists(file_name): 23 | with open(file_name, "r", encoding=encoding, errors="ignore") as f: 24 | reader = csv.reader(f, delimiter=",") 25 | for r in reader: 26 | row_norm = [] 27 | for c in r: 28 | row_norm.append(c) 29 | content.append(row_norm) 30 | return content 31 | 32 | 33 | def save_object_csv(file_name, rows): 34 | create_dir(file_name) 35 | temp_file = "%s.temp" % file_name 36 | with open(temp_file, "w") as f: 37 | try: 38 | writer = csv.writer(f, delimiter=",", quotechar='"', quoting=csv.QUOTE_ALL) 39 | for r in rows: 40 | if ( 41 | isinstance(r, list) 42 | or isinstance(r, tuple) 43 | or isinstance(r, np.ndarray) 44 | ): 45 | writer.writerow(r) 46 | else: 47 | writer.writerow([r]) 48 | except Exception as message: 49 | print(message) 50 | if os.path.exists(file_name): 51 | os.remove(file_name) 52 | os.rename(temp_file, file_name) 53 | 54 | 55 | def get_files_from_dir_subdir(folder_path, extension="*"): 56 | all_files = [] 57 | for root, _, file_dirs in os.walk(folder_path): 58 | for file_dir in fnmatch.filter(file_dirs, "*.%s" % extension): 59 | if ".DS_Store" not in file_dir: 60 | all_files.append(os.path.join(root, file_dir)) 61 | return all_files 62 | 63 | 64 | def get_files_from_dir( 65 | folder_path, extension="*", limit_reader=-1, is_sort=False, reverse=False 66 | ): 67 | all_file_dirs = get_files_from_dir_subdir(folder_path, extension) 68 | 69 | if is_sort: 70 | file_with_size = [(f, os.path.getsize(f)) for f in all_file_dirs] 71 | file_with_size.sort(key=lambda f: f[1], reverse=reverse) 72 | all_file_dirs = [f for f, _ in file_with_size] 73 | if limit_reader < 0: 74 | 75 | limit_reader = len(all_file_dirs) 76 | return all_file_dirs[:limit_reader] 77 | 78 | 79 | def get_encoding(source, method="charamel"): 80 | result = "utf-8" 81 | if os.path.isfile(source): 82 | with open(source, "rb") as file_open: 83 | # Read all content --> make sure about the file encoding 84 | file_content = file_open.read() 85 | 86 | # predict encoding 87 | if method == "charamel": 88 | try: 89 | import charamel 90 | 91 | charamel.Detector() 92 | encoding_detector = charamel.Detector() 93 | detector = encoding_detector.detect(file_content) 94 | if detector: 95 | result = detector.value 96 | except Exception as message: 97 | print(message) 98 | pass 99 | else: 100 | detector = chardet.detect(file_content) 101 | if detector["encoding"]: 102 | result = detector["encoding"] 103 | return result 104 | 105 | 106 | def load_table(dir_table): 107 | def parse_xml_table(source): 108 | tables_xml = pandas.read_html(source) 109 | if tables_xml: 110 | return [tables_xml[0].columns.values.tolist()] + tables_xml[ 111 | 0 112 | ].values.tolist() 113 | else: 114 | return None 115 | 116 | table_obj = None 117 | encoding = get_encoding(dir_table) 118 | file_ext = os.path.splitext(dir_table)[1][1:] 119 | if file_ext == "csv": 120 | table_obj = load_object_csv(dir_table, encoding=encoding) 121 | elif file_ext == "tsv": 122 | table_obj = petl.fromtsv(dir_table, encoding=encoding) 123 | elif file_ext == "txt": 124 | table_obj = petl.fromtext(dir_table, encoding=encoding) 125 | elif file_ext == "xls": 126 | table_obj = petl.fromxls(dir_table, encoding=encoding) 127 | elif file_ext in ["xlsm", "xlsb", "xltx", "xlsx", "xlt", "xltm"]: 128 | table_obj = petl.fromxlsx(dir_table) 129 | elif file_ext == "xml": 130 | table_obj = parse_xml_table(dir_table) 131 | cells = [] 132 | if table_obj: 133 | for row in table_obj: 134 | row_norm = [] 135 | for col in row: 136 | tmp_cell = str(col) 137 | # tmp_cell = ul.norm_text(str(col), punctuations=True, lower=False) 138 | # tmp_date = ul.get_date(tmp_cell) 139 | # if tmp_date: 140 | # tmp_cell = tmp_date 141 | row_norm.append(tmp_cell) 142 | if row_norm: 143 | # row = ftfy.fix_text(row) 144 | cells.append(row_norm) 145 | 146 | return cells 147 | -------------------------------------------------------------------------------- /data/semtab/0A2WQW7B.csv: -------------------------------------------------------------------------------- 1 | col0,col1,col2 2 | We've#the Zenith Toyer A,300.29999999999995,21.042 3 | Ritz-Carltoo Toronto,209.5902,18.981 4 | Yingli ower,285.85499999999996,20.019999999999996 5 | Ccnterra Tower,175.761,17.91 6 | Nauru Hose,191.9,19.88 7 | Heast Tower,182.546,21.020999999999997 8 | Mlami Tower,192.91,19.038 9 | Torse Cepsa,250.0381,19.0 10 | Dltus Skyscraer,125.62499999999999,18.036 11 | Seat of he European Central Bank,184.075,18.162 12 | -------------------------------------------------------------------------------- /data/semtab/2T_10.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/data/semtab/2T_10.zip -------------------------------------------------------------------------------- /data/semtab/atable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/data/semtab/atable.zip -------------------------------------------------------------------------------- /data/semtab/atable_2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/data/semtab/atable_2.zip -------------------------------------------------------------------------------- /data/semtab/atable_3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/data/semtab/atable_3.zip -------------------------------------------------------------------------------- /data/semtab/mytables.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/data/semtab/mytables.zip -------------------------------------------------------------------------------- /data/semtab/tables.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/data/semtab/tables.zip -------------------------------------------------------------------------------- /docs/mtab.md: -------------------------------------------------------------------------------- 1 | MTab: Tabular Data Annotation 2 | =========== 3 | --- 4 | 5 | ### News: 6 | - To be expected: Data analysis, and QA for table data. 7 | - 2021/06/04 - Address the run time error of big table annotation. Solution: only process 1000 cells of tables as the default setting. However, you can adjust the parameter "limit" as your need by adding "?limit=1000" of the API. We also set the timeout limit of our API up to 3 days. 8 | - 2021/02/23 - API is online at https://mtab.app. This API is optimized and running on Mac mini M1. 9 | 10 | ### Features: 11 | - Semantic Annotation with knowledge graphs: Wikidata, Wikipedia, DBpedia 12 | - Annotate table cells with entities 13 | - Annotate table attributes (columns) with entity types, or classes. Currently, the tool supports table attributes as table columns. 14 | - Annotate the relation between table attributes (columns) with properties (relations, or predicates). 15 | - Structure Annotation: 16 | - Table type prediction: matrix, relational, layout (under development) 17 | - Header detection 18 | - Core attribute (subject column, or primary key) detection 19 | - basic stats including number of rows, columns, cells. 20 | - data types (under development) 21 | - languages (under development) 22 | - Good for table interpretation, data integration, and knowledge discovery. 23 | 24 | ### Interface: 25 | https://mtab.app/mtab 26 | 27 | ### API URL: 28 | https://mtab.app/api/v1/mtab 29 | 30 | ### Usage: 31 | Users can send table files (in CSV, Excel, TSV format) to the tool and get the annotations. 32 | 33 | **Note: We do not keep your data. After processing your tables, we will delete your data immediately.** 34 | 35 | - Due to the efficiency issue, the API will do annotation only the first 1000 rows of the input table.However, you can adjust the API parameter as “limit=1000”. Maybe you can change it to 1 million if you have 1 million rows in your table, but it will take more time to do annotation. For example: 36 | ```bash 37 | % curl -X POST -F file=@"YOUR_FILE_LOCATION/YOUR_TABLE.xltx" https://mtab.app/api/v1/mtab?limit=1000000 38 | ``` 39 | 40 | 41 | ### Annotate a table: 42 | Annotate a table in the Excel format [0AJSJYAL.xltx](https://github.com/phucty/mtab_tool/blob/master/static/others/0AJSJYAL.xltx) 43 | 44 | ```bash 45 | % curl -X POST -F file=@"YOUR_FILE_LOCATION/0AJSJYAL.xltx" https://mtab.app/api/v1/mtab 46 | ``` 47 | 48 | Expected Answer: 49 | ```json 50 | { 51 | "n_tables": 1, 52 | "status": "Success", 53 | "tables": [ 54 | { 55 | "name": "0AJSJYAL", 56 | "run_time": 0.8414499759674072, 57 | "semantic": { 58 | "cea": [ 59 | { 60 | "annotation": { 61 | "dbpedia": "http://dbpedia.org/resource/Newport,_Arkansas", 62 | "desc": "city in Arkansas, USA", 63 | "label": "Newport", 64 | "wikidata": "http://www.wikidata.org/entity/Q79414", 65 | "wikipedia": "http://en.wikipedia.org/wiki/Newport,_Arkansas" 66 | }, 67 | "target": [ 68 | 1, 69 | 0 70 | ] 71 | }, 72 | { 73 | "annotation": { 74 | "dbpedia": "http://dbpedia.org/resource/Thomas_(2001_film)", 75 | "desc": "2001 film by Raffaele Mertes", 76 | "label": "Thomas", 77 | "wikidata": "http://www.wikidata.org/entity/Q2421872", 78 | "wikipedia": "http://en.wikipedia.org/wiki/Thomas_(2001_film)" 79 | }, 80 | "target": [ 81 | 2, 82 | 0 83 | ] 84 | }, 85 | { 86 | "annotation": { 87 | "dbpedia": "http://dbpedia.org/resource/8082_Haynes", 88 | "desc": "asteroid", 89 | "label": "8082 Haynes", 90 | "wikidata": "http://www.wikidata.org/entity/Q533244", 91 | "wikipedia": "http://en.wikipedia.org/wiki/8082_Haynes" 92 | }, 93 | "target": [ 94 | 3, 95 | 0 96 | ] 97 | }, 98 | { 99 | "annotation": { 100 | "desc": "family name", 101 | "label": "Lampitt", 102 | "wikidata": "http://www.wikidata.org/entity/Q37468695" 103 | }, 104 | "target": [ 105 | 4, 106 | 0 107 | ] 108 | }, 109 | { 110 | "annotation": { 111 | "dbpedia": "http://dbpedia.org/resource/Solanki", 112 | "desc": "family name", 113 | "label": "Solanki", 114 | "wikidata": "http://www.wikidata.org/entity/Q37521226", 115 | "wikipedia": "http://en.wikipedia.org/wiki/Solanki" 116 | }, 117 | "target": [ 118 | 5, 119 | 0 120 | ] 121 | }, 122 | { 123 | "annotation": { 124 | "dbpedia": "http://dbpedia.org/resource/Weston,_Colorado", 125 | "desc": "unincorporated community in Colorado", 126 | "label": "Weston", 127 | "wikidata": "http://www.wikidata.org/entity/Q7989353", 128 | "wikipedia": "http://en.wikipedia.org/wiki/Weston,_Colorado" 129 | }, 130 | "target": [ 131 | 6, 132 | 0 133 | ] 134 | } 135 | ], 136 | "cpa": [], 137 | "cta": [ 138 | { 139 | "annotation": [ 140 | { 141 | "dbpedia": "http://dbpedia.org/resource/Human_settlement", 142 | "desc": "community of any size, in which people live", 143 | "label": "human settlement", 144 | "wikidata": "http://www.wikidata.org/entity/Q486972", 145 | "wikipedia": "http://en.wikipedia.org/wiki/Human_settlement" 146 | }, 147 | { 148 | "dbpedia": "http://dbpedia.org/resource/Surname", 149 | "desc": "part of a naming scheme for individuals, used in many cultures worldwide", 150 | "label": "family name", 151 | "wikidata": "http://www.wikidata.org/entity/Q101352", 152 | "wikipedia": "http://en.wikipedia.org/wiki/Surname" 153 | } 154 | ], 155 | "target": 0 156 | } 157 | ] 158 | }, 159 | "status": "Success", 160 | "structure": { 161 | "cells": 37, 162 | "columns": 7, 163 | "core_attribute": 0, 164 | "encoding": "utf-8", 165 | "headers": [ 166 | 0 167 | ], 168 | "r_cells": 0.7551020408163265, 169 | "rows": 7, 170 | "table type": "vertical relation" 171 | }, 172 | "table_cells": [ 173 | [ 174 | "col0", 175 | "col1", 176 | "col2", 177 | "col3", 178 | "col4", 179 | "col5", 180 | "col6" 181 | ], 182 | [ 183 | "Newport", 184 | "31", 185 | "8", 186 | "95", 187 | "2", 188 | "-", 189 | "-" 190 | ], 191 | [ 192 | "Thomas", 193 | "30", 194 | "5", 195 | "98", 196 | "2", 197 | "-", 198 | "-" 199 | ], 200 | [ 201 | "Haynes", 202 | "25", 203 | "8", 204 | "68", 205 | "2", 206 | "-", 207 | "-" 208 | ], 209 | [ 210 | "Lampitt", 211 | "29.4", 212 | "10", 213 | "73", 214 | "3", 215 | "-", 216 | "-" 217 | ], 218 | [ 219 | "Solanki", 220 | "19", 221 | "4", 222 | "76", 223 | "1", 224 | "-", 225 | "-" 226 | ], 227 | [ 228 | "Weston", 229 | "1", 230 | "0", 231 | "1", 232 | "0", 233 | "-", 234 | "-" 235 | ] 236 | ] 237 | } 238 | ] 239 | } 240 | ``` 241 | 242 | 243 | ### Annotate multiple tables: 244 | Note: 245 | - Please do not send more than 100 tables for one request to avoid data transmission corruption. (We only process 100 tables per request). 246 | - Please put your tables in a folder named tables and compress like this file [mytables.zip](https://github.com/phucty/mtab_tool/blob/master/static/others/mytables.zip). (We only accept a compressed file in zip format to speed up data transmission) 247 | ``` 248 | mytable.zip 249 | |-- tables (folder) 250 | | |--table_1.csv 251 | | |--table_2.csv 252 | | |--... 253 | ``` 254 | **Command:** 255 | ```bash 256 | % curl -X POST -F file=@"YOUR_FILE_LOCATION/mytables.zip" https://mtab.app/api/v1/mtab 257 | ``` 258 | 259 | **Expected Answer:** 260 | Refer to the [mytables.json](https://github.com/phucty/mtab_tool/blob/master/static/others/mytables.json) as the full answers 261 | 262 | 263 | ### Annotate multiple tables with targets (CEA, CTA, and CPA as [SemTab challenge](https://www.cs.ox.ac.uk/isg/challenges/sem-tab/)): 264 | Note: 265 | The format of the compressed file like [mytables_ntar.zip](https://github.com/phucty/mtab_tool/blob/master/static/others/mytables_ntar.zip). 266 | ``` 267 | mytable_ntar.zip 268 | |-- tables (folder) 269 | | |--table_1.csv 270 | | |--table_2.csv 271 | | |--... 272 | |-- cea.csv (Cell annotation targets in the format of [table ID, row index, column index]) 273 | |-- cta.csv (Column annotation targets in the format of [table ID, column index]) 274 | |-- cpa.csv (The relation between two columns in the format of [table ID, column 1, column 2] 275 | ``` 276 | 277 | **Command:** 278 | ```bash 279 | % curl -X POST -F file=@"YOUR_ZIP_FILE_LOCATION/mytables_ntar.zip" https://mtab.app/api/v1/mtab 280 | ``` 281 | **Expected Answer:** 282 | 283 | Refer to the [mytables_ntar.json](https://github.com/phucty/mtab_tool/blob/master/static/others/mytables_ntar.json) as the full answers 284 | 285 | ### Other Examples: 286 | #### Table Annotation 287 | 288 | 289 | #### Data correction: 290 | Input: Tabular data 291 | 292 | | col0 | col1 | col2 | col3 | 293 | |-------------------------|----------|------------|------------| 294 | | 2MASS J10540655-0031018 | -5.7 | 19.3716366 | 13.6356351 | 295 | | 2MASS J0464841+0715177 | -2.77475 | 26.671236 | 11.8187551 | 296 | | 2MAS J08351104+2006371 | 72.216 | 3.7242888 | 128.151961 | 297 | | 2MASS J08330994+186328 | -6.993 | 6.0962562 | 127.649963 | 298 | 299 | Output: 300 | 301 | | [star](http://www.wikidata.org/entity/Q523) | [radial velocity](http://www.wikidata.org/prop/direct/P2216) | [parallax](http://www.wikidata.org/prop/direct/P2214) | [right ascension](http://www.wikidata.org/prop/direct/P6257) | 302 | |-------------------------|-----------------|----------|--------------------| 303 | | [2MASS J00540655-0031018](http://www.wikidata.org/entity/Q222120) | -5.70 | 19.2561 | 13.52741580209200 | 304 | | [2MASS J00464841+0715177](http://www.wikidata.org/entity/Q222110) | -2.75 | 26.6180 | 11.70173767885790 | 305 | | [2MASS J08351104+2006371](http://www.wikidata.org/entity/Q78611172) | 72 | 3.6984 | 128.79594070217040 | 306 | | [2MASS J08330994+1806328](http://www.wikidata.org/entity/Q78610810) | -7 | 6.1146 | 128.29142004157090 | -------------------------------------------------------------------------------- /docs/mtabes.md: -------------------------------------------------------------------------------- 1 | MTabES: Entity Search 2 | =========== 3 | --- 4 | 5 | ### Features: 6 | - The indexed database (entity labels) is a combination of the three Knowledge Graphs: Wikidata, Wikipedia, and DBpedia, including entity labels, aliases, other names, redirect entity labels, and disambiguation entities. There are 249,388,985 labels, 91,216,260 entities at 2021/01/01. 7 | - Multilingual support. 8 | - Work well with noisy text such as misspelling or abbreviation 9 | - Can be used for the tasks of entity search or entity-based OCR post-processing. 10 | 11 | 12 | ### Interface: 13 | https://mtab.app/mtabes 14 | 15 | ### API URL: 16 | https://mtab.app/api/v1/search 17 | 18 | ### Parameter: 19 | - q: search query. This parameter is required. 20 | - limit: maximum number of relevant entities to return. The value should be from 1 to 1000. The default value is 20. 21 | - m: one of three value [b, f, a]. The default value is a. 22 | - b: keywords search with BM25 (hyper-parameters: b=0.75, k1=1.2). 23 | - f: fuzzy search with an edit-distance (Damerau–Levenshtein distance). 24 | - a: the weighted aggregation of keyword search and fuzzy search. This model yields slightly better performance (1-3 % accuracy improvement) than fuzzy search. 25 | 26 | - info: one of two value [0, 1]. The default value is 0. 27 | - 0: do not return entity labels, description, mapping URLs of DBpedia and Wikipedia. 28 | - 1: return entity labels, description, mapping URLs of DBpedia and Wikipedia. 29 | - expensive: one of two value [0, 1]. The default value is 0. 30 | - 0: efficiency mode. Perform early stopping in the fuzzy search. 31 | - 1: Brute-force search. This mode could slightly improve search performance (improve 1-2% accuracy), but it might take a long time to get answers (about ten times longer than the efficiency mode). 32 | ### Examples: 33 | Searching a query of "2MASS J10540655-0031018". 34 | 35 | Note that: At 2021/01/01, we could not get any answer by using the standard lookup (Wikidata, Wikipedia, DBpedia, or Google Search) 36 | 37 | **Command:** 38 | ```bash 39 | % curl -X GET "https://mtab.app/api/v1/search?limit=3&m=a&info=1&q=2MASS%20J10540655-0031018" 40 | ``` 41 | Expected Answer: 42 | ```json 43 | { 44 | "hits": [ 45 | { 46 | "des": "brown dwarf", 47 | "id": "Q222120", 48 | "label": "2MASS J00540655-0031018", 49 | "score": 0.39831033397179416, 50 | "wd": "http://www.wikidata.org/entity/Q222120" 51 | }, 52 | { 53 | "des": null, 54 | "id": "Q87130330", 55 | "label": "TYC 4151-458-1", 56 | "score": 0.23949881593395422, 57 | "wd": "http://www.wikidata.org/entity/Q87130330" 58 | }, 59 | { 60 | "des": null, 61 | "id": "Q89756929", 62 | "label": "TYC 5033-427-1", 63 | "score": 0.043365759204671825, 64 | "wd": "http://www.wikidata.org/entity/Q89756929" 65 | } 66 | ], 67 | "run_time": 1.1118018627166748, 68 | "status": "Success", 69 | "total": "3" 70 | } 71 | ``` 72 | **MTabES Benchmarking:** 73 | 74 | - SemTab 2020 Round 1 75 | 76 | 77 | 78 | [comment]: <> (![](../interface/static/images/MTabESSemTabR1.png)) 79 | - SemTab 2020 Round 2 80 | 81 | 82 | 83 | [comment]: <> (![](../interface/static/images/MTabESSemTabR2.png)) 84 | - SemTab 2020 Round 3 85 | 86 | 87 | 88 | [comment]: <> (![](../interface/static/images/MTabESSemTabR3.png)) 89 | - SemTab 2020 Round 4 90 | 91 | 92 | 93 | [comment]: <> (![](../interface/static/images/MTabESSemTabR4.png)) 94 | - Tough Tables 95 | 96 | 97 | 98 | [comment]: <> (![](../interface/static/images/MTabESSemTab2T.png)) -------------------------------------------------------------------------------- /interface/static/images/MTabESSemTab2T.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/MTabESSemTab2T.png -------------------------------------------------------------------------------- /interface/static/images/MTabESSemTabR1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/MTabESSemTabR1.png -------------------------------------------------------------------------------- /interface/static/images/MTabESSemTabR2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/MTabESSemTabR2.png -------------------------------------------------------------------------------- /interface/static/images/MTabESSemTabR3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/MTabESSemTabR3.png -------------------------------------------------------------------------------- /interface/static/images/MTabESSemTabR4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/MTabESSemTabR4.png -------------------------------------------------------------------------------- /interface/static/images/logo_mtab_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/logo_mtab_1.png -------------------------------------------------------------------------------- /interface/static/images/logo_mtab_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/logo_mtab_2.png -------------------------------------------------------------------------------- /interface/static/images/logo_mtab_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/logo_mtab_3.png -------------------------------------------------------------------------------- /interface/static/images/logo_mtab_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/logo_mtab_4.png -------------------------------------------------------------------------------- /interface/static/images/mtab_pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/images/mtab_pic.png -------------------------------------------------------------------------------- /interface/static/others/mytables.json: -------------------------------------------------------------------------------- 1 | { 2 | "n_tables": 2, 3 | "status": "Success", 4 | "tables": [ 5 | { 6 | "file_name": "0CF12YZK.csv", 7 | "run_time": 28.576568126678467, 8 | "semantic": { 9 | "cea": [ 10 | { 11 | "annotation": { 12 | "dbpedia": "http://dbpedia.org/resource/Price,_Utah", 13 | "wikidata": "http://www.wikidata.org/entity/Q482891", 14 | "wikipedia": "http://en.wikipedia.org/wiki/Price,_Utah" 15 | }, 16 | "target": [ 17 | 1, 18 | 0 19 | ] 20 | }, 21 | { 22 | "annotation": { 23 | "dbpedia": "http://dbpedia.org/resource/Amguid_crater", 24 | "wikidata": "http://www.wikidata.org/entity/Q248727", 25 | "wikipedia": "http://en.wikipedia.org/wiki/Amguid_crater" 26 | }, 27 | "target": [ 28 | 2, 29 | 0 30 | ] 31 | }, 32 | { 33 | "annotation": { 34 | "dbpedia": "http://dbpedia.org/resource/Zucchius_(crater)", 35 | "wikidata": "http://www.wikidata.org/entity/Q227650", 36 | "wikipedia": "http://en.wikipedia.org/wiki/Zucchius_(crater)" 37 | }, 38 | "target": [ 39 | 3, 40 | 0 41 | ] 42 | }, 43 | { 44 | "annotation": { 45 | "dbpedia": "http://dbpedia.org/resource/Capella", 46 | "wikidata": "http://www.wikidata.org/entity/Q12970", 47 | "wikipedia": "http://en.wikipedia.org/wiki/Capella" 48 | }, 49 | "target": [ 50 | 4, 51 | 0 52 | ] 53 | }, 54 | { 55 | "annotation": { 56 | "dbpedia": "http://dbpedia.org/resource/Gaudibert_(crater)", 57 | "wikidata": "http://www.wikidata.org/entity/Q211287", 58 | "wikipedia": "http://en.wikipedia.org/wiki/Gaudibert_(crater)" 59 | }, 60 | "target": [ 61 | 5, 62 | 0 63 | ] 64 | }, 65 | { 66 | "annotation": { 67 | "dbpedia": "http://dbpedia.org/resource/Thales_(crater)", 68 | "wikidata": "http://www.wikidata.org/entity/Q201509", 69 | "wikipedia": "http://en.wikipedia.org/wiki/Thales_(crater)" 70 | }, 71 | "target": [ 72 | 6, 73 | 0 74 | ] 75 | }, 76 | { 77 | "annotation": { 78 | "wikidata": "http://www.wikidata.org/entity/Q697934" 79 | }, 80 | "target": [ 81 | 7, 82 | 0 83 | ] 84 | }, 85 | { 86 | "annotation": { 87 | "dbpedia": "http://dbpedia.org/resource/Lagrange_(crater)", 88 | "wikidata": "http://www.wikidata.org/entity/Q195032", 89 | "wikipedia": "http://en.wikipedia.org/wiki/Lagrange_(crater)" 90 | }, 91 | "target": [ 92 | 8, 93 | 0 94 | ] 95 | }, 96 | { 97 | "annotation": { 98 | "dbpedia": "http://dbpedia.org/resource/Regiomontanus_(crater)", 99 | "wikidata": "http://www.wikidata.org/entity/Q175368", 100 | "wikipedia": "http://en.wikipedia.org/wiki/Regiomontanus_(crater)" 101 | }, 102 | "target": [ 103 | 9, 104 | 0 105 | ] 106 | }, 107 | { 108 | "annotation": { 109 | "dbpedia": "http://dbpedia.org/resource/De_Gasparis_(crater)", 110 | "wikidata": "http://www.wikidata.org/entity/Q168113", 111 | "wikipedia": "http://en.wikipedia.org/wiki/De_Gasparis_(crater)" 112 | }, 113 | "target": [ 114 | 10, 115 | 0 116 | ] 117 | }, 118 | { 119 | "annotation": { 120 | "dbpedia": "http://dbpedia.org/resource/Adams_(lunar_crater)", 121 | "wikidata": "http://www.wikidata.org/entity/Q166188", 122 | "wikipedia": "http://en.wikipedia.org/wiki/Adams_(lunar_crater)" 123 | }, 124 | "target": [ 125 | 11, 126 | 0 127 | ] 128 | }, 129 | { 130 | "annotation": { 131 | "dbpedia": "http://dbpedia.org/resource/Gardnos_crater", 132 | "wikidata": "http://www.wikidata.org/entity/Q164971", 133 | "wikipedia": "http://en.wikipedia.org/wiki/Gardnos_crater" 134 | }, 135 | "target": [ 136 | 12, 137 | 0 138 | ] 139 | }, 140 | { 141 | "annotation": { 142 | "dbpedia": "http://dbpedia.org/resource/Diophantus_(crater)", 143 | "wikidata": "http://www.wikidata.org/entity/Q164095", 144 | "wikipedia": "http://en.wikipedia.org/wiki/Diophantus_(crater)" 145 | }, 146 | "target": [ 147 | 13, 148 | 0 149 | ] 150 | }, 151 | { 152 | "annotation": { 153 | "dbpedia": "http://dbpedia.org/resource/Agrippa_(crater)", 154 | "wikidata": "http://www.wikidata.org/entity/Q153150", 155 | "wikipedia": "http://en.wikipedia.org/wiki/Agrippa_(crater)" 156 | }, 157 | "target": [ 158 | 14, 159 | 0 160 | ] 161 | }, 162 | { 163 | "annotation": { 164 | "dbpedia": "http://dbpedia.org/resource/Agatharchides_(crater)", 165 | "wikidata": "http://www.wikidata.org/entity/Q153140", 166 | "wikipedia": "http://en.wikipedia.org/wiki/Agatharchides_(crater)" 167 | }, 168 | "target": [ 169 | 15, 170 | 0 171 | ] 172 | }, 173 | { 174 | "annotation": { 175 | "dbpedia": "http://dbpedia.org/resource/Cavendish_(crater)", 176 | "wikidata": "http://www.wikidata.org/entity/Q143729", 177 | "wikipedia": "http://en.wikipedia.org/wiki/Cavendish_(crater)" 178 | }, 179 | "target": [ 180 | 16, 181 | 0 182 | ] 183 | }, 184 | { 185 | "annotation": { 186 | "dbpedia": "http://dbpedia.org/resource/Mersenius_(crater)", 187 | "wikidata": "http://www.wikidata.org/entity/Q143365", 188 | "wikipedia": "http://en.wikipedia.org/wiki/Mersenius_(crater)" 189 | }, 190 | "target": [ 191 | 17, 192 | 0 193 | ] 194 | }, 195 | { 196 | "annotation": { 197 | "dbpedia": "http://dbpedia.org/resource/Zagut_(crater)", 198 | "wikidata": "http://www.wikidata.org/entity/Q140418", 199 | "wikipedia": "http://en.wikipedia.org/wiki/Zagut_(crater)" 200 | }, 201 | "target": [ 202 | 18, 203 | 0 204 | ] 205 | }, 206 | { 207 | "annotation": { 208 | "dbpedia": "http://dbpedia.org/resource/Hausen_(crater)", 209 | "wikidata": "http://www.wikidata.org/entity/Q134149", 210 | "wikipedia": "http://en.wikipedia.org/wiki/Hausen_(crater)" 211 | }, 212 | "target": [ 213 | 19, 214 | 0 215 | ] 216 | }, 217 | { 218 | "annotation": { 219 | "dbpedia": "http://dbpedia.org/resource/Abulfeda_(crater)", 220 | "wikidata": "http://www.wikidata.org/entity/Q133615", 221 | "wikipedia": "http://en.wikipedia.org/wiki/Abulfeda_(crater)" 222 | }, 223 | "target": [ 224 | 20, 225 | 0 226 | ] 227 | }, 228 | { 229 | "annotation": { 230 | "wikidata": "http://www.wikidata.org/entity/Q22239279" 231 | }, 232 | "target": [ 233 | 21, 234 | 0 235 | ] 236 | }, 237 | { 238 | "annotation": { 239 | "dbpedia": "http://dbpedia.org/resource/Anděl_(crater)", 240 | "wikidata": "http://www.wikidata.org/entity/Q130049", 241 | "wikipedia": "http://en.wikipedia.org/wiki/Anděl_(crater)" 242 | }, 243 | "target": [ 244 | 22, 245 | 0 246 | ] 247 | }, 248 | { 249 | "annotation": { 250 | "dbpedia": "http://dbpedia.org/resource/Aristoteles_(crater)", 251 | "wikidata": "http://www.wikidata.org/entity/Q128108", 252 | "wikipedia": "http://en.wikipedia.org/wiki/Aristoteles_(crater)" 253 | }, 254 | "target": [ 255 | 23, 256 | 0 257 | ] 258 | }, 259 | { 260 | "annotation": { 261 | "dbpedia": "http://dbpedia.org/resource/Aristillus_(crater)", 262 | "wikidata": "http://www.wikidata.org/entity/Q128041", 263 | "wikipedia": "http://en.wikipedia.org/wiki/Aristillus_(crater)" 264 | }, 265 | "target": [ 266 | 24, 267 | 0 268 | ] 269 | }, 270 | { 271 | "annotation": { 272 | "dbpedia": "http://dbpedia.org/resource/Harpalus_(crater)", 273 | "wikidata": "http://www.wikidata.org/entity/Q128035", 274 | "wikipedia": "http://en.wikipedia.org/wiki/Harpalus_(crater)" 275 | }, 276 | "target": [ 277 | 25, 278 | 0 279 | ] 280 | }, 281 | { 282 | "annotation": { 283 | "dbpedia": "http://dbpedia.org/resource/Eudoxus_(lunar_crater)", 284 | "wikidata": "http://www.wikidata.org/entity/Q128013", 285 | "wikipedia": "http://en.wikipedia.org/wiki/Eudoxus_(lunar_crater)" 286 | }, 287 | "target": [ 288 | 26, 289 | 0 290 | ] 291 | }, 292 | { 293 | "annotation": { 294 | "dbpedia": "http://dbpedia.org/resource/Laroin", 295 | "wikidata": "http://www.wikidata.org/entity/Q198121", 296 | "wikipedia": "http://en.wikipedia.org/wiki/Laroin" 297 | }, 298 | "target": [ 299 | 27, 300 | 0 301 | ] 302 | }, 303 | { 304 | "annotation": { 305 | "dbpedia": "http://dbpedia.org/resource/Philolaus_(crater)", 306 | "wikidata": "http://www.wikidata.org/entity/Q116169", 307 | "wikipedia": "http://en.wikipedia.org/wiki/Philolaus_(crater)" 308 | }, 309 | "target": [ 310 | 28, 311 | 0 312 | ] 313 | }, 314 | { 315 | "annotation": { 316 | "dbpedia": "http://dbpedia.org/resource/Mouche", 317 | "wikidata": "http://www.wikidata.org/entity/Q18411720", 318 | "wikipedia": "http://en.wikipedia.org/wiki/Mouche" 319 | }, 320 | "target": [ 321 | 29, 322 | 0 323 | ] 324 | }, 325 | { 326 | "annotation": { 327 | "dbpedia": "http://dbpedia.org/resource/Pascal_(crater)", 328 | "wikidata": "http://www.wikidata.org/entity/Q115739", 329 | "wikipedia": "http://en.wikipedia.org/wiki/Pascal_(crater)" 330 | }, 331 | "target": [ 332 | 30, 333 | 0 334 | ] 335 | }, 336 | { 337 | "annotation": { 338 | "dbpedia": "http://dbpedia.org/resource/Plato_(crater)", 339 | "wikidata": "http://www.wikidata.org/entity/Q115383", 340 | "wikipedia": "http://en.wikipedia.org/wiki/Plato_(crater)" 341 | }, 342 | "target": [ 343 | 31, 344 | 0 345 | ] 346 | }, 347 | { 348 | "annotation": { 349 | "dbpedia": "http://dbpedia.org/resource/Abel_(disambiguation)", 350 | "wikidata": "http://www.wikidata.org/entity/Q224167", 351 | "wikipedia": "http://en.wikipedia.org/wiki/Abel_(disambiguation)" 352 | }, 353 | "target": [ 354 | 32, 355 | 0 356 | ] 357 | }, 358 | { 359 | "annotation": { 360 | "dbpedia": "http://dbpedia.org/resource/Abul_Wafa_(crater)", 361 | "wikidata": "http://www.wikidata.org/entity/Q115062", 362 | "wikipedia": "http://en.wikipedia.org/wiki/Abul_Wafa_(crater)" 363 | }, 364 | "target": [ 365 | 33, 366 | 0 367 | ] 368 | }, 369 | { 370 | "annotation": { 371 | "dbpedia": "http://dbpedia.org/resource/Saussure_(crater)", 372 | "wikidata": "http://www.wikidata.org/entity/Q74583", 373 | "wikipedia": "http://en.wikipedia.org/wiki/Saussure_(crater)" 374 | }, 375 | "target": [ 376 | 34, 377 | 0 378 | ] 379 | }, 380 | { 381 | "annotation": { 382 | "dbpedia": "http://dbpedia.org/resource/Longomontanus_(crater)", 383 | "wikidata": "http://www.wikidata.org/entity/Q73533", 384 | "wikipedia": "http://en.wikipedia.org/wiki/Longomontanus_(crater)" 385 | }, 386 | "target": [ 387 | 35, 388 | 0 389 | ] 390 | }, 391 | { 392 | "annotation": { 393 | "dbpedia": "http://dbpedia.org/resource/Orontius_(crater)", 394 | "wikidata": "http://www.wikidata.org/entity/Q64067", 395 | "wikipedia": "http://en.wikipedia.org/wiki/Orontius_(crater)" 396 | }, 397 | "target": [ 398 | 36, 399 | 0 400 | ] 401 | }, 402 | { 403 | "annotation": { 404 | "dbpedia": "http://dbpedia.org/resource/Esclangon_(crater)", 405 | "wikidata": "http://www.wikidata.org/entity/Q63694", 406 | "wikipedia": "http://en.wikipedia.org/wiki/Esclangon_(crater)" 407 | }, 408 | "target": [ 409 | 37, 410 | 0 411 | ] 412 | }, 413 | { 414 | "annotation": { 415 | "dbpedia": "http://dbpedia.org/resource/Kepler_(band)", 416 | "wikidata": "http://www.wikidata.org/entity/Q6393189", 417 | "wikipedia": "http://en.wikipedia.org/wiki/Kepler_(band)" 418 | }, 419 | "target": [ 420 | 38, 421 | 0 422 | ] 423 | }, 424 | { 425 | "annotation": { 426 | "wikidata": "http://www.wikidata.org/entity/Q45550018" 427 | }, 428 | "target": [ 429 | 39, 430 | 0 431 | ] 432 | }, 433 | { 434 | "annotation": { 435 | "dbpedia": "http://dbpedia.org/resource/Daguerre_(crater)", 436 | "wikidata": "http://www.wikidata.org/entity/Q1157392", 437 | "wikipedia": "http://en.wikipedia.org/wiki/Daguerre_(crater)" 438 | }, 439 | "target": [ 440 | 40, 441 | 0 442 | ] 443 | }, 444 | { 445 | "annotation": { 446 | "wikidata": "http://www.wikidata.org/entity/Q1057579" 447 | }, 448 | "target": [ 449 | 41, 450 | 0 451 | ] 452 | }, 453 | { 454 | "annotation": { 455 | "dbpedia": "http://dbpedia.org/resource/Cyrillus_(crater)", 456 | "wikidata": "http://www.wikidata.org/entity/Q1148824", 457 | "wikipedia": "http://en.wikipedia.org/wiki/Cyrillus_(crater)" 458 | }, 459 | "target": [ 460 | 42, 461 | 0 462 | ] 463 | }, 464 | { 465 | "annotation": { 466 | "dbpedia": "http://dbpedia.org/resource/Curtius_(crater)", 467 | "wikidata": "http://www.wikidata.org/entity/Q1145827", 468 | "wikipedia": "http://en.wikipedia.org/wiki/Curtius_(crater)" 469 | }, 470 | "target": [ 471 | 43, 472 | 0 473 | ] 474 | }, 475 | { 476 | "annotation": { 477 | "dbpedia": "http://dbpedia.org/resource/Crüger_(crater)", 478 | "wikidata": "http://www.wikidata.org/entity/Q1142589", 479 | "wikipedia": "http://en.wikipedia.org/wiki/Crüger_(crater)" 480 | }, 481 | "target": [ 482 | 44, 483 | 0 484 | ] 485 | } 486 | ], 487 | "cpa": [ 488 | { 489 | "annotation": { 490 | "wikidata": "http://www.wikidata.org/prop/direct/P4511" 491 | }, 492 | "target": [ 493 | 0, 494 | 1 495 | ] 496 | }, 497 | { 498 | "annotation": { 499 | "wikidata": "http://www.wikidata.org/prop/direct/P2386" 500 | }, 501 | "target": [ 502 | 0, 503 | 2 504 | ] 505 | } 506 | ], 507 | "cta": [ 508 | { 509 | "annotation": { 510 | "dbpedia": "http://dbpedia.org/resource/Impact_crater", 511 | "wikidata": "http://www.wikidata.org/entity/Q55818", 512 | "wikipedia": "http://en.wikipedia.org/wiki/Impact_crater" 513 | }, 514 | "target": 0 515 | } 516 | ] 517 | }, 518 | "structure": { 519 | "columns": 3, 520 | "core_attribute": 0, 521 | "header": [ 522 | 0 523 | ], 524 | "missing ratio": 0, 525 | "row": 45, 526 | "table type": "vertical relation" 527 | }, 528 | "table_id": "0CF12YZK" 529 | }, 530 | { 531 | "file_name": "K0PM5GMK.csv", 532 | "run_time": 17.138594150543213, 533 | "semantic": { 534 | "cea": [ 535 | { 536 | "annotation": { 537 | "wikidata": "http://www.wikidata.org/entity/Q32094061" 538 | }, 539 | "target": [ 540 | 1, 541 | 0 542 | ] 543 | }, 544 | { 545 | "annotation": { 546 | "wikidata": "http://www.wikidata.org/entity/Q244822" 547 | }, 548 | "target": [ 549 | 1, 550 | 1 551 | ] 552 | }, 553 | { 554 | "annotation": { 555 | "dbpedia": "http://dbpedia.org/resource/Spain", 556 | "wikidata": "http://www.wikidata.org/entity/Q29", 557 | "wikipedia": "http://en.wikipedia.org/wiki/Spain" 558 | }, 559 | "target": [ 560 | 1, 561 | 2 562 | ] 563 | }, 564 | { 565 | "annotation": { 566 | "wikidata": "http://www.wikidata.org/entity/Q30302686" 567 | }, 568 | "target": [ 569 | 1, 570 | 3 571 | ] 572 | }, 573 | { 574 | "annotation": { 575 | "wikidata": "http://www.wikidata.org/entity/Q27966457" 576 | }, 577 | "target": [ 578 | 2, 579 | 0 580 | ] 581 | }, 582 | { 583 | "annotation": { 584 | "dbpedia": "http://dbpedia.org/resource/Blue", 585 | "wikidata": "http://www.wikidata.org/entity/Q1088", 586 | "wikipedia": "http://en.wikipedia.org/wiki/Blue" 587 | }, 588 | "target": [ 589 | 2, 590 | 1 591 | ] 592 | }, 593 | { 594 | "annotation": { 595 | "dbpedia": "http://dbpedia.org/resource/Czechoslovakia", 596 | "wikidata": "http://www.wikidata.org/entity/Q33946", 597 | "wikipedia": "http://en.wikipedia.org/wiki/Czechoslovakia" 598 | }, 599 | "target": [ 600 | 2, 601 | 2 602 | ] 603 | }, 604 | { 605 | "annotation": { 606 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 607 | }, 608 | "target": [ 609 | 2, 610 | 3 611 | ] 612 | }, 613 | { 614 | "annotation": { 615 | "wikidata": "http://www.wikidata.org/entity/Q27089347" 616 | }, 617 | "target": [ 618 | 3, 619 | 0 620 | ] 621 | }, 622 | { 623 | "annotation": { 624 | "dbpedia": "http://dbpedia.org/resource/Yellow", 625 | "wikidata": "http://www.wikidata.org/entity/Q943", 626 | "wikipedia": "http://en.wikipedia.org/wiki/Yellow" 627 | }, 628 | "target": [ 629 | 3, 630 | 1 631 | ] 632 | }, 633 | { 634 | "annotation": { 635 | "dbpedia": "http://dbpedia.org/resource/Peru", 636 | "wikidata": "http://www.wikidata.org/entity/Q419", 637 | "wikipedia": "http://en.wikipedia.org/wiki/Peru" 638 | }, 639 | "target": [ 640 | 3, 641 | 2 642 | ] 643 | }, 644 | { 645 | "annotation": { 646 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 647 | }, 648 | "target": [ 649 | 3, 650 | 3 651 | ] 652 | }, 653 | { 654 | "annotation": { 655 | "wikidata": "http://www.wikidata.org/entity/Q7382095" 656 | }, 657 | "target": [ 658 | 4, 659 | 0 660 | ] 661 | }, 662 | { 663 | "annotation": { 664 | "dbpedia": "http://dbpedia.org/resource/Blue", 665 | "wikidata": "http://www.wikidata.org/entity/Q1088", 666 | "wikipedia": "http://en.wikipedia.org/wiki/Blue" 667 | }, 668 | "target": [ 669 | 4, 670 | 1 671 | ] 672 | }, 673 | { 674 | "annotation": { 675 | "dbpedia": "http://dbpedia.org/resource/Russia", 676 | "wikidata": "http://www.wikidata.org/entity/Q159", 677 | "wikipedia": "http://en.wikipedia.org/wiki/Russia" 678 | }, 679 | "target": [ 680 | 4, 681 | 2 682 | ] 683 | }, 684 | { 685 | "annotation": { 686 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 687 | }, 688 | "target": [ 689 | 4, 690 | 3 691 | ] 692 | }, 693 | { 694 | "annotation": { 695 | "wikidata": "http://www.wikidata.org/entity/Q5718706" 696 | }, 697 | "target": [ 698 | 5, 699 | 0 700 | ] 701 | }, 702 | { 703 | "annotation": { 704 | "dbpedia": "http://dbpedia.org/resource/Yellow", 705 | "wikidata": "http://www.wikidata.org/entity/Q943", 706 | "wikipedia": "http://en.wikipedia.org/wiki/Yellow" 707 | }, 708 | "target": [ 709 | 5, 710 | 1 711 | ] 712 | }, 713 | { 714 | "annotation": { 715 | "dbpedia": "http://dbpedia.org/resource/Spain", 716 | "wikidata": "http://www.wikidata.org/entity/Q29", 717 | "wikipedia": "http://en.wikipedia.org/wiki/Spain" 718 | }, 719 | "target": [ 720 | 5, 721 | 2 722 | ] 723 | }, 724 | { 725 | "annotation": { 726 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 727 | }, 728 | "target": [ 729 | 5, 730 | 3 731 | ] 732 | }, 733 | { 734 | "annotation": { 735 | "wikidata": "http://www.wikidata.org/entity/Q5718562" 736 | }, 737 | "target": [ 738 | 6, 739 | 0 740 | ] 741 | }, 742 | { 743 | "annotation": { 744 | "dbpedia": "http://dbpedia.org/resource/Yellow", 745 | "wikidata": "http://www.wikidata.org/entity/Q943", 746 | "wikipedia": "http://en.wikipedia.org/wiki/Yellow" 747 | }, 748 | "target": [ 749 | 6, 750 | 1 751 | ] 752 | }, 753 | { 754 | "annotation": { 755 | "dbpedia": "http://dbpedia.org/resource/Spain", 756 | "wikidata": "http://www.wikidata.org/entity/Q29", 757 | "wikipedia": "http://en.wikipedia.org/wiki/Spain" 758 | }, 759 | "target": [ 760 | 6, 761 | 2 762 | ] 763 | }, 764 | { 765 | "annotation": { 766 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 767 | }, 768 | "target": [ 769 | 6, 770 | 3 771 | ] 772 | }, 773 | { 774 | "annotation": { 775 | "wikidata": "http://www.wikidata.org/entity/Q5558049" 776 | }, 777 | "target": [ 778 | 7, 779 | 0 780 | ] 781 | }, 782 | { 783 | "annotation": { 784 | "dbpedia": "http://dbpedia.org/resource/Yellow", 785 | "wikidata": "http://www.wikidata.org/entity/Q943", 786 | "wikipedia": "http://en.wikipedia.org/wiki/Yellow" 787 | }, 788 | "target": [ 789 | 7, 790 | 1 791 | ] 792 | }, 793 | { 794 | "annotation": { 795 | "dbpedia": "http://dbpedia.org/resource/Spain", 796 | "wikidata": "http://www.wikidata.org/entity/Q29", 797 | "wikipedia": "http://en.wikipedia.org/wiki/Spain" 798 | }, 799 | "target": [ 800 | 7, 801 | 2 802 | ] 803 | }, 804 | { 805 | "annotation": { 806 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 807 | }, 808 | "target": [ 809 | 7, 810 | 3 811 | ] 812 | }, 813 | { 814 | "annotation": { 815 | "wikidata": "http://www.wikidata.org/entity/Q24942296" 816 | }, 817 | "target": [ 818 | 8, 819 | 0 820 | ] 821 | }, 822 | { 823 | "annotation": { 824 | "dbpedia": "http://dbpedia.org/resource/Green", 825 | "wikidata": "http://www.wikidata.org/entity/Q3133", 826 | "wikipedia": "http://en.wikipedia.org/wiki/Green" 827 | }, 828 | "target": [ 829 | 8, 830 | 1 831 | ] 832 | }, 833 | { 834 | "annotation": { 835 | "dbpedia": "http://dbpedia.org/resource/Spain", 836 | "wikidata": "http://www.wikidata.org/entity/Q29", 837 | "wikipedia": "http://en.wikipedia.org/wiki/Spain" 838 | }, 839 | "target": [ 840 | 8, 841 | 2 842 | ] 843 | }, 844 | { 845 | "annotation": { 846 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 847 | }, 848 | "target": [ 849 | 8, 850 | 3 851 | ] 852 | }, 853 | { 854 | "annotation": { 855 | "wikidata": "http://www.wikidata.org/entity/Q24942285" 856 | }, 857 | "target": [ 858 | 9, 859 | 0 860 | ] 861 | }, 862 | { 863 | "annotation": { 864 | "dbpedia": "http://dbpedia.org/resource/Blue", 865 | "wikidata": "http://www.wikidata.org/entity/Q1088", 866 | "wikipedia": "http://en.wikipedia.org/wiki/Blue" 867 | }, 868 | "target": [ 869 | 9, 870 | 1 871 | ] 872 | }, 873 | { 874 | "annotation": { 875 | "dbpedia": "http://dbpedia.org/resource/Spain", 876 | "wikidata": "http://www.wikidata.org/entity/Q29", 877 | "wikipedia": "http://en.wikipedia.org/wiki/Spain" 878 | }, 879 | "target": [ 880 | 9, 881 | 2 882 | ] 883 | }, 884 | { 885 | "annotation": { 886 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 887 | }, 888 | "target": [ 889 | 9, 890 | 3 891 | ] 892 | }, 893 | { 894 | "annotation": { 895 | "wikidata": "http://www.wikidata.org/entity/Q4485721" 896 | }, 897 | "target": [ 898 | 10, 899 | 0 900 | ] 901 | }, 902 | { 903 | "annotation": { 904 | "dbpedia": "http://dbpedia.org/resource/Red", 905 | "wikidata": "http://www.wikidata.org/entity/Q3142", 906 | "wikipedia": "http://en.wikipedia.org/wiki/Red" 907 | }, 908 | "target": [ 909 | 10, 910 | 1 911 | ] 912 | }, 913 | { 914 | "annotation": { 915 | "dbpedia": "http://dbpedia.org/resource/German_Reich", 916 | "wikidata": "http://www.wikidata.org/entity/Q41304", 917 | "wikipedia": "http://en.wikipedia.org/wiki/Weimar_Republic" 918 | }, 919 | "target": [ 920 | 10, 921 | 2 922 | ] 923 | }, 924 | { 925 | "annotation": { 926 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 927 | }, 928 | "target": [ 929 | 10, 930 | 3 931 | ] 932 | }, 933 | { 934 | "annotation": { 935 | "wikidata": "http://www.wikidata.org/entity/Q11698194" 936 | }, 937 | "target": [ 938 | 11, 939 | 0 940 | ] 941 | }, 942 | { 943 | "annotation": { 944 | "dbpedia": "http://dbpedia.org/resource/Green", 945 | "wikidata": "http://www.wikidata.org/entity/Q3133", 946 | "wikipedia": "http://en.wikipedia.org/wiki/Green" 947 | }, 948 | "target": [ 949 | 11, 950 | 1 951 | ] 952 | }, 953 | { 954 | "annotation": { 955 | "dbpedia": "http://dbpedia.org/resource/Malta", 956 | "wikidata": "http://www.wikidata.org/entity/Q233", 957 | "wikipedia": "http://en.wikipedia.org/wiki/Malta" 958 | }, 959 | "target": [ 960 | 11, 961 | 2 962 | ] 963 | }, 964 | { 965 | "annotation": { 966 | "wikidata": "http://www.wikidata.org/entity/Q30302686" 967 | }, 968 | "target": [ 969 | 11, 970 | 3 971 | ] 972 | }, 973 | { 974 | "annotation": { 975 | "dbpedia": "http://dbpedia.org/resource/Flag_of_the_People's_Liberation_Army", 976 | "wikidata": "http://www.wikidata.org/entity/Q10872945", 977 | "wikipedia": "http://en.wikipedia.org/wiki/Flag_of_the_People's_Liberation_Army" 978 | }, 979 | "target": [ 980 | 12, 981 | 0 982 | ] 983 | }, 984 | { 985 | "annotation": { 986 | "dbpedia": "http://dbpedia.org/resource/Red", 987 | "wikidata": "http://www.wikidata.org/entity/Q3142", 988 | "wikipedia": "http://en.wikipedia.org/wiki/Red" 989 | }, 990 | "target": [ 991 | 12, 992 | 1 993 | ] 994 | }, 995 | { 996 | "annotation": { 997 | "dbpedia": "http://dbpedia.org/resource/China", 998 | "wikidata": "http://www.wikidata.org/entity/Q148", 999 | "wikipedia": "http://en.wikipedia.org/wiki/China" 1000 | }, 1001 | "target": [ 1002 | 12, 1003 | 2 1004 | ] 1005 | }, 1006 | { 1007 | "annotation": { 1008 | "wikidata": "http://www.wikidata.org/entity/Q20970435" 1009 | }, 1010 | "target": [ 1011 | 12, 1012 | 3 1013 | ] 1014 | }, 1015 | { 1016 | "annotation": { 1017 | "wikidata": "http://www.wikidata.org/entity/Q11913350" 1018 | }, 1019 | "target": [ 1020 | 13, 1021 | 0 1022 | ] 1023 | }, 1024 | { 1025 | "annotation": { 1026 | "dbpedia": "http://dbpedia.org/resource/Yellow", 1027 | "wikidata": "http://www.wikidata.org/entity/Q943", 1028 | "wikipedia": "http://en.wikipedia.org/wiki/Yellow" 1029 | }, 1030 | "target": [ 1031 | 13, 1032 | 1 1033 | ] 1034 | }, 1035 | { 1036 | "annotation": { 1037 | "dbpedia": "http://dbpedia.org/resource/Czech_Republic", 1038 | "wikidata": "http://www.wikidata.org/entity/Q213", 1039 | "wikipedia": "http://en.wikipedia.org/wiki/Czech_Republic" 1040 | }, 1041 | "target": [ 1042 | 13, 1043 | 2 1044 | ] 1045 | }, 1046 | { 1047 | "annotation": { 1048 | "wikidata": "http://www.wikidata.org/entity/Q20970430" 1049 | }, 1050 | "target": [ 1051 | 13, 1052 | 3 1053 | ] 1054 | }, 1055 | { 1056 | "annotation": { 1057 | "wikidata": "http://www.wikidata.org/entity/Q1006483" 1058 | }, 1059 | "target": [ 1060 | 14, 1061 | 0 1062 | ] 1063 | }, 1064 | { 1065 | "annotation": { 1066 | "dbpedia": "http://dbpedia.org/resource/Red", 1067 | "wikidata": "http://www.wikidata.org/entity/Q3142", 1068 | "wikipedia": "http://en.wikipedia.org/wiki/Red" 1069 | }, 1070 | "target": [ 1071 | 14, 1072 | 1 1073 | ] 1074 | }, 1075 | { 1076 | "annotation": { 1077 | "dbpedia": "http://dbpedia.org/resource/Weimar_Republic", 1078 | "wikidata": "http://www.wikidata.org/entity/Q183", 1079 | "wikipedia": "http://en.wikipedia.org/wiki/Germany" 1080 | }, 1081 | "target": [ 1082 | 14, 1083 | 2 1084 | ] 1085 | }, 1086 | { 1087 | "annotation": { 1088 | "wikidata": "http://www.wikidata.org/entity/Q30302686" 1089 | }, 1090 | "target": [ 1091 | 14, 1092 | 3 1093 | ] 1094 | }, 1095 | { 1096 | "annotation": { 1097 | "dbpedia": "http://dbpedia.org/resource/Flag_of_the_Armenian_Soviet_Socialist_Republic", 1098 | "wikidata": "http://www.wikidata.org/entity/Q877603", 1099 | "wikipedia": "http://en.wikipedia.org/wiki/Flag_of_the_Armenian_Soviet_Socialist_Republic" 1100 | }, 1101 | "target": [ 1102 | 15, 1103 | 0 1104 | ] 1105 | }, 1106 | { 1107 | "annotation": { 1108 | "dbpedia": "http://dbpedia.org/resource/Blue", 1109 | "wikidata": "http://www.wikidata.org/entity/Q1088", 1110 | "wikipedia": "http://en.wikipedia.org/wiki/Blue" 1111 | }, 1112 | "target": [ 1113 | 15, 1114 | 1 1115 | ] 1116 | }, 1117 | { 1118 | "annotation": { 1119 | "dbpedia": "http://dbpedia.org/resource/Armenian_Soviet_Socialist_Republic", 1120 | "wikidata": "http://www.wikidata.org/entity/Q132856", 1121 | "wikipedia": "http://en.wikipedia.org/wiki/Armenian_Soviet_Socialist_Republic" 1122 | }, 1123 | "target": [ 1124 | 15, 1125 | 2 1126 | ] 1127 | }, 1128 | { 1129 | "annotation": { 1130 | "wikidata": "http://www.wikidata.org/entity/Q30302657" 1131 | }, 1132 | "target": [ 1133 | 15, 1134 | 3 1135 | ] 1136 | }, 1137 | { 1138 | "annotation": { 1139 | "dbpedia": "http://dbpedia.org/resource/Flag_of_Piedmont", 1140 | "wikidata": "http://www.wikidata.org/entity/Q1094206", 1141 | "wikipedia": "http://en.wikipedia.org/wiki/Flag_of_Piedmont" 1142 | }, 1143 | "target": [ 1144 | 16, 1145 | 0 1146 | ] 1147 | }, 1148 | { 1149 | "annotation": { 1150 | "dbpedia": "http://dbpedia.org/resource/Blue", 1151 | "wikidata": "http://www.wikidata.org/entity/Q1088", 1152 | "wikipedia": "http://en.wikipedia.org/wiki/Blue" 1153 | }, 1154 | "target": [ 1155 | 16, 1156 | 1 1157 | ] 1158 | }, 1159 | { 1160 | "annotation": { 1161 | "dbpedia": "http://dbpedia.org/resource/Italy", 1162 | "wikidata": "http://www.wikidata.org/entity/Q38", 1163 | "wikipedia": "http://en.wikipedia.org/wiki/Italy" 1164 | }, 1165 | "target": [ 1166 | 16, 1167 | 2 1168 | ] 1169 | }, 1170 | { 1171 | "annotation": { 1172 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 1173 | }, 1174 | "target": [ 1175 | 16, 1176 | 3 1177 | ] 1178 | }, 1179 | { 1180 | "annotation": { 1181 | "dbpedia": "http://dbpedia.org/resource/Transnistria", 1182 | "wikidata": "http://www.wikidata.org/entity/Q907112", 1183 | "wikipedia": "http://en.wikipedia.org/wiki/Transnistria" 1184 | }, 1185 | "target": [ 1186 | 17, 1187 | 0 1188 | ] 1189 | }, 1190 | { 1191 | "annotation": { 1192 | "dbpedia": "http://dbpedia.org/resource/Green", 1193 | "wikidata": "http://www.wikidata.org/entity/Q3133", 1194 | "wikipedia": "http://en.wikipedia.org/wiki/Green" 1195 | }, 1196 | "target": [ 1197 | 17, 1198 | 1 1199 | ] 1200 | }, 1201 | { 1202 | "annotation": { 1203 | "dbpedia": "http://dbpedia.org/resource/Moldova", 1204 | "wikidata": "http://www.wikidata.org/entity/Q217", 1205 | "wikipedia": "http://en.wikipedia.org/wiki/Moldova" 1206 | }, 1207 | "target": [ 1208 | 17, 1209 | 2 1210 | ] 1211 | }, 1212 | { 1213 | "annotation": { 1214 | "wikidata": "http://www.wikidata.org/entity/Q30302657" 1215 | }, 1216 | "target": [ 1217 | 17, 1218 | 3 1219 | ] 1220 | }, 1221 | { 1222 | "annotation": { 1223 | "dbpedia": "http://dbpedia.org/resource/Flag_of_Crimea", 1224 | "wikidata": "http://www.wikidata.org/entity/Q225489", 1225 | "wikipedia": "http://en.wikipedia.org/wiki/Flag_of_Crimea" 1226 | }, 1227 | "target": [ 1228 | 18, 1229 | 0 1230 | ] 1231 | }, 1232 | { 1233 | "annotation": { 1234 | "dbpedia": "http://dbpedia.org/resource/Blue", 1235 | "wikidata": "http://www.wikidata.org/entity/Q1088", 1236 | "wikipedia": "http://en.wikipedia.org/wiki/Blue" 1237 | }, 1238 | "target": [ 1239 | 18, 1240 | 1 1241 | ] 1242 | }, 1243 | { 1244 | "annotation": { 1245 | "dbpedia": "http://dbpedia.org/resource/Russia", 1246 | "wikidata": "http://www.wikidata.org/entity/Q159", 1247 | "wikipedia": "http://en.wikipedia.org/wiki/Russia" 1248 | }, 1249 | "target": [ 1250 | 18, 1251 | 2 1252 | ] 1253 | }, 1254 | { 1255 | "annotation": { 1256 | "wikidata": "http://www.wikidata.org/entity/Q30302657" 1257 | }, 1258 | "target": [ 1259 | 18, 1260 | 3 1261 | ] 1262 | }, 1263 | { 1264 | "annotation": { 1265 | "dbpedia": "http://dbpedia.org/resource/Flag_of_Guernsey", 1266 | "wikidata": "http://www.wikidata.org/entity/Q158591", 1267 | "wikipedia": "http://en.wikipedia.org/wiki/Flag_of_Guernsey" 1268 | }, 1269 | "target": [ 1270 | 19, 1271 | 0 1272 | ] 1273 | }, 1274 | { 1275 | "annotation": { 1276 | "dbpedia": "http://dbpedia.org/resource/Red", 1277 | "wikidata": "http://www.wikidata.org/entity/Q3142", 1278 | "wikipedia": "http://en.wikipedia.org/wiki/Red" 1279 | }, 1280 | "target": [ 1281 | 19, 1282 | 1 1283 | ] 1284 | }, 1285 | { 1286 | "annotation": { 1287 | "dbpedia": "http://dbpedia.org/resource/Guernsey", 1288 | "wikidata": "http://www.wikidata.org/entity/Q25230", 1289 | "wikipedia": "http://en.wikipedia.org/wiki/Bailiwick_of_Guernsey" 1290 | }, 1291 | "target": [ 1292 | 19, 1293 | 2 1294 | ] 1295 | }, 1296 | { 1297 | "annotation": { 1298 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 1299 | }, 1300 | "target": [ 1301 | 19, 1302 | 3 1303 | ] 1304 | }, 1305 | { 1306 | "annotation": { 1307 | "dbpedia": "http://dbpedia.org/resource/Flag_of_Saba", 1308 | "wikidata": "http://www.wikidata.org/entity/Q429900", 1309 | "wikipedia": "http://en.wikipedia.org/wiki/Flag_of_Saba" 1310 | }, 1311 | "target": [ 1312 | 20, 1313 | 0 1314 | ] 1315 | }, 1316 | { 1317 | "annotation": { 1318 | "dbpedia": "http://dbpedia.org/resource/Yellow", 1319 | "wikidata": "http://www.wikidata.org/entity/Q943", 1320 | "wikipedia": "http://en.wikipedia.org/wiki/Yellow" 1321 | }, 1322 | "target": [ 1323 | 20, 1324 | 1 1325 | ] 1326 | }, 1327 | { 1328 | "annotation": { 1329 | "dbpedia": "http://dbpedia.org/resource/Kingdom_of_the_Netherlands", 1330 | "wikidata": "http://www.wikidata.org/entity/Q55", 1331 | "wikipedia": "http://en.wikipedia.org/wiki/Netherlands" 1332 | }, 1333 | "target": [ 1334 | 20, 1335 | 2 1336 | ] 1337 | }, 1338 | { 1339 | "annotation": { 1340 | "wikidata": "http://www.wikidata.org/entity/Q20970431" 1341 | }, 1342 | "target": [ 1343 | 20, 1344 | 3 1345 | ] 1346 | } 1347 | ], 1348 | "cpa": [ 1349 | { 1350 | "annotation": { 1351 | "wikidata": "http://www.wikidata.org/prop/direct/P462" 1352 | }, 1353 | "target": [ 1354 | 0, 1355 | 1 1356 | ] 1357 | }, 1358 | { 1359 | "annotation": { 1360 | "wikidata": "http://www.wikidata.org/prop/direct/P17" 1361 | }, 1362 | "target": [ 1363 | 0, 1364 | 2 1365 | ] 1366 | }, 1367 | { 1368 | "annotation": { 1369 | "wikidata": "http://www.wikidata.org/prop/direct/P2061" 1370 | }, 1371 | "target": [ 1372 | 0, 1373 | 3 1374 | ] 1375 | } 1376 | ], 1377 | "cta": [ 1378 | { 1379 | "annotation": { 1380 | "dbpedia": "http://dbpedia.org/resource/Flag", 1381 | "wikidata": "http://www.wikidata.org/entity/Q14660", 1382 | "wikipedia": "http://en.wikipedia.org/wiki/Flag" 1383 | }, 1384 | "target": 0 1385 | }, 1386 | { 1387 | "annotation": { 1388 | "dbpedia": "http://dbpedia.org/resource/Color", 1389 | "wikidata": "http://www.wikidata.org/entity/Q1075", 1390 | "wikipedia": "http://en.wikipedia.org/wiki/Color" 1391 | }, 1392 | "target": 1 1393 | }, 1394 | { 1395 | "annotation": { 1396 | "wikidata": "http://www.wikidata.org/entity/Q20970434" 1397 | }, 1398 | "target": 3 1399 | } 1400 | ] 1401 | }, 1402 | "structure": { 1403 | "columns": 4, 1404 | "core_attribute": 0, 1405 | "header": [ 1406 | 0 1407 | ], 1408 | "missing ratio": 0, 1409 | "row": 21, 1410 | "table type": "vertical relation" 1411 | }, 1412 | "table_id": "K0PM5GMK" 1413 | } 1414 | ] 1415 | } -------------------------------------------------------------------------------- /interface/static/others/mytables.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/interface/static/others/mytables.zip -------------------------------------------------------------------------------- /interface/templates/md.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}{{ md_title }}{% endblock %} 3 | {% block content %} 4 | {{ md_content | safe }} 5 | {% endblock %} -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | charamel == 1.0.0 2 | numpy == 1.19.2 3 | pandas == 1.1.5 4 | petl == 1.7.4 5 | requests == 2.27.1 6 | openpyxl 7 | -------------------------------------------------------------------------------- /results.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/results.zip -------------------------------------------------------------------------------- /run_2t.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import fnmatch 3 | import json 4 | import os 5 | import signal 6 | import urllib 7 | from collections import defaultdict, Counter 8 | from contextlib import closing 9 | from datetime import timedelta 10 | from math import pi 11 | from multiprocessing import Pool 12 | from time import time, sleep 13 | 14 | import chardet 15 | import matplotlib.pyplot as plt 16 | import numpy 17 | import pandas 18 | import petl 19 | import requests 20 | from contextlib2 import contextmanager 21 | from requests.adapters import HTTPAdapter 22 | from requests.packages.urllib3.util.retry import Retry 23 | from tqdm import tqdm 24 | 25 | import m_config as cf 26 | 27 | DOMAIN = "https://mtab.app" 28 | 29 | DIR_ROOT = "/Users/phucnguyen/git/mtab" 30 | 31 | # Dataset Directories 32 | DIR_TABLES = DIR_ROOT + "/data/tables/{challenge}/{data_name}/tables" 33 | 34 | # Target files 35 | DIR_CEA_TAR = DIR_ROOT + "/data/tables/{challenge}/{data_name}/cea.csv" 36 | DIR_CTA_TAR = DIR_ROOT + "/data/tables/{challenge}/{data_name}/cta.csv" 37 | DIR_CPA_TAR = DIR_ROOT + "/data/tables/{challenge}/{data_name}/cpa.csv" 38 | 39 | 40 | DIR_CEA_GT = DIR_ROOT + "/data/tables/{challenge}/{data_name}/gt/CEA_2T_WD_gt.csv" 41 | 42 | # Result files 43 | DIR_CEA_RES = DIR_ROOT + "/results/{challenge}/{data_name}/{source}/cea.csv" 44 | DIR_CTA_RES = DIR_ROOT + "/results/{challenge}/{data_name}/{source}/cta.csv" 45 | DIR_CPA_RES = DIR_ROOT + "/results/{challenge}/{data_name}/{source}/cpa.csv" 46 | 47 | 48 | # Request config 49 | LIMIT_TIME_OUT = 259200 # 2h: 7200 1D: 86400 3D:259200 50 | LIMIT_RETRIES = 3 51 | 52 | 53 | @contextmanager 54 | def time_limit(seconds): 55 | def signal_handler(signum, frame): 56 | raise Exception("Timed out!") 57 | 58 | signal.signal(signal.SIGALRM, signal_handler) 59 | signal.alarm(seconds) 60 | try: 61 | yield 62 | finally: 63 | signal.alarm(0) 64 | 65 | 66 | def create_dir(file_dir): 67 | """Create a directory 68 | 69 | Args: 70 | file_dir (str): file directory 71 | """ 72 | folder_dir = os.path.dirname(file_dir) 73 | if not os.path.exists(folder_dir): 74 | os.makedirs(folder_dir) 75 | 76 | 77 | def load_object_csv(file_name, encoding="utf8"): 78 | content = [] 79 | if os.path.exists(file_name): 80 | with open(file_name, "r", encoding=encoding, errors="ignore") as f: 81 | reader = csv.reader(f, delimiter=",") 82 | for r in reader: 83 | row_norm = [] 84 | for c in r: 85 | row_norm.append(c) 86 | content.append(row_norm) 87 | return content 88 | 89 | 90 | def save_object_csv(file_name, rows): 91 | create_dir(file_name) 92 | temp_file = "%s.temp" % file_name 93 | with open(temp_file, "w") as f: 94 | try: 95 | writer = csv.writer(f, delimiter=",", quotechar='"', quoting=csv.QUOTE_ALL) 96 | for r in rows: 97 | if ( 98 | isinstance(r, list) 99 | or isinstance(r, tuple) 100 | or isinstance(r, numpy.ndarray) 101 | ): 102 | writer.writerow(r) 103 | else: 104 | writer.writerow([r]) 105 | except Exception as message: 106 | print(message) 107 | if os.path.exists(file_name): 108 | os.remove(file_name) 109 | os.rename(temp_file, file_name) 110 | 111 | 112 | def get_files_from_dir_subdir(folder_path, extension="*"): 113 | all_files = [] 114 | for root, _, file_dirs in os.walk(folder_path): 115 | for file_dir in fnmatch.filter(file_dirs, "*.%s" % extension): 116 | if ".DS_Store" not in file_dir: 117 | all_files.append(os.path.join(root, file_dir)) 118 | return all_files 119 | 120 | 121 | def get_files_from_dir( 122 | folder_path, extension="*", limit_reader=-1, is_sort=False, reverse=False 123 | ): 124 | all_file_dirs = get_files_from_dir_subdir(folder_path, extension) 125 | 126 | if is_sort: 127 | file_with_size = [(f, os.path.getsize(f)) for f in all_file_dirs] 128 | file_with_size.sort(key=lambda f: f[1], reverse=reverse) 129 | all_file_dirs = [f for f, _ in file_with_size] 130 | if limit_reader < 0: 131 | 132 | limit_reader = len(all_file_dirs) 133 | return all_file_dirs[:limit_reader] 134 | 135 | 136 | def get_encoding(source, method="charamel"): 137 | result = "utf-8" 138 | if os.path.isfile(source): 139 | with open(source, "rb") as file_open: 140 | # Read all content --> make sure about the file encoding 141 | file_content = file_open.read() 142 | 143 | # predict encoding 144 | if method == "charamel": 145 | try: 146 | import charamel 147 | 148 | charamel.Detector() 149 | encoding_detector = charamel.Detector() 150 | detector = encoding_detector.detect(file_content) 151 | if detector: 152 | result = detector.value 153 | except Exception as message: 154 | print(message) 155 | pass 156 | else: 157 | detector = chardet.detect(file_content) 158 | if detector["encoding"]: 159 | result = detector["encoding"] 160 | return result 161 | 162 | 163 | def load_table(dir_table): 164 | def parse_xml_table(source): 165 | tables_xml = pandas.read_html(source) 166 | if tables_xml: 167 | return [tables_xml[0].columns.values.tolist()] + tables_xml[ 168 | 0 169 | ].values.tolist() 170 | else: 171 | return None 172 | 173 | table_obj = None 174 | encoding = get_encoding(dir_table) 175 | file_ext = os.path.splitext(dir_table)[1][1:] 176 | if file_ext == "csv": 177 | table_obj = load_object_csv(dir_table, encoding=encoding) 178 | elif file_ext == "tsv": 179 | table_obj = petl.fromtsv(dir_table, encoding=encoding) 180 | elif file_ext == "txt": 181 | table_obj = petl.fromtext(dir_table, encoding=encoding) 182 | elif file_ext == "xls": 183 | table_obj = petl.fromxls(dir_table, encoding=encoding) 184 | elif file_ext in ["xlsm", "xlsb", "xltx", "xlsx", "xlt", "xltm"]: 185 | table_obj = petl.fromxlsx(dir_table) 186 | elif file_ext == "xml": 187 | table_obj = parse_xml_table(dir_table) 188 | cells = [] 189 | if table_obj: 190 | for row in table_obj: 191 | row_norm = [] 192 | for col in row: 193 | tmp_cell = str(col) 194 | # tmp_cell = ul.norm_text(str(col), punctuations=True, lower=False) 195 | # tmp_date = ul.get_date(tmp_cell) 196 | # if tmp_date: 197 | # tmp_cell = tmp_date 198 | row_norm.append(tmp_cell) 199 | if row_norm: 200 | # row = ftfy.fix_text(row) 201 | cells.append(row_norm) 202 | 203 | return cells 204 | 205 | 206 | TABLE_CATEGORIES = { 207 | "ALL": ([""], []), 208 | "CTRL_WIKI": (["WIKI"], ["NOISE2"]), 209 | "CTRL_DBP": (["CTRL", "DBP"], ["NOISE2"]), 210 | "CTRL_NOISE2": (["CTRL", "NOISE2"], []), 211 | "TOUGH_T2D": (["T2D"], ["NOISE2"]), 212 | "TOUGH_HOMO": (["HOMO"], ["SORTED", "NOISE2"]), 213 | "TOUGH_MISC": (["MISC"], ["NOISE2"]), 214 | "TOUGH_MISSP": (["MISSP"], ["NOISE1", "NOISE2"]), 215 | "TOUGH_SORTED": (["SORTED"], ["NOISE2"]), 216 | "TOUGH_NOISE1": (["NOISE1"], []), 217 | "TOUGH_NOISE2": (["TOUGH", "NOISE2"], []), 218 | } 219 | 220 | 221 | def _is_table_in_cat(x, whitelist, blacklist): 222 | b = True 223 | for i in whitelist: 224 | if not (b and (i in x)): 225 | return False 226 | for e in blacklist: 227 | if not (b and (e not in x)): 228 | return False 229 | return True 230 | 231 | 232 | def precision_score(correct_cells, annotated_cells): 233 | """ 234 | Precision = (# correctly annotated cells) / (# annotated cells) 235 | :param correct_cells: 236 | :param annotated_cells: 237 | :return: 238 | """ 239 | return ( 240 | float(len(correct_cells)) / len(annotated_cells) 241 | if len(annotated_cells) > 0 242 | else 0.0 243 | ) 244 | 245 | 246 | def recall_score(correct_cells, gt_cell_ent): 247 | """ 248 | Recall = (# correctly annotated cells) / (# target cells) 249 | :param correct_cells: 250 | :param gt_cell_ent: 251 | :return: 252 | """ 253 | return float(len(correct_cells)) / len(gt_cell_ent.keys()) 254 | 255 | 256 | def f1_score(precision, recall): 257 | """ 258 | F1 Score = (2 * Precision * Recall) / (Precision + Recall) 259 | :param precision: 260 | :param recall: 261 | :return: 262 | """ 263 | return ( 264 | (2 * precision * recall) / (precision + recall) 265 | if (precision + recall) > 0 266 | else 0.0 267 | ) 268 | 269 | 270 | def _get_radar_plot(scores, title): 271 | categories = list(scores.keys()) 272 | N = len(categories) 273 | angles = [n / float(N) * 2 * pi for n in range(N)] 274 | angles += angles[:1] 275 | 276 | f = plt.figure() 277 | ax = plt.subplot(111, polar=True) 278 | ax.set_theta_offset(pi / 2) 279 | ax.set_theta_direction(-1) 280 | 281 | plt.xticks(angles[:-1], categories) 282 | ax.set_rlabel_position(0) 283 | plt.yticks([0.25, 0.5, 0.75], ["0.25", "0.50", "0.75"], color="grey", size=7) 284 | plt.ylim(0, 1) 285 | 286 | values = list(map(lambda x: x["f1"], scores.values())) 287 | values += values[:1] 288 | ax.plot(angles, values, linewidth=1, linestyle="solid", label="f1") 289 | ax.fill(angles, values, "b", alpha=0.1) 290 | for angle, value in zip(angles, values): 291 | ax.annotate( 292 | round(value, 2), (angle, value), size=8, weight="bold", ha="center", c="b" 293 | ) 294 | 295 | values = list(map(lambda x: x["precision"], scores.values())) 296 | values += values[:1] 297 | ax.plot(angles, values, linewidth=1, linestyle="solid", label="precision") 298 | ax.fill(angles, values, "r", alpha=0.1) 299 | 300 | values = list(map(lambda x: x["recall"], scores.values())) 301 | values += values[:1] 302 | ax.plot(angles, values, linewidth=1, linestyle="solid", label="recall") 303 | ax.fill(angles, values, "g", alpha=0.1) 304 | 305 | plt.legend(loc="upper right", bbox_to_anchor=(0.1, 0.1)) 306 | plt.title(title, size=11, y=1.1) 307 | 308 | return f 309 | 310 | 311 | def _write_df( 312 | df, filename, drop=True, strip=True, index=False, header=True, quoting=csv.QUOTE_ALL 313 | ): 314 | if drop: 315 | df = df.drop_duplicates() 316 | if strip: 317 | df = df.apply(lambda x: x.str.strip() if x.dtype == "object" else x) 318 | df.to_csv(filename, index=index, header=header, quoting=quoting) 319 | 320 | 321 | def score_cea(gs_file, submission_file): 322 | scores = {} 323 | gt = pandas.read_csv( 324 | gs_file, 325 | delimiter=",", 326 | names=["tab_id", "col_id", "row_id", "entity"], 327 | dtype={"tab_id": str, "col_id": str, "row_id": str, "entity": str}, 328 | keep_default_na=False, 329 | ) 330 | sub = pandas.read_csv( 331 | submission_file, 332 | delimiter=",", 333 | names=["tab_id", "col_id", "row_id", "entity"], 334 | dtype={"tab_id": str, "col_id": str, "row_id": str, "entity": str}, 335 | keep_default_na=False, 336 | ) 337 | 338 | gt = gt.to_dict("records") 339 | sub = sub.to_dict("records") 340 | 341 | gt_cell_ent = dict() 342 | gt_cell_ent_orig = dict() 343 | for row in gt: 344 | cell = "%s %s %s" % (row["tab_id"], row["col_id"], row["row_id"]) 345 | gt_cell_ent[cell] = urllib.parse.unquote(row["entity"]).lower().split(" ") 346 | gt_cell_ent_orig[cell] = row["entity"].split(" ") 347 | 348 | gt_cell_ent[cell] = [i.replace(cf.WD, "") for i in gt_cell_ent[cell]] 349 | gt_cell_ent_orig[cell] = [i.replace(cf.WD, "") for i in gt_cell_ent_orig[cell]] 350 | 351 | correct_cells, wrong_cells, annotated_cells = set(), list(), set() 352 | for row in sub: 353 | cell = "%s %s %s" % (row["tab_id"], row["col_id"], row["row_id"]) 354 | if cell in gt_cell_ent: 355 | if cell in annotated_cells: 356 | raise Exception("Duplicate cells in the submission file") 357 | else: 358 | annotated_cells.add(cell) 359 | 360 | annotation = urllib.parse.unquote(row["entity"]).lower() 361 | if annotation in gt_cell_ent[cell]: 362 | correct_cells.add(cell) 363 | else: 364 | wrong_cells.append( 365 | { 366 | "table": row["tab_id"], 367 | "col": int(row["col_id"]), 368 | "row": int(row["row_id"]), 369 | "actual": row["entity"], 370 | "target": " ".join(gt_cell_ent_orig[cell]), 371 | } 372 | ) 373 | 374 | for cat in TABLE_CATEGORIES: 375 | include, exclude = TABLE_CATEGORIES[cat] 376 | c_cells = {x for x in correct_cells if _is_table_in_cat(x, include, exclude)} 377 | a_cells = {x for x in annotated_cells if _is_table_in_cat(x, include, exclude)} 378 | g_cells = dict( 379 | filter( 380 | lambda elem: _is_table_in_cat(elem[0], include, exclude), 381 | gt_cell_ent.items(), 382 | ) 383 | ) 384 | if len(g_cells) > 0: 385 | precision = precision_score(c_cells, a_cells) 386 | recall = recall_score(c_cells, g_cells) 387 | f1 = f1_score(precision, recall) 388 | scores[cat] = { 389 | "precision": precision, 390 | "recall": recall, 391 | "f1": f1, 392 | "correct": len(c_cells), 393 | "gt": len(g_cells), 394 | "submit": len(a_cells), 395 | } 396 | 397 | return scores 398 | 399 | 400 | class MTab(object): 401 | def __init__(self): 402 | self.F_MTAB = f"{DOMAIN}/api/v1.1/mtab" 403 | 404 | self.session = requests.Session() 405 | retries = Retry( 406 | total=LIMIT_RETRIES, 407 | backoff_factor=1, 408 | status_forcelist=[500, 502, 503, 504], 409 | ) 410 | self.session.mount("https://", HTTPAdapter(max_retries=retries)) 411 | self.session.mount("http://", HTTPAdapter(max_retries=retries)) 412 | 413 | def _request(self, func_name, query_args, retries=3, message=""): 414 | responds = defaultdict() 415 | if retries == 0: 416 | print(message) 417 | return responds 418 | try: 419 | # _responds = requests.post(func_name, json=query_args, timeout=self.TIME_OUT) 420 | _responds = self.session.post( 421 | func_name, json=query_args, timeout=LIMIT_TIME_OUT 422 | ) 423 | if _responds.status_code == 200: 424 | responds = _responds.json() 425 | if not responds or ( 426 | responds.get("status") == "Error" and not responds.get("message") 427 | ): 428 | sleep(300) 429 | return self._request( 430 | func_name, 431 | query_args, 432 | retries - 1, 433 | message=f"Error: Retry {retries-1}", 434 | ) 435 | except Exception as message: 436 | if func_name == self.F_MTAB and query_args.get("table_name"): 437 | args_info = func_name + ": " + query_args.get("table_name") 438 | else: 439 | args_info = func_name 440 | sleep(300) 441 | return self._request( 442 | func_name, query_args, retries - 1, message=f"\n{message} - {args_info}" 443 | ) 444 | return responds 445 | 446 | def get_table_annotation(self, args): 447 | try: 448 | with time_limit(LIMIT_TIME_OUT): 449 | responds = self._request(self.F_MTAB, args) 450 | except Exception as message: 451 | print(message) 452 | responds = self.get_table_annotation(args) 453 | return responds 454 | 455 | 456 | def pool_table_annotation(args): 457 | responds = {} 458 | map_row_index = args.pop("map_row_index") 459 | try: 460 | mtab_api = MTab() 461 | responds = mtab_api.get_table_annotation(args) 462 | except Exception as message: 463 | print(message) 464 | responds.update({"status": "Error", "message": message}) 465 | 466 | # overloading - try 10 times, 5s / a sleep 467 | if (not responds or responds["status"] == "Error") and args.get("sleep", 0) < 50: 468 | sleep(5) 469 | args.update({"sleep": args.get("sleep", 0) + 5}) 470 | print(args.get("sleep", 0)) 471 | return pool_table_annotation(args) 472 | 473 | if responds.get("semantic") and responds["semantic"].get("cea"): 474 | responds["semantic"]["cea"] = [ 475 | [map_row_index[r], c, a] for r, c, a in responds["semantic"]["cea"] 476 | ] 477 | return args, responds 478 | 479 | 480 | def load_resources( 481 | challenge="semtab2020", 482 | data_name="2T", 483 | search_mode="a", 484 | table_limit=0, 485 | search_limit=50, 486 | search_expensive=False, 487 | chunk_size=200, 488 | chunk_limit=0, 489 | ): 490 | dir_folder_tables = DIR_TABLES.format(challenge=challenge, data_name=data_name) 491 | 492 | # Load tables 493 | dir_tables = get_files_from_dir(dir_folder_tables, is_sort=True, reverse=True) 494 | 495 | if table_limit: 496 | dir_tables = dir_tables[:table_limit] 497 | 498 | # Matching targets 499 | tar_cea, tar_cta, tar_cpa = defaultdict(list), defaultdict(list), defaultdict(list) 500 | 501 | # Load targets 502 | dir_tar_cea = DIR_CEA_TAR.format(challenge=challenge, data_name=data_name) 503 | dir_tar_cta = DIR_CTA_TAR.format(challenge=challenge, data_name=data_name) 504 | dir_tar_cpa = DIR_CPA_TAR.format(challenge=challenge, data_name=data_name) 505 | # Load target cea 506 | for line in load_object_csv(dir_tar_cea): 507 | table_name, row_i, col_i = line[:3] 508 | tar_cea[table_name].append([row_i, col_i]) 509 | 510 | # Load target cta 511 | for line in load_object_csv(dir_tar_cta): 512 | table_name, col_i = line[:2] 513 | tar_cta[table_name].append(col_i) 514 | 515 | # Load target cpa 516 | for line in load_object_csv(dir_tar_cpa): 517 | table_name, col_i1, col_i2 = line[:3] 518 | tar_cpa[table_name].append([col_i1, col_i2]) 519 | 520 | # Create input args in chunks 521 | args = [] 522 | total_cea = 0 523 | for dir_table in dir_tables: 524 | table_name = os.path.splitext(os.path.basename(dir_table))[0] 525 | table_content = load_object_csv(dir_table) 526 | chunk_tar_cea = tar_cea.get(table_name) 527 | lines = {row_i for row_i, col_i in chunk_tar_cea} 528 | lines = sorted(list(lines), key=lambda x: int(x)) 529 | buff_table = [] 530 | buff_line = set() 531 | buff_line_map = {} 532 | buff_line_map_inverse = {} 533 | count_tar = 0 534 | for line in lines: 535 | line = int(line) 536 | buff_line.add(line) 537 | buff_line_map[line] = len(buff_table) 538 | buff_line_map_inverse[len(buff_table)] = line 539 | buff_table.append(table_content[line]) 540 | if len(buff_line) == chunk_size or line == int(lines[-1]): 541 | chunks_tar_cea_obj = [ 542 | [str(buff_line_map[int(row_i)]), col_i] 543 | for row_i, col_i in chunk_tar_cea 544 | if int(row_i) in buff_line 545 | ] 546 | args_obj = { 547 | "table": buff_table, 548 | "table_name": table_name, 549 | "tar_cea": chunks_tar_cea_obj, 550 | "tar_cta": tar_cta.get(table_name), 551 | "tar_cpa": tar_cpa.get(table_name), 552 | "search_mode": search_mode, 553 | "search_limit": search_limit, 554 | "search_expensive": search_expensive, 555 | "map_row_index": buff_line_map_inverse, 556 | } 557 | count_tar += len(chunks_tar_cea_obj) 558 | args.append(args_obj) 559 | buff_line = set() 560 | buff_table = [] 561 | buff_line_map = {} 562 | buff_line_map_inverse = {} 563 | if count_tar != len(chunk_tar_cea): 564 | print("Missing targets: " + table_name) 565 | total_cea += count_tar 566 | if chunk_limit: 567 | args = args[:chunk_limit] 568 | 569 | total_tables = len(dir_tables) 570 | 571 | return args, total_cea, total_tables 572 | 573 | 574 | def m_call_run_semtab( 575 | challenge="semtab2020", 576 | data_name="2T", 577 | n_thread=1, 578 | search_mode="a", 579 | table_limit=0, 580 | search_limit=50, 581 | search_expensive=False, 582 | chunk_size=200, 583 | chunk_limit=0, 584 | ): 585 | start = time() 586 | args, total_cea, total_tables = load_resources( 587 | challenge, 588 | data_name, 589 | search_mode, 590 | table_limit, 591 | search_limit, 592 | search_expensive, 593 | chunk_size, 594 | chunk_limit, 595 | ) 596 | # Call MTab 597 | res_cea, res_cta, res_cpa = ( 598 | defaultdict(Counter), 599 | defaultdict(Counter), 600 | defaultdict(Counter), 601 | ) 602 | # Save annotation files 603 | domain = "online" 604 | 605 | dir_cea_res = DIR_CEA_RES.format( 606 | challenge=challenge, data_name=data_name, source=domain 607 | ) 608 | dir_cta_res = DIR_CTA_RES.format( 609 | challenge=challenge, data_name=data_name, source=domain 610 | ) 611 | dir_cpa_res = DIR_CPA_RES.format( 612 | challenge=challenge, data_name=data_name, source=domain 613 | ) 614 | 615 | def save_final_result(dir_res_obj, res_obj): 616 | res_cea_final = [] 617 | for key, values in res_obj.items(): 618 | res_cea_final.append(list(key) + [max(values, key=values.get)]) 619 | res_cea_final.sort(key=lambda x: x[0]) 620 | save_object_csv(dir_res_obj, res_cea_final) 621 | return res_cea_final 622 | 623 | p_bar = tqdm(total=total_cea) 624 | processed_tables = set() 625 | with closing(Pool(processes=n_thread)) as p: 626 | for input_args, output_args in p.imap_unordered(pool_table_annotation, args): 627 | processed_tables.add(input_args["table_name"]) 628 | p_bar.update(len(input_args["tar_cea"])) 629 | p_bar.set_description( 630 | desc=f"{len(processed_tables)}/{total_tables}. " 631 | + input_args["table_name"] 632 | ) 633 | if not output_args or output_args["status"] == "Error": 634 | if output_args.get("message"): 635 | print(output_args.get("message")) 636 | else: 637 | print( 638 | "Error: Could not get POST input, please retry again. (The server is overloading now)" 639 | ) 640 | continue 641 | if not output_args.get("semantic"): 642 | continue 643 | if output_args["semantic"].get("cea"): 644 | for r, c, a in output_args["semantic"]["cea"]: 645 | res_cea[(output_args["table_name"], r, c)][a] += len( 646 | input_args["tar_cea"] 647 | ) 648 | 649 | if output_args["semantic"].get("cta"): 650 | for c, a in output_args["semantic"]["cta"]: 651 | res_cta[(output_args["table_name"], c)][a[0]] += len( 652 | input_args["tar_cea"] 653 | ) 654 | if output_args["semantic"].get("cpa"): 655 | for c1, c2, a in output_args["semantic"]["cpa"]: 656 | res_cpa[(output_args["table_name"], c1, c2)][a[0]] += len( 657 | input_args["tar_cea"] 658 | ) 659 | 660 | save_final_result(dir_cea_res, res_cea) 661 | save_final_result(dir_cta_res, res_cta) 662 | save_final_result(dir_cpa_res, res_cpa) 663 | p_bar.close() 664 | 665 | save_final_result(dir_cea_res, res_cea) 666 | save_final_result(dir_cta_res, res_cta) 667 | save_final_result(dir_cpa_res, res_cpa) 668 | 669 | print(f"Run time: {str(timedelta(seconds=round(time() - start)))}") 670 | 671 | 672 | if __name__ == "__main__": 673 | challenge = "semtab2020" 674 | data_name = "2T" 675 | domain = "online" 676 | 677 | m_call_run_semtab( 678 | challenge=challenge, 679 | data_name=data_name, 680 | n_thread=4, 681 | table_limit=0, 682 | search_mode="a", 683 | search_limit=100, 684 | search_expensive=True, 685 | chunk_size=200, 686 | chunk_limit=0, 687 | ) 688 | scores = score_cea( 689 | DIR_CEA_GT.format(challenge=challenge, data_name=data_name), 690 | DIR_CEA_RES.format(challenge=challenge, data_name=data_name, source=domain), 691 | ) 692 | print(json.dumps(scores, indent=4)) 693 | 694 | 695 | """ 696 | 180/180. Z4M8AT89: 100%|██████████████████████████████████████| 667244/667244 [21:53:57<00:00, 8.46it/s] 697 | { 698 | "ALL": { 699 | "precision": 0.8954061559997541, 700 | "recall": 0.8953726073220591, 701 | "f1": 0.8953893813466541, 702 | "correct": 597432, 703 | "gt": 667244, 704 | "submit": 667219 705 | } 706 | } 707 | """ 708 | -------------------------------------------------------------------------------- /static/images/MTabESSemTab2T.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/MTabESSemTab2T.png -------------------------------------------------------------------------------- /static/images/MTabESSemTabR1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/MTabESSemTabR1.png -------------------------------------------------------------------------------- /static/images/MTabESSemTabR2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/MTabESSemTabR2.png -------------------------------------------------------------------------------- /static/images/MTabESSemTabR3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/MTabESSemTabR3.png -------------------------------------------------------------------------------- /static/images/MTabESSemTabR4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/MTabESSemTabR4.png -------------------------------------------------------------------------------- /static/images/logo_mtab_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/logo_mtab_1.png -------------------------------------------------------------------------------- /static/images/logo_mtab_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/logo_mtab_2.png -------------------------------------------------------------------------------- /static/images/logo_mtab_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/logo_mtab_3.png -------------------------------------------------------------------------------- /static/images/logo_mtab_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/logo_mtab_4.png -------------------------------------------------------------------------------- /static/images/mtab_pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/mtab_pic.png -------------------------------------------------------------------------------- /static/images/semtab2019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/semtab2019.png -------------------------------------------------------------------------------- /static/images/semtab2020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/semtab2020.png -------------------------------------------------------------------------------- /static/images/semtab2021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/images/semtab2021.png -------------------------------------------------------------------------------- /static/others/0AJSJYAL.xltx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/others/0AJSJYAL.xltx -------------------------------------------------------------------------------- /static/others/mytables.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/others/mytables.zip -------------------------------------------------------------------------------- /static/others/mytables_ntar.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phucty/mtab_tool/c4642017d6c8b23453d7695c162fb5711b87a683/static/others/mytables_ntar.zip -------------------------------------------------------------------------------- /static/others/semtab2021/biotable/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/others/semtab2021/hardtable/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------