{"id":29051472,"url":"https://github.com/giacomomarchioro/pyx3p","last_synced_at":"2026-03-18T00:36:39.563Z","repository":{"id":81647130,"uuid":"153329567","full_name":"giacomomarchioro/pyx3p","owner":"giacomomarchioro","description":"Unofficial class in Python to open the x3p file created by OpenGPS consortium.","archived":false,"fork":false,"pushed_at":"2025-04-02T14:10:49.000Z","size":44,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-02T15:23:47.558Z","etag":null,"topics":["format","instruments","metrology","surfaces"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/giacomomarchioro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-16T17:51:35.000Z","updated_at":"2025-04-02T14:10:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"8dc40ad4-f755-405e-b7e4-20356a97d1fc","html_url":"https://github.com/giacomomarchioro/pyx3p","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/giacomomarchioro/pyx3p","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fpyx3p","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fpyx3p/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fpyx3p/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fpyx3p/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/giacomomarchioro","download_url":"https://codeload.github.com/giacomomarchioro/pyx3p/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fpyx3p/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262150132,"owners_count":23266835,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["format","instruments","metrology","surfaces"],"created_at":"2025-06-26T22:10:37.523Z","updated_at":"2025-10-30T07:36:46.322Z","avatar_url":"https://github.com/giacomomarchioro.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pyx3p\nThis is an unofficial Python module that allows opening the .x3p file format created by [OpenGPS consortium](http://open-gps.sourceforge.net/).\n\n## How it's structured\nThis module is an implementation of the X3P format data structure using the dot\nnotation. The XML structure of the .x3p is almost always maintained and made\naccessible using the dot notation. For instance, for accessing the revision field. First, we create an instance of X3Pfile class (e.g. `anx3pfile`) then we can use\nanx3pfile.record1.revison.\nThe same is true for the other fields (creator, comment, etc. etc.). \nFew exceptions have been made to this rule: when there is a data structure that\nis clearly easier to describe using an array, a numpy array is used.\nThis happens:\n\n    - for the rotation matrix there are no r11,r12 etc. etc. params but a 3 x 3\n      numpy matrix (r11 at index 0,0)\n    - in case there is a profile encoded in the xml file ( a DataList).\n\nThe attribute `data` contains the data as a masked numpy array. Using this data structure it is possible to add the valid points as a `mask` attribute.\n\n## Requirements\nAll the module is based on the standard library except for numpy.\n\n## Installation\nYou can install the module using: \n```\npip install git+https://github.com/giacomomarchioro/pyx3p\n```\n\n## Reading an .x3p file \nThe followings examples assume you have downloaded the .x3p file samples from the [OpenGPS website](https://sourceforge.net/projects/open-gps/files/Sample-Files/).\n\n```python\nfrom x3p import X3Pfile\nanx3pfile = X3Pfile('1-euro-star.x3p')\n# access an attribute\nanx3pfile.record1.featuretype\nanx3pfile.record1.axes.CX.axistype\n# access the data\nanx3pfile.data\n```\n\nFor plotting, matplotlib can be used.\n\n```python\n# assuming you have run succeffuly the previous code\nimport matplotlib.pyplot as plt\nplt.imshow(anx3pfile.data)\nplt.colorbar()\nplt.show()\n```\n\n## Writing an .x3p file\n**This feature is under testing**\nWriting a file can be done easily using the same data structure. Because the module does not use any `.xsd` for checking the XML structure all the rules on the `.xsd` file have been converted in python conditional statements. To ensure that the XML structure is correct the user should use the `set` methods create for every attribute.\n\n```python\nfrom x3p import X3Pfile\nimport numpy as np\nimport hashlib \n# We create an empty data structure\nanx3pfile = X3Pfile()\nanx3pfile.set_VendorSpecificID(\"https://github.com/giacomomarchioro/pyx3p\")\n# Record 1\nanx3pfile.record1.set_featuretype('SUR')\n\nanx3pfile.record1.axes.CX.set_axistype('I')\nanx3pfile.record1.axes.CX.set_increment(50/1000**2) # 50 microns scan step\nanx3pfile.record1.axes.CX.set_offset(50/1000) # 50 mm offset\n# anx3pfile.record1.axes.CX.set_datatype(\"L\")\n\nanx3pfile.record1.axes.CY.set_axistype('I')\nanx3pfile.record1.axes.CY.set_increment(50/1000**2) # 50 microns scan step\nanx3pfile.record1.axes.CY.set_offset(50/1000) # 50 mm offset\n# anx3pfile.record1.axes.CY.set_datatype(\"L\")\n\n# CZ is by default incremental with increment 1\n# anx3pfile.record1.axes.CZ.set_datatype(\"L\")\n# Record 2\nanx3pfile.record2.set_calibrationdate(\"2008-08-25T13:59:21.4+02:00\")\nanx3pfile.record2.set_creator(\"Giacomo Marchioro\")\nanx3pfile.record2.set_date(\"2008-08-25T13:59:21.4+02:00\")\nanx3pfile.record2.instrument.set_manufacturer(\"Univeristy of Verona (Optimet-Physics Instrumente)\")\nanx3pfile.record2.instrument.set_model(\"ConoProbe-3H\")\nanx3pfile.record2.instrument.set_serial(\"Not availabe\")\nanx3pfile.record2.instrument.set_version(\"v3\")\nanx3pfile.record2.probingsystem.set_identification(\"25 mm lens\")\nanx3pfile.record2.probingsystem.set_type(\"NonContacting\")\nanx3pfile.record2.set_comment(\"Example of scan.\")\n\n# we generate a 2D array of distances with a sine pattern as sample data\nsin2d = np.vstack([np.sin(np.arange(-12.0, 12.0, 1))]*12)/1000**2 # microns\n# Create boolean mask array\nmask = np.zeros(sin2d.shape, dtype=bool)  # Important: specify dtype=bool\n# we mask the forth, fifth and sixth row (True values will be masked)\nmask[[3,4,5],:] = True\n# Create masked array with the boolean mask\ndata = np.ma.masked_array(sin2d, mask=mask)\nanx3pfile.set_data(data)\nanx3pfile.write('mytest2')\n```\n\n## Things to remember\nWe save the mask in the `bindata\\valids.bin` (I could not find any recomandation on the standard).\nThe data must be provided in the following dimension data[layers,x_dim,y_dim]. Remember it is a layer if X and Y are set to incremental otherwise the other two array contain the coordinates of the heights variations.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiacomomarchioro%2Fpyx3p","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgiacomomarchioro%2Fpyx3p","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiacomomarchioro%2Fpyx3p/lists"}