Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic support for in-app "Quick Start" guides #3813

Merged
merged 22 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/re_data_store/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ re_smart_channel.workspace = true
re_tracing.workspace = true
re_types.workspace = true

anyhow.workspace = true
document-features.workspace = true
itertools.workspace = true
nohash-hasher.workspace = true
Expand Down
35 changes: 33 additions & 2 deletions crates/re_data_store/src/store_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use nohash_hasher::IntMap;
use re_arrow_store::{DataStoreConfig, GarbageCollectionOptions};
use re_log_types::{
ApplicationId, ComponentPath, DataCell, DataRow, DataTable, EntityPath, EntityPathHash, LogMsg,
PathOp, RowId, SetStoreInfo, StoreId, StoreInfo, StoreKind, TimePoint, Timeline,
PathOp, RowId, SetStoreInfo, StoreId, StoreInfo, StoreKind, StoreSource, Time, TimePoint,
Timeline,
};
use re_types::{components::InstanceKey, Loggable as _};

Expand Down Expand Up @@ -210,7 +211,7 @@ impl EntityDb {

// ----------------------------------------------------------------------------

/// A in-memory database built from a stream of [`LogMsg`]es.
/// An in-memory database built from a stream of [`LogMsg`]es.
///
/// NOTE: all mutation is to be done via public functions!
pub struct StoreDb {
Expand All @@ -237,6 +238,36 @@ impl StoreDb {
}
}

/// Helper function to create a recording from a [`StoreInfo`] and a some [`DataRow`]s.
///
/// This is useful to programmatically create recordings from within the viewer, which cannot
/// use the `re_sdk`, which is not Wasm-compatible.
pub fn from_rows(
app_id: impl Into<ApplicationId>,
rows: impl IntoIterator<Item = DataRow>,
) -> anyhow::Result<Self> {
abey79 marked this conversation as resolved.
Show resolved Hide resolved
let store_info = StoreInfo {
application_id: app_id.into(),
store_id: StoreId::random(StoreKind::Recording),
is_official_example: true,
started: Time::now(),
store_source: StoreSource::Viewer,
store_kind: StoreKind::Recording,
abey79 marked this conversation as resolved.
Show resolved Hide resolved
};

let mut store_db = StoreDb::new(store_info.store_id.clone());

store_db.set_store_info(SetStoreInfo {
row_id: RowId::random(),
info: store_info,
});
for row in rows {
store_db.add_data_row(&row)?;
}

Ok(store_db)
}

#[inline]
pub fn entity_db(&self) -> &EntityDb {
&self.entity_db
Expand Down
4 changes: 4 additions & 0 deletions crates/re_log_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ pub enum StoreSource {
file_source: FileSource,
},

/// Generated from the viewer itself.
Viewer,

/// Perhaps from some manual data ingestion?
Other(String),
}
Expand All @@ -362,6 +365,7 @@ impl std::fmt::Display for StoreSource {
FileSource::DragAndDrop => write!(f, "File via drag-and-drop"),
FileSource::FileDialog => write!(f, "File via file dialog"),
},
Self::Viewer => write!(f, "Viewer generated"),
abey79 marked this conversation as resolved.
Show resolved Hide resolved
Self::Other(string) => format!("{string:?}").fmt(f), // put it in quotes
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/re_viewer/data/quick_start_guides/cpp_native.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## C++ Quick Start

TODO(ab)
abey79 marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 3 additions & 0 deletions crates/re_viewer/data/quick_start_guides/how_does_it_work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### How does it work?

TBC
abey79 marked this conversation as resolved.
Show resolved Hide resolved
59 changes: 59 additions & 0 deletions crates/re_viewer/data/quick_start_guides/python_native.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
## Python Quick Start

### Installing the Rerun SDK

The Rerun SDK is available on [PyPI](https://pypi.org/) under the
[`rerun-sdk`](https://pypi.org/project/rerun-sdk/) name. It can be installed like any other
Python package:

```sh
pip3 install rerun-sdk
abey79 marked this conversation as resolved.
Show resolved Hide resolved
```

### Try out the viewer

The Rerun SDK comes with a demo that can be used to try the viewer. You can send a demo recording
to this viewer using the following command:

```sh
python3 -m rerun_sdk.demo --connect
```

This will open a new recording that looks like this:

![Demo recording](https://static.rerun.io/quickstart2_simple_cube/632a8f1c79f70a2355fad294fe085291fcf3a8ae/768w.png)


### Logging your own data

Instead of a pre-packaged demo, you can log your own data. Copy and paste the following snippet in a new
Python file and execute it to create a new recording in this viewer:

```python
import rerun as rr
import numpy as np

# Initialize the SDK and give our recording a unique name
rr.init("my_own_data")
abey79 marked this conversation as resolved.
Show resolved Hide resolved

# Connect to a local viewer using the default port
rr.connect()


# Create some data
SIZE = 10

pos_grid = np.meshgrid(*[np.linspace(-10, 10, SIZE)]*3)
positions = np.vstack([d.reshape(-1) for d in pos_grid]).T

col_grid = np.meshgrid(*[np.linspace(0, 255, SIZE)]*3)
colors = np.vstack([c.reshape(-1) for c in col_grid]).astype(np.uint8).T

# Log the data
rr.log(
# name under which this entity is logged (known as "entity path")
"my_points",
# log data as a 3D point cloud archetype
rr.Points3D(positions, colors=colors, radii=0.5)
)
abey79 marked this conversation as resolved.
Show resolved Hide resolved
```
3 changes: 3 additions & 0 deletions crates/re_viewer/data/quick_start_guides/rust_native.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Rust Quick Start

TODO(ab)
abey79 marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 6 additions & 0 deletions crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,12 @@ impl App {
}
}

SystemCommand::LoadStoreDb(store_db) => {
let store_id = store_db.store_id().clone();
store_hub.insert_recording(store_db);
store_hub.set_recording_id(store_id);
}

SystemCommand::ResetViewer => self.reset(store_hub, egui_ctx),
SystemCommand::UpdateBlueprint(blueprint_id, updates) => {
let blueprint_db = store_hub.store_db_mut(&blueprint_id);
Expand Down
5 changes: 4 additions & 1 deletion crates/re_viewer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ impl AppEnvironment {
llvm_version: llvm_version.clone(),
},

StoreSource::File { .. } | StoreSource::Unknown | StoreSource::Other(_) => {
StoreSource::File { .. }
| StoreSource::Unknown
| StoreSource::Viewer
| StoreSource::Other(_) => {
// We should not really get here

#[cfg(debug_assertions)]
Expand Down
8 changes: 8 additions & 0 deletions crates/re_viewer/src/store_hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ impl StoreHub {
}
}

/// Insert a new recording into the [`StoreHub`].
///
/// Note that the recording is not automatically made active. Use [`StoreHub::set_recording_id`]
/// if needed.
pub fn insert_recording(&mut self, store_db: StoreDb) {
self.store_dbs.insert_recording(store_db);
}

/// Mutable access to a [`StoreDb`] by id
pub fn store_db_mut(&mut self, store_id: &StoreId) -> &mut StoreDb {
self.store_dbs.store_db_entry(store_id)
Expand Down
80 changes: 72 additions & 8 deletions crates/re_viewer/src/ui/welcome_screen/welcome_page.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::{large_text_button, status_strings, url_large_text_button, WelcomeScreenResponse};
use egui::{NumExt, Ui};
use re_log_types::LogMsg;
use itertools::Itertools;
use re_data_store::StoreDb;
use re_log_types::{DataRow, EntityPath, LogMsg, RowId, TimePoint};
use re_smart_channel::ReceiveSet;
use re_ui::UICommandSender;
use re_viewer_context::{SystemCommand, SystemCommandSender};

//const CPP_QUICKSTART: &str = "https://www.rerun.io/docs/getting-started/cpp";
const PYTHON_QUICKSTART: &str = "https://www.rerun.io/docs/getting-started/python";
const RUST_QUICKSTART: &str = "https://www.rerun.io/docs/getting-started/rust";
const SPACE_VIEWS_HELP: &str = "https://www.rerun.io/docs/getting-started/viewer-walkthrough";

/// Show the welcome page.
Expand Down Expand Up @@ -58,10 +58,39 @@ fn onboarding_content_ui(
Visualize synchronized data from multiple processes, locally or over a network.",
image: &re_ui::icons::WELCOME_SCREEN_LIVE_DATA,
add_buttons: Box::new(|ui: &mut egui::Ui| {
// TODO(ab): activate when C++ is ready!
// url_large_text_button(ui, "C++", CPP_QUICKSTART);
url_large_text_button(ui, "Python", PYTHON_QUICKSTART);
url_large_text_button(ui, "Rust", RUST_QUICKSTART);
if large_text_button(ui, "C++").clicked() {
open_quick_start(
command_sender,
[
include_str!("../../../data/quick_start_guides/cpp_native.md"),
include_str!("../../../data/quick_start_guides/how_does_it_work.md"),
],
"C++ Quick Start",
"cpp_quick_start",
);
}
if large_text_button(ui, "Python").clicked() {
open_quick_start(
command_sender,
[
include_str!("../../../data/quick_start_guides/python_native.md"),
include_str!("../../../data/quick_start_guides/how_does_it_work.md"),
],
"Python Quick Start",
"python_quick_start",
);
}
if large_text_button(ui, "Rust").clicked() {
open_quick_start(
command_sender,
[
include_str!("../../../data/quick_start_guides/rust_native.md"),
include_str!("../../../data/quick_start_guides/how_does_it_work.md"),
],
"Rust Quick Start",
"rust_quick_start",
);
}
abey79 marked this conversation as resolved.
Show resolved Hide resolved

false
}),
Expand Down Expand Up @@ -231,3 +260,38 @@ fn image_banner(ui: &mut egui::Ui, icon: &re_ui::Icon, column_width: f32, max_im
);
});
}

fn open_quick_start<'a>(
command_sender: &re_viewer_context::CommandSender,
parts: impl IntoIterator<Item = &'a str>,
app_id: impl AsRef<str>,
entity_path: impl AsRef<str>,
) {
let markdown = parts.into_iter().join("\n");
let res = open_markdown_recording(command_sender, markdown, app_id, entity_path);
if let Err(err) = res {
re_log::error!("Failed to load quick start: {}", err);
}
}

fn open_markdown_recording(
command_sender: &re_viewer_context::CommandSender,
markdown: impl AsRef<str>,
app_id: impl AsRef<str>,
entity_path: impl AsRef<str>,
) -> anyhow::Result<()> {
let text_doc = re_types::archetypes::TextDocument::new(markdown.as_ref())
abey79 marked this conversation as resolved.
Show resolved Hide resolved
.with_media_type(re_types::components::MediaType::markdown());

let row = DataRow::from_archetype(
RowId::random(),
TimePoint::timeless(),
EntityPath::from(entity_path.as_ref()),
&text_doc,
)?;

let store_db = StoreDb::from_rows(app_id.as_ref(), [row])?;
command_sender.send_system(SystemCommand::LoadStoreDb(store_db));

Ok(())
}
3 changes: 2 additions & 1 deletion crates/re_viewer/src/viewer_analytics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ impl ViewerAnalytics {
re_log_types::FileSource::DragAndDrop => "file_drag_and_drop".to_owned(),
re_log_types::FileSource::FileDialog => "file_dialog".to_owned(),
},
StoreSource::Viewer => "viewer".to_owned(),
StoreSource::Other(other) => other.clone(),
};

Expand Down Expand Up @@ -210,7 +211,7 @@ impl ViewerAnalytics {
self.deregister("llvm_version"); // can't be both!
}
StoreSource::CSdk => {} // TODO(andreas): Send version and set it.
StoreSource::Unknown | StoreSource::Other(_) => {}
StoreSource::Unknown | StoreSource::Viewer | StoreSource::Other(_) => {}
}

self.register("store_source", store_source);
Expand Down
4 changes: 4 additions & 0 deletions crates/re_viewer_context/src/command_sender.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use re_data_source::DataSource;
use re_data_store::StoreDb;
use re_log_types::{DataRow, StoreId};
use re_ui::{UICommand, UICommandSender};

Expand All @@ -10,6 +11,9 @@ pub enum SystemCommand {
/// Load some data.
LoadDataSource(DataSource),

/// Load some log messages.
LoadStoreDb(StoreDb),

/// Reset the `Viewer` to the default state
ResetViewer,

Expand Down