use crate::keys as pk;
use crate::tex::{Meaning, Token};
use crate::{Error, PT};
use super::keys;
use super::{toks, Engine};
#[derive(Debug, Clone)]
pub struct Colorbar {
saved: Vec<(String, Meaning)>,
meta: [f64; 2],
width: f64,
height: f64,
parent: std::rc::Rc<super::draw::Frame>,
pub bands: Option<Vec<Token>>,
}
thread_local! {
static PARENT: std::cell::RefCell<Option<std::rc::Rc<super::draw::Frame>>> = const { std::cell::RefCell::new(None) };
}
pub fn parent() -> Option<std::rc::Rc<super::draw::Frame>> {
PARENT.with(|p| p.borrow().clone())
}
const SAVED: &[&str] = &[
"/pgfplots/every colorbar/.@cmd",
"/pgfplots/colorbar shift/.@cmd",
"/pgfplots/colorbar horizontal/lowlevel/.@cmd",
"/pgfplots/colorbar vertical/lowlevel/.@cmd",
"/pgfplots/every tick/.@cmd",
"/pgfplots/every minor tick/.@cmd",
"/pgfplots/every major tick/.@cmd",
"/pgfplots/every axis grid/.@cmd",
"/pgfplots/every minor grid/.@cmd",
"/pgfplots/every major grid/.@cmd",
"/pgfplots/every tick label/.@cmd",
"/pgfplots/colormap name",
"/pgfplots/colorbar/width",
"/pgfplots/colorbar pos*",
"/pgfplots/@colorbar sampled",
"/pgfplots/@colorbar line",
"/pgfplots/colormap access",
];
pub fn snapshot(e: &mut Engine, meta: [f64; 2], box_size: (f64, f64), parent: super::draw::Frame) -> Option<Colorbar> {
if !keys::flag(e, "/pgfplots/colorbar") {
return None;
}
if !keys::value(e, "/pgfplots/colorbar to name").is_empty() {
return None;
}
let mut saved: Vec<(String, Meaning)> = SAVED.iter().map(|k| (pk::macro_name(k), e.tex.meaning_of(&pk::macro_name(k)))).collect();
let name = keys::value(e, "/pgfplots/colormap name");
let cm = pk::macro_name(&format!("/pgfplots/@colormaps/{name}"));
saved.push((cm.clone(), e.tex.meaning_of(&cm)));
let meta = if meta[0].is_finite() && meta[1].is_finite() && meta[1] > meta[0] {
meta
} else {
e.warn("colorbar: the axis has no point meta, it shows 0 to 1");
[0.0, 1.0]
};
Some(Colorbar { saved, meta, width: box_size.0, height: box_size.1, parent: std::rc::Rc::new(parent), bands: None })
}
impl Engine {
pub fn draw_colorbar(&mut self, cb: &Colorbar) -> Result<(), Error> {
self.begin_group();
let r = (|| -> Result<(), Error> {
for (name, meaning) in &cb.saved {
self.tex.set_meaning(&Token::cs(name), meaning.clone(), false);
}
let num = super::super::pgf_number;
keys::set(self, "/pgfplots/@colorbar axis", "true");
keys::set(self, "/pgfplots/point meta min", &num(cb.meta[0]));
keys::set(self, "/pgfplots/point meta max", &num(cb.meta[1]));
keys::set(self, "/pgfplots/parent axis width", &format!("{}pt", num(cb.width / PT)));
keys::set(self, "/pgfplots/parent axis height", &format!("{}pt", num(cb.height / PT)));
self.begin_group();
self.st.key_path = "/pgfplots".into();
keys::run(self, "every colorbar")?;
let horizontal = keys::value(self, "/pgfplots/@colorbar orientation") == "h";
self.end_group();
let sampled = keys::value_tokens(self, "/pgfplots/@colorbar sampled").filter(|v| !pk::trim(v).is_empty());
let (style, n) = match (&cb.bands, &sampled) {
(Some(b), _) => (format!("contour filled={{{}}}", crate::tex::tokens_to_string(b)), 2),
(None, Some(s)) => (crate::tex::tokens_to_string(s), keys::number(self, "/pgfplots/samples").unwrap_or(25.0).max(2.0) as usize),
(None, None) => ("surf,shader=interp".to_string(), 2),
};
let (lo, hi) = (cb.meta[0], cb.meta[1]);
let at = |k: usize| lo + (hi - lo) * k as f64 / (n - 1) as f64;
let mut coords = String::new();
let line = sampled.is_some() && keys::flag(self, "/pgfplots/@colorbar line");
let mut extra = String::new();
if line {
for k in 0..n {
let v = num(at(k));
coords.push_str(&if horizontal { format!("({v},0.5) ") } else { format!("(0.5,{v}) ") });
}
let pos = keys::value(self, "/pgfplots/colorbar pos*");
extra = if horizontal {
format!("axis x line*={},y axis line style={{/pgfplots/every colorbar sampled line}},", if pos == "t" { "top" } else { "bottom" })
} else {
format!("axis y line*={},x axis line style={{/pgfplots/every colorbar sampled line}},", if pos == "l" { "left" } else { "right" })
};
}
for side in [0, 1].into_iter().filter(|_| !line) {
for k in 0..n {
let v = num(at(k));
coords.push_str(&if horizontal { format!("({v},{side}) ") } else { format!("({side},{v}) ") });
}
if side == 0 {
coords.push_str("\\par ");
}
}
let meta = if horizontal { "x" } else { "y" };
let code = format!(
"\\begin{{axis}}[every colorbar,colorbar shift,colorbar=false,{extra}]\\addplot[{style},point meta={meta},forget plot] coordinates {{{coords}}};\\end{{axis}}"
);
let before = PARENT.with(|p| p.replace(Some(cb.parent.clone())));
let r = self.run_tokens(toks(&code));
PARENT.with(|p| *p.borrow_mut() = before);
r
})();
self.end_group();
r
}
}