YAE43L6AF2HPQYJZDQGFYGFEV7722SUMAXXMP2ZQZMPE7VC6EWKAC
PK7JY27R55PZON4SPFLJBX66IAE47SXBRAGDHXM4SN6TKZXO5LMAC
SPSFTMLRZE2R4EBAAQKWBUZDRYZ36S2VFTBIJRE6XS7JMKELV4AQC
GQVS55HIQLU7KPJNRMF57QUM4EATSWFQRCS7ZEJMJPUXFX2NHSYAC
TTR5IFSG25VNBQ2F2FNOLUMTEIHVBHFOEXYB2ZWEHWOURUV4GJMQC
SAHJYVNBUBBIUBI4ZMAXK4QJFOT54M5UA3W2HQMTNDSP3GGCRX7QC
2CCG6KUP6VL2Q7WQKLVNIPPGZWHSWIOWETRCS3APZTV4WSF5GLWAC
XI5ALEH6NPTQWB6O62QV62EP4H3K7WSNTHCOGT3LZIIU6I2YDGIQC
4QOTH75I2VINLY52J75OR3E3B5CN5ITHJGOAKQYXI6PH3XLJ6DBQC
XPXYFEZMZJSF2GOFG5HTCMLVHINNVRYIVWV7KJ6A7A3PG3CM2TGAC
PQKGZNQGSRWMV3D6AUUBH3JUICKXXKDV4OLLDUM3YP5ESORBYKLAC
5B2HBV3JTNBNJYEJ4BXFQDEP2D552SBJFPY6STKSK7SPFZYSTCFAC
BB2T6X3XK3Y4JFOMBGKTFVL6BZ5NOGBTPSCK4ADRSZQLQKQHESLAC
EHEK63WARL6PGYZMCSOH53JXOYPHNGWZO4QP5RKODPIQJ53IWDDQC
E2T2A74YPYLDPT2FCBLRJSJTDND2D5EDDRSXJZCUOQVEEIVCM2MAC
TSY4YBBZ4AEW2JTEI4AS5FGTTUZR5WE3TENDHVIOWWY6V2DRT7ZQC
GUXZCEWWPBCHXO26JVWZ74CTSDFDDO775YR7FKY7UGVZCA7GCSYAC
2SABVMY3A2RZDF3KJXZSMJ2UQ4Q5EW422G4DVBJRKK26S2ESGVQAC
4MG5JFXTKAE3SOVKGGNKEUTNCKOWEBHTGKVZHJWLWE3PTZTQKHPAC
UUD3CJZLSTAVLMIXIWE4CHN5HQSFM6K3DCPWECJMKGXDOROK4G4AC
DataSpec,
DataType,
DateRange,
data_from_file,
MonthlyDate,
// DataSpec,
DataType,
// DateRange,
// data_from_file,
// MonthlyDate,
// --- 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>);
/// 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);
/// 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>,
/// 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>,
/// ```
/// 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 {
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())
})
}
// 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> {
fn try_into(self) -> Result<UISpec, Self::Error> {
Ok(
UISpec(self.vec_at("ui_spec::ui_graphic")?)
)
}
}
// GraphicJson builder
let mut graphic_json = GraphicJson {
country: *country,
index: *index,
lines: Vec::new(),
sized: None,
};
/// ```
/// 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(),
))
},
};
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);
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);
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")?)
/// 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>,
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> {
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);
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")?,
/// ```
/// 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,
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> {
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")?,
// 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),
// )
// }
/// 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>,
}
// /// 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()
// )
// )},
// };
// 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!(),
// }
// }
}
/// 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>,