2013-02-22 60 views
7

我有一個巨大的字典結構像這樣的:簡單工具/庫形象化巨大的蟒蛇字典

my_data = { 
    'key1': { 
     '_': 'value1': 'aaa' 
    }, 
    'key2': { 
     '_': 'value2': 'bbb', 
     'key2.1': { 
      '_': 'ccc', 
      'key2.1.1': { 
       '_': 'ddd' 
      } 
     } 
     'key2.2': { 
      '_': 'eee', 
      'key2.2.1': { 
       '_': 'fff' 
      } 
      'key2.2.2': { 
       '_': 'ggg' 
      }    
     } 
    } 
} 

等。

我想它是一種樹表示的顯示給用戶,使用GTK,TK或任何東西能夠瀏覽它摺疊和展開的分支,可能搜索鍵和值。

可能我不需要用手開發這樣的工具,並且已經有東西可以將這類數據直觀地展現出來了嗎?

+4

如果你的字典只包含簡單的類型,它可能會更容易將其編碼爲JSON,並找到一個JSON觀衆。 – 2013-02-22 12:03:59

+0

@PavelAnossov同意。這是解決問題的可能方法。 – lig 2013-02-22 15:00:42

回答

6

我終於結束了我轉換成數據作爲json建議@PavelAnossov使用d3 Tree Layout

enter image description here

+0

你是否符合你所包含的d3鏈接中顯示的「name」「children」json格式?如果是這樣,你能分享更多的完整解決方案嗎?我很難將類似的字典結構轉換爲json格式。 – chisaipete 2013-04-24 16:51:53

+0

那是我的同事在工作中產生的一堆醜陋的硬編碼。我不認爲我能夠(並且不想)在任何地方共享這一專有代碼。 – lig 2013-04-25 17:54:13

+0

我完全理解!感謝您的答覆 - 我希望有人解決了這個問題:) – chisaipete 2013-04-25 22:08:21

6

我不知道一個隨時可以使用的工具,但你可以使用Traits UI迅速發展自己的

from enthought.traits.api \ 
    import HasTraits, Instance 

from enthought.traits.ui.api \ 
    import View, VGroup, Item, ValueEditor 

class DictEditor(HasTraits): 
    Object = Instance(object) 

    def __init__(self, obj, **traits): 
     super(DictEditor, self).__init__(**traits) 
     self.Object = obj 

    def trait_view(self, name=None, view_elements=None): 
     return View(
      VGroup(
      Item('Object', 
        label  = 'Debug', 
        id   = 'debug', 
        editor  = ValueEditor(), 
        style  = 'custom', 
        dock  = 'horizontal', 
        show_label = False 
      ), 
     ), 
      title  = 'Dictionary Editor', 
      width  = 800, 
      height = 600, 
      resizable = True, 
     ) 


def build_sample_data(): 
    my_data = dict(zip(range(10),range(10,20))) 
    my_data[11] = dict(zip(range(10),range(10,20))) 
    my_data[11][11] = dict(zip(range(10),range(10,20))) 
    return my_data 

# Test 
if __name__ == '__main__': 
    my_data = build_sample_data() 
    b = DictEditor(my_data) 
    b.configure_traits() 

就是這樣。你必須像一個GUI:

性狀UI使用模型 - 視圖 - 控制器的方法,而不必需要以編程方式創建的每個窗口小部件創建GUI。在這裏,我使用預定義的ValueEditor來顯示任意類型。現在你可以擴展它以支持搜索,過濾等... enter image description here

編輯

,易擴充,支持過濾:

# -*- coding: utf-8 -*- 
""" 
Created on Fri Feb 22 12:52:28 2013 

@author: kranzth 
""" 
from enthought.traits.api \ 
    import HasTraits, Instance, Str, on_trait_change 

from enthought.traits.ui.api \ 
    import View, VGroup, Item, ValueEditor, TextEditor 

from copy import deepcopy 

class DictEditor(HasTraits): 
    SearchTerm = Str() 
    Object = Instance(object) 

    def __init__(self, obj, **traits): 
     super(DictEditor, self).__init__(**traits) 
     self._original_object = obj 
     self.Object = self._filter(obj) 

    def trait_view(self, name=None, view_elements=None): 
     return View(
      VGroup(
      Item('SearchTerm', 
        label  = 'Search:', 
        id   = 'search', 
        editor  = TextEditor(), 
        #style  = 'custom', 
        dock  = 'horizontal', 
        show_label = True 
      ), 
      Item('Object', 
        label  = 'Debug', 
        id   = 'debug', 
        editor  = ValueEditor(), 
        style  = 'custom', 
        dock  = 'horizontal', 
        show_label = False 
      ), 
     ), 
      title  = 'Dictionary Editor', 
      width  = 800, 
      height = 600, 
      resizable = True, 
     ) 

    @on_trait_change("SearchTerm") 
    def search(self): 
     self.Object = self._filter(self._original_object, self.SearchTerm) 

    def _filter(self, object_, search_term=None): 
     def has_matching_leaf(obj): 
      if isinstance(obj, list): 
       return any(
         map(has_matching_leaf, obj)) 
      if isinstance(obj, dict): 
       return any(
         map(has_matching_leaf, obj.values())) 
      else: 
       try: 
        if not str(obj) == search_term: 
         return False 
        return True 
       except ValueError: 
        False 

     obj = deepcopy(object_) 
     if search_term is None: 
      return obj 

     if isinstance(obj, dict): 
      for k in obj.keys(): 
       if not has_matching_leaf(obj[k]): 
        del obj[k] 

      for k in obj.keys(): 
       if isinstance(obj, dict): 
        obj[k] = self._filter(obj[k], search_term) 
       elif isinstance(obj, list): 
        filter(has_matching_leaf,obj[k]) 

     return obj 



def build_sample_data(): 
    def make_one_level_dict(): 
     return dict(zip(range(100), 
         range(100,150) + map(str,range(150,200)))) 

    my_data = make_one_level_dict() 
    my_data[11] = make_one_level_dict() 
    my_data[11][11] = make_one_level_dict() 
    return my_data 

# Test 
if __name__ == '__main__': 
    my_data = build_sample_data() 
    b = DictEditor(my_data) 
    b.configure_traits() 

會給你一個文本框「濾波器原樣你型」。搜索並不適用於所有情況下完全正確的,但你可以計算出的主意。

請注意,在本示例中,dict中的數據部分是整數,部分是字符串,並且會找到這兩種類型。

enter image description here

+0

不錯的一個。會給它一個嘗試 – lig 2013-02-22 15:01:20

+0

對不起。不能將此標記爲簡單。半小時後,我仍然從安裝的模塊中獲得'NotImplemented'錯誤。 PyPi也不是官方的github版本。 「enthought.traits.ui」程序包很有可能工作,但我無法使其工作。 – lig 2013-02-22 15:34:27

+0

你在哪個操作系統上?在Linux上安裝很簡單,在Windows上我推薦Python(x,y) – 2013-02-23 07:49:41

1

如果您使用的是IDE設置斷點字典初始化後,有你想探索隨後在調試模式下運行的數據。應該有在調試模式下的「變量」視圖,您可以展開和摺疊字典,你提到的。

+0

它意味着應用程序用戶:) – lig 2015-06-19 11:32:32

1

只是補充@ Thorsten的答案。因爲很久以前traits已經重構了包。運行托爾斯滕代碼正確的方法是:

  1. 安裝特性模塊:sudo apt-get install python-traitsui
  2. 變化的模塊導入線在他的代碼:

    from traits.api \ 
    import HasTraits, Instance, Str, on_trait_change 
    
    from traitsui.api \ 
    import View, VGroup, Item, ValueEditor, TextEditor 
    
+0

有沒有一種方法來使用pip安裝它?因爲我暫時不使用Ubuntu。我希望能夠將它安裝在Fedora和Windows上。 – lig 2015-07-28 19:12:25

+1

我想你可以使用「pip install tr​​aitsui」,因爲它是在pypi網站上註冊的:https://pypi.python.org/pypi/traitsui – czxttkl 2015-07-28 19:56:47

+0

只是讓大家知道,這仍然在2018年工作。我安裝pyqt4從Christoph Gohlke的頁面和「pip install tr​​aitsui」。然後這些MOD對Thorsten的答案很好。 – 2018-02-26 03:07:10

2

這個簡單的函數打印一本字典以表格形式。它也可以處理嵌套字典。

def visualise_dict(d,lvl=0): 

    # go through the dictionary alphabetically 
    for k in sorted(d): 

     # print the table header if we're at the beginning 
     if lvl == 0 and k == sorted(d)[0]: 
      print('{:<25} {:<15} {:<10}'.format('KEY','LEVEL','TYPE')) 
      print('-'*79) 

     indent = ' '*lvl # indent the table to visualise hierarchy 
     t = str(type(d[k])) 

     # print details of each entry 
     print("{:<25} {:<15} {:<10}".format(indent+str(k),lvl,t)) 

     # if the entry is a dictionary 
     if type(d[k])==dict: 
      # visualise THAT dictionary with +1 indent 
      visualise_dict(d[k],lvl+1) 

與樣品詞典:

d = {} 
d.update({1:{},2:{}}) 
d[1]['foo'] = {} 
d[1]['foo']['bar'] = 1 
d[2]['bar'] = 5.2 

visualise_dict(d) 

回報

In [1]: visualise_dict(d) 
KEY      LEVEL   TYPE  
------------------------------------------------------------------------------- 
1       0    <class 'dict'> 
    foo      1    <class 'dict'> 
    bar     2    <class 'int'> 
2       0    <class 'dict'> 
    bar      1    <class 'float'> 
0

如果您使用的瀏覽器與JSONViewer擴展,這可能爲你工作:

import json 
import tempfile 
import os 
import subprocess 
def view_obj(obj): 
    (f, filepath)= tempfile.mkstemp() 
    os.close(f) 
    with open(filepath, 'w') as f: 
    json.dump(obj, f) 
    subprocess.call(["google-chrome", filepath]) 

view_obj({'key':'value'}) # Opens Chrome and renders JSON nicely 
2

有已經有一些很好的答案了在這裏,但我相信這個符合「簡單」(它只使用python bult-in庫tkinter和uuid)。

它是基於約翰·蓋恩斯小的在another question回答,威爾潔具修改以支持名單,由我修改,也支持元組(Python的3運行)。

我也對其進行了重組,以便您可以使用簡單的tk_tree_view(data)這樣簡單的方式調用查看器,傳遞字典(如末尾的示例中所示)。

import uuid 
import tkinter as tk 
from tkinter import ttk 


def j_tree(tree, parent, dic): 
    for key in sorted(dic.keys()): 
     uid = uuid.uuid4() 
     if isinstance(dic[key], dict): 
      tree.insert(parent, 'end', uid, text=key) 
      j_tree(tree, uid, dic[key]) 
     elif isinstance(dic[key], tuple): 
      tree.insert(parent, 'end', uid, text=str(key) + '()') 
      j_tree(tree, uid, 
        dict([(i, x) for i, x in enumerate(dic[key])])) 
     elif isinstance(dic[key], list): 
      tree.insert(parent, 'end', uid, text=str(key) + '[]') 
      j_tree(tree, uid, 
        dict([(i, x) for i, x in enumerate(dic[key])])) 
     else: 
      value = dic[key] 
      if isinstance(value, str): 
       value = value.replace(' ', '_') 
      tree.insert(parent, 'end', uid, text=key, value=value) 


def tk_tree_view(data): 
    # Setup the root UI 
    root = tk.Tk() 
    root.title("tk_tree_view") 
    root.columnconfigure(0, weight=1) 
    root.rowconfigure(0, weight=1) 

    # Setup the Frames 
    tree_frame = ttk.Frame(root, padding="3") 
    tree_frame.grid(row=0, column=0, sticky=tk.NSEW) 

    # Setup the Tree 
    tree = ttk.Treeview(tree_frame, columns=('Values')) 
    tree.column('Values', width=100, anchor='center') 
    tree.heading('Values', text='Values') 
    j_tree(tree, '', data) 
    tree.pack(fill=tk.BOTH, expand=1) 

    # Limit windows minimum dimensions 
    root.update_idletasks() 
    root.minsize(root.winfo_reqwidth(), root.winfo_reqheight()) 
    root.mainloop() 


if __name__ == "__main__": 
    # Setup some test data 
    data = { 
     "firstName": "John", 
     "lastName": "Smith", 
     "gender": "male", 
     "age": 32, 
     "address": { 
      "streetAddress": "21 2nd Street", 
      "city": "New York", 
      "state": "NY", 
      "postalCode": "10021"}, 
     "phoneNumbers": [ 
      {"type": "home", "number": "212 555-1234"}, 
      {"type": "fax", 
      "number": "646 555-4567", 
      "alphabet": [ 
       "abc", 
       "def", 
       "ghi"] 
      } 
     ]} 

    # call it with 
    tk_tree_view(data) 

它看起來像這樣:

enter image description here

+0

這也很奇妙(2018年)。一流的解決方案。 – 2018-02-26 03:11:22

+0

如果你想保留鍵的順序(如果你使用的是一個ordereddict),把這個'in sort(dic.keys())'中的鍵改成'for for key for dic.keys()' – 2018-02-26 18:56:35