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

Feat export svg #39

Merged
merged 7 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
431 changes: 423 additions & 8 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "shu"
version = "0.7.1"
version = "0.8.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "High-dimensional metabolic maps."
Expand All @@ -22,6 +22,8 @@ serde = "1.0.147"
serde_json = "1.0.88"
proc-macro2 = "1.0.43"
chrono = "0.4.31"
roarsvg = "0.4.1"
image = "0.24.6"

# dependencies exclusive for wasm32
[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand Down
5 changes: 3 additions & 2 deletions docs/source/plotting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,9 @@ After moving, rotating and scaling the axes as desired, all these new coordinate
can be saved to a new map in the settings window (only available for the desktop
app) for futures shu sessions.

A PNG/JPEG/BMP/TGA image of the map can also be exported through the settings
window (for all platforms and web).
An SVG image of the map can also be exported through the settings window (for all
platforms and the web). PNG/JPEG/BMP/TGA are also supported if the provided paths
have one of their corresponding extensions.

Hover
-----
Expand Down
8 changes: 4 additions & 4 deletions src/aesthetics.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::escher::{ArrowTag, CircleTag, Hover, Tag};
use crate::funcplot::{
build_grad, from_grad_clamped, lerp, max_f32, min_f32, path_to_vec, plot_box_point, plot_hist,
plot_kde, plot_line, plot_scales, zero_lerp,
plot_kde, plot_line, plot_scales, zero_lerp, IgnoreSave,
};
use crate::geom::{
AesFilter, AnyTag, Drag, GeomArrow, GeomHist, GeomMetabolite, HistPlot, HistTag, PopUp, Side,
Expand Down Expand Up @@ -700,13 +700,13 @@ fn plot_hover_hist(
});
})
.with_children(|parent| {
parent.spawn(scales.x_0);
parent.spawn((scales.x_0, IgnoreSave));
})
.with_children(|parent| {
parent.spawn(scales.x_n);
parent.spawn((scales.x_n, IgnoreSave));
})
.with_children(|parent| {
parent.spawn(scales.y);
parent.spawn((scales.y, IgnoreSave));
})
.insert((AnyTag { id: hover.node_id }, (*is_met).clone()));
}
Expand Down
10 changes: 10 additions & 0 deletions src/escher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub struct EscherPlugin;
impl Plugin for EscherPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(NodeToText::default())
.insert_resource(MapDimensions::default())
.add_systems(Update, load_map);
}
}
Expand Down Expand Up @@ -353,12 +354,19 @@ pub struct Hover {
pub xlimits: Option<(f32, f32)>,
}

#[derive(Resource, Default)]
pub struct MapDimensions {
pub x: f32,
pub y: f32,
}

/// Load escher map once the asset is available.
/// The colors correspond to the default escher colors.
pub fn load_map(
mut commands: Commands,
mut state: ResMut<MapState>,
mut info_state: ResMut<Info>,
mut map_dims: ResMut<MapDimensions>,
mut node_to_text: ResMut<NodeToText>,
asset_server: Res<AssetServer>,
mut custom_assets: ResMut<Assets<EscherMap>>,
Expand Down Expand Up @@ -397,6 +405,8 @@ pub fn load_map(
total_x / metabolites.len() as f32,
total_y / metabolites.len() as f32,
);
map_dims.x = center_x;
map_dims.y = center_y;
// add infinitesimal epsilon to each arrow so they don't flicker because of z-ordering
// metabolites are not expected to occupy the same space, but better to be safe
let mut z_eps = 1e-6;
Expand Down
8 changes: 7 additions & 1 deletion src/funcplot.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
//! Functions for plotting data.

use bevy::prelude::{Color, Font, Handle, Text, Text2dBundle, TextStyle, Transform, Vec2};
use bevy::prelude::{
Color, Component, Font, Handle, Text, Text2dBundle, TextStyle, Transform, Vec2,
};
use bevy_prototype_lyon::{
entity::ShapeBundle,
prelude::{GeometryBuilder, Path, PathBuilder, Stroke},
shapes,
};
use colorgrad::{Color as GradColor, CustomGradient, Gradient};

#[derive(Component)]
/// Marker trait to avoid outputting an [`Entity`] to the screen.
pub struct IgnoreSave;

/// Maximum of a slice.
pub fn max_f32(slice: &[f32]) -> f32 {
slice
Expand Down
16 changes: 11 additions & 5 deletions src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub struct UiState {
pub map_path: String,
pub data_path: String,
pub screen_path: String,
pub hide: bool,
// since this type and field are private, Self has to be initialized
// with Default::default(), ensuring that the fallbacks for colors (empty string) are set.
_init: Init,
Expand Down Expand Up @@ -141,9 +142,10 @@ impl Default for UiState {
condition: String::from(""),
conditions: vec![String::from("")],
save_path: format!("this_map-{}.json", Utc::now().format("%T-%Y")),
screen_path: format!("screenshot-{}.png", Utc::now().format("%T-%Y")),
screen_path: format!("screenshot-{}.svg", Utc::now().format("%T-%Y")),
map_path: String::from("my_map.json"),
data_path: String::from("my_data.metabolism.json"),
hide: false,
_init: Init,
}
}
Expand Down Expand Up @@ -179,18 +181,21 @@ impl UiState {
}

#[derive(Event)]
struct SaveEvent(String);
pub struct SaveEvent(String);

/// Settings for appearance of map and plots.
/// This is managed by [`bevy_egui`] and it is separate from the rest of the GUI.
fn ui_settings(
pub fn ui_settings(
mut egui_context: EguiContexts,
mut state: ResMut<UiState>,
mut save_events: EventWriter<SaveEvent>,
mut load_events: EventWriter<FileDragAndDrop>,
mut screen_events: EventWriter<ScreenshotEvent>,
windows: Query<(Entity, &Window), With<PrimaryWindow>>,
) {
if state.hide {
return;
}
egui::Window::new("Settings").show(egui_context.ctx_mut(), |ui| {
for (geom, ext) in ["Reaction", "Metabolite"]
.into_iter()
Expand Down Expand Up @@ -220,7 +225,7 @@ fn ui_settings(

ui.checkbox(&mut state.zero_white, "Zero as white");

if let Some(first_cond) = state.conditions.get(0) {
if let Some(first_cond) = state.conditions.first() {
if !((first_cond.is_empty()) & (state.conditions.len() == 1)) {
let conditions = state.conditions.clone();
let condition = &mut state.condition;
Expand Down Expand Up @@ -248,7 +253,8 @@ fn ui_settings(
if ui.button("Image").clicked() {
screen_events.send(ScreenshotEvent {
path: state.screen_path.clone(),
})
});
state.hide = true;
}
ui.text_edit_singleline(&mut state.screen_path);
})
Expand Down
15 changes: 9 additions & 6 deletions src/info.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Information to show in the UI.
use crate::funcplot::lerp;
use crate::funcplot::{lerp, IgnoreSave};
use std::time::Duration;

use bevy::prelude::*;
Expand Down Expand Up @@ -78,11 +78,14 @@ fn spawn_info_box(mut commands: Commands, top: f32, right: f32) {
.insert(InfoBox)
.insert(Interaction::default())
.with_children(|p| {
p.spawn(TextBundle {
focus_policy: bevy::ui::FocusPolicy::Block,
z_index: ZIndex::Global(12),
..Default::default()
});
p.spawn((
TextBundle {
focus_policy: bevy::ui::FocusPolicy::Block,
z_index: ZIndex::Global(12),
..Default::default()
},
IgnoreSave,
));
});
}

Expand Down
5 changes: 2 additions & 3 deletions src/legend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ use crate::{
};

mod setup;
use setup::{
spawn_legend, LegendArrow, LegendBox, LegendCircle, LegendCondition, LegendHist, Xmin,
};
use setup::{spawn_legend, LegendArrow, LegendBox, LegendCircle};
pub use setup::{LegendCondition, LegendHist, Xmax, Xmin};

/// Procedural legend generation.
pub struct LegendPlugin;
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod screenshot;
mod tests;

use escher::{EscherMap, EscherPlugin, MapState};
use screenshot::{RawAsset, RawFontStorage};

#[cfg(not(target_arch = "wasm32"))]
fn main() {
Expand Down Expand Up @@ -199,6 +200,9 @@ fn setup_system(mut commands: Commands, asset_server: Res<AssetServer>) {
reaction_data: None,
loaded: false,
});
let fira: Handle<RawAsset> = asset_server.load("fonts/FiraSans-Bold.tttx");
let assis: Handle<RawAsset> = asset_server.load("fonts/Assistant-Regular.tttx");
commands.insert_resource(RawFontStorage { fira, assis });

commands
.spawn(Camera2dBundle {
Expand Down
Loading
Loading