Найти в Дзене
Один Rust не п...Rust

Визуализация данных API на Rust

Для чего нужна данная статья? :

- Для поиска компромисса между библиотеками визуализации данных из API.

Зачем Вам это уметь? :

- Научиться использовать HTTP-клиенты, такие как reqwest или ureq.

- Использовать библиотеку Plotters и Yew для построения графиков.

Установите зависимости plotters и yew-plotters (если они доступны). Если нет yew-plotters, то используйте plotters и сохраните изображение на диск, а затем отобразите его в компоненте Yew.

use plotters::prelude::*;

use serde::Deserialize;

use yew::prelude::*;

use yew::services::fetch::{FetchService, FetchTask, Request, Response};

use anyhow::Error;

#[derive(Deserialize, Debug)]

struct ApiResponse {

values: Vec<f64>,

}
struct Model {

link: ComponentLink<Self>,

fetch_task: Option<FetchTask>,

data: Option<ApiResponse>,

image_url: Option<String>,

}
enum Msg {

FetchData,

FetchReady(Result<ApiResponse, Error>),

RenderPlot,

}
impl Component for Model {

type Message = Msg;

type Properties = ();

fn create(ctx: &Context<Self>) -> Self {
Self {

link: ctx.link().clone(),

fetch_task: None,

data: None,

image_url: None,

}

}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {

match msg {

Msg::FetchData => {

let request = Request::get("https://api.example.com/data")

.body(Ok(()))
.expect("Could not build request.");
let callback = ctx.link().callback(

|response: Response<Json<Result<ApiResponse, Error>>>| {

let Json(data) = response.into_body();

Msg::FetchReady(data)

},

);

let task = FetchService::fetch(request, callback).expect("failed to start request");

self.fetch_task = Some(task);

true

}

Msg::FetchReady(response) => {

self.data = response.ok();

self.fetch_task = None;

ctx.link().send_message(Msg::RenderPlot);

true

}

Msg::RenderPlot => {

if let Some(ref data) = self.data {

// Рендеринг графика с использованием Plotters

let file_path = "plot.png";

let root = BitMapBackend::new(file_path, (640, 480)).into_drawing_area();

root.fill(&WHITE).unwrap();

let mut chart = ChartBuilder::on(&root)

.caption("API Data Plot", ("sans-serif", 50))

.build_cartesian_2d(0..data.values.len(),

0.0..*data.values.iter().max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap())

.unwrap();

chart.draw_series(LineSeries::new(

data.values.iter().enumerate().map(|(x, y)| (x, *y)),

&RED,

)).unwrap();

root.present().unwrap();

// Задаем URL для отображения изображения

self.image_url = Some(file_path.to_string());

}

true

}

}

}
fn view(&self, ctx: &Context<Self>) -> Html {

html! {

<div>

<button onclick={ctx.link().callback(|_| Msg::FetchData)}>{ "Fetch Data" }</button>

{ self.view_data() }

{ if let Some(ref url) = self.image_url {

html! {

<div>

<img src={url.clone()} alt="Plot"/>

</div>

}

} else {

html! {

<div>{ "No plot available" }</div>

}

}}

</div>

}

}

}

impl Model {

fn view_data(&self) -> Html {

if let Some(ref data) = self.data {

html! {

<div>

{ for data.values.iter().map(|value| html! { <p>{ value }</p> }) }

</div>

}

} else {

html! {

<div>{ "No data" }</div>

}

}

}

}

fn main() {

yew::start_app::<Model>();

}

Этот пример сохраняет изображение графика в файл и отображает его в компоненте Yew.