Skip to content

Commit

Permalink
Merge pull request #1 from JanCVanB/expand_config
Browse files Browse the repository at this point in the history
Expand config to do a lot more
  • Loading branch information
JanCVanB authored Feb 19, 2022
2 parents 6d36da6 + be747b2 commit 4a12599
Show file tree
Hide file tree
Showing 21 changed files with 521 additions and 111 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Roc platforms for drawing plots with Plotters
# Roc platform for drawing plots with Plotters

[Roc](https://roc-lang.org/)
+
[Plotters](https://github.com/38/plotters)
= <3

![hello world example image](./examples/hello_world.png)
![hello world example image](./examples/hello_world.svg)

## How to example

Expand Down
Binary file added examples/hello_world.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/hello_world.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 44 additions & 9 deletions examples/hello_world.roc
Original file line number Diff line number Diff line change
@@ -1,12 +1,47 @@
app "hello_world"
packages { pf: "../platforms/bitmap-chart" }
imports []
provides [ options ] to pf
packages { pf: "../platform" }
imports [ pf.Config.{blue, green, red, cyan} ]
provides [ config ] to pf

options = {
outputFilePath: "./examples/hello_world.png",
title: "Hello, World!",
subtitle: "These strings are coming from Roc :)",
width: 1024,
height: 768,
config =
{
outputFilePath: "./examples/hello_world.svg",
title: "Hello, World!",
subtitle: "",
width: 1024,
height: 768,
lines: [
{ name: "cosine", color: green, points: cos },
{ name: "cosine x 2", color: cyan, points: cosX2 },
{ name: "sine", color: blue, points: sin },
{ name: "sine x 2", color: red, points: sinX2 },
],
bounds: {
xMin: -3.2,
xMax: 3.2,
yMin: -2.1,
yMax: 2.1,
},
fonts: {
titleFamily: "sans-serif",
titleSize: 60,
subtitleFamily: "sans-serif",
subtitleSize: 40,
},
labels: {
xCount: 20,
yCount: 10,
},
layout: {
chartMargin: 5,
labelArea: 50,
},
}

pi = 3.141592653589793
ok = \r -> Result.withDefault r 0
domain = List.range -100 101 |> List.map (\i -> pi * (Num.toFloat i) / 100 |> ok)
cos = domain |> List.map (\x -> P2 x (Num.cos x))
sin = domain |> List.map (\x -> P2 x (Num.sin x))
cosX2 = domain |> List.map (\x -> P2 x (2 * Num.cos x))
sinX2 = domain |> List.map (\x -> P2 x (2 * Num.sin x))
207 changes: 207 additions & 0 deletions examples/hello_world.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
2 changes: 1 addition & 1 deletion platforms/bitmap-chart/Cargo.toml → platform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ name = "host"
path = "src/main.rs"

[dependencies]
roc_std = { path = "../../roc/roc_std" }
roc_std = { path = "../roc/roc_std" }
libc = "0.2"
plotters = "0.3.1"

Expand Down
70 changes: 70 additions & 0 deletions platform/Config.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
interface Config
exposes [ Config, black, white, red, green, blue, cyan, magenta, yellow ]
imports []

Bounds :
{
xMin: F64,
xMax: F64,
yMin: F64,
yMax: F64,
}

# TODO: probably move some of this into a different module.
Color :
{
r: U8,
g: U8,
b: U8,
}

black = { r: 0, g: 0, b: 0 }
white = { r: 255, g: 255, b: 255 }
red = { r: 255, g: 0, b: 0 }
green = { r: 0, g: 255, b: 0 }
blue = { r: 0, g: 0, b: 255 }
cyan = { r: 0, g: 255, b: 255 }
magenta = { r: 255, g: 0, b: 255 }
yellow = { r: 255, g: 255, b: 0 }

Fonts :
{
titleFamily: Str,
titleSize: U32,
subtitleFamily: Str,
subtitleSize: U32,
}

Labels :
{
xCount: Nat,
yCount: Nat,
}

Layout :
{
chartMargin: U32,
labelArea: U32,
}

Line :
{
name: Str,
color: Color,
points: List [P2 F64 F64],
}

# TODO: Make this a `List` and support it in the platform (with `Vec`?)
Config :
{
outputFilePath : Str,
title : Str,
subtitle : Str,
width : U32,
height : U32,
lines : List Line,
bounds : Bounds,
fonts : Fonts,
labels : Labels,
layout : Layout,
}
9 changes: 9 additions & 0 deletions platform/Package-Config.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
platform "roc-plotters/bitmap-chart"
requires {} { config : Config }
exposes [ Config ]
packages {}
imports [ Config.{ Config } ]
provides [ configForHost ]

configForHost : Config
configForHost = config
File renamed without changes.
File renamed without changes.
81 changes: 81 additions & 0 deletions platform/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use roc_std::{RocList, RocStr};

#[derive(Default, Debug, Copy, Clone)]
#[repr(C)]
pub struct P2 {
pub x: f64,
pub y: f64,
}

#[derive(Default, Debug, Copy, Clone)]
#[repr(C)]
pub struct Bounds {
pub xMax: f64,
pub xMin: f64,
pub yMax: f64,
pub yMin: f64,
}

#[derive(Default, Debug, Copy, Clone)]
#[repr(C)]
pub struct Color {
pub b: u8,
pub g: u8,
pub r: u8,
}

#[derive(Default, Debug)]
#[repr(C)]
pub struct Fonts {
pub subtitleFamily: RocStr,
pub titleFamily: RocStr,
pub subtitleSize: u32,
pub titleSize: u32,
}

#[derive(Default, Debug)]
#[repr(C)]
pub struct Labels {
pub xCount: usize,
pub yCount: usize,
}

#[derive(Default, Debug)]
#[repr(C)]
pub struct Layout {
pub chartMargin: u32,
pub labelArea: u32,
}

#[derive(Default, Debug)]
#[repr(C)]
pub struct Line {
pub name: RocStr,
pub points: RocList<P2>,
pub color: Color,
}

#[derive(Default, Debug)]
#[repr(C)]
pub struct Config {
pub bounds: Bounds,
pub fonts: Fonts,
pub labels: Labels,
pub lines: RocList<Line>,
pub output_file_path: RocStr,
pub subtitle: RocStr,
pub title: RocStr,
pub height: u32,
pub layout: Layout,
pub width: u32,
}

pub fn roc_config() -> Config {
extern "C" {
#[link_name = "roc__configForHost_1_exposed_generic"]
fn call(_: &mut Config);
}
let mut config = Config::default();
unsafe { call(&mut config) };
dbg!(config)
}
13 changes: 13 additions & 0 deletions platform/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::config::roc_config;
use crate::plot::plot;

pub mod config;
pub mod memory;
pub mod plot;

#[no_mangle]
pub extern "C" fn rust_main() -> i32 {
let config = roc_config();
plot(&config);
0
}
File renamed without changes.
File renamed without changes.
93 changes: 93 additions & 0 deletions platform/src/plot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use crate::config::Config;
use plotters::coord::Shift;
use plotters::prelude::*;

pub fn plot(config: &Config) {
let is_svg = config.output_file_path.as_str().ends_with(".svg");
if is_svg {
let backend = construct_svg_backend(config);
plot_with(backend, config).expect("failed to plot with svg backend");
} else {
let backend = construct_bitmap_backend(config);
plot_with(backend, config).expect("failed to plot with bitmap backend");
}
}

fn construct_area<Backend: DrawingBackend>(
backend: Backend,
config: &Config,
) -> Result<DrawingArea<Backend, Shift>, DrawingAreaErrorKind<Backend::ErrorType>> {
let area = backend.into_drawing_area();
area.fill(&WHITE)?;
let area = area.titled(
config.title.as_str(),
(config.fonts.titleFamily.as_str(), config.fonts.titleSize),
)?;
Ok(area)
}

fn construct_builder<'a, Backend: DrawingBackend>(
area: &'a DrawingArea<Backend, Shift>,
config: &'a Config,
) -> ChartBuilder<'a, 'a, Backend> {
let subtitle = config.subtitle.as_str();
let mut builder = ChartBuilder::on(area);
builder.margin(config.layout.chartMargin)
.set_all_label_area_size(config.layout.labelArea);
if subtitle.len() > 0 {
builder.caption(
config.subtitle.as_str(),
(config.fonts.subtitleFamily.as_str(), config.fonts.subtitleSize),
);
}
return builder;
}

fn construct_bitmap_backend(config: &Config) -> BitMapBackend {
BitMapBackend::new(
config.output_file_path.as_str(),
(config.width, config.height),
)
}

fn construct_svg_backend(config: &Config) -> SVGBackend {
SVGBackend::new(
config.output_file_path.as_str(),
(config.width, config.height),
)
}

fn plot_with<Backend: DrawingBackend>(
backend: Backend,
config: &Config,
) -> Result<(), DrawingAreaErrorKind<Backend::ErrorType>> {
let area = construct_area(backend, config)?;
let mut builder = construct_builder(&area, config);
let mut context = builder.build_cartesian_2d(
config.bounds.xMin..config.bounds.xMax,
config.bounds.yMin..config.bounds.yMax,
)?;
context.configure_mesh()
.x_labels(config.labels.xCount)
.y_labels(config.labels.yCount)
.disable_mesh()
.x_label_formatter(&|v| format!("{:?}", v)) // TODO: Format labels in Roc.
.y_label_formatter(&|v| format!("{:?}", v)) // TODO: Format labels in Roc.
.draw()?;
for line in config.lines.iter() {
let v: Vec<(f64, f64)> = line.points.iter().map(|point| (point.x, point.y)).collect();
let color = RGBColor(line.color.r, line.color.g, line.color.b);
context.draw_series(LineSeries::new(v, color))?
.label(line.name.as_str())
.legend(move |(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], color));
}
context.configure_series_labels().border_style(&BLACK).draw()?;
area.present().unwrap_or_else(|_| {
panic!(
"I failed to draw your plot to {} !",
config.output_file_path.as_str(),
)
});
println!("I drew your plot to {}", config.output_file_path.as_str());
Ok(())
}
23 changes: 0 additions & 23 deletions platforms/bitmap-chart/Package-Config.roc

This file was deleted.

16 changes: 0 additions & 16 deletions platforms/bitmap-chart/src/lib.rs

This file was deleted.

Loading

0 comments on commit 4a12599

Please sign in to comment.