Animated scatter plot with plotly makes an undesired crossing of bubbles - animation

I've done this scatter with plotly express and added an animation. Also, I adjusted the scatter to make it appears as such as a bubble chart. All works great, except for one issue. When I press the button to start the graph animation and one bubble is 'reached' and 'overtaken' by another bubble, they cross each other. By itself, it doesn't create a wrong result, but it's an undesired effect. I've showed the situation in the gif reachable with this link:
https://github.com/TheHextech/start2impact/blob/master/Data_Science/Food_Project_DataVisualization_DataManipulation/normal_animation.gif
However, if I manually drag the spinbox of the animation this effect doesn't show up (check this other link to see the gif https://github.com/TheHextech/start2impact/blob/master/Data_Science/Food_Project_DataVisualization_DataManipulation/dragged_spinbox.gif).
Why does this happen? And how can I fix this problem avoiding the 'overtake' during the normal animation? I share here the entire code of the graph:
fig = px.scatter(
data_frame=chn_food_feed,
x='production',
y='item',
size='production',
size_max=80,
animation_frame='years',
color='element',
color_discrete_map={
'Feed':'brown',
'Food':'orange'},
hover_name='item',
hover_data=dict(
item = False,
element = False),
range_x=[chn_food_feed.production.min()-5000, chn_food_feed.production.max()+50000],
range_y=[-1, 5.5])
fig.update_layout(
title="Storyline of China's top 3 Food and Feed items produced in 2013",
title_x = 0.5,
title_y = 0.95,
title_xanchor='center',
title_yanchor='top',
legend_title_text='Elements',
xaxis = dict(title='Production (1000 tons)'),
yaxis = dict(title=None))
# Speed up the animation
fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 250
fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 250
fig.show(renderer='notebook_connected') # For VS Code visulization of animation

Related

get a 2D bounding box from a 3D object

I have a scene filled with ~hundred oblong asteroid shaped objects. I want to place a text label under each one so that the label is visible from any camera angle. I billboard the text so that it always faces the camera.
At first, everything looks great by placing text below the 3d object using .translateY. However, as you start to moving around the scene, labels no longer are 'below' the object depending on your camera position. This especially true when you orient using trackballControls.
How can I place text 'below' the object no matter the orientation. Perhaps if I create a 2d bounding box around each object in relation to the camera on each frame - I could then place the text label right below that 2d box.
I'm also concerned that calculating 2d bounding boxes on a hundred 3d objects every frame could get expensive. Thoughts?
screenshots:
At first, text labels appear correctly translated -y below the object
but as you rotate the camera, labels get sideways
flipping the camera all the way around shows the labels upside down
My goal is to have the labels below the objects no matter the camera orientation.
Did you tried to add the Text Labels to the Object?
object.add(Label) instead of scene.add(Label)
I have a demo site here that might help give you source to look at:
https://dl.dropboxusercontent.com/u/31495717/cubemaker/index.html
This site places textual DOM elements at a screen coordinate-based constant distance from a 3D object, styled with CSS, within the render loop, when the mouse pointer is moved over the 3D object.
From the source:
var id_label = document.createElement('div');
id_label.id = INTERSECTED.name;
id_label.style.position = 'absolute';
id_label.style.top = '-10000px';
id_label.style.left = '-10000px';
id_label.innerHTML = '<span class="particle_label">' + INTERSECTED.name + '<br><span class="particle_sublabel">' + INTERSECTED.subname + '</span></span>';
container.appendChild(id_label);
var id_label_rect = id_label.getBoundingClientRect();
id_label.style.top = (screen_object_center.y - 0.85 * (id_label_rect.height / 2)) + 'px';
if (mouse.x < 0)
id_label.style.left = (screen_object_center.x - horizontal_fudge * (screen_object_edge.x - screen_object_center.x)) + 'px';
else {
id_label.style.left = (screen_object_center.x + horizontal_fudge * (screen_object_edge.x - screen_object_center.x) - id_label_rect.width) + 'px';
id_label.style.textAlign = 'right';
}
The DOM element is drawn offscreen and then repositioned based on attributes of its bounding box and the world coordinates of the 3D element it is associated with. When the mouse pointer is moved outside the 3D element bounds, the text label is removed from the DOM.
Since you are always showing your labels, you might modify this to draw the element once in an initialization step, and simply change the top and left style attributes within the render loop.

SVG performance drop when animating 2 or more elements, RaphaelJS

I am testing SVG performance using RaphaelJS library.
My code works, can be found here: JSFiddle
When you type in textbox "1" and press "add", a rectangle will be generated on screen and 4 animations will loop on it- moving right, down, left, up (also rotating, scaling and changing colour).
Performance seems to be ok. But add another element on stage and the performance gets knocked down to minimum in 3-4 seconds. Checked in Chrome timeline, the thing that is getting stacked up is "Animation Frame Fired - > Install Timer".
Perhaps I am doing loop incorrectly? Altough next animation starts when the previous ends, through callback function. Or is it Raphael itself? Should I try doing this with SVG and SMIL? (Raphael uses VML)
Any ideas?
------------------------------------UPDATE--------------------------------------
With RaphaelJS I did bad animation loop hooks, see answer below.
But another problem that does occur - add 1 element 10 times and you can see how animations get distorted, not finishing their full cycle, or add 10 elements 1 time and after few seconds you can see delayed animations on some of the elements.
I made SMIL version JSFiddle (no Raphael here), animations do not lag, delay, but they get syncronized. Can anyone explain why? And how to make those animations NOT sync, but unique?
I think the problem is you are recursively calling animations on a set.
So at the end of each animation, each element in the set calls an animation for the set again, so it spirals and grinds to a halt. You can get around this, by using 'this' instead of the set 'rectangles'.
//define 4 animations
var move_up = Raphael.animation({fill: "green", transform: "t0,0r360s1,1"}, 400, function(){ this.attr({"transform" : "t0,0"}); this.animate(move_right); });
var move_left = Raphael.animation({fill: "yellow", transform: "t0,100r270s0.5,0.5"}, 400, function(){ this.animate(move_up); });
var move_down = Raphael.animation({fill: "red", transform: "t100,100r180s1,1"}, 400, function(){ this.animate(move_left); });
var move_right = Raphael.animation({fill: "blue", transform: "t100,0r90s1.5,1.5"}, 400, function(){this.animate(move_down); });
jsfiddle

How to Draw BoundingBox or Tag Objects Which Has Less Area Than Others

In my image I have 5 Objects in black-white form. Some are respectively small, some are bigger.
So what i am trying to do is drawing a BoundingBox or tag the objects which has less area than others (ex. under 10pixels/area) .
I couldn't make this happen, can anyone help?
That's two separate problems. The first is to select only objects above a certain area. So simply remove all objects below it:
clean = bwareaopen (im, 10); # remove all objects with area below 10
Then for the second problem there are many possibilities. You can get their borders:
borders = bwperim (clean);
imshow (borders);
You can label them:
labeled = bwlabel (clean);
imshow (labeled);
Or you can get their bounding box (which depending on the shape of your objects may overlap):
props = regionprops (clean, 'BoundingBox');
all_bb = props.BoundingBox;
boxes = false (size (clean));
for i = 1:numel (all_bb)
bb = all_bb{i};
bb(round (bb(2):bb(2)+bb(4), bb(1):bb(1)+bb(3))) = true;
end
imshow (boxes);
Note: this was written out of my head, no testing. There may be small oversights, but nothing major.

VBA Chart Manipulation Slow

I wrote some Excel VBA code that generates a scatterplot and changes a few properties of the chart. (Code is below for reference.) The code moves slowly through tasks like deleting the chart legend, removing horizontal/vertical gridlines, and changing the X and Y series. Excel's timer gives me the following duration for each task:
insert scatterplot: 0.01171875
delete series: 0
plot x vs y: 0.55859375
delete legend: 0.5703125
delete chart title: 0.66015625
remove grid: 1.3046875
format axes: 0
overall: 3.11328125
Removing the grid, changing the title, plotting the X and Y series, and deleting the legend seem to take a long time. I've googled for alternative ways to write the code, but haven't been able to find anything useful. The code works entirely as expected, except for the slow speed. Any ideas as to what's causing the bad performance, and how I can speed this up? Thanks in advance.
EDIT: I've already turned off screen updating while working with the chart. The chart is generated/formatted while a userform is open, if that makes any difference.
Here is the relevant snippet of code:
With ActiveChart
'Delete all series currently in plot
Do While .FullSeriesCollection.Count > 0
.FullSeriesCollection(1).Delete
Loop
'Plot Actual (Y) vs. Inverse Distribution (X)
.SeriesCollection.NewSeries
.FullSeriesCollection(1).XValues = "=" & tempSheetName & "!$C:$C"
.FullSeriesCollection(1).Values = "=" & tempSheetName & "!$A:$A"
'Delete legend
.Legend.Delete
'Delete chart title
.SetElement (msoElementChartTitleNone)
'Remove gridlines
.SetElement (msoElementPrimaryValueGridLinesNone)
.SetElement (msoElementPrimaryCategoryGridLinesNone)
'Format axes
Dim xAxis As Axis, yAxis As Axis
Set xAxis = .Axes(xlCategory)
Set yAxis = .Axes(xlValue)
With yAxis
'Title y axis "actual"
.HasTitle = True
.AxisTitle.Caption = "Actual"
'Add tick marks
.MajorTickMark = xlOutside
End With
With xAxis
'Title x axis by dist type
.HasTitle = True
.AxisTitle.Caption = dist.getDistType
'Add tick marks
.MajorTickMark = xlOutside
End With
End With
Without the data and machine specifics it can be hard to say why this is slow, although here are some alternatives to some of the code you have.
The first and foremost thing I'd change is not to Activate the chart. If you are creating the chart through code, do so but set it to a variable, eg Set wcChart = ThisWorkbook.Charts.Add. Then change With ActiveChart to With wcChart.
Also, delete the FullSeriesCollection and then delete the chart title, remove the gridlines and change the axes before filling up the new data. The chart manipulation should be quicker with less data in the chart. Be careful here though because changing aspects of the chart in different orders can produce different outputs (as an example the layout of a legend).
You fill the new FullSeriesCollection with the entire columns of A and C, specify the exact range of the data rather than the whole column.
Other changes to try, I'm not saying these will work but they are worth a shot if you haven't tried. Instead of checking for a FullSeriesCollection each time:
Do While .FullSeriesCollection.Count > 0
.FullSeriesCollection(1).Delete
Loop
The following may be quicker:
For ii = .FullSeriesCollection.Count To 1 Step -1
.FullSeriesCollection(ii).Delete
Next ii
Also, instead of .SetElement for the Chart title and Gridlines I use the following:
'You have to set the title to 'True' before it'll work with 'False'. Go figure.
.HasTitle = True
.HasTitle = False
.HasMajorGridlines = False
.HasMinorGridlines = False

d3 autospace overlapping tick labels

Is there a way in d3 to not draw overlapping tick labels? For example, if I have a bar chart, but the bars are only 5 pixels wide and the labels are 10 pixels wide, I end up with a cluttered mess. I'm currently working on an implementation to only draw the labels when they do not overlap. I can't find any existing way to do that, but wasn't sure if anyone else had dealt with this problem.
There is no way of doing this automatically in D3. You can set the number of ticks or the tick values explicitly (see the documentation), but you'll have to figure out the respective numbers/values yourself. Another option would be to rotate the labels such that there is less chance of them overlapping.
Alternatively, like suggested in the other answer, you could try using a force layout to place the labels. To clarify, you would use the force layout on the labels only -- this is completely independent of the type of chart. I have done this in this example, which is slightly more relevant than the one linked in the other answer.
Note that if you go with the force layout solution, you don't have to animate the position of the labels. You could simply compute the force layout until it converges and then plot the labels.
I've had a similar problem with multiple (sub-)axis, where the last tick overlaps my vertical axis in some situations (depending on the screen width), so I've just wrote a little function that compares the position of the end of the text label with the position of the next axis. This code is very specific to my use case, but could adapted easily to your needs:
var $svg = $('#svg');
// get the last tick of each of my sub-axis
$('.tick-axis').find('.tick:last-of-type').each(function() {
// get position of the end of this text field
var endOfTextField = $(this).offset().left + $(this).find('text').width();
// get the next vertical axis
var $nextAxis = $('line[data-axis="' + $(this).closest('.tick-axis').attr('data-axis') + '"]');
// there is no axis on the very right, so just use the svg width
var positionOfAxis = ($nextAxis.length > 0) ? $nextAxis.offset().left : $svg.offset().left + $svg.width();
// hide the ugly ones!
if (endOfTextField > positionOfAxis) {
$(this).attr('class', 'tick hide');
}
});
The ticks with color: aqua are the hidden ones:

Resources