milliams / plotlib Goto Github PK
View Code? Open in Web Editor NEWData plotting library for Rust
Home Page: https://plotlib.org
License: MIT License
Data plotting library for Rust
Home Page: https://plotlib.org
License: MIT License
Reading the 1.0 roadmap .png support seems to be planned. Is there anything ongoing for implementing this?
Otherwise, the easiest way seems to rely on an existing svg renderer like librsvg or resvg. Exporting an svg would consists of creating the svg root node, finding good export options and handing those over to the renderer.
The major downside of this approach, despite the increased compile times, is in my opinion the dependency on a system library like cairo or qt. resvg allows to choose from these, librsvg is based on cairo. Thus, it may be appropriate to hide these backends behind feature flags.
As a plus, many more image formats should be exportable. For resvg, I was able to export .bmp, .jpg, .png and probably more.
I could offer a hand for implementing this, just let me know about your preferences.
This issue tracks the features we want to add to showing grids.
I'm interested in doing some data exploration in Rust, and plotlib looks like it is a promising tool for helping to visualize some things, without having to go through the trouble of writing the data to file and plotting with Python or such.
Unfortunately, I'm having getting trouble starting up with plotlib at the moment. I'd primarily like to focus on an issue I'm having with the first function in the tests file, test_no_data.rs
, called test_data_with_one_length()
. This seems like sort of the basic "Hello, world!" of the running a scatter graph, although the current example listed on home page README
also doesn't compile at the moment. For reference, I'm using Rust 1.32.0-stable, on Ubuntu 18.04 LTS. My cargo.toml
file has the most recent crate available, plotlib = "0.3"
.
The function test_data_with_one_length()
has the following code, which I'm using in main()
:
// Scatter plots expect a list of pairs
let data1 = [(-3.0, 2.3)];
// We create our scatter plot from the data
let s1 = Scatter::from_slice(&data1).style(
scatter::Style::new()
.marker(Marker::Square) // setting the marker to be a square
.colour("#DD3355"),
); // and a custom colour
// The 'view' describes what set of data is drawn
let v = ContinuousView::new()
.add(&s1)
.x_range(-5., 10.)
.y_range(-2., 6.)
.x_label("Some varying variable")
.y_label("The response of something");
// A page with a single view is then saved to an SVG file
Page::single(&v)
.save("/tmp/scatter_one_length.svg")
.unwrap();
This produces three main errors:
ContinuousView
is not an available function. I've confirmed this with the crates.io
documentation, and when let v = ContinuousView::new()
is replaced with View::new()
, the error goes away.Scatter::from_slice(&data1)
is not valid, as the ::as_slice()
method doesn't appear in the documentation at all. However, when this is replaced with ::from_vec()
instead, this error disappears as well.unwrap()
doesn't appear to be implemented for Page::save()
, but we can put a quick hold on error handling and remove that for the time being.At this point, cargo build
finishes successfully. However, when I try actually running this example, the program panics with the following message:
thread 'main' panicked at 'assertion failed: lower < upper', /home/chrism/.cargo/registry/src/github.com-1ecc6299db9ec823/plotlib-0.3.0/src/axis.rs:15:9
I don't have an obvious solution for fixing this (since the numbers in the axis ranges seem valid) according to the axis.rs
bounds checker, so wanted to bring it to your attention. I'm looking forward to have a native library like this be available (as I'm sure others are), and appreciate the time you've put into it so far. Thanks, and if you have any questions on reproducing these bugs, please let me know.
Hello I'm having troubles using your library, I'm hoping maybe you could help me and we could add the code to your examples.
I'm trying to reimplement this python
import matplotlib.pyplot as plt
alphabet = "abcdefghijklmnopqrstuvwxyz"
# Get Message from user
message = "This is a long message"
letter_counts = [message.count(l) for l in alphabet]
letter_colors = plt.cm.hsv([0.8*i/max(letter_counts) for i in letter_counts])
plt.bar(range(26), letter_counts, color=letter_colors)
plt.xticks(range(26), alphabet) # letter labels on x-axis
plt.tick_params(axis="x", bottom=False) # no ticks, only labels on x-axis
plt.title("Frequency of each letter")
plt.savefig("output.png")
into rust
so far what I'm working with is
use std::collections::btree_map::BTreeMap;
use plotlib::style::BarChart;
fn main() {
let message: &str = "This is a long message";
let mut count = BTreeMap::new();
for c in message.trim().to_lowercase().chars() {
if c.is_alphabetic() {
*count.entry(c).or_insert(0) += 1
}
}
println!("Number of occurences per character");
for (ch, count) in &count {
println!("{:?}: {}", ch, count);
let count = *count as f64;
plotlib::barchart::BarChart::new(count).label(ch.to_string());
}
let v = plotlib::view::CategoricalView::new();
plotlib::page::Page::single(&v)
.save("barchart.svg")
.expect("saving svg");
}
I'm not sure how to use data in the btree with plotlib,
I'm using version 0.4.0 by the way
Would be nice to have grouped bar charts, like this
https://chartio.com/assets/24e451/tutorials/charts/grouped-bar-charts/c1fde6017511bbef7ba9bb245a113c07f8ff32173a7c0d742a4e1eac1930a3c5/grouped-bar-example-1.png
I get no text output when trying to convert a categorical view to text. When writing to svg, like barchart example, I see them, but when trying to convert to text, the output is empty.
use plotlib::{
repr::BarChart,
style::BoxStyle,
view::{CategoricalView, View},
};
fn main() {
let b1 = BarChart::new(5.3).label("1");
let b2 = BarChart::new(2.6)
.label("2")
.style(&BoxStyle::new().fill("darkolivegreen"));
let v = CategoricalView::new()
.add(b1)
.add(b2)
.x_label("Experiment")
.to_text(20, 20)
.unwrap();
println!("{:?}", v);let v = CategoricalView::new()
.add(b1)
.add(b2)
.x_label("Experiment")
.to_text(20, 20)
.unwrap();
println!("{:?}", v);
}
This way, one can really imagine whether this example is the right fit for the job.
Sending a PR asap
Just an idea: to have an enum with the named colors for SVG, like "burlywood". However, this would maybe not work for other formats... but neither would the string "burlywood". The enum could have a variant Hex(u32)
or Hex(String)
.
So I am not sure; opening this for discussion.
Related to #22 I suppose. The files in the examples folder seem to work but the example in the README.md still produces errors:
error[E0432]: unresolved imports `plotlib::style::Marker`, `plotlib::style::Point`
--> src/main.rs:3:22
|
3 | use plotlib::style::{Marker, Point};
| ^^^^^^ ^^^^^ no `Point` in `style`
| |
| no `Marker` in `style`
error[E0433]: failed to resolve: could not find `Style` in `scatter`
--> src/main.rs:13:25
|
13 | .style(scatter::Style::new()
| ^^^^^ could not find `Style` in `scatter`
error[E0433]: failed to resolve: could not find `Style` in `scatter`
--> src/main.rs:20:25
|
20 | .style(scatter::Style::new() // uses the default marker
| ^^^^^ could not find `Style` in `scatter`
warning: unused import: `Point`
--> src/main.rs:3:30
|
3 | use plotlib::style::{Marker, Point};
| ^^^^^
|
= note: #[warn(unused_imports)] on by default
error[E0599]: no function or associated item named `new` found for type `dyn plotlib::view::View` in the current scope
--> src/main.rs:24:19
|
24 | let v = View::new()
| ------^^^
| |
| function or associated item not found in `dyn plotlib::view::View`
error: aborting due to 4 previous errors
Some errors occurred: E0432, E0433, E0599.
For more information about an error, try `rustc --explain E0432`.
Now you get an error because it selects y_max = y_min = y
Hey
I tried to implement a scattterplot similar to the example and noticed that I need to use use plotlib::scatter::Scatter;
instead of use plotlib::repr::Scatter;
as written in the example project.
The failure
crate that plotlib
depends on is deprecated. Are there plans to replace it?
Thanks for putting this together, outputting a SVG is a great fit for my CLI app, so looking forward to trying this out some more.
I've been experimenting using this package to plot some "real" data, and some of it is a little boring, including a series with only a single value, but unfortunately this panics on the 0.3.0
tag since the default axis calculation needs at least two different values in the series.
With
[dependencies]
plotlib= { git = "https://github.com/milliams/plotlib", tag = "0.3.0" }
a cut down version of the example in the readme, with a single value in data1
:
extern crate plotlib;
use plotlib::scatter::Scatter;
use plotlib::scatter;
use plotlib::style::{Marker, Point};
use plotlib::view::View;
use plotlib::page::Page;
fn main() {
// Scatter plots expect a list of pairs
let data1 = [(-3.0, 2.3)];
// We create our scatter plot from the data
let s1 = Scatter::from_vec(&data1)
.style(scatter::Style::new()
.marker(Marker::Square) // setting the marker to be a square
.colour("#DD3355")); // and a custom colour
// The 'view' describes what set of data is drawn
let v = View::new()
.add(&s1)
.x_range(-5., 10.)
.y_range(-2., 6.)
.x_label("Some varying variable")
.y_label("The response of something");
// A page with a single view is then saved to an SVG file
Page::single(&v).save("scatter.svg");
}
produces this error at runtime:
thread 'main' panicked at 'assertion failed: lower < upper', D:\rust\cargo\git\checkouts\plotlib-407c626431dc1ac2\8ed7480\src\axis.rs:15:9
stack backtrace:
0: std::sys::windows::backtrace::unwind_backtrace
at C:\projects\rust\src\libstd\sys\windows\backtrace\mod.rs:65
1: std::sys_common::backtrace::_print
at C:\projects\rust\src\libstd\sys_common\backtrace.rs:71
2: std::sys_common::backtrace::print
at C:\projects\rust\src\libstd\sys_common\backtrace.rs:59
3: std::panicking::default_hook::{{closure}}
at C:\projects\rust\src\libstd\panicking.rs:211
4: std::panicking::default_hook
at C:\projects\rust\src\libstd\panicking.rs:227
5: std::panicking::rust_panic_with_hook
at C:\projects\rust\src\libstd\panicking.rs:463
6: std::panicking::begin_panic<str*>
at C:\projects\rust\src\libstd\panicking.rs:397
7: plotlib::axis::Range::new
at D:\rust\cargo\git\checkouts\plotlib-407c626431dc1ac2\8ed7480\src\axis.rs:15
8: plotlib::view::View::default_x_range
at D:\rust\cargo\git\checkouts\plotlib-407c626431dc1ac2\8ed7480\src\view.rs:88
9: plotlib::view::View::create_axes
at D:\rust\cargo\git\checkouts\plotlib-407c626431dc1ac2\8ed7480\src\view.rs:103
10: plotlib::view::View::to_svg
at D:\rust\cargo\git\checkouts\plotlib-407c626431dc1ac2\8ed7480\src\view.rs:127
11: plotlib::page::Page::to_svg
at D:\rust\cargo\git\checkouts\plotlib-407c626431dc1ac2\8ed7480\src\page.rs:40
12: plotlib::page::Page::save<str*>
at D:\rust\cargo\git\checkouts\plotlib-407c626431dc1ac2\8ed7480\src\page.rs:68
13: plot_test::main
at .\src\main.rs:27
14: std::rt::lang_start::{{closure}}<()>
at C:\projects\rust\src\libstd\rt.rs:74
15: std::rt::lang_start_internal::{{closure}}
at C:\projects\rust\src\libstd\rt.rs:59
16: std::panicking::try::do_call<closure,i32>
at C:\projects\rust\src\libstd\panicking.rs:310
17: panic_unwind::__rust_maybe_catch_panic
at C:\projects\rust\src\libpanic_unwind\lib.rs:105
18: std::panicking::try
at C:\projects\rust\src\libstd\panicking.rs:289
19: std::panic::catch_unwind
at C:\projects\rust\src\libstd\panic.rs:374
20: std::rt::lang_start_internal
at C:\projects\rust\src\libstd\rt.rs:58
21: std::rt::lang_start<()>
at C:\projects\rust\src\libstd\rt.rs:74
22: main
23: invoke_main
at f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:78
24: __scrt_common_main_seh
at f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:283
25: BaseThreadInitThunk
26: RtlUserThreadStart
error: process didn't exit successfully: `target\debug\plot_test.exe` (exit code: 101)
It looks like the problem is that when there is a single data point, x_range
in scatter.ts
,
fn x_range(&self) -> (f64, f64) {
let mut min = f64::INFINITY;
let mut max = f64::NEG_INFINITY;
for &(x, _) in &self.data {
min = min.min(x);
max = max.max(x);
}
(min, max)
}
returns the same value for min
and max
, so the assert!(lower < upper);
fails.
It also fails if there are no entries in self.data
, since it will leave lower
as f64::INFINITY
and upper
as f64::NEG_INFINITY
.
I'm just getting started with Rust, but a pattern that I've seen in other code is to use a fold to produce values when the collection may be empty:
fn x_range(&self) -> Option<(f64, f64)> {
self.data.iter().fold(None, |result, &(x, _)| match result {
None => Some((x, x)),
Some((min, max)) => Some((min.min(x), max.max(x))),
})
}
That could be a fix for the no entries situation, for a single entry the assert probably needs to be relaxed, or the caller could define a default range of say min
to min + 1
if min == max
.
Hello, total noob here. How do I add a legend to my plot? In the docs it looks like legend is under plotlib::repr::Plot, but I'm not sure how to implement it. Cheers.
It seems like currently svg is rendered with transparent background.
I was able to change background color by changing this line to
let mut document = Document::new().set("viewBox", (0, 0, width, height)).set("style", "background-color:white");
Can we add an option to set background color of the plot ?
Page::save
silently does nothing when the file extension is not one of a supported format. It should return an error, in my opinion. The reason I make an issue instead of fixing it myself is: what error should it return?
I think we should use the failure
crate. But then the question is: should we make an enum for possible errors, or just bail!("some text message")
? Not sure what is common to do.
I think it might make sense to merge Line
and Scatter
types into a more general type.
They have common fields data: Vec<(f64, f64)>
, style: SomeStyle
, and in the future legend: Option<String>
.
My suggestion is to then distinguish between a line plot and a scatter plot, only through the style struct. The style struct could either be an enum or hold an enum - it needs some form of polymorphism. One idea could be (fast sketch):
struct Style {
color: String,
width: f64,
geometry:
}
enum Geometry {
Lines,
Circle,
Square,
Cross,
}
or enum Style { Lines {width: f64, .......}, Points {.....}}
is another idea.
My second suggestion is to get rid of Function
which is very similar to Line
, and instead just implement a fn on Line
for example pub fn from_function(f: Fn(f64) -> f64) -> Line
We should be able to collect the objects being plotted and create a legend. We need to know:
As seen in the line example one of the value on the y axis it's been formatted as something like 0.0000000012 while the other values are 1.0 2.0 and so on.
obviously, formatting with a fixed value of decimals could be wrong for other examples.
Is it possible to somehow recognize the float rounding based on the lenght of other values of the y ticks and dinamically found a rounding?
Lines 57 to 60 in c732707
vs
pub enum Cow<'a, B> where
B: 'a + ToOwned + ?Sized, {
Borrowed(&'a B),
Owned(<B as ToOwned>::Owned),
}
This struct exactly matches the std::borrow::Cow
type. Unless extra functionality is required, the stdlib type should probably be used.
There should be functionality to set the color of the text that labels each axis.
This is an overview issue to track all the feature we want before 1.0:
Documentation is lacking and various examples are not working. What plans do you have for the docs/examples? Are you working on this fulltime?
Please post a new version that updates these dependencies
It would also be great if it would be possible to fill them.
The SSL certificate for the website expired last week.
A view with categorical entries along the x-axis and continuous values along the y-axis
Is there any way to generate it flipped, i.e. categorical along Y axis and continuous along the X?
I had a problem when trying to save a figure, that generate_ticks(..)
in src/axis.rs
ran indefinitely (or until overflow happened in debug mode), with input min:-0.8230515814500334, max:-0.8230515813631452, step_size:0.00000000002
.
The problem is obviously that it starts at 0.0 and counts up 0.00000000002
at a time so that for example after 5 million iterations it is only at -0.0001
.
One solution could be to not start counting from 0.0, but rather from min
rounded to the nearest step_size
.
And so is quite useless.
The mod representation
needs to be public.
Hello,
In one of my projects using plotlib, (can be seen here), I'm overlaying several scatter plots in different colors into the same plot. In order of accomplish that, I'm using a pattern like the one below, which allows for an arbitrary number of individual scatter plots to be added to a single view. However, due to the borrow checker, and being unable to modify the ContinuousView
struct field representations
directly since it's not public, I've had to clone the library locally, modify it, and point my Cargo.toml
file there instead.
Would it be possible to open up those fields publicly? I realize it's typical to leave them private by default, but I'm not sure if there's a soundness or security implication that would get in the way. Alternatively, is there a more idiomatic way of doing this?
let mut scatter_plots: Vec<Plot> = Vec::new();
for i in 0..clusters.len() {
let mut rng = rand::thread_rng();
let color = format!("#{}", rng.gen_range(0, 999999).to_string()); // This is just a convenient way of coming up with different colors
let s: Plot = Plot::new(
vec![clusters[i].clone()] // clusters is of type Vec<Vec<(f64,f64)>>
)
.point_style(PointStyle::new().colour(color));
scatter_plots.push(c);
}
let mut v = ContinuousView::new()
.x_range(-5., 5.)
.y_range(-5., 5.)
.x_label("x-axis")
.y_label("y-axis");
for plot in scatter_plots {
v.representations.push(Box::new(plot.clone())); // Can't do this because the `representations` field is currently private.
// It compiles and works when I open that field publicly, though.
// v.add(plot.clone()); // Can't do this because Copy can't be implement on ContinuousView because of a String dependency, so the borrow checker doesn't like it
// I haven't found a way around this, since it seems to be based on language-level guarantees
}
None of the examples compile, probably due to the refactoring of modules hierarchy.
Also, it would be nice, if output images of examples are uploaded, because then it would be easier to glance the capabilities of this library.
I notice in #3 that @milliams is keen for lots more plot types
A plot I use a lot in matplotlib is the contour plot, i have some ideas as to how to do this in plotlib but before i get too carried away do you have firm ideas as to how to handle this sort of thing?
Would you welcome a PR adding such a plot?
PS I have been really enjoying using your lib so far, thanks to all involved!
I noticed that in #3 it was mentioned that Chrono's DateTime format will be implemented as one of the accepted types, was wondering whether this is in development or whether we should just convert to some value of time since Epoch?
Both x
and y
axis seperately. This would help exploratory data analysis a lot
Please feel free to link this.
Hi, I'm starting to use this crate to create plots as examples of my point process simulation library, and I thought it'd be nice if one could use custom dimensions for plots rather than the hard-coded ones.
Right now, I'm getting around it by getting the SVG document using the as_view()
method from the view::View
trait and manually saving the file.
If you'd like to, maybe I could make a pull request for this ?
Hi Matt,
First thing first thank you a lot for writing this lib: I love it (especially since it means I dont have to resrort to python to plot my graphs).
You've basically changed most of the APIs between 0.4.0 and 0.5.0, and thats perfectly fine (doc says api are in a state of flux) and I really like the new APIs however it turns out that I can no longer plot my graphs to terminal since I made the change (Saving to SVG is ok though).
As mentioned in the design philosophy on the wiki, I'd like to be able to automatically map representations to views by their dimension types.
For starters, this means consolidating the current DiscreteView
and ContinuousView
into one 2D view which can have either a continuous or discrete dimension on each axis. This means that we should be able to define a view as being continuous×continuous, continuous×discrete, discrete×continuous or discrete×discrete.
The user should then be able to take a BoxPlot
representation (which can be thought of as having an implicit discrete×continuous dimensionality) and map it to a continuous×discrete view so that it plots horizontally.
Before we jump into implementation, some questions:
Most of these suggestions, I will already implement locally as I work on my project (which uses plotlib to plot stuff). I will submit a PR after a while. Until then, I open this issue so that you may discuss or protest against some of my suggestions. I can then change or revert that point. So please state your opinion!
I will keep it updated as I think of new things.
I think that taking Box<MyTrait>
rather than &'a MyTrait
in general makes a better programming interface, eliminating lifetimes. Examples: Page::add_plot
and ContinuousView::add
both take references to traits. In fact I was forced to change the latter function to add(mut self, repr: Box<ContinuousRepresentation>)
because of lifetime issues in my project (more specifically, I created the data in a loop. The old solution would require me to store the data in a Vec and then loop again over that Vec to plot the data). It remains, however, to change to Box
in other functions. Done in #40
[PR #29] Naming: It's rather confusing to have struct line::Line
, struct line::Style
and also trait style::Line
. I think we should find some way to rename them. Especially try to not make the Line
s unique only through the module paths. We could for example name them struct Line
, struct LineStyle
and trait LineStyleTrait
.
[PR #29] Remove the Style
traits. I don't see the need for a trait for every kind of Style. The only one that has two implementors is style::Line
. However these two implementors are identical.
Naming: There are some opportunities for shorter names. Some words are quite commonly shortened, such as s/Representation/Repr
.
The only thing that is visible of the top-most number os 0000000005
, but it's actually 5.60000000005
.
Here is the svg file: http://sprunge.us/QdSTRO
Here is the input data to plotlib:
[(10.0, 5.554613094409367), (15.0, 5.571373799732846), (20.0, 5.580786175835321), (25.0, 5.594389457136185), (30.0, 5.588413866453277), (35.0, 5.581090728388583), (40.0, 5.564882932873482), (45.0, 5.5655230910515785), (50.0, 5.575694697314061), (55.0, 5.563091468885199), (60.0, 5.505139387304649), (65.0, 5.435932668847201), (70.0, 5.392844844207445), (75.0, 5.375070392542875), (80.0, 5.370750095478286), (85.0, 5.355376048261111), (90.0, 5.348519533974179), (95.0, 5.344626082423696), (100.0, 5.3274562508487024), (105.0, 5.329445069896911), (110.0, 5.330588028449412), (115.0, 5.335541125490482), (120.0, 5.32486693110636), (125.0, 5.326145859928657), (130.0, 5.3267627195905245), (135.0, 5.324000652981454), (140.0, 5.327175540775914), (145.0, 5.326936653662645), (150.0, 5.326319101633424), (155.0, 5.3195335123314775), (160.0, 5.318547022604354), (165.0, 5.318984347429394), (170.0, 5.317016756493654), (175.0, 5.320569820967218), (180.0, 5.321774086633875), (185.0, 5.3192970755289), (190.0, 5.308293371083831), (195.0, 5.286882630232821), (200.0, 5.264732108073603), (205.0, 5.254215082718998), (210.0, 5.242928735217475), (215.0, 5.229751139000503), (220.0, 5.202672283250928), (225.0, 5.180185883522078), (230.0, 5.156744670958561), (235.0, 5.134800944115094), (240.0, 5.127834870263292), (245.0, 5.121960601961146), (250.0, 5.115420107250173), (255.0, 5.1122765198698215), (260.0, 5.107215561118251), (265.0, 5.09911659020747), (270.0, 5.088330837894482), (275.0, 5.085926681262303), (280.0, 5.084239392471663), (285.0, 5.083673161411417), (290.0, 5.084211846974766), (295.0, 5.081707528453846), (300.0, 5.078245582248812)]
[(10.0, 5.554613094409367), (15.0, 5.571373799732846), (20.0, 5.580786175835321), (25.0, 5.594389457136185), (30.0, 5.588413866453277), (35.0, 5.585615659886031), (40.0, 5.587206724645493), (45.0, 5.571298729005933), (50.0, 5.558131825575247), (55.0, 5.544393316154019), (60.0, 5.53813614296059), (65.0, 5.523535700145619), (70.0, 5.4996913881052105), (75.0, 5.472378149492847), (80.0, 5.45374886101448), (85.0, 5.4324287369128195), (90.0, 5.410797420874291), (95.0, 5.393886671682631), (100.0, 5.361498295387429), (105.0, 5.320841464177755), (110.0, 5.277655355217769), (115.0, 5.242304398506202), (120.0, 5.220685015560172), (125.0, 5.197350800910618), (130.0, 5.180128027249545), (135.0, 5.165155622245212), (140.0, 5.157291822432492), (145.0, 5.160809304386804), (150.0, 5.1621050182918875), (155.0, 5.164784237269466), (160.0, 5.170044410029799), (165.0, 5.176610149099485), (170.0, 5.178943153694296), (175.0, 5.180969369533339), (180.0, 5.181202553209083), (185.0, 5.180421437704337), (190.0, 5.183487260078211), (195.0, 5.190838759095146), (200.0, 5.19805536865893), (205.0, 5.205331656977181), (210.0, 5.211848936948826), (215.0, 5.215886880659793), (220.0, 5.2191099964160355), (225.0, 5.214903056232922), (230.0, 5.209356626646803), (235.0, 5.210631952871428), (240.0, 5.212151991487046), (245.0, 5.214216204923996), (250.0, 5.206883052633969), (255.0, 5.207739240362648), (260.0, 5.207163350519838), (265.0, 5.205506780136554), (270.0, 5.207203657870471), (275.0, 5.206951561696365), (280.0, 5.208947475530317), (285.0, 5.20313975184542), (290.0, 5.204589733890532), (295.0, 5.205217982298412), (300.0, 5.202972315747025)]
[(10.0, 5.656477554152827), (15.0, 5.518753423352734), (20.0, 5.538369232714198), (25.0, 5.523798152568706), (30.0, 5.53725576641077), (35.0, 5.5218183424410014), (40.0, 5.523350461669418), (45.0, 5.531653410599423), (50.0, 5.519886110360921), (55.0, 5.495504075954746), (60.0, 5.483291143318121), (65.0, 5.485041358928483), (70.0, 5.49360138294122), (75.0, 5.4993546868179255), (80.0, 5.495793588413891), (85.0, 5.499689269619098), (90.0, 5.502345293847687), (95.0, 5.499380450456559), (100.0, 5.4860808187812), (105.0, 5.474888395868257), (110.0, 5.469030439040476), (115.0, 5.459149366952276), (120.0, 5.448213297843009), (125.0, 5.433420015075955), (130.0, 5.42028426873691), (135.0, 5.4039370730625), (140.0, 5.389449304230735), (145.0, 5.374739029115512), (150.0, 5.357460575330139), (155.0, 5.340662553581878), (160.0, 5.313241383144196), (165.0, 5.269444679770821), (170.0, 5.238487323826094), (175.0, 5.2086113937648335), (180.0, 5.189242228426556), (185.0, 5.1744945041051), (190.0, 5.159483304652246), (195.0, 5.14430017185943), (200.0, 5.117318556745862), (205.0, 5.10072786906999), (210.0, 5.084061503647151), (215.0, 5.075762136466544), (220.0, 5.068552343275285), (225.0, 5.062863726182678), (230.0, 5.051815330935621), (235.0, 5.031358091612719), (240.0, 5.021260071788471), (245.0, 5.010255285851625), (250.0, 5.003961940532494), (255.0, 4.99636579001612), (260.0, 4.987814326450532), (265.0, 4.980644666607665), (270.0, 4.963432971258708), (275.0, 4.956729825460665), (280.0, 4.948738350016256), (285.0, 4.943941669083361), (290.0, 4.93958132651051), (295.0, 4.933664938830087), (300.0, 4.928992049266768)]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.