I'm trying to draw car trips on a plane. I'm using Plotters library.
Here is some code example of trips' drawing procedure:
pub fn save_trips_as_a_pic<'a>(trips: &CarTrips, resolution: (u32, u32))
{
// Some initializing stuff
/// <...>
let root_area =
BitMapBackend::new("result.png", (resolution.0, resolution.1)).into_drawing_area();
root_area.fill(&WHITE).unwrap();
let root_area =
root_area.margin(10,10,10,10).titled("TITLE",
("sans-serif", 20).into_font()).unwrap();
let drawing_areas =
root_area.split_evenly((cells.1 as usize, cells.0 as usize));
for (index, trip) in trips.get_trips().iter().enumerate(){
let mut chart =
ChartBuilder::on(drawing_areas.get(index).unwrap())
.margin(5)
.set_all_label_area_size(50)
.build_ranged(50.0f32..54.0f32, 50.0f32..54.0f32).unwrap();
chart.configure_mesh().x_labels(20).y_labels(10)
.disable_mesh()
.x_label_formatter(&|v| format!("{:.1}", v))
.y_label_formatter(&|v| format!("{:.1}", v))
.draw().unwrap();
let coors = trip.get_points();
{
let draw_result =
chart.draw_series(series_from_coors(&coors, &BLACK)).unwrap();
draw_result.label(format!("TRIP {}",index + 1)).legend(
move |(x, y)|
PathElement::new(vec![(x, y), (x + 20, y)], &random_color));
}
{
// Here I put red dots to see exact nodes
chart.draw_series(points_series_from_trip(&coors, &RED));
}
chart.configure_series_labels().border_style(&BLACK).draw().unwrap();
}
}
What I got now on Rust Plotters:
So, after drawing it in the 'result.png' image file, I struggle to understand these "lines", because I don't see the map itself. I suppose, there is some way in this library to put a map "map.png" in the background of the plot. If I would use Python, this problem will be solved like this:
# here we got a map image;
img: Image.Image = Image.open("map-image.jpg")
img.putalpha(64)
imgplot = plt.imshow(img)
# let's pretend that we got our map size in pixels and coordinates
# just in right relation to each other.
scale = 1000
x_shift = 48.0
y_shift = 50.0
coor_a = Coordinate(49.1, 50.4)
coor_b = Coordinate(48.9, 51.0)
x_axis = [coor_a.x, coor_b.x]
x_axis = [(element-x_shift) * scale for element in x_axis]
y_axis = [coor_a.y, coor_b.y]
y_axis = [(element-y_shift) * scale for element in y_axis]
plt.plot(x_axis, y_axis, marker='o')
plt.show()
Desired result on Python
Well, that's easy on Python, but I got no idea, how to do similar thing on Rust.
Related
I am trying stuff out with plotter-rs and I wanted to create an histogram with float values ranging from 0.0f64 to 1.0f64 and have like 50 segments.
Following is what I have been trying. .build_cartesion_2d() is the part that creates bars with a define range on the x and y axis.
use plotters::prelude::*;
use tch::{kind,Tensor};
let path = path.unwrap_or("plots/0.png");
let root = BitMapBackend::new(path, (1280, 720)).into_drawing_area();
root.fill(&WHITE)?;
let mut chart = ChartBuilder::on(&root)
.set_label_area_size(LabelAreaPosition::Left, 40)
.set_label_area_size(LabelAreaPosition::Bottom, 40)
.caption("Histogram", ("sans-serif", 40))
.build_cartesian_2d((0i64..10).into_segmented(), 0i64..100)
.unwrap();
chart.configure_mesh().draw().unwrap();
let t = Tensor::rand(&[100], kind::FLOAT_CPU);
t.print();
let data: ndarray::ArrayD<f64> = (&t).try_into().unwrap();
root.draw_series(
Histogram::vertical(&chart)
.style(BLUE.filled())
.margin(10)
.data(data.map(|x| (((x*100.).round()/100.) as i64, 1))),
).unwrap();
Cargo.toml :
[package]
name = "test-rs"
version = "0.1.0"
edition = "2021"
[dependencies]
ndarray = "0.15.6"
plotters = "0.3.4"
tch = "0.10.1"```
I am attempting to recreate this example as a test for a flow diagram for a project I am working on: https://dannyjnwong.github.io/STROBE-CONSORT-Diagrams-in-R/
That page shows the code should result in a diagram that looks like this: https://dannyjnwong.github.io/figures/2018-02-12-STROBE-CONSORT-Diagrams-in-R/STROBE.png
However, when I try running the same exact code in RStudio I get this instead, the horizontal arrows do not render as horizontal, they instead curve downwards:
Is there any way to force these arrows to be straight and horizontal as they are in the github example? Could it perhaps be related to the version of DiagrammeR? That post uses DiagrammeR_0.9.2 while mine is using DiagrammeR_1.0.6.1 I would like to avoid having to roll back my version of the package if possible. Thanks!
I use ortho splines with DiagrammeR to get horizontal lines in my flowcharts. I tried using add_global_graph_attrs with create_graph in your example which produced horizontal lines but did not keep the architecture intact.
Here is how I have made similar graphs. I use glue for convenience to insert specific values and text in the flowchart. Perhaps this may be helpful for you.
library(DiagrammeR)
library(glue)
n <- 1000
exclude1 <- 100
exclude2 <- 50
include1 <- n - exclude1 - exclude2
grViz(
glue("digraph my_flowchart {{
graph[splines = ortho]
node [fontname = Helvetica, shape = box, width = 4, height = 1]
node1[label = <Total available patients<br/>(n = {n})>]
blank1[label = '', width = 0.01, height = 0.01]
excluded1[label = <Excluded because of<br/>exclusion criteria (n={exclude1})>]
node1 -> blank1[dir = none];
blank1 -> excluded1[minlen = 2];
{{ rank = same; blank1 excluded1 }}
blank2[label = '', width = 0.01, height = 0.01]
excluded2[label = <Excluded because of missing values (n={exclude2})>]
blank1 -> blank2[dir = none];
blank2 -> excluded2[minlen = 2];
{{ rank = same; blank2 excluded2 }}
node2[label = <Included for analysis<br/>(n={include1})>]
blank2 -> node2;
node3[label = <Data linked with<br/>external dataset>]
node2 -> node3;
}}")
)
Note: a couple of efforts have been made to construct CONSORT diagrams:
https://github.com/higgi13425/ggconsort
https://github.com/tgerke/ggconsort
Diagram
I tried to make a simple application which solves ode for given starting value y_0.
For example we can have:
dy/dt = -2ty
Using some tutorials (scilab site and a youtube tutorial) I arrive at current version:
function dy = f(t,y)
dy = -2*t*y;
endfunction
function updatePlot()
clf(right)
y0 = get(y0CONTROL,"value");
t0 = 0;
t = 0:0.1:10
solution = ode(y0,t0,t,f);
plot(solution, right)
endfunction
gui = figure();
gui.visible = "on";
gui.immediate_drawing = "on";
left = uicontrol(gui,...
'style','frame',...
'layout','gridbag',...
'constraints', createConstraints('border', 'left',))
right = uicontrol(gui,...
'style','frame',...
'layout','border',...
'constraints', createConstraints('border', 'center'))
y0CONTROL = uicontrol(left, ...
'style','slider', ...
'max', 10, ...
'min', -10, ...
'value',-1,...
'callback', 'updatePlot')
updatePlot()
As one can see I attempted to use clf(right) to clear previous graph and plot(solution,right) to plot in now presumably empty right frame.
And yet this attempt fails - old lines stay on the graph after movement of the slider.
Please tell me how to correct this.
a more smooth solution is just to change the curve data:
function updatePlot()
y0CONTROL;
y0 = y0CONTROL.value
curve=y0CONTROL.user_data
t0 = 0;
t = 0:0.1:10
solution = ode(y0,t0,t,f);
if curve==[] then //first call
plot(t,solution)
curve=gce().children(1); //the handle on the curve
y0CONTROL.user_data=curve;
else //other calls
ax=gca();
ax.data_bounds(:,2)=[min(solution);max(solution)];
curve.data(:,2)=solution.';
end
endfunction
gui = figure();
ax=gca();
gui.visible = "on";
gui.immediate_drawing = "on";
y0CONTROL = uicontrol(gui, ...
'style','slider', ...
'position',[20 20 100 20],...
'max', 10, ...
'min', -10, ...
'value',-1,...
'callback', 'updatePlot()',...
'user_data',[])
ax.background=-2;
updatePlot()
It turns out that refreshing effect can be achieved by substituting
clf(right)
with
current_axes = gca()
delete(current_axes)
This was useful.
How can I find a point ( C (x,y,z) ) between 2 points ( A(x,y,z) , B(x,y,z) ) in a thgree.js scene?
I know that with this: mid point I can find the middle point between them, but I don't want the middle point, I want to find the point which is between them and also has distance a from the A point?
in this picture you can see what I mean :
Thank you.
Basically you need to get the direction vector between the two points (D), normalize it, and you'll use it for getting the new point in the way: NewPoint = PointA + D*Length.
You could use length normalized (0..1) or as an absolute value from 0 to length of the direction vector.
Here you can see some examples using both methods:
Using absolute value:
function getPointInBetweenByLen(pointA, pointB, length) {
var dir = pointB.clone().sub(pointA).normalize().multiplyScalar(length);
return pointA.clone().add(dir);
}
And to use with percentage (0..1)
function getPointInBetweenByPerc(pointA, pointB, percentage) {
var dir = pointB.clone().sub(pointA);
var len = dir.length();
dir = dir.normalize().multiplyScalar(len*percentage);
return pointA.clone().add(dir);
}
See it in action: http://jsfiddle.net/8mnqjsge/
Hope it helps.
I know the question is for THREE.JS and I end up looking for something similar in Babylon JS.
Just in case if you are using Babylon JS Vector3 then the formula would translate to:
function getPointInBetweenByPerc(pointA, pointB, percentage) {
var dir = pointB.clone().subtract(pointA);
var length = dir.length();
dir = dir.normalize().scale(length *percentage);
return pointA.clone().add(dir);
}
Hope it help somebody.
This is known as lerp between two points
e.g. in Three:
C = new Three.Vector3()
C.lerpVectors(A, B, a)
also in generic this is just a single lerp (linear interpolation) math (basically (a * t) + b * (1 - t)) on each axis. Lerp can be described as follows:
function lerp (a, b, t) {
return a + t * (b - a)
}
in your case (see above) :
A = {
x: lerp(A.x, B.x, a),
y: lerp(A.y, B.y, a),
z: lerp(A.z, B.z, a)
}
In the discussion of the colour colorMatrix:bias it reads :
This filter performs a matrix multiplication, as follows, to transform the color vector:
s.r = dot(s, redVector) s.g = dot(s, greenVector) s.b = dot(s, blueVector) s.a = dot(s, alphaVector) s = s + bias
Is there any way to gain access to the data values for the various colour vectors?
The discussion you're referring to, in the C4 documentation, refers to the process that a filter uses for calculating a matrix multiplication. This is actually just a description of what the filter does to the colors in the image when it gets applied.
In fact, what's happening under the hood is that the colorMatrix: method sets up a CIFilter called CIColorMatrix and applies this to a C4Image. Unfortunately the source code for the CIColorMatrix filter isn't provided by Apple.
So, a longwinded answer to your question is:
You can't access color components for pixels in a C4Image through the CIColorMatrix filter. But, the C4Image class has a property called CGImage (e.g. yourC4Image.CGImage) which you can use to get pixel data.
A good, simple technique can be found HERE
EDIT:
I got obsessed last night with this question, and added these two methods to the C4Image class:
Method for loading pixel data:
-(void)loadPixelData {
NSUInteger width = CGImageGetWidth(self.CGImage);
NSUInteger height = CGImageGetHeight(self.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
bytesPerPixel = 4;
bytesPerRow = bytesPerPixel * width;
rawData = malloc(height * bytesPerRow);
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), self.CGImage);
CGContextRelease(context);
}
And a method for accessing pixel color:
-(UIColor *)colorAt:(CGPoint)point {
if(rawData == nil) {
[self loadPixelData];
}
NSUInteger byteIndex = bytesPerPixel * point.x + bytesPerRow * point.y;
CGFloat r, g, b, a;
r = rawData[byteIndex];
g = rawData[byteIndex + 1];
b = rawData[byteIndex + 2];
a = rawData[byteIndex + 3];
return [UIColor colorWithRed:RGBToFloat(r) green:RGBToFloat(g) blue:RGBToFloat(b) alpha:RGBToFloat(a)];
}
That's how I would apply the techniques from the other post I mentioned.