Completed first try at UIData.
[?]
CrEcTsRjb1hHQjHuumqRfqdbVV4X58iLEubi4noaDPFa
Jul 24, 2021, 9:13 AM
YAE43L6AF2HPQYJZDQGFYGFEV7722SUMAXXMP2ZQZMPE7VC6EWKACDependencies
- [2]
PK7JY27RIntegrate date_range with transforms. - [3]
GQVS55HIFinished generate_ts_spec() function. - [4]
PQKGZNQGAdded class field to GraphicJson. - [5]
BB2T6X3XImproved documentation. - [6]
UUD3CJZLMaking error handling more comprehensive. - [7]
2SABVMY3Finished into_json() functionality. - [8]
SAHJYVNBRemoved checking functionality. - [9]
EHEK63WACleaning up ts.rs. - [10]
77SIQZ3ESeparating out spec generation. - [11]
TSY4YBBZChanged ts Spec datastructures to new format. - [12]
E2T2A74YAdded class field to GraphicSpec. - [13]
K4CH53V4Added GPL2 license, included missing source files. - [14]
XPXYFEZMFinished code for building TSJson struct. - [15]
5B2HBV3JCompleted first try at ts Json data-structure. - [16]
XI5ALEH6Take advantage of keytree FromStr functionality. - [17]
SPSFTMLRCompleted loading ts_data from specification. - [18]
4QOTH75IFixed UI specification code. - [19]
TTR5IFSGWorking on building generic TSSpec. - [20]
2CCG6KUPRedo time-series spec. - [21]
YJXKWWM6Added max() min() n GraphicJson and cleaned up serialization - [*]
GUXZCEWWAdded Country enum. - [*]
4MG5JFXTFirst record.
Change contents
- replacement in src/ui.rs at line 3
#![allow(dead_code)]use std::collections::BTreeMap;use std::convert::TryInto;use std::fs; - replacement in src/ui.rs at line 7
use std::collections::HashMap;use std::convert::TryInto;use serde::Serialize; - edit in src/ui.rs at line 11
KeyTree, - replacement in src/ui.rs at line 19[3.364]→[3.8:22](∅→∅),[3.22]→[3.364:378](∅→∅),[3.364]→[3.364:378](∅→∅),[3.378]→[3.138:153](∅→∅),[3.153]→[3.23:43](∅→∅),[3.378]→[3.23:43](∅→∅),[3.43]→[3.0:17](∅→∅),[3.378]→[3.0:17](∅→∅)
DataSpec,DataType,DateRange,data_from_file,MonthlyDate,// DataSpec,DataType,// DateRange,// data_from_file,// MonthlyDate, - edit in src/ui.rs at line 25
SeriesJson,SeriesSpec,Transform, - replacement in src/ui.rs at line 31
// --- JSON Serializers -------------------------------------------------------------/// The top-level datastructure, served as JSON, that specifies all the data required to build a UI/// plot.pub struct UIJson(HashMap<(Country, usize), UIGraphicJson>);pub struct UIData(pub BTreeMap<(Country, usize), String>); - replacement in src/ui.rs at line 33
impl UIJson {#[derive(Debug, Serialize)]pub struct FixedScale {x_max: f32,x_min: f32,y_max: f32,y_min: f32,} - replacement in src/ui.rs at line 41
/// Create an empty `UIJson`.pub fn new() -> Self {UIJson(HashMap::new())}pub struct Json(BTreeMap<(Country, usize), GraphicJson>); - replacement in src/ui.rs at line 43
/// Insert a `UIGraphicJson` into `UIJson`. If the country already exists, increment the index/// in the key until a space is available.pub fn insert(&mut self, ui_graphic_json: UIGraphicJson) {let mut ix = 0;while self.0.get(&(ui_graphic_json.country, 0)).is_none() {ix += 1;impl Json {pub fn into_ui_data(&self) -> Result<UIData, Error> {let mut map: BTreeMap<(Country, usize), String> = BTreeMap::new();for (key, value) in self.0.iter() {let json = serde_json::to_string(&value).map_err(|_| {failed_to_serialize_to_json(file!(),line!(),)})?;map.insert(*key, json); - replacement in src/ui.rs at line 57
self.0.insert((ui_graphic_json.country, ix), ui_graphic_json);}Ok(UIData(map))} - replacement in src/ui.rs at line 61
/// A UI plot. `UIGraphicJson` can be serialized to JSON.pub struct UIGraphicJson {country: Country,title: String,lines: Vec<UILineJson>,#[derive(Debug, Serialize)]pub struct GraphicJson {country: Country,index: usize,lines: Vec<LineJson>,sized: Option<FixedScale>, - replacement in src/ui.rs at line 69
/// A line in a UI plot. `UILineJson` can be serialized to JSON.pub struct UILineJson {data: RegularTimeSeries<2>,#[derive(Debug, Serialize)]pub struct LineJson {x_series_id: SeriesId,y_series_id: SeriesId,rts: RegularTimeSeries<2>,x_transforms: Vec<Transform>,y_transforms: Vec<Transform>, - replacement in src/ui.rs at line 78
// --- Specification ----------------------------------------------------------------pub struct Spec(Vec<GraphicSpec>); - replacement in src/ui.rs at line 80[3.475]→[3.475:491](∅→∅),[3.491]→[3.1115:1349](∅→∅),[3.1349]→[3.758:810](∅→∅),[3.758]→[3.758:810](∅→∅),[3.810]→[3.1350:1381](∅→∅),[3.1381]→[3.810:818](∅→∅),[3.810]→[3.810:818](∅→∅),[3.818]→[3.73:112](∅→∅)
/// ```/// ui:/// country: Australia/// index: 0////// time_series:/// data_type: u/// series: AUSURAMS_a/// time_series:/// data_type: i/// series: _/// line:/// x: 0/// y: 1/// transform: indent/// ```pub struct UISpec(Vec<UIGraphicSpec>);impl Spec { - replacement in src/ui.rs at line 82
impl UISpec {/// Read in ts specification from file./// ```/// let ts_spec = ts::Spec::from_file("ui_spec.keytree");/// ```pub fn from_file(path: &str) -> Result<Self, Error> {let source_spec = match fs::read_to_string(path) {Ok(ss) => ss,Err(err) => { return Err(failed_to_read_file(file!(),line!(),&err.to_string()))},};let kt = KeyTree::parse(&source_spec).unwrap();kt.to_ref().try_into().map_err(|err: keytree::error::Error| {keytree_error(file!(), line!(), &err.to_string())})} - replacement in src/ui.rs at line 103[3.1398]→[3.1398:1478](∅→∅),[3.1478]→[3.23:53](∅→∅),[3.53]→[3.1522:1572](∅→∅),[3.1522]→[3.1522:1572](∅→∅),[3.1572]→[3.54:60](∅→∅)
// Convert UISpec into UIJson.pub (crate) fn into_json(&self,data_spec: &DataSpec,root_path: &str) -> Result<UIJson, Error>{pub fn into_json(&self, root_path: &str) -> Result<Json, Error> { - replacement in src/ui.rs at line 105
let mut ui_json = UIJson::new();for ui_graphic_spec in &self.0 {let ui_graphic_json = ui_graphic_spec.into_json(data_spec,root_path,)?;ui_json.insert(ui_graphic_json);}Ok(ui_json)}}let mut json = BTreeMap::new(); - replacement in src/ui.rs at line 107
impl<'a> TryInto<UISpec> for KeyTreeRef<'a> {type Error = keytree::Error;for GraphicSpec {country,index,seriess,lines,} in &self.0 { - replacement in src/ui.rs at line 114[3.1071]→[3.147:214](∅→∅),[3.214]→[3.323:379](∅→∅),[3.379]→[3.267:277](∅→∅),[3.267]→[3.267:277](∅→∅),[3.277]→[3.1227:1235](∅→∅),[3.1227]→[3.1227:1235](∅→∅)
fn try_into(self) -> Result<UISpec, Self::Error> {Ok(UISpec(self.vec_at("ui_spec::ui_graphic")?))}}// GraphicJson builderlet mut graphic_json = GraphicJson {country: *country,index: *index,lines: Vec::new(),sized: None,}; - replacement in src/ui.rs at line 122
/// ```/// ui_graphic:/// country: Australia/// index: 0////// time_series:/// data_type: u/// series: AUSURAMS_a/// transform: ident/// time_series:/// data_type: i/// series: _/// transform: ident/// line:/// x: 0/// y: 1/// ```pub struct UIGraphicSpec {///pub country: Country,///pub title: String,///pub index: usize,///pub time_series: Vec<UITimeSeriesSpec>,///pub line: Vec<UILineSpec>,}for LineSpec {x,y,} in lines {let x_rts = match seriess.get(x) {Some(s) => s.read_data_with_transforms(*country, root_path)?,None => {return Err(failed_to_reference_series(file!(),line!(),&x.to_string(),))},}; - replacement in src/ui.rs at line 137
impl UIGraphicSpec {let y_rts = match seriess.get(y) {Some(series_json) => series_json.read_data_with_transforms(*country, root_path)?,None => {return Err(failed_to_reference_series(file!(),line!(),&y.to_string(),))},}; - replacement in src/ui.rs at line 148[3.1898]→[3.1898:1943](∅→∅),[3.1943]→[3.62:92](∅→∅),[3.92]→[3.1987:2120](∅→∅),[3.1987]→[3.1987:2120](∅→∅)
pub (crate) fn into_json(&self,data_spec: &DataSpec,root_path: &str) -> Result<UIGraphicJson, Error>{let mut v = Vec::new();for line_spec in &self.line {let rts = x_rts.zip_one_one(y_rts); - replacement in src/ui.rs at line 150
let x_time_series_spec = &self.time_series[line_spec.x];let y_time_series_spec = &self.time_series[line_spec.y];let line_json = line_spec.into_json(data_spec,x_time_series_spec,y_time_series_spec,root_path,).unwrap();v.push(line_json);}Ok(UIGraphicJson {country: self.country,title: self.title.clone(),lines: v,let line_json = LineJson {x_series_id: x.clone(),y_series_id: y.clone(),rts: rts,x_transforms: seriess.get(x).unwrap().transforms.clone(),y_transforms: seriess.get(y).unwrap().transforms.clone(),};graphic_json.lines.push(line_json); - replacement in src/ui.rs at line 160
)}json.insert((*country, *index), graphic_json);}Ok(Json(json))} - replacement in src/ui.rs at line 166
impl<'a> TryInto<UIGraphicSpec> for KeyTreeRef<'a> {impl<'a> TryInto<Spec> for KeyTreeRef<'a> { - replacement in src/ui.rs at line 169
fn try_into(self) -> Result<UIGraphicSpec, Self::Error> {fn try_into(self) -> Result<Spec, Self::Error> { - replacement in src/ui.rs at line 171[3.1573]→[3.1126:1154](∅→∅),[3.1154]→[3.380:719](∅→∅),[3.719]→[3.1680:1694](∅→∅),[3.1438]→[3.1680:1694](∅→∅),[3.1680]→[3.1680:1694](∅→∅)
UIGraphicSpec {country: self.value("ui_graphic::country")?,index: self.value("ui_graphic::index")?,title: self.value("ui_graphic::title")?,time_series: self.vec_at("ui_graphic::time_series")?,line: self.vec_at("ui_graphic::line")?,}Spec(self.vec_at("ui_spec::ui_graphic")?) - replacement in src/ui.rs at line 176[3.1942]→[3.1942:2013](∅→∅),[3.2013]→[3.1439:1493](∅→∅),[3.1493]→[3.2618:2774](∅→∅),[3.2618]→[3.2618:2774](∅→∅),[3.2774]→[3.2696:2742](∅→∅),[3.754]→[3.2804:2841](∅→∅),[3.2742]→[3.2804:2841](∅→∅),[3.2804]→[3.2804:2841](∅→∅),[3.2841]→[3.2743:2808](∅→∅)
/// An integer reference to a series, for x and y coordinates./// ```/// line:/// x: 0/// y: 1/// ```/// For instance in this example, x refers to the first time-series AUSURAMS_a, and y refers to the/// second time-series.pub struct UILineSpec {x: usize,y: usize,start_date: Option<MonthlyDate>,end_date: Option<MonthlyDate>,transform2: Transform2,pub struct GraphicSpec {pub country: Country,pub index: usize,pub seriess: BTreeMap<SeriesId, SeriesSpec>,pub lines: Vec<LineSpec>, - replacement in src/ui.rs at line 183
impl UILineSpec {impl<'a> TryInto<GraphicSpec> for KeyTreeRef<'a> {type Error = keytree::Error; - replacement in src/ui.rs at line 186[3.2830]→[3.2830:2875](∅→∅),[3.2875]→[3.93:118](∅→∅),[3.118]→[3.2914:3120](∅→∅),[3.2914]→[3.2914:3120](∅→∅)
pub (crate) fn into_json(&self,data: &DataSpec,x: &UITimeSeriesSpec,y: &UITimeSeriesSpec,root_path: &str) -> Result<UILineJson, Error>{x.assert_data_type(DataType::U)?;y.assert_data_type(DataType::Inf)?;fn try_into(self) -> Result<GraphicSpec, Self::Error> { - replacement in src/ui.rs at line 188[3.3121]→[3.3121:3240](∅→∅),[3.3240]→[3.154:224](∅→∅),[3.224]→[3.3314:3456](∅→∅),[3.3314]→[3.3314:3456](∅→∅),[3.3456]→[3.225:271](∅→∅),[3.271]→[3.3500:3538](∅→∅),[3.3500]→[3.3500:3538](∅→∅)
let x_data = x.time_series_data(data, root_path)?;let y_data = y.time_series_data(data, root_path)?;let range = DateRange::new(&self.start_date, &self.end_date);let xy_data = match self.transform2 {Transform2::Zip => {let mut xy_data = x_data.zip_one_one(y_data);xy_data.with_range(&range.0);xy_data}let v: Vec<SeriesSpec> = self.vec_at("graphic::series")?;let mut seriess = BTreeMap::new();for series_spec in v {seriess.insert(series_spec.series_id.clone(), series_spec); - edit in src/ui.rs at line 193
Ok(UILineJson {data: xy_data,})}} - edit in src/ui.rs at line 194[3.2879]→[3.2879:2929](∅→∅),[3.2929]→[3.1494:1527](∅→∅),[3.1527]→[3.2953:2954](∅→∅),[3.2953]→[3.2953:2954](∅→∅),[3.2954]→[3.1528:1587](∅→∅)
impl<'a> TryInto<UILineSpec> for KeyTreeRef<'a> {type Error = keytree::Error;fn try_into(self) -> Result<UILineSpec, Self::Error> { - replacement in src/ui.rs at line 195
UILineSpec {x: self.value("line::x")?,y: self.value("line::y")?,start_date: self.opt_value("line::start_date")?,end_date: self.opt_value("line::end_date")?,transform2: self.value("line::transform2")?,GraphicSpec {country: self.value("graphic::country")?,index: self.value("graphic::index")?,seriess,lines: self.vec_at("graphic::line")?, - replacement in src/ui.rs at line 205[3.2007]→[3.4223:4224](∅→∅),[3.4223]→[3.4223:4224](∅→∅),[3.5393]→[3.2198:2340](∅→∅),[3.2414]→[3.2414:2440](∅→∅),[3.2440]→[3.4501:4555](∅→∅)
/// ```/// time_series:/// data_type: u/// series: AUSURAMS_a/// transform: ident/// ```pub struct UITimeSeriesSpec {data_type: DataType,series_id: SeriesId,transform1: Transform1,pub struct LineSpec {x: SeriesId,y: SeriesId, - edit in src/ui.rs at line 209
impl UITimeSeriesSpec { - replacement in src/ui.rs at line 210[3.4583]→[3.4583:4747](∅→∅),[3.4747]→[3.200:436](∅→∅),[3.436]→[3.4836:4905](∅→∅),[3.4836]→[3.4836:4905](∅→∅),[3.4905]→[3.119:149](∅→∅),[3.149]→[3.4944:5014](∅→∅),[3.4944]→[3.4944:5014](∅→∅),[3.5014]→[3.437:1000](∅→∅),[3.268]→[3.5113:5119](∅→∅),[3.1000]→[3.5113:5119](∅→∅),[3.5113]→[3.5113:5119](∅→∅),[3.2491]→[3.5415:5417](∅→∅),[3.5119]→[3.5415:5417](∅→∅),[3.5415]→[3.5415:5417](∅→∅),[3.5558]→[3.5558:5559](∅→∅),[3.5559]→[3.2492:2570](∅→∅),[3.2596]→[3.2596:2660](∅→∅)
pub (crate) fn assert_data_type(&self, data_type: DataType) -> Result<(), Error> {if self.data_type == data_type {Ok(())} else {Err(data_type_mismatch(file!(),line!(),&self.data_type.to_string(),&data_type.to_string()))}}pub (crate) fn time_series_data(&self,data_spec: &DataSpec,root_path: &str) -> Result<RegularTimeSeries<1>, Error>{let series_spec = match data_spec.get_series_spec(&self.series_id) {Some(series_spec) => series_spec,None => {return Err(series_id_not_in_dataspec(file!(),line!(),&self.series_id.to_string()))},};data_from_file(series_spec.country,series_spec.data_type,series_spec.series_id,root_path)}}/// ```/// time_series:/// data_type: u/// series: AUSURAMS_a/// ```impl<'a> TryInto<UITimeSeriesSpec> for KeyTreeRef<'a> {impl<'a> TryInto<LineSpec> for KeyTreeRef<'a> { - replacement in src/ui.rs at line 213
fn try_into(self) -> Result<UITimeSeriesSpec, Self::Error> {fn try_into(self) -> Result<LineSpec, Self::Error> { - replacement in src/ui.rs at line 215
UITimeSeriesSpec {data_type: self.value("time_series::data_type")?,series_id: self.value("time_series::series")?,transform1: self.value("time_series::transform1")?,LineSpec {x: self.value("line::x")?,y: self.value("line::y")?, - edit in src/ui.rs at line 222[3.7102]→[3.7102:7103](∅→∅),[3.7103]→[3.1352:1720](∅→∅),[3.1720]→[3.7103:7104](∅→∅),[3.4027]→[3.7103:7104](∅→∅),[3.7103]→[3.7103:7104](∅→∅),[3.7104]→[3.1721:1873](∅→∅),[3.1873]→[3.4156:4157](∅→∅),[3.4156]→[3.4156:4157](∅→∅)
// fn parse_date(s: &str) -> Result<MonthlyDate, keytree::Error> {// let year = s[..=4].parse::<usize>().map_err(|err| keytree::Error(Box::new(keytree::ErrorKind::User(err.to_string()))))?;// let month = s[5..].parse::<usize>().map_err(|err| keytree::Error(Box::new(keytree::ErrorKind::User(err.to_string()))))?;// Ok(MonthlyDate::ym(year, month))// }// #[test]// fn test_parse_date() {// let s = "1999-03";// assert!(// parse_date(s),// MonthlyDate(1999, 3),// )// } - replacement in src/ts.rs at line 15
use crate::{ DataType, DateRange, MonthlyDate, SeriesId, SeriesMetaData, SeriesSpec };use crate::{ DataType, DateRange, MonthlyDate, SeriesId, SeriesJson, SeriesMetaData, SeriesSpec }; - edit in src/ts.rs at line 66[2.121]→[3.93:168](∅→∅),[3.130]→[3.93:168](∅→∅),[3.321]→[3.93:168](∅→∅),[3.168]→[3.321:353](∅→∅),[3.321]→[3.321:353](∅→∅)
// Title is displayed if Some otherwise no or default title displayed.title_opt: Option<String>, - edit in src/ts.rs at line 72[3.415]→[3.574:775](∅→∅),[3.775]→[3.415:467](∅→∅),[3.415]→[3.415:467](∅→∅),[3.467]→[2.122:148](∅→∅),[2.148]→[3.467:579](∅→∅),[3.467]→[3.467:579](∅→∅),[3.4915]→[3.4915:4916](∅→∅)
/// A component of `Json` that is a single data series. Series are referenced by graphics through an/// index, so that each series can be used multiple times, without being downloaded multiple times.#[derive(Debug, Serialize)]pub struct SeriesJson {series_id: SeriesId,rts: RegularTimeSeries<1>,meta: Option<SeriesMetaData>,transforms: Vec<Transform>,} - edit in src/ts.rs at line 124
let mut m_series: BTreeMap<SeriesId, (usize, SeriesJson)> = BTreeMap::new(); - edit in src/ts.rs at line 128
let mut m_series: BTreeMap<SeriesId, (usize, SeriesJson)> = BTreeMap::new(); - edit in src/ts.rs at line 130[3.199]→[2.149:317](∅→∅),[3.199]→[3.1308:1309](∅→∅),[2.317]→[3.1308:1309](∅→∅),[3.1308]→[3.1308:1309](∅→∅)
// if m_series.contains_key(series_id) {// println!("Duplicate series_id");// panic!()// }; - replacement in src/ts.rs at line 139
//Build graphics from graphics specification.// Build graphics from graphics specification. - edit in src/ts.rs at line 145
title_opt, - edit in src/ts.rs at line 148
// Construct GraphicJsonlet t_opt = match title_opt {Some(title_opt) => Some(title_opt.clone()),None => None,}; - replacement in src/ts.rs at line 154
Some(GraphicCategory::Collated) => GraphicCategory::Collated,Some(GraphicCategory::Collation) => GraphicCategory::Collation, - edit in src/ts.rs at line 172
// Sets the kind of text display under each graphic. - replacement in src/ts.rs at line 177
Some(GraphicCategory::Collated) => TextSpec::Link,Some(GraphicCategory::Collation) => TextSpec::Link, - edit in src/ts.rs at line 183
- edit in src/ts.rs at line 185
title_opt: t_opt, - edit in src/ts.rs at line 188
// Construct indices for series in GraphicJson - edit in src/ts.rs at line 189
// We have - edit in src/ts.rs at line 200
// dbg!(ix); - edit in src/ts.rs at line 207
- replacement in src/ts.rs at line 430
Collated,Collation, - replacement in src/ts.rs at line 444
"collation" => Ok(GraphicCategory::Collated),"collation" => Ok(GraphicCategory::Collation), - replacement in src/ts.rs at line 455
GraphicCategory::Collated => "collation",GraphicCategory::Collation => "collation", - edit in src/ts.rs at line 476
pub title_opt: Option<String>, - edit in src/ts.rs at line 492
title_opt: self.opt_value("graphic::title")?, - edit in src/ts.rs at line 507[3.1761]→[3.3809:3856](∅→∅),[3.7063]→[3.3809:3856](∅→∅),[3.3856]→[3.2332:2378](∅→∅),[3.2332]→[3.2332:2378](∅→∅),[3.2472]→[3.2472:2483](∅→∅)
if let Some(title) = &self.title_opt {kt.push_value(1, "title", title);} - edit in src/ts.rs at line 551[3.4285]
- replacement in src/main.rs at line 56
let ts_spec = ts::Spec::from_file("ts_spec.keytree").unwrap();// let ts_spec = ts::Spec::from_file("ts_spec.keytree").unwrap(); - replacement in src/main.rs at line 60
ts_spec.into_json(&root_dir).unwrap().into_ts_data().unwrap();// ts_spec.into_json(&root_dir).unwrap().into_ts_data().unwrap(); - edit in src/main.rs at line 73
// Step 5 - edit in src/main.rs at line 76
let ui_spec = ui::Spec::from_file("ui_spec.keytree").unwrap();// ui_spec.into_json(&root_dir).unwrap().into_ts_data().unwrap(); - replacement in src/lib.rs at line 173
// pub mod ui;pub mod ui; - replacement in src/lib.rs at line 523
category_opt: Some(GraphicCategory::Collated),title_opt: None,category_opt: Some(GraphicCategory::Collation), - edit in src/lib.rs at line 547
title_opt: None, - edit in src/lib.rs at line 771[3.17681]→[3.17681:17682](∅→∅),[3.17682]→[3.4001:4257](∅→∅),[3.4257]→[3.1497:1498](∅→∅),[3.1497]→[3.1497:1498](∅→∅),[3.1498]→[3.4258:4595](∅→∅)
// /// Return `Self` given a `series_id`.// pub fn from_series_id(series_id: &str, root_path: &str) -> Result<Self, Error> {// let sid = SeriesId::from_str(series_id).unwrap();// let data_spec = DataSpec::from_file(root_path)?;// let key = match data_spec.reverse.get(&sid) {// Some(key) => key,// None => { return Err(// series_id_not_in_dataspec(// file!(),// line!(),// &series_id.to_string()// )// )},// }; - edit in src/lib.rs at line 772
// match data_spec.map.get(&key) {// Some(series_specs) => {// Ok(// series_specs.iter()// .find(|series_spec| series_spec.series_id == sid)// .unwrap()// .clone()// )// },// None => unreachable!(),// }// } - replacement in src/lib.rs at line 777
let rts = self.read_data_without_transform(country, root_path)?;let mut rts = self.read_data_without_transform(country, root_path)?; - replacement in src/lib.rs at line 783
match transform {rts = match transform { - replacement in src/lib.rs at line 1143
let mut transforms: Vec<Transform> = self.vec_value("series::transforms")?;let mut transforms: Vec<Transform> = self.vec_value("series::transform")?; - edit in src/lib.rs at line 1246
}/// A component of `Json` that is a single data series. Series are referenced by graphics through an/// index, so that each series can be used multiple times, without being downloaded multiple times.#[derive(Debug, Serialize)]pub struct SeriesJson {series_id: SeriesId,rts: RegularTimeSeries<1>,meta: Option<SeriesMetaData>,transforms: Vec<Transform>,