|
|
import { useQuery } from "@tanstack/react-query";
|
|
|
import {
|
|
|
BarController,
|
|
|
BarElement,
|
|
|
CategoryScale,
|
|
|
Chart as ChartJS,
|
|
|
Tooltip as ChartTooltip,
|
|
|
Legend,
|
|
|
LinearScale,
|
|
|
LineElement,
|
|
|
PointElement,
|
|
|
Title,
|
|
|
} from 'chart.js';
|
|
|
import { Line } from "react-chartjs-2";
|
|
|
import { api } from "../api.js";
|
|
|
|
|
|
ChartJS.register(
|
|
|
CategoryScale,
|
|
|
BarController,
|
|
|
PointElement,
|
|
|
LineElement,
|
|
|
LinearScale,
|
|
|
BarElement,
|
|
|
Title,
|
|
|
ChartTooltip,
|
|
|
Legend
|
|
|
);
|
|
|
|
|
|
const GRAPH_LABELS_MAP= {
|
|
|
target_dist_shap: "Расстояние до ближайшего постамата Мой постамат",
|
|
|
target_post_cnt_shap: "Кол-во точек Мой постамат*",
|
|
|
target_cnt_ao_mean_shap: "Средний трафик в точках Мой постамат в АО",
|
|
|
rival_pvz_cnt_shap: "Кол-во ПВЗ*",
|
|
|
rival_post_cnt_shap: "Кол-во постаматов конкурентов *",
|
|
|
metro_dist_shap: "Расстояние до метро",
|
|
|
property_price_bargains_shap: "Цена сделок жилой недвижимости*",
|
|
|
property_price_offers_shap: "Цена предложений жилой недвижимости*",
|
|
|
property_mean_floor_shap: "Средняя этажность застройки*",
|
|
|
property_era_shap: "Эпоха жилой недвижимости*",
|
|
|
flats_cnt_shap: "Кол-во квартир*",
|
|
|
popul_home_shap: "Численность проживающего населения*",
|
|
|
popul_job_shap: "Численность работающего населения*",
|
|
|
yndxfood_sum_shap: "Сумма заказов Яндекс.Еда*",
|
|
|
yndxfood_cnt_shap: "Кол-во заказов Яндекс.Еда*",
|
|
|
school_cnt_shap: "Кол-во школ*",
|
|
|
kindergar_cnt_shap: "Кол-во детсадов*",
|
|
|
public_stop_cnt_shap: "Кол-во остановок общ. транспорта*",
|
|
|
sport_center_cnt_shap: "Кол-во спортивных центров*",
|
|
|
pharmacy_cnt_shap: "Кол-во аптек*",
|
|
|
supermarket_cnt_shap: "Кол-во супермаркетов*",
|
|
|
supermarket_premium_cnt_shap: "Кол-во премиальных супермаркетов*",
|
|
|
clinic_cnt_shap: "Кол-во поликлиник*",
|
|
|
bank_cnt_shap: "Кол-во банков*",
|
|
|
reca_cnt_shap: "Кол-во точек общепита*",
|
|
|
lab_cnt_shap: "Кол-во лабораторий*",
|
|
|
culture_cnt_shap: "Кол-во объектов культуры*",
|
|
|
attraction_cnt_shap: "Кол-во достопримечательностей*",
|
|
|
mfc_cnt_shap: "Кол-во МФЦ*",
|
|
|
bc_cnt_shap: "Кол-во бизнес-центров*",
|
|
|
tc_cnt_shap: "Кол-во торговых центров*",
|
|
|
business_activity_shap: "Бизнес активность",
|
|
|
}
|
|
|
export const PointChart = ({ point }) => {
|
|
|
const { data: meanData } = useQuery(
|
|
|
["mean-data"],
|
|
|
async () => {
|
|
|
const { data } = await api.get(
|
|
|
`https://postamates.spatialsystems.ru/api/avg_bi_values/`
|
|
|
);
|
|
|
|
|
|
return data;
|
|
|
},
|
|
|
{
|
|
|
refetchOnWindowFocus: false,
|
|
|
refetchOnMount: false
|
|
|
}
|
|
|
);
|
|
|
|
|
|
const options = {
|
|
|
indexAxis: 'y',
|
|
|
elements: {
|
|
|
bar: {
|
|
|
borderWidth: 0,
|
|
|
borderRadius: 5,
|
|
|
pointStyle: 'circle'
|
|
|
},
|
|
|
},
|
|
|
plugins: {
|
|
|
legend: {
|
|
|
display: false
|
|
|
},
|
|
|
tooltip: {
|
|
|
displayColors: false,
|
|
|
yAlign: "top",
|
|
|
callbacks: {
|
|
|
label: function(context) {
|
|
|
const label = []
|
|
|
const shap_key = Object.keys(GRAPH_LABELS_MAP).find(key => GRAPH_LABELS_MAP[key] === context.label);
|
|
|
const key = shap_key.substring(0, shap_key.length - 5)
|
|
|
if (context.datasetIndex === 0) label.push("Значение: " + point[key]);
|
|
|
if (context.parsed.x !== null) {
|
|
|
let labelText = "";
|
|
|
if (context.datasetIndex === 0) labelText = "Вклад в прогноз, %: ";
|
|
|
if (context.datasetIndex === 1) labelText = "Минимальный вклад в прогноз, %: ";
|
|
|
if (context.datasetIndex === 2) labelText = "Максимальный вклад в прогноз, %: ";
|
|
|
label.push(labelText + context.parsed.x);
|
|
|
}
|
|
|
return label;
|
|
|
},
|
|
|
body: () => {
|
|
|
return "Вклад в прогноз, %:"
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
},
|
|
|
scales: {
|
|
|
y: {
|
|
|
stacked: true,
|
|
|
},
|
|
|
x: {
|
|
|
title: {
|
|
|
display: true,
|
|
|
text: 'Вклад в прогноз, %',
|
|
|
},
|
|
|
grid: {
|
|
|
color: function(context) {
|
|
|
if (context.tick.value === 0) {
|
|
|
return "#000000";
|
|
|
}
|
|
|
|
|
|
return "#E5E5E5";
|
|
|
},
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const labels = Object.keys(GRAPH_LABELS_MAP).sort((a, b) => {
|
|
|
if (Math.abs(point[a]) < Math.abs(point[b])) return 1;
|
|
|
else return -1;
|
|
|
}).slice(0, 15);
|
|
|
|
|
|
const data = {
|
|
|
labels: labels.map((l) => GRAPH_LABELS_MAP[l]),
|
|
|
datasets: [
|
|
|
{
|
|
|
data: labels.map((l) => point[l]),
|
|
|
backgroundColor: labels.map((l) => point[l]).map(v => v <= 0 ? '#CC2500' : '#278211'),
|
|
|
hoverBackgroundColor: labels.map((l) => point[l]).map(v => v <= 0 ? '#F22C00' : '#2DB20C'),
|
|
|
type: 'line',
|
|
|
showLine: false,
|
|
|
},
|
|
|
{
|
|
|
data: labels.map((l) => meanData ? meanData[`min_${l}`] : 0),
|
|
|
backgroundColor: "#cccccc",
|
|
|
hoverBackgroundColor: "#aaaaaa",
|
|
|
type: 'bar',
|
|
|
showLine: false,
|
|
|
},
|
|
|
{
|
|
|
data: labels.map((l) => meanData ? meanData[`max_${l}`] : 0),
|
|
|
backgroundColor: "#cccccc",
|
|
|
|
|
|
hoverBackgroundColor: "#aaaaaa",
|
|
|
type: 'bar',
|
|
|
showLine: false,
|
|
|
},
|
|
|
],
|
|
|
};
|
|
|
return <Line options={options} data={data} />
|
|
|
} |