obspy中文教程(八)
- Handling custom defined tags in QuakeML and the ObsPy Catalog/Event framework (在QuakeML和ObsPy的目录/事件框架中处理自定义标记)
除了QuakeML标准定义的“usual”信息之外,QuakeML还允许使用自定义元素。它允许:
- a自定义命名空间属性到QuakeML命名空间标记
- b自定义命名空间子标签到QuakeML命名空间元素
ObsPy可以在输入/输出QuakeML的过程中处理事件类型对象中的基本自定义标记和自定义属性。
以下基本示例说明如何使用自定义xml标记/属性输出有效的QuakeML文件:
from obspy import Catalog, UTCDateTime extra = {'my_tag': {'value': True, 'namespace': 'http://some-page.de/xmlns/1.0', 'attrib': {'{http://some-page.de/xmlns/1.0}my_attrib1': '123.4', '{http://some-page.de/xmlns/1.0}my_attrib2': '567'}}, 'my_tag_2': {'value': u'True', 'namespace': 'http://some-page.de/xmlns/1.0'}, 'my_tag_3': {'value': 1, 'namespace': 'http://some-page.de/xmlns/1.0'}, 'my_tag_4': {'value': UTCDateTime('2013-01-02T13:12:14.600000Z'), 'namespace': 'http://test.org/xmlns/0.1'}, 'my_attribute': {'value': 'my_attribute_value', 'type': 'attribute', 'namespace': 'http://test.org/xmlns/0.1'}} cat = Catalog() cat.extra = extra cat.write('my_catalog.xml', format='QUAKEML', nsmap={'my_ns': 'http://test.org/xmlns/0.1'})
所有储存在自定义QuakeML中的信息必须存为带有自定义信息(如Catalog, Event, Pick)的extra属性的dict 或AttribDict对象。关键字用作xml标记的名称,xml标记的内容在一个字典中定义:'value'定义标记的内容(对象的字符串表示形式存储在文本xml输出中)。 'namespace'必须为标记指定自定义命名空间。 'type'可用于指定额外信息是应存储为子元素('element',default)还是存储为属性('attribute')。 自定义子元素的属性可以以字典的形式提供为'attrib'。如果需要更好的可读性,输出xml中的命名空间缩写可以在输出期间指定为QuakeML,方法是将命名空间缩写映射字典作为nsmap参数提供给Catalog.write()。上例的xml输出如下所示:
<?xml version='1.0' encoding='utf-8'?> <q:quakeml xmlns:q='http://quakeml.org/xmlns/quakeml/1.2' xmlns:ns0='http://some-page.de/xmlns/1.0' xmlns:my_ns='http://test.org/xmlns/0.1' xmlns='http://quakeml.org/xmlns/bed/1.2'> <eventParameters publicID='smi:local/b425518c-9445-40c7-8284-d1f299ed2eac' my_ns:my_attribute='my_attribute_value'> <ns0:my_tag ns0:my_attrib1='123.4' ns0:my_attrib2='567'>true</ns0:my_tag> <my_ns:my_tag_4>2013-01-02T13:12:14.600000Z</my_ns:my_tag_4> <ns0:my_tag_2>True</ns0:my_tag_2> <ns0:my_tag_3>1</ns0:my_tag_3> </eventParameters> </q:quakeml>
再次使用read_events()读取上述xml时,自定义标记被解析并附加到相应的事件类型对象(在此示例中为Catalog对象)为“.extra”。 请注意,所有值都作为文本字符串读取:
from obspy import read_events cat = read_events('my_catalog.xml') print(cat.extra)
AttribDict({u'my_tag': {u'attrib': {'{http://some-page.de/xmlns/1.0}my_attrib2': '567', '{http://some-page.de/xmlns/1.0}my_attrib1': '123.4'}, u'namespace': u'http://some-page.de/xmlns/1.0', u'value': 'true'}, u'my_tag_4': {u'namespace': u'http://test.org/xmlns/0.1', u'value': '2013-01-02T13:12:14.600000Z'}, u'my_attribute': {u'type': u'attribute', u'namespace': u'http://test.org/xmlns/0.1', u'value': 'my_attribute_value'}, u'my_tag_2': {u'namespace': u'http://some-page.de/xmlns/1.0', u'value': 'True'}, u'my_tag_3': {u'namespace': u'http://some-page.de/xmlns/1.0', u'value': '1'}})
自定义标签可以嵌套:
from obspy import Catalog from obspy.core import AttribDict ns = 'http://some-page.de/xmlns/1.0' my_tag = AttribDict() my_tag.namespace = ns my_tag.value = AttribDict() my_tag.value.my_nested_tag1 = AttribDict() my_tag.value.my_nested_tag1.namespace = ns my_tag.value.my_nested_tag1.value = 1.23E+10 my_tag.value.my_nested_tag2 = AttribDict() my_tag.value.my_nested_tag2.namespace = ns my_tag.value.my_nested_tag2.value = True cat = Catalog() cat.extra = AttribDict() cat.extra.my_tag = my_tag cat.write('my_catalog.xml', 'QUAKEML')
这将产生类似于以下内容的xml输出:
<?xml version='1.0' encoding='utf-8'?> <q:quakeml xmlns:q='http://quakeml.org/xmlns/quakeml/1.2' xmlns:ns0='http://some-page.de/xmlns/1.0' xmlns='http://quakeml.org/xmlns/bed/1.2'> <eventParameters publicID='smi:local/97d2b338-0701-41a4-9b6b-5903048bc341'> <ns0:my_tag> <ns0:my_nested_tag1>12300000000.0</ns0:my_nested_tag1> <ns0:my_nested_tag2>true</ns0:my_nested_tag2> </ns0:my_tag> </eventParameters> </q:quakeml>
输出的XML可以再次使用read_events()读取,嵌套标签可使用下面的方法检索:
from obspy import read_events cat = read_events('my_catalog.xml') print(cat.extra.my_tag.value.my_nested_tag1.value) print(cat.extra.my_tag.value.my_nested_tag2.value)
结果:
12300000000.0 true
可以使用OrderedDict为额外属性控制额外标签的顺序:
from collections import OrderedDict from obspy.core.event import Catalog, Event ns = 'http://some-page.de/xmlns/1.0' my_tag1 = {'namespace': ns, 'value': 'some value 1'} my_tag2 = {'namespace': ns, 'value': 'some value 2'} event = Event() cat = Catalog(events=[event]) event.extra = OrderedDict() event.extra['myFirstExtraTag'] = my_tag2 event.extra['mySecondExtraTag'] = my_tag1 cat.write('my_catalog.xml', 'QUAKEML')
- Handling custom defined tags in StationXML with the Obspy Inventory(使用Obspy Inventory处理StationXML中的自定义标签)
以下基本示例说明如何输出包含其他xml标记/属性的StationXML文件:
from obspy import Inventory, UTCDateTime from obspy.core.inventory import Network from obspy.core.util import AttribDict extra = AttribDict({ 'my_tag': { 'value': True, 'namespace': 'http://some-page.de/xmlns/1.0', 'attrib': { '{http://some-page.de/xmlns/1.0}my_attrib1': '123.4', '{http://some-page.de/xmlns/1.0}my_attrib2': '567' } }, 'my_tag_2': { 'value': u'True', 'namespace': 'http://some-page.de/xmlns/1.0' }, 'my_tag_3': { 'value': 1, 'namespace': 'http://some-page.de/xmlns/1.0' }, 'my_tag_4': { 'value': UTCDateTime('2013-01-02T13:12:14.600000Z'), 'namespace': 'http://test.org/xmlns/0.1' }, 'my_attribute': { 'value': 'my_attribute_value', 'type': 'attribute', 'namespace': 'http://test.org/xmlns/0.1' } }) inv = Inventory([Network('XX')], 'XX') inv[0].extra = extra inv.write('my_inventory.xml', format='STATIONXML', nsmap={'my_ns': 'http://test.org/xmlns/0.1', 'somepage_ns': 'http://some-page.de/xmlns/1.0'})
要存储在定制的StationXML中的所有自定义信息必须以dict 或AttribDict对象的形式存储,作为应携带附加自定义信息的对象的.extra属性(例如,Network, Station, Channel)。关键字作xml标记的名称,xml标记的内容在简单字典中定义:'value'定义标记的内容(对象的字符串表示形式存储在文本xml输出中)。 'namespace'必须为标记指定自定义命名空间。 'type'可用于指定额外信息是应存储为子元素('element',default)还是存储为属性('attribute')。 自定义子元素的属性可以以字典的形式提供为“attrib”。
如果需要更好可读性,输出xml中的命名空间缩写可以在输出期间指定为StationXML,方法是将名称空间缩写映射字典作为nsmap参数提供给Inventory.write()。xml输出如下所示:
<?xml version='1.0' encoding='UTF-8'?> <FDSNStationXML xmlns:my_ns="http://test.org/xmlns/0.1" xmlns:somepage_ns="http://some-page.de/xmlns/1.0" xmlns="http://www.fdsn.org/xml/station/1" schemaVersion="1.0"> <Source>XX</Source> <Module>ObsPy 1.0.2</Module> <ModuleURI>https://www.obspy.org</ModuleURI> <Created>2016-10-17T18:32:28.696287+00:00</Created> <Network code="XX"> <somepage_ns:my_tag somepage_ns:my_attrib1="123.4" somepage_ns:my_attrib2="567">True</somepage_ns:my_tag> <my_ns:my_tag_4>2013-01-02T13:12:14.600000Z</my_ns:my_tag_4> <my_ns:my_attribute>my_attribute_value</my_ns:my_attribute> <somepage_ns:my_tag_2>True</somepage_ns:my_tag_2> <somepage_ns:my_tag_3>1</somepage_ns:my_tag_3> </Network> </FDSNStationXML>
再次读取上面的XML时,使用read_inventory(),自定义标记被解析并作为为'.extra'附加到相应的网络类型对象(在此示例中为Inventory对象)。请注意,所有值都作为文本字符串读取:
from obspy import read_inventory inv = read_inventory('my_inventory.xml') print(inv[0].extra)
AttribDict({ u'my_tag': AttribDict({ 'attrib': { '{http://some-page.de/xmlns/1.0}my_attrib2': '567', '{http://some-page.de/xmlns/1.0}my_attrib1': '123.4' }, 'namespace': 'http://some-page.de/xmlns/1.0', 'value': 'True' }), u'my_tag_4': AttribDict({ 'namespace': 'http://test.org/xmlns/0.1', 'value': '2013-01-02T13:12:14.600000Z' }), u'my_attribute': AttribDict({ 'namespace': 'http://test.org/xmlns/0.1', 'value': 'my_attribute_value' }), u'my_tag_2': AttribDict({ 'namespace': 'http://some-page.de/xmlns/1.0', 'value': 'True' }), u'my_tag_3': AttribDict({ 'namespace': 'http://some-page.de/xmlns/1.0', 'value': '1' }) })
自定义标签可以嵌套:
from obspy import Inventory from obspy.core.inventory import Network from obspy.core.util import AttribDict ns = 'http://some-page.de/xmlns/1.0' my_tag = AttribDict() my_tag.namespace = ns my_tag.value = AttribDict() my_tag.value.my_nested_tag1 = AttribDict() my_tag.value.my_nested_tag1.namespace = ns my_tag.value.my_nested_tag1.value = 1.23E+10 my_tag.value.my_nested_tag2 = AttribDict() my_tag.value.my_nested_tag2.namespace = ns my_tag.value.my_nested_tag2.value = True inv = Inventory([Network('XX')], 'XX') inv[0].extra = AttribDict() inv[0].extra.my_tag = my_tag inv.write('my_inventory.xml', format='STATIONXML', nsmap={'somepage_ns': 'http://some-page.de/xmlns/1.0'})
这将产生类似于以下内容的xml输出:
<?xml version='1.0' encoding='UTF-8'?> <FDSNStationXML xmlns:somepage_ns="http://some-page.de/xmlns/1.0" xmlns="http://www.fdsn.org/xml/station/1" schemaVersion="1.0"> <Source>XX</Source> <Module>ObsPy 1.0.2</Module> <ModuleURI>https://www.obspy.org</ModuleURI> <Created>2016-10-17T18:45:14.302265+00:00</Created> <Network code="XX"> <somepage_ns:my_tag> <somepage_ns:my_nested_tag1>12300000000.0</somepage_ns:my_nested_tag1> <somepage_ns:my_nested_tag2>True</somepage_ns:my_nested_tag2> </somepage_ns:my_tag> </Network> </FDSNStationXML>
输出XML可以使用read_inventory()再次读取,嵌套标签使用下面的方法检索:
from obspy import read_inventory inv = read_inventory('my_inventory.xml') print(inv[0].extra.my_tag.value.my_nested_tag1.value) print(inv[0].extra.my_tag.value.my_nested_tag2.value)
结果:
12300000000.0 True
- Creating a StationXML file from Scratch (从Scratch创建StationXML文件)
在地震学中有时需要创建自定义StationXML文件。本节演示如何使用ObsPy完成这样的任务请注意,这不一定比直接编辑XML文件更容易或更容易观察,但它确实提供了一种与ObsPy的其余部分更紧密结合的方法,并且可以保证最终结果有效。
这里假定您对FDSN StationXML standard.有一定的了解。我们将创建一个相当简单的StationXML文件,并且许多参数是可选的。 ObsPy将在写入时根据其模式验证生成的StationXML文件,以确保最终文件对StationXML模式有效。下图显示了ObsPy内部表示的基本结构。
每个大框都是一个对象,所有对象都必须分层链接以形成一个Inventory对象。Inventory可以包含任意数量的网络对象,这些对象又可以包含任意数量的工作站对象,这些工具又可以包含任意数量的信道对象。对于每个信道,仪器响应可以存储为response属性。
使用ObsPy的NRL客户端,可以从IRIS DMC Library of Nominal Responses(NRL)中查找仪器响应并将其附加到每个信道。
import obspy from obspy.core.inventory import Inventory, Network, Station, Channel, Site from obspy.clients.nrl import NRL # We'll first create all the various objects. These strongly follow the # hierarchy of StationXML files. inv = Inventory( # We'll add networks later. networks=[], # The source should be the id whoever create the file. source="ObsPy-Tutorial") net = Network( # This is the network code according to the SEED standard. code="XX", # A list of stations. We'll add one later. stations=[], description="A test stations.", # Start-and end dates are optional. start_date=obspy.UTCDateTime(2016, 1, 2)) sta = Station( # This is the station code according to the SEED standard. code="ABC", latitude=1.0, longitude=2.0, elevation=345.0, creation_date=obspy.UTCDateTime(2016, 1, 2), site=Site(name="First station")) cha = Channel( # This is the channel code according to the SEED standard. code="HHZ", # This is the location code according to the SEED standard. location_code="", # Note that these coordinates can differ from the station coordinates. latitude=1.0, longitude=2.0, elevation=345.0, depth=10.0, azimuth=0.0, dip=-90.0, sample_rate=200) # By default this accesses the NRL online. Offline copies of the NRL can # also be used instead nrl = NRL() # The contents of the NRL can be explored interactively in a Python prompt, # see API documentation of NRL submodule: # http://docs.obspy.org/packages/obspy.clients.nrl.html # Here we assume that the end point of data logger and sensor are already # known: response = nrl.get_response( # doctest: +SKIP sensor_keys=['Streckeisen', 'STS-1', '360 seconds'], datalogger_keys=['REF TEK', 'RT 130 & 130-SMA', '1', '200']) # Now tie it all together. cha.response = response sta.channels.append(cha) net.stations.append(sta) inv.networks.append(net) # And finally write it to a StationXML file. We also force a validation against # the StationXML schema to ensure it produces a valid StationXML file. # # Note that it is also possible to serialize to any of the other inventory # output formats ObsPy supports. inv.write("station.xml", format="stationxml", validate=True)
- Connecting to a SeedLink Server(连接到SeedLink服务器)
obspy.clients.seedlink模块提供了Python实现的SeedLink客户端协议。obspy.clients.seedlink.easyseedlink子模块包含SeedLink实现的高级接口,有助于创建SeedLink客户端。
使用create_client()函数创建一个新的EasySeedLinkClient类是连接到SeedLink服务器的最简单方法。它接受一个从SeedLink服务器接收的新数据的函数作为参数,例如:
def handle_data(trace): print('Received the following trace:') print(trace) print()
此函数随后可以与SeedLink服务器URL一同传递给create_client()创建一个客户端:
client = create_client('geofon.gfz-potsdam.de', on_data=handle_data)
客户端在创建时立即连接到服务器。
-
-
- 发送INFO请求到服务器
-
客户端可以发送INFO请求到服务器:
# Send the INFO:ID request client.get_info('ID') # Returns: # <?xml version="1.0"?>\n<seedlink software="SeedLink v3.2 (2014.071)" organization="GEOFON" started="2014/09/01 14:08:37.4192"/>\n
INFO请求的响应是XML格式的。客户端提供了检索和解析服务器功能的快捷方式(经由一个INFO:CAPABILITIES请求。)
>>> client.capabilities ['dialup', 'multistation', 'window-extraction', 'info:id', 'info:capabilities', 'info:stations', 'info:streams']
首次访问属性时会提取和解析这些功能,并在此之后进行缓存。
为了开始接受波形数据,需要先通过select_stream()函数选择至少一个stream。
client.select_stream('BW', 'MANZ', 'EHZ')
多个stream也可以被选择,也支持SeedLink通配符:
client.select_stream('BW', 'ROTZ', 'EH?')
选择stream后,客户端就准备好进入streaming模式了:
client.run()
这将从服务器开始流式传输数据。 在从服务器接收的每个完整跟踪时,使用跟踪对象调用上面定义的函数:
Received new data: BW.MANZ..EHZ | 2014-09-04T19:47:25.625000Z - 2014-09-04T19:47:26.770000Z | 200.0 Hz, 230 samples Received new data: BW.ROTZ..EHZ | 2014-09-04T19:47:22.685000Z - 2014-09-04T19:47:24.740000Z | 200.0 Hz, 412 samples Received new data: BW.ROTZ..EHZ | 2014-09-04T19:47:24.745000Z - 2014-09-04T19:47:26.800000Z | 200.0 Hz, 412 samples Received new data: BW.ROTZ..EHN | 2014-09-04T19:47:20.870000Z - 2014-09-04T19:47:22.925000Z | 200.0 Hz, 412 samples Received new data: BW.ROTZ..EHN | 2014-09-04T19:47:22.930000Z - 2014-09-04T19:47:24.985000Z | 200.0 Hz, 412 samples
对于高级用法,继承EasySeedLinkClient类可以更好地控制。下列代码实现与上面相同的客户端:
class DemoClient(EasySeedLinkClient): """ A custom SeedLink client """ def on_data(self, trace): """ Override the on_data callback """ print('Received trace:') print(trace) print()