翻译自http://www.pytables.org/usersguide/tutorials.html

多维表单元格和自动健全性检查

现在是一个更真实的例子(即代码中有错误)的时候了。我们将创建两个直接从根节点分支的组,Particles和Events。然后,我们将在每个组中创建三个表。在Particle中,我们将根据Particle 类创建表,在Events中根据Event类创建表。

之后,我们将为这些表提供许多记录。最后,我们将读取新创建的表 /Events/TEvent3 ,并利用复杂列表的方法从中选择一些值。

查看下一个脚本(您可以在examples/tutorial2.py 中找到它)。它似乎可以完成上述所有操作,但它包含一些bugs。请注意,此 Particle 类与上一教程中定义的类没有直接关系;这个类更简单(请注意,多维列名为pressure和temperature)。

我们还引入了一种新方式来将 Table 描述为结构化的 NumPy dtype(甚至是字典),如您在Event的描述符所见。有关可以传递给此方法的不同类型的描述符对象,请参阅 File.create_table()

import tables as tb
import numpy as np # Describe a particle record
class Particle(tb.IsDescription):
name = tb.StringCol(itemsize=16) # 16-character string
lati = tb.Int32Col() # integer
longi = tb.Int32Col() # integer
pressure = tb.Float32Col(shape=(2,3)) # array of floats (single-precision)
temperature = tb.Float64Col(shape=(2,3)) # array of doubles (double-precision) # Native NumPy dtype instances are also accepted
Event = np.dtype([
("name" , "S16"),
("TDCcount" , np.uint8),
("ADCcount" , np.uint16),
("xcoord" , np.float32),
("ycoord" , np.float32)
]) # And dictionaries too (this defines the same structure as above)
# Event = {
# "name" : tb.StringCol(itemsize=16),
# "TDCcount" : tb.UInt8Col(),
# "ADCcount" : tb.UInt16Col(),
# "xcoord" : tb.Float32Col(),
# "ycoord" : tb.Float32Col(),
# } # Open a file in "w"rite mode
fileh = tb.open_file("tutorial2.h5", mode="w") # Get the HDF5 root group
root = fileh.root # Create the groups:
for groupname in ("Particles", "Events"):
group = fileh.create_group(root, groupname) # Now, create and fill the tables in Particles group
gparticles = root.Particles # Create 3 new tables
for tablename in ("TParticle1", "TParticle2", "TParticle3"):
# Create a table
table = fileh.create_table("/Particles", tablename, Particle, "Particles: "+tablename) # Get the record object associated with the table:
particle = table.row # Fill the table with 257 particles
for i in range(257):
# First, assign the values to the Particle record
particle['name'] = f'Particle: {i:6d}'
particle['lati'] = i
particle['longi'] = 10 - i ########### Detectable errors start here. Play with them!
particle['pressure'] = np.array(i * np.arange(2 * 3)).reshape((2, 4)) # Incorrect
#particle['pressure'] = np.array(i * np.arange(2 * 3)).reshape((2, 3)) # Correct
########### End of errors particle['temperature'] = i ** 2 # Broadcasting # This injects the Record values
particle.append() # Flush the table buffers
table.flush() # Now, go for Events:
for tablename in ("TEvent1", "TEvent2", "TEvent3"):
# Create a table in Events group
table = fileh.create_table(root.Events, tablename, Event, "Events: "+tablename) # Get the record object associated with the table:
event = table.row # Fill the table with 257 events
for i in range(257):
# First, assign the values to the Event record
event['name'] = f'Event: {i:6d}'
event['TDCcount'] = i % (1<<8) # Correct range ########### Detectable errors start here. Play with them!
event['xcoor'] = float(i ** 2) # Wrong spelling
#event['xcoord'] = float(i ** 2) # Correct spelling
event['ADCcount'] = "sss" # Wrong type
#event['ADCcount'] = i * 2 # Correct type
########### End of errors event['ycoord'] = float(i) ** 4 # This injects the Record values
event.append() # Flush the buffers
table.flush() # Read the records from table "/Events/TEvent3" and select some
table = root.Events.TEvent3
e = [ p['TDCcount'] for p in table if p['ADCcount'] < 20 and 4 <= p['TDCcount'] < 15 ]
print(f"Last record ==> {p}")
print("Selected values ==> {e}")
print("Total selected records ==> {len(e)}") # Finally, close the file (this also will flush all the remaining buffers!)
fileh.close()

1. 形状检查

如果您仔细查看代码,您会发现它不起作用。将返回以下错误:

$ python3 tutorial2.py
Traceback (most recent call last):
File "tutorial2.py", line 60, in <module>
particle['pressure'] = array(i * arange(2 * 3)).reshape((2, 4)) # Incorrect
ValueError: total size of new array must be unchanged
Closing remaining open files: tutorial2.h5... done

此错误表明您正尝试将形状不兼容的数组分配给表格单元格。查看源代码,我们看到我们试图将形状 (2,4) 的数组分配给pressure元素,而该元素定义的形状是 (2,3)。

通常,这些类型的操作是被禁止的,只有一个例外:当您将标量值分配给多维列单元格时,所有单元格元素都填充有标量值。例如:

particle['temperature'] = i ** 2    # Broadcasting

值 i**2 分配给温度表单元格的所有元素。此功能由 NumPy 包提供,称为广播

2. 字段名检查

修复上一个错误并重新运行程序后,我们又遇到了另一个错误。

$ python3 tutorial2.py
Traceback (most recent call last):
File "tutorial2.py", line 73, in ?
event['xcoor'] = float(i ** 2) # Wrong spelling
File "tableextension.pyx", line 1094, in tableextension.Row.__setitem__
File "tableextension.pyx", line 127, in tableextension.get_nested_field_cache
File "utilsextension.pyx", line 331, in utilsextension.get_nested_field
KeyError: 'no such column: xcoor'

此错误表明我们正在尝试为Event表对象中不存在的字段赋值。通过仔细查看 Event 类属性,我们发现我们拼错了 xcoord 字段(我们改写了 xcoor)。这对于 Python 来说是不寻常的行为,因为通常当您为不存在的实例变量赋值时,Python 会创建一个具有该名称的新变量。在处理包含固定字段名称列表的对象时,这样的功能可能很危险。 PyTables 检查该字段是否存在并在检查失败时引发 KeyError。

3. 数据类型检查

最后,我们将在这里找到的最后一个问题是 TypeError 异常。

$ python3 tutorial2.py
Traceback (most recent call last):
File "tutorial2.py", line 75, in ?
event['ADCcount'] = "sss" # Wrong type
File "tableextension.pyx", line 1111, in tableextension.Row.__setitem__
TypeError: invalid type (<type 'str'>) for column ``ADCcount``

而且,如果我们将受影响的行更改为:

event.ADCcount = i * 2        # Correct type

我们将看到脚本顺利结束。

您可以在Figure 4 中看到使用此(更正的)脚本创建的结构。特别要注意表 /Particles/TParticle2 中的多维列单元格。

图 4. 教程 2 的表层次结构。

使用链接更方便地访问节点

链接是特殊节点,可用于创建到现有节点的额外路径。 PyTables 支持三种链接:硬链接、软链接(又名符号链接)和外部链接。

硬链接让用户创建额外的路径来访问同一文件中的另一个节点,一旦创建,它们就与引用的节点对象没有区别,只是它们在对象树中具有不同的路径。例如,如果引用的节点是一个 Table 对象,那么新的硬链接本身将成为一个 Table 对象。从这一点开始,您将能够从两个不同的路径访问同一个 Table 对象:原始路径和新的硬链接路径。如果您删除表的一条路径,您将能够通过另一条路径到达它。

软链接类似于硬链接,但它们保持自己的个性。当您创建到另一个节点的软链接时,您将获得一个指向该节点的新 SoftLink 对象。但是,为了访问指向的节点,您需要对它dereference(间接引用) 。

最后,外部链接就像软链接,不同之处在于它们指向外部文件中的节点,而不是同一文件中的节点。它们由 ExternalLink 类表示,并且与软链接一样,您需要dereference 它们才能访问指向的节点。

交互式的例子

现在我们将学习如何处理链接。您可以在examples/links.py中找到本节中使用的代码。

首先,让我们创建一个具有一些组结构的文件:

>>> import tables as tb
>>> f1 = tb.open_file('links1.h5', 'w')
>>> g1 = f1.create_group('/', 'g1')
>>> g2 = f1.create_group(g1, 'g2')

现在,我们将在 /g1 和 /g1/g2 组上放置一些数据集:

>>> a1 = f1.create_carray(g1, 'a1', tb.Int64Atom(), shape=(10000,))
>>> t1 = f1.create_table(g2, 't1', {'f1': tb.IntCol(), 'f2': tb.FloatCol()})

现在,我们可以开始嗨了。我们将创建一个新组,比如 /gl,我们将在其中放置我们的链接并开始创建一个硬链接:

>>> gl = f1.create_group('/', 'gl')
>>> ht = f1.create_hard_link(gl, 'ht', '/g1/g2/t1') # ht points to t1
>>> print(f"``{ht}`` is a hard link to: ``{t1}``")
``/gl/ht (Table(0,)) `` is a hard link to: ``/g1/g2/t1 (Table(0,)) ``

您可以看到我们如何在 /gl/ht 中创建指向 /g1/g2/t1 中现有表的硬链接。看看硬链接是如何表示的;它看起来像一个表,实际上,它是一个真正的。我们有两种不同的路径来访问该表,原始的 /g1/g2/t1 和新的 /gl/ht。

如果我们删除原始路径,我们仍然可以使用新路径到达表:

>>> t1.remove()
>>> print(f"table continues to be accessible in: ``{f1.get_node('/gl/ht')}``")
table continues to be accessible in: ``/gl/ht (Table(0,)) ``

到现在为止还挺好。现在,让我们创建几个软链接:

>>> la1 = f1.create_soft_link(gl, 'la1', '/g1/a1')  # la1 points to a1
>>> print(f"``{la1}`` is a soft link to: ``{la1.target}``")
``/gl/la1 (SoftLink) -> /g1/a1`` is a soft link to: ``/g1/a1``
>>> lt = f1.create_soft_link(gl, 'lt', '/g1/g2/t1') # lt points to t1
>>> print(f"``{lt}`` is a soft link to: ``{lt.target}``")
``/gl/lt (SoftLink) -> /g1/g2/t1 (dangling)`` is a soft link to: ``/g1/g2/t1``

好的,我们看到第一个链接 /gl/la1 指向数组 /g1/a1。请注意链接的是SoftLink,以及引用节点如何存储在目标实例属性中。

指向 /g1/g2/t1 的第二个链接 (/gt/lt) 也已成功创建,但检查它的字符串后,我们发现它被标记为(dangling)’。为什么是这样?因为我们最近删除了访问表 t1 的 /g1/g2/t1 路径。当打印它时,对象知道它指向nowhere并报告这一点。这是快速了解软链接是否指向现有节点的好方法。

因此,让我们重新创建已删除的 t1 表路径:

>>> t1 = f1.create_hard_link('/g1/g2', 't1', '/gl/ht')
>>> print(f"``{lt}`` is not dangling anymore")
``/gl/lt (SoftLink) -> /g1/g2/t1`` is not dangling anymore

软链接现在指向现有节点了。

当然,要使软链接服务于任何实际目的,我们需要一种获取指向节点的方法。碰巧软链接是可调用的,这就是获取被引用节点的方法:

>>> plt = lt()
>>> print(f"dereferred lt node: ``{plt}``")
dereferred lt node: ``/g1/g2/t1 (Table(0,)) ``
>>> pla1 = la1()
>>> print(f"dereferred la1 node: ``{pla1}``")
dereferred la1 node: ``/g1/a1 (CArray(10000,)) ``

现在, plt 是对 t1 表的 Python 引用,而 pla1 是指 a1 数组。容易吧?

现在让我们假设 a1 是一个数组,其访问速度对我们的应用程序至关重要。一种可能的解决方案是将整个文件移动到速度更快的磁盘中,例如固态磁盘,以便可以大大减少访问延迟。然而,碰巧我们的文件太大而无法放入我们新买的(尽管容量很小)SSD 磁盘。一种解决方案是仅将 a1 数组复制到适合我们的 SSD 磁盘的单独文件中。但是,我们的应用程序将能够处理两个文件而不是一个文件,这显着增加了复杂性,这不是一件好事。

解决办法就是外部链接!正如我们已经说过的,外部链接类似于软链接,但它们旨在链接外部文件中的对象。回到我们的问题,让我们将 a1 数组复制到另一个文件中:

>>> f2 = tb.open_file('links2.h5', 'w')
>>> new_a1 = a1.copy(f2.root, 'a1')
>>> f2.close() # close the other file

现在,我们可以删除现有的软链接并在其位置创建外部链接:

>>> la1.remove()
>>> la1 = f1.create_external_link(gl, 'la1', 'links2.h5:/a1')
>>> print(f"``{la1}`` is an external link to: ``{la1.target}``")
``/gl/la1 (ExternalLink) -> links2.h5:/a1`` is an external link to: ``links2.h5:/a1``

让我们尝试dereferring它:

>>> new_a1 = la1()  # dereferrencing la1 returns a1 in links2.h5
>>> print(f"dereferred la1 node: ``{new_a1}``")
dereferred la1 node: ``/a1 (CArray(10000,)) ``

好吧,看来我们可以访问外部节点了。但只是为了确保节点在另一个文件中:

>>> print("new_a1 file:", new_a1._v_file.filename)
new_a1 file: links2.h5

好的,节点肯定在外部文件中。因此,您不必担心您的应用程序:无论链接是内部(软)还是外部链接,它的工作方式都完全相同。

最后,这里是最终文件中对象的转储,只是为了更好地了解我们的结尾:

>>> f1.close()
>>> exit()
$ ptdump links1.h5
/ (RootGroup) ''
/g1 (Group) ''
/g1/a1 (CArray(10000,)) ''
/gl (Group) ''
/gl/ht (Table(0,)) ''
/gl/la1 (ExternalLink) -> links2.h5:/a1
/gl/lt (SoftLink) -> /g1/g2/t1
/g1/g2 (Group) ''
/g1/g2/t1 (Table(0,)) ''

本教程到此结束。我希望它可以帮助您了解链接的有用性。我相信您会找到其他方式来使用更适合您自己需求的链接。

PyTables 教程(二)多维表单元格和自动健全性检查,使用链接更方便地访问节点的更多相关文章

  1. 在Excel工作表单元格中引用当前工作表名称

    在Excel工作表单元格中引用当前工作表名称 有多份Excel表格表头标题都为"××学校第1次拉练考试××班成绩表",由于工作表结构都是一样的,所以我每次都是复制工作表然后编辑修改 ...

  2. GZFramwork数据库层《二》单据表增删改查(自动生成单据号码)

    运行效果: 使用代码生成器(GZCodeGenerate)生成tb_EmpLeave的Model 生成器源代码下载地址: https://github.com/GarsonZhang/GZCodeGe ...

  3. eas之编辑表单元格

    --指定表列行单元不可编辑 // 锁定表格.行.列.单元 table.getStyleAttributes().getProtection().setLocked(true); row.getStyl ...

  4. JQgrid实现全表单元格编辑

    1 jQuery("#baseWageDataValueGrid").jqGrid('setGridParam',{'cellEdit':true}); 2 3 //修改所有td ...

  5. Swift - 实现点击UITableView单元格时自动展开单元格

    下面是一个列表单元格cell的折叠展开效果的demo.当点击单元格时会展开该单元格,便于显示一些详情什么的.点击其他单元格原来的会关闭,同时有动画效果. 效果如如下:   代码如下: 1 2 3 4 ...

  6. 实操记录之-----Ant Design of Vue 增强版动态合并单元格,自动根据数据进行合并,可自定义横纵向合并

    前几天搞了个简易版的动态合并单元格 但是需求有变化,就只能稍微改改了~~ 欢迎路过的各位大佬指出我代码的问题~~~~ 另: 代码执行效率不是很高,如果需要大量渲染更多数据建议可以直接使用原生 < ...

  7. DataGridView单元格内容自动匹配下拉显示

    页面显示数据使用的控件是ComponentFactory.Krypton.Toolkit中的KryptonDataGridView控件.在指定“商品”单元格中需要根据用户输入内容自动匹配数据库中商品信 ...

  8. [EXCEL] 在单元格中自动输入时间和日期

    选中需输入的单元格,直接按下“Ctrl+:”组合键可输入当前日期:如果直接按下“Ctrl+Shift+:”组合键即可输入当前时间:当然也可以在单元格中先输入其他文字然后再按以上组合键,如先输入“当前时 ...

  9. Jquery实现双击表单元格可编辑

    <script type="text/javascript"> function doTableTdEditClick(param){ doTdEditable(par ...

  10. jqgrid 不能选中行, 每次点击单元格都自动选中第一行

    最使用jqgrid表格插件写了一个功能.功能完成后显示一切正常,但是经过测试后发现,每次点击数据行时,都会自动选中第一行,无法选中其他数据行.经过一番探索,最终发现是加载进来的字段没有主键导致了这个问 ...

随机推荐

  1. python3.9不支持win7

    安装:Anaconda3-2022.10-Windows-x86_64.exe 会报错:Failed to create Anaconda menus 详细信息:Error loading Pytho ...

  2. 浏览器tab标签切换触发监听事件visibilitychange

    document.addEventListener('visibilitychange', function() { if(document.hidden){ //当页面切换或隐藏时触发的代码,可以用 ...

  3. [Unity]关于Unity中的触摸类Input.Touch以及简单的虚拟摇杆实现

    InputTouch 使用Unity开发的游戏大多是移动端游戏,而一些移动端游戏完全使用触摸操作而不是点击Button Unity使用Input.Touch来管理触摸操作 Input.TouchCou ...

  4. 别再写一堆的 for 循环了!Java 8 中的 Stream 轻松遍历树形结构,是真的牛逼

    实体类:Menu.java /** * Menu * * @author lcry */ @Data @Builder public class Menu { /** * id */ public I ...

  5. docker下载java镜像,执行xxx.jar文件

    docker pull java:8u111

  6. 关于精准UWB人员定位系统解决方案

    WB技术, 目前主要应用在室内定位.人员定位系统等定位领域.近年来被应用在无线定位和雷达测距应用中,因此作为民用雷达和民用测距取得了较快的发展.而今天,我们主要要来介绍的产品就是UWB技术的芯片DW1 ...

  7. spider_爬取斗图啦所有表情包(图片保存)

    """爬取斗图吧里面的所有表情包知识点总结: 一.使用requests库进行爬取,随机请求头(网站反爬措施少.挂个请求头足矣) 二.具体思路: 1.先爬取所有的图片url ...

  8. java.net.ConnectException: Your endpoint configuration is wrong; For more details see: http://wiki.apache.org/hadoop/UnsetHostnameOrPort

    今天使用在hive中建表,并在hive中将查询到的语句插入到新表中时,一直开在如图所示位置不动 等待了20多分钟,然后报了这么个错 java.net.ConnectException: Your en ...

  9. Python3.6多线程爬虫

    Python版本 3.6 简单写一个爬虫,在写的过程熟悉Python语法,不得不说Python用起来真666; 代码功能是访问网站首页将所有a标签值作为文件夹,将当前网页所有图片下载对应文件夹中;其实 ...

  10. wireguard 在openwrt中的配置

    按照网上教程正常配置,防火墙通信规则中,选择打开监听端口,目标设备:设备(输入),目标端口:监听端口. 客户端设置:注意路由器的IP地址(段)要填0.0.0.0/0.