How can a series be removed from the XYChartScrollbar in amCharts v4?
It was added in much the same way as series are added to the chart:
chart.scrollbarX = new am4charts.XYChartScrollbar();
chart.scrollbarX.series.push(series);
Removing it seems to remove it from the List (chart.scrollbarX.series.length goes from 1 to 0) but it remains on the scrollbar display. I've also tried removeIndex, but no luck there either.
// removes from List, but still displayed
var scrollbarIndex = chart.scrollbarX.series.indexOf(series);
chart.scrollbarX.series.removeIndex(scrollbarIndex);
// same result, removed from List but still displayed
chart.scrollbarX.series.removeValue(series);
I have also tried calling invalidate() and even deepInvalidate() to try to get the scrollbar to refresh but no success.
An example pen is at https://codepen.io/anon/pen/OrQvbw?editors=0011. Clicking on a toggle button adds the series to the chart and scrollbar, but only removes it from the chart.
Removing a series from the scrollbar itself does not seem to remove the series from the scrollbar's chart which itself is a whole other chart with distinct series. Going to look into this more and get back to you.
In the meantime, we can piggy back off of the scrollbar's removeValue method via the series' List's "removed" event, to do the same thing on scrollbarChart. The scrollbarChart's series are all clones of the original chart's series, presuming a series only ever has 1 clone and that that clone is within scrollbarChart, this code seems to do the trick (removed.oldValue is the series we just removed from scrollbarX.series):
chart.scrollbarX.series.events.on("removed", function(removed){
chart.scrollbarX.scrollbarChart.series.removeValue(removed.oldValue.clones.getIndex(0));
});
Here's a fork of your demo with that addition:
https://codepen.io/team/amcharts/pen/1b623a1b4ddf6a198bc80bdf5f5e1514
Related
I'd like to have dc.js chart which slides along a selection, e.g. in the Nasdaq example https://dc-js.github.io/dc.js/ you would select a sub-selection of time then click "animate" button and the selection filter would slide along the x-axis at a pre-determined step size.
I'm a bit lost as to where one would start...does anyone have any ideas?
Most of what you need to do is set the current filter on the relevant chart based on a timer, instead of based on user interaction.
I've copied the relevant parts of the Nasdaq example into a fiddle to illustrate this: https://jsfiddle.net/0zkbyyqu/9/
Once the charts are in place, the animation is just a matter of changing the filter based on a setInterval. For obscure reasons, we want to use the focus method of the moveChart, not the filter method, but it's essentially doing the same thing, with a little more code to reflect the changes in the range chart:
var beginYear = 1985;
window.setInterval(function() {
moveChart.focus([
new Date(beginYear, 0,0,0,0,0,0),
new Date(beginYear+3, 0,0,0,0,0,0)]);
if(++beginYear > 2009)
beginYear = 1985;
}, 1000);
(If you were using the filter method, you'd have to construct a dc.filters.RangedFilter, as detailed here: Initial Range selection in DC.js chart)
I have left off your idea about the initial selection of the range coming from the user, and just gone with a range of 3 years. This example just starts animating as soon as it is loaded. You can fetch the current filter using chart.filter(); the result will be a RangedFilter, which is an array of two dates. Hopefully it is clear how to add start/stop buttons to the animation.
A couple of things are tricky about this approach:
It's tricky using a chart with transitions when you also have a timer or streaming data. In this case, I had to reduce the transitionDuration to 500ms for it to make any sense, but the cause-and-effect is still a little confusing. Not sure what to do about this.
The area chart transitions are incorrect so you get some weird artifacts.
I have a number of graphs, for simplicity take this example on jsfiddle, where there is a brush-on graph, a bar chart keyed on time and a row chart keyed on some categories. In addition, I use the d3-tip library for the tooltips (in the link above a very simplified version of my tip).
In order to avoid the creation of a bar-row in a rowChart, I used the fake-group as outlined in the FAQ of dc-js (and here as well).
The fake group works well, not displaying the C category on the row chart.
However, if I brush on some months with 0 data, when I reset the filter (just click anywhere but the filtered region on the brushon chart), the d3-tip on the row chart disappears.
Notice the if the group is created without the fake-grouping-function, this problem does not arise.
Any explanation why this happens?
How to avoid this (without loosing the remove_empty_bins)?
Although you can use dc.js and d3.js interchangeably, and dc.js is intentionally a "leaky abstraction", some things will go better if you do them the idiomatic dc.js way.
I have two suggestions:
Apply your tooltips in response to dc.js events so that they will get reapplied when new graphical objects are created (or re-created).
Use chart.selectAll instead of d3.selectAll when modifying the charts.
Okay, #2 actually has no bearing on this question, but it does help scope the selects better so that it's harder for them to miss the chart or accidentally modify stuff elsewhere in the page.
Implementing #1 looks something like this:
month_chart.on('pretransition', function(chart) {
chart.selectAll('rect.bar').call(month_tip)
.on('mouseover', month_tip.show).on('mouseout', month_tip.hide);
});
loc_chart1.on('pretransition', function(chart) {
chart.selectAll('g.row').call(loc_tip)
.on('mouseover', loc_tip.show).on('mouseout', loc_tip.hide);
});
The pretransition event fires right after a render or redraw, so it's usually the best moment to manipulate dc's elements. Much better than just running the code globally. I like to set everything up, then call dc.renderAll(), then allow the renders and redraws to take care of themselves later on.
In particular, when those bars get added back in when remove_empty_bins stops removing them, these events will pick them up and re-tip them.
Fork of your fiddle: https://jsfiddle.net/gordonwoodhull/5feL3gko/4/
In D3 I am working on customizing and adding to #Rengel's timeline (link shown in JS Fiddle.
I've successfully created a similar timeline based on tracks, and it also allows users to filter project data based on checkbox values. Each piece of data now has a tooltip, and there are letters from another dataset populating underneath the projects in the same svg container. Now finally I want to add a brush like this one - wrobstory's from the blocks website.
I have only recently started to work on brush events so I am very much a noob, which is why I am unsure how I am going wrong. There is a JS Fiddle I created at: https://jsfiddle.net/rootseire/2vq8028o/2/ which shows everything working before the brush gets called. When I select a section of the timeline, the brush appears, it calculates indexes and extent. But it changes the y state of the year and the year text then transitions down the page.
I have been trying to see why this is happening, but I think I need to step back from the code as it might be just that I am not referencing the correct element. Here is the code for when the mouse pointer drags over the interface:
vis.on('mousedown', function(){
brush_elm = vis.select(".brush").node();
new_click_event = new Event('mousedown');
new_click_event.pageX = d3.event.pageX;
new_click_event.clientX = d3.event.clientX;
new_click_event.pageY = d3.event.pageY;
new_click_event.clientY = d3.event.clientY;
brush_elm.dispatchEvent(new_click_event);
});
But I think it might have something to do with the .points selector. How can I make the brush target the x-axis, the project rectangles and the letters together?
Thanks in advance,
P
When you use a DataVisualization Chart object and you add points to it, the graph is automatically updated but when you change the points the chart is not updated. For example:
System.Windows.Forms.DataVisualization.Charting.Chart myChart;
// When you add points, the chart is automatically redrawn.
myChart.Series[0].Points.AddXY(0,0);
myChart.Series[0].Points.AddXY(1,1);
myChart.Series[0].Points.AddXY(2,0);
// When I change the value of points, the chart is not automatically redrawn.
myChart.Series[0].Points[0].SetValueXY(0,1);
How can I force a redraw of the chart? Something like myChart.Update() or something. As a workaround I'm deleting the last point and re-adding it at each update to force a redraw, but I would like something a little bit more elegant.:
// Re-add last point to force redraw.
myChart.Series[0].Points.RemoveAt(2);
myChart.Series[0].Points.AddXY(2,0);
I have an annotated timeline chart that gets new data over ajax. It's working fine, new points come in and I redraw the graph. My graph has two lines, so there are two labels in the legend on top. For whatever stupid reason, every single time the graph is redrawn, the legend labels swap places! So it will say
Foo 5.2 Bar 3.6
And then I'll refresh (and there will be no new data, so the call to redraw is 100% identical to the previous one) and now it says
Bar 3.6 Foo 5.2
In the respective red and blue, of course. What on earth would possess the applet to do this? Is there any way I can control the order of legend labels? I couldn't find anything about it in the official documentation.
Try using google.visualization.DataTable. For example:
dataTable = new google.visualization.DataTable({cols:graphColumns, rows:graphRows});
chart = new google.visualization.AnnotatedTimeLine($('#chart_div')[0]);
chart.draw(dataTable)
I use it this way and don't have any problems with my legend values.