Skip to content

Commit 96b3f2e

Browse files
authored
Merge pull request #75 from tilak-io/66-documentation-for-sequences
66 documentation for sequences
2 parents 270454e + b2a2a32 commit 96b3f2e

File tree

6 files changed

+123
-26
lines changed

6 files changed

+123
-26
lines changed

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ TiPlot is an open-source visualisation tool for flight logs. With TiPlot, you ca
2828
- 3D viewer for displaying the paths of your UAVs.
2929
- Add multiple UAVs to compare flights.
3030
- Sync the 3D view with a specific timestamp by hovering over it.
31+
- Perform customized operations on data currently being processed.
3132
- Ability to send a data dictionary and entities to be displayed in the 3D view over TCP port `5555` from a Python script or a Jupyter notebook.
3233
- Layouts are automatically saved after every change.
3334
- Drag and drop plots to reposition them.
@@ -41,7 +42,7 @@ TiPlot is an open-source visualisation tool for flight logs. With TiPlot, you ca
4142

4243
### Prebuilt AppImage
4344

44-
To install TiPlot using the prebuilt AppImage, follow these steps:
45+
To run TiPlot using the prebuilt AppImage, follow these steps:
4546

4647
1. Download the latest AppImage from the [releases page](https://github.com/tilak-io/tiplot/releases/latest).
4748
2. Make the AppImage executable by running:
@@ -116,6 +117,43 @@ Note that `datadict` is the data dictionary returned by the parser.
116117

117118
For more info check out the Jupyter notebooks in the [templates](https://github.com/tilak-io/tiplot/blob/main/templates) folder.
118119

120+
## Running Sequences and Custom Operations
121+
122+
In this guide, we will walk you through the process of creating and executing sequences, which are Python functions containing a set of operations to manipulate log data. These sequences can be customized to suit your specific needs. Follow these steps to get started:
123+
124+
1. **Set Preferred Editor**: Ensure that you have configured your preferred code editor in the tool settings by navigating to `Tools > Settings > General > External Editor`. If you intend to use a terminal-based editor such as Vim or Nano, make sure to specify the appropriate command to launch the terminal. (i.e: `kitty nvim` for kitty, `gnome-terminal -- nvim` for ubuntu's default terminal, `xterm -e nvim` for xterm...)
125+
126+
2. **Create a New Sequence**: To begin, create a new sequence by navigating to `Tools > Sequences > Add New Sequence`.
127+
128+
3. **Provide a Descriptive Name**: Give your sequence a meaningful and descriptive name that reflects its purpose.
129+
130+
4. **Edit the Sequence**: Upon creating a new sequence, your preferred code editor will open with a template function. You can now define the operations you want to perform on the log data.
131+
132+
Here's an example of a sequence that transforms log data from the NED (North-East-Down) representation to the ENU (East-North-Up) representation for a topic called `vehicle_local_position_enu`:
133+
134+
```python
135+
def handle_data(datadict):
136+
import numpy as np
137+
new = datadict
138+
# Coordinate transformation matrix from NED to ENU
139+
NED_to_ENU = np.array([
140+
[0, 1, 0], # East (ENU X) corresponds to North (NED Y)
141+
[1, 0, 0], # North (ENU Y) corresponds to East (NED X)
142+
[0, 0, -1] # Up (ENU Z) corresponds to -Down (NED Z)
143+
])
144+
# Apply the coordinate transformation to the 'x', 'y', and 'z' columns
145+
new['vehicle_local_position_enu'] = new['vehicle_local_position'].copy()
146+
xyz_ned = new['vehicle_local_position_enu'][['x', 'y', 'z']].values
147+
xyz_enu = np.dot(xyz_ned, NED_to_ENU.T) # Transpose the transformation matrix for NED to ENU
148+
new['vehicle_local_position_enu'][['x', 'y', 'z']] = xyz_enu
149+
return new
150+
```
151+
152+
***NOTE: the imports should be inside the function***
153+
154+
Feel free to adapt and customize your sequence function to perform the operations that are relevant to your data processing needs.
155+
156+
Happy sequencing 🎉!
119157

120158
## Contributing
121159
We welcome contributions to TiPlot. If you would like to contribute, please follow these steps:

api/server.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,21 @@ def create_sequence_file():
403403

404404
return {"ok": ok, "err": err}
405405

406-
406+
@app.route('/open_sequence_file', methods=['POST'])
407+
def open_sequence_file():
408+
body = request.get_json()
409+
sequence_name = body['sequence']
410+
sequence_file = sequences_dir + sequence_name
411+
try:
412+
command = body['editorBinary'].split(" ")
413+
command.append(sequence_file)
414+
subprocess.Popen(command) # run the command asyncronously
415+
ok = True
416+
err = "no error"
417+
except:
418+
err = traceback.format_exc()
419+
ok = False
420+
return {"ok": ok, "err": err}
407421

408422
@socketio.on("disconnect")
409423
def disconnected():

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tiplot",
3-
"version": "1.1.9",
3+
"version": "1.2.0",
44
"private": true,
55
"homepage": "./",
66
"proxy": "http://localhost:5000",
@@ -44,7 +44,7 @@
4444
"react-bootstrap-submenu": "^3.0.1",
4545
"react-dom": "^18.2.0",
4646
"react-grid-layout": "^1.3.4",
47-
"react-icons": "^4.4.0",
47+
"react-icons": "^4.10.1",
4848
"react-new-window": "^1.0.1",
4949
"react-plotly.js": "^2.6.0",
5050
"react-router-dom": "^6.6.2",

src/components/ToolBar.js

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
1-
import { useState, useEffect } from "react";
1+
import { useEffect, useState } from "react";
22
import {
3+
Button,
34
Container,
5+
Form,
6+
Modal,
47
Nav,
5-
Navbar,
68
NavDropdown,
7-
Modal,
8-
Button,
9+
Navbar,
910
Tab,
10-
Tabs,
1111
Table,
12-
Form
12+
Tabs
1313
} from "react-bootstrap";
1414
import { DropdownSubmenu, NavDropdownMenu } from "react-bootstrap-submenu";
15-
import { FaToggleOn, FaToggleOff, FaInfoCircle } from "react-icons/fa";
16-
import { FcRadarPlot, FcScatterPlot, FcHeatMap } from "react-icons/fc";
1715
import "react-bootstrap-submenu/dist/index.css";
18-
import logo from "../static/img/logo.png";
19-
import { generateUUID } from "three/src/math/MathUtils";
20-
import { PORT } from "../static/js/constants";
16+
import { FaInfoCircle, FaToggleOff, FaToggleOn } from "react-icons/fa";
17+
import { FcHeatMap, FcRadarPlot, FcScatterPlot } from "react-icons/fc";
18+
import { LuEdit, LuPlay } from "react-icons/lu";
2119
import { ToastContainer, toast } from "react-toastify";
2220
import "react-toastify/dist/ReactToastify.css";
21+
import { generateUUID } from "three/src/math/MathUtils";
22+
import logo from "../static/img/logo.png";
23+
import { PORT } from "../static/js/constants";
24+
import { defaultSettings } from "../views/Settings";
2325

2426
function ToolBar({
2527
page,
@@ -287,9 +289,19 @@ function ToolBar({
287289
rows.push(
288290
<NavDropdown.Item
289291
key={generateUUID()}
290-
onClick={() => runSequence(seq_name)}
292+
style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}
291293
>
292-
{seq_name}
294+
<div>{seq_name}</div>
295+
&nbsp;
296+
<div className="form-group">
297+
<Button variant="outline-success"
298+
onClick={() => runSequence(seq_name)}
299+
><LuPlay /></Button>
300+
&nbsp;
301+
<Button variant="outline-outline"
302+
onClick={() => openFileWithEditor(seq_name)}
303+
><LuEdit /></Button>
304+
</div>
293305
</NavDropdown.Item>
294306
);
295307
});
@@ -316,13 +328,32 @@ function ToolBar({
316328
}
317329
).then((res) => res.json());
318330

319-
if (response.ok) toast.success(`"${name}" created successfully`);
320-
else toast.error(response.err);
331+
if (response.ok) {
332+
toast.success(`"${name}" created successfully`);
333+
openFileWithEditor(`${name}.py`);
334+
}
335+
else {
336+
toast.error(response.err);
337+
}
321338

322339
getSequences();
323340
setShowCreateMessage(false);
324341
};
325342

343+
const openFileWithEditor = async (sequenceName) => {
344+
const general_settings = parseLocalStorage("general_settings");
345+
const externalEditor =
346+
general_settings.externalEditor ?? defaultSettings["externalEditor"];
347+
const response = await fetch(`http://localhost:${PORT}/open_sequence_file`, {
348+
headers: {
349+
"Content-Type": "application/json",
350+
},
351+
method: "POST",
352+
body: JSON.stringify({ sequence: sequenceName, editorBinary: externalEditor }),
353+
}).then((res) => res.json());
354+
if (!response.ok) toast.error(response.err);
355+
}
356+
326357
const paramSearch = (query, dict) => {
327358
const value = query.target.value;
328359
setSearchQuery(value);

src/views/Settings.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const defaultSettings = {
1313
dampingFactor: 0.8,
1414
fov: 75,
1515
textYValue: 0,
16+
externalEditor: "/usr/bin/code"
1617
};
1718

1819
function Settings() {
@@ -72,6 +73,19 @@ function Settings() {
7273
<ToolBar page="settings" />
7374
<Container className="settings-page">
7475
<Form>
76+
<fieldset>
77+
<legend>• General ⚙️</legend>
78+
<InputGroup>
79+
<InputGroup.Text>External Editor</InputGroup.Text>
80+
<Form.Control
81+
onChange={handleChange}
82+
id="externalEditor"
83+
type="text"
84+
min={1}
85+
aria-label="ExternalEditor"
86+
/>
87+
</InputGroup>
88+
</fieldset>
7589
<fieldset>
7690
<legend>• View Layouts 🪟</legend>
7791
<Form.Check

yarn.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3712,9 +3712,9 @@ caniuse-api@^3.0.0:
37123712
lodash.uniq "^4.5.0"
37133713

37143714
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426:
3715-
version "1.0.30001443"
3716-
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001443.tgz#8fc85f912d5471c9821acacf9e715c421ca0dd1f"
3717-
integrity sha512-jUo8svymO8+Mkj3qbUbVjR8zv8LUGpGkUM/jKvc9SO2BvjCI980dp9fQbf/dyLs6RascPzgR4nhAKFA4OHeSaA==
3715+
version "1.0.30001522"
3716+
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz"
3717+
integrity sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==
37183718

37193719
canvas-fit@^1.5.0:
37203720
version "1.5.0"
@@ -9867,10 +9867,10 @@ react-grid-layout@^1.3.4:
98679867
react-draggable "^4.0.0"
98689868
react-resizable "^3.0.4"
98699869

9870-
react-icons@^4.4.0:
9871-
version "4.7.1"
9872-
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.7.1.tgz#0f4b25a5694e6972677cb189d2a72eabea7a8345"
9873-
integrity sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==
9870+
react-icons@^4.10.1:
9871+
version "4.10.1"
9872+
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.10.1.tgz#3f3b5eec1f63c1796f6a26174a1091ca6437a500"
9873+
integrity sha512-/ngzDP/77tlCfqthiiGNZeYFACw85fUjZtLbedmJ5DTlNDIwETxhwBzdOJ21zj4iJdvc0J3y7yOsX3PpxAJzrw==
98749874

98759875
react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0:
98769876
version "16.13.1"

0 commit comments

Comments
 (0)