perspective_viewer/session/column_defaults_update.rs
1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors. ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use std::iter::IntoIterator;
14
15use itertools::Itertools;
16use perspective_client::config::*;
17
18use super::metadata::*;
19use crate::js::plugin::*;
20
21#[extend::ext]
22pub impl ViewConfigUpdate {
23 /// Appends additional columns to the `columns` field of this
24 /// `ViewConfigUpdate` by picking appropriate new columns from the
25 /// `SessionMetadata`, give the necessary column requirements of the plugin
26 /// provided by a `ViewConfigRequirements`. For example, an "X/Y Scatter"
27 /// chart needs a minimum of 2 numeric columns to be drawable.
28 fn set_update_column_defaults(
29 &mut self,
30 metadata: &SessionMetadata,
31 columns: &[Option<String>],
32 requirements: &ViewConfigRequirements,
33 ) {
34 if let (
35 None,
36 ViewConfigRequirements {
37 min: Some(min_cols),
38 names,
39 ..
40 },
41 ) = (&self.columns, &requirements)
42 {
43 // first try to take 2 numeric columns from existing config
44 let numeric_config_columns = columns
45 .iter()
46 .flatten()
47 .filter(|x| {
48 matches!(
49 metadata.get_column_table_type(x),
50 Some(ColumnType::Float | ColumnType::Integer)
51 )
52 })
53 .take(*min_cols)
54 .cloned()
55 .map(Some)
56 .collect::<Vec<_>>();
57
58 if numeric_config_columns.len() == *min_cols {
59 self.columns = Some(
60 numeric_config_columns
61 .into_iter()
62 .pad_using(names.as_ref().map_or(0, |x| x.len()), |_| None)
63 .collect::<Vec<_>>(),
64 );
65 } else {
66 // Append numeric columns from all columns and try again
67 let config_columns = numeric_config_columns
68 .clone()
69 .into_iter()
70 .chain(
71 metadata
72 .get_table_columns()
73 .into_iter()
74 .flatten()
75 .filter(|x| {
76 !numeric_config_columns
77 .iter()
78 .any(|y| y.as_ref() == Some(*x))
79 })
80 .filter(|x| {
81 matches!(
82 metadata.get_column_table_type(x),
83 Some(ColumnType::Float | ColumnType::Integer)
84 )
85 })
86 .cloned()
87 .map(Some),
88 )
89 .take(*min_cols)
90 .collect::<Vec<_>>();
91
92 if config_columns.len() == *min_cols {
93 self.columns = Some(
94 config_columns
95 .into_iter()
96 .pad_using(names.as_ref().map_or(0, |x| x.len()), |_| None)
97 .collect::<Vec<_>>(),
98 );
99 } else {
100 self.columns = Some(
101 metadata
102 .get_table_columns()
103 .into_iter()
104 .flatten()
105 .take(*min_cols)
106 .cloned()
107 .map(Some)
108 .collect::<Vec<_>>(),
109 );
110 }
111 }
112 } else if self.columns.is_none() {
113 let mut columns = columns.to_vec();
114 let initial_len = columns.len();
115 if let Some(last_filled) = columns.iter().rposition(|x| x.is_some()) {
116 columns.truncate(last_filled + 1);
117 if let ViewConfigRequirements {
118 names: Some(names), ..
119 } = &requirements
120 {
121 columns = columns
122 .into_iter()
123 .enumerate()
124 .filter(|(idx, x)| *idx < names.len() || x.is_some())
125 .map(|(_, x)| x)
126 .pad_using(names.len(), |_| None)
127 .collect::<Vec<_>>();
128 } else {
129 columns = columns
130 .into_iter()
131 .filter(|x| x.is_some())
132 .collect::<Vec<_>>();
133 }
134
135 if initial_len != columns.len() {
136 self.columns = Some(columns);
137 }
138 }
139 }
140 }
141}