Reputation: 1
I did a scatter plot with legends , text and annotations . But when i click on the legend text and annotations associated with the bubble remains. Please check the below code.
const getAnnotations = () => {
if (totalRecords <= 10) {
const annotations: any[] = [];
const placedPositions: { x: number; y: number }[] = [];
const groupedData = new Map<string, { storeLabels: string[], x: number, y: number, z: number }>();
// Group data by total_sales and spearman_correlation
data.forEach((item) => {
const storeLabel = item[firstColumnFieldName] || "Unknown Store";
const key = `${item.total_sales}-${item.spearman_correlation}`;
if (!groupedData.has(key)) {
groupedData.set(key, { storeLabels: [], x: item.total_sales, y: item.spearman_correlation, z: item.max_sales });
}
groupedData.get(key)!.storeLabels.push(storeLabel);
});
// Alternating offsets for y (up and down)
let isPositiveYOffset = true;
groupedData.forEach(({ storeLabels, x, y, z }) => {
// Only include annotations where spearman_correlation is greater than 0.2 or less than -0.2
if (y <= 0.5 && y >= -0.5) return; // Skip if correlation is between -0.2 and 0.2
const combinedLabel = storeLabels.join(", <br>"); // Combine store names with commas
const isShortLabel = combinedLabel.length <= 3; // Check if label is short
// Calculate bubble size based on total_sales (or another metric if necessary)
const bubbleSize = calculateBubbleSize(y, totalRecords, x, z, allLessThanOrEqualZero);
// Check if label can fit inside the bubble
const labelFitsInsideBubble = !isLabelTooBig(combinedLabel, bubbleSize);
// Alternate between positive and negative y offsets for annotation placement
const yOffset = isPositiveYOffset ? 30 : -30;
// Switch between positive and negative offsets for next annotation
isPositiveYOffset = !isPositiveYOffset;
// Function to check if an annotation overlaps with either an existing bubble or annotation
const isOverlapping = (x: number, y: number, bubbleSize: number) => {
// Check if it overlaps with other annotations
const annotationOverlap = placedPositions.some(pos => {
const distance = calculateDistance(pos.x, pos.y, x, y);
return distance < bubbleSize * 0.8; // Adjust threshold as necessary for annotations
});
// Check if it overlaps with any bubbles
const bubbleOverlap = placedPositions.some(pos => {
const distance = calculateDistance(pos.x, pos.y, x, y);
return distance < bubbleSize; // Adjust threshold for bubbles
});
// If either overlaps, return true
return annotationOverlap || bubbleOverlap;
};
// Apply the y offset and check for overlap with bubbles and annotations
let currentX = x; // Keep the x position same for each annotation
let currentY = y + yOffset; // Apply y offset (up/down)
// If it overlaps with existing bubbles or annotations, skip this annotation
if (isOverlapping(currentX, currentY, bubbleSize)) {
return;
}
// No overlap, so add the position
placedPositions.push({ x: currentX, y: currentY });
// Add the annotation to the list
annotations.push({
x: x,
y: y,
text: `<b>${combinedLabel}</b>`, // Display combined label
showarrow: !labelFitsInsideBubble, // Show arrow if label is outside
arrowhead: 1,
arrowwidth: 2,
ax: labelFitsInsideBubble ? 10 : 30, // Offset if label is too big
ay: labelFitsInsideBubble ? yOffset : -yOffset, // Adjust vertical offset if label is too big
font: { size: labelFitsInsideBubble ? 12 : 10, color: labelFitsInsideBubble ? "white" : "black", weight: "800" },
bgcolor: labelFitsInsideBubble ? "transparent" : "white", // Transparent if label fits
bordercolor: labelFitsInsideBubble ? "transparent" : "black",
borderradius: 10, // Rounded corners
xanchor: isShortLabel ? "center" : undefined,
yanchor: isShortLabel ? "middle" : undefined,
arrowcolor: "black", // Set arrow color
});
});
return annotations;
}
return [];
};
Here i want to remove annotations when toggled over the label. Let me know if one can simply toggle the legend and remove the associated annotations and text on the bubble. How can we control legend and text according to the toggle legend button.
Upvotes: 0
Views: 9