2013-02-22 61 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