Flex Chart Sorting ColumnSeries Order - sorting

I am trying to create a BarChart that will display values within a ColumnSeries in an order dependant of there value.
So for instance, If I had a ColumnSeries in a BarChart , one showing profit, the other showing expenses, it will render correctly if the profit is more than the expenses because the expenses series is rendered on top.
However, if the expenses is more than profit, the profit will not be viewable as it will be rendered underneath expenses.
At this point I am going to try and include an image to display my problem...
OK it turns out that I am not allowed to display an image :(
The image did show that profit in February is 500 but the profit of 300 in January is hidden because the Expenses of 500 is displaying over it.
You can run the code below to create the example:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var expenses:ArrayCollection = new ArrayCollection([
{Month:"Jan", Profit:300, Expenses:500},
{Month:"Feb", Profit:500, Expenses:300}
]);
]]></mx:Script>
<mx:Panel title="Bar Chart">
<mx:BarChart id="myChart" dataProvider="{expenses}" showDataTips="true" type="overlaid" >
<mx:verticalAxis>
<mx:CategoryAxis dataProvider="{expenses}" categoryField="Month" />
</mx:verticalAxis>
<mx:series>
<mx:BarSeries yField="Month" xField="Profit" displayName="Profit" />
<mx:BarSeries yField="Month" xField="Expenses" displayName="Expenses" />
</mx:series>
</mx:BarChart>
<mx:Legend dataProvider="{myChart}"/>
</mx:Panel>
An obvious solution to this would be to make the BarChart type 'clustered' as both values will be seen, however my client requires the BarChart to be 'overlaid', so currently some smaller values are hidden.
I would expect that there is a way to sort the order of the BarSeries but I cant seem to find how and I would really appreciate someone's superior knowledge on charting. ;)

Related

Recharts X-Axis auto not showing most values in ticks for times?

I've just converted my project from using react vis over to recharts. I'm currently looking into why the ticks aren't showing as expected. There are 96 datapoints that should be showing up and the cartesian grid shows them, but no tick labels appear other than the few at weird times not aligned to the datapoints I provide. (The tick marks should be at a 30 minute interval.)
Is there a way to have the ticks show up just where I specify them in the data?
This is what I currently have (I thought "interval" was supposed to make all the ticks appear). I have the time specified as milliseconds and then format them, which seems to work for the most part.
<LineChart data={datapoints}>
<XAxis dataKey="x"
domain = {['auto', 'auto']}
name = 'Time'
tickFormatter = {(unixTime) => moment(unixTime).format('HH:mm')}
interval={0}
type = 'number'/>
<YAxis />
<CartesianGrid/>
<Tooltip/>
<Legend/>
{this.props.yLines.map(lineKey => {
return <Line dot={false} type="monotone" dataKey={lineKey} isAnimationActive={false}/>
})}
</LineChart>
And this is what is showing up:
Vs what I would expect (all intervals showing)
Update: I have since added tickCount={96} (like I had with react-vis) but the times are still at weird increments. Like 6:33, 8:20, etc. instead of 30 minute increments.
Any help would be appreciated!
You can use interval={0} in your XAxis. It will show all tick
Use scale="time" in your XAxis.

Get only non-filtered data from dc.js chart (dimension / group)

So this is a question regarding a rather specific problem. As I know from Gordon, main contributor of dc.js, there is no support for elasticY(true) function for logarithmic scales.
So, after knowing this, I tried to implement my own solution, by building a workaround, inside dc.js's renderlet event. This event is always triggered by a click of the user onto the barchart. What I wanted to do is this:
let groupSize = this.getGroupSize(fakeGroup, this.yValue);
let maximum = group.top(1)[0].value;
let minimum = group.top(groupSize)[groupSize-1].value;
console.log(minimum, maximum);
chart.y(d3.scale.log().domain([minimum, maximum])
.range(this.height, 0)
.nice()
.clamp(true));
I thought, that at this point the "fakeGroup" (which is just group.top(50)) contains only the data points that are NOT filtered out after the user clicked somewhere. However, this group always contains all data points that are in the top 50 and doesn't change on filter events.
What I really wanted is get all data points that are NOT filtered out, to get a new maximum and minimum for the yScale and rescale the yAxis accordingly by calling chart.y(...) again.
Is there any way to get only data rows that are still in the chart and not filtered out. I also tried using remove_empty_bins(group) but didn't have any luck with that. Somewhere is always all() or top() missing, even after giving remove_empty_bins both functions.
This is how i solved it:
I made a function called rescale(), which looks like this:
rescale(chart, group, fakeGroup) {
let groupSize = this.getGroupSize(fakeGroup, this.yValue);
let minTop = group.top(groupSize)[groupSize-1].value;
let minimum = minTop > 0 ? minTop : 0.0001;
let maximum = group.top(1)[0].value;
chart.y(d3.scale.log().domain([minimum, maximum])
.range(this.height, 0)
.nice()
.clamp(true));}
I think the parameters are pretty self-explanatory, I just get my chart, the whole group as set by dimension.group.reduceSum and a fake group I created, which contains the top 50 elements, to reduce bar count of my chart.
The rescale() method is called in the event listener
chart.on('preRedraw', (chart) => {
this.rescale(chart, group, fakeGroup);
}
So what I do is re-defining (re-setting min and max values regarding filtered data) the charts yAxis everytime the chart gets redrawn, which happens to also be every time one of my charts is filtered. So now, the scale always fits the filtered data the chart contains after filtering another chart.

DC.js Choropleth filtering Issue

I am trying to filter data on my choropleth chart from a bargraph. Strange thing is that it is not showing correct value on selecting a bar from the accompanying bar chart.
Here is the jsfiddle: https://jsfiddle.net/anmolkoul/jk8LammL/
The script code begins from line 4794
If i select WIN004 from the bar chart, it should highlight only five states and the tooltip should reflect the values for the data. Some states are highlighted for whom WIN004 does not exist.
I changed the properties of the choropleth from
.colors(d3.scale.quantize().range(["#F90D00", "#F63F00", "#F36F01", "#F09E01", "#EDCB02", "#DDEA03", "#ADE703", "#7EE404", "#50E104", "#24DE05", "#05DB11"]))
.colorDomain([-1, 1])
To
.colors(d3.scale.linear().range(["green", "white", "red"]))
.colorDomain([-2, 0, 2])
But i get a lot of white states where its hard to discern what has been highlighted. The tool tip for some white-ed-out states show -0.00 :/
Here is the fiddle http://jsfiddle.net/anmolkoul/jk8LammL/1/
So i guess either its a problem with my color range or how my data is getting parsed.
I would ideally like to specify the data ranges in the .colorDomain based on the top and bottom values of the riskIndicator dimension. My functions are not working though. Should i use d3.max or riskIndicator.top here?
EDIT:
I got the color domain dynamic by using the min and max values but still the graph is not performing as expected? Could this be an issue with the geochoropleth chart? I further took a working geochoropleth example and ported my data to it and even that gave me the same issue of representing data incorrectly. I thoughit could be a data problem but i validated using a couple of good BI tools and their map charts displayed data correctly.
Could this be an issue with the dc choropleth?
Thank you.
Anmol
This has the same root cause as the issue in this question:
Crossfilter showing negative numbers on dc.js with no negative numbers in the dataset
In short, floating point numbers don't always cancel out to zero when added and subtracted. This "fake group" will ensure they snap to zero when they get close:
function snap_to_zero(source_group) {
return {
all:function () {
return source_group.all().map(function(d) {
return {key: d.key,
value: (Math.abs(d.value)<1e-6) ? 0 : d.value};
});
}
};
}
Added it to the FAQ!

crossfilter.js multidimensional "dimension"

not sure how to do this. I have the following data:
Date, Country, QuantityA, QuantityB.
I want to make a timeline Chart with the ratio between Quantity A and B. I also want to create a barChart with Country, which will show the ratio in every country.
The problem is that the ratios are not additive, so if I do this:
var timeDim = ndx.dimension(function(d) {return d.Date;});
ratioAB = timeDim.group().reduceSum(function(d) {return QuantityA/QuantityB}
This will return the ratios for every country separately and will add them up. What I want is to add up QuantityA and QuantityB and then do the ratio.
Thus, the timeline chart will only show the right ratio if I filter in one of the countries.
Is there a way to add both the country and the date as a dimension?
You can create a custom grouping to calculate the sum of QuantityA, the sum of QuantityB, and the ratio between the 2. Or you could just create 2 sum groups, one summing QuantityA, the other QuantityB, and then calculate the ratio when you build the visualization.

How to use Visual Studio Charts to draw a 'Manhattan* Chart'?

*This is a name I have seen used for the style of chart I'm after - not sure how 'official' this name is.
What I would like:
Bar Chart
X - Day of the Week
Y - Number of items
Z - Week Number, receding back into the chart.
I'm not sure that the Chart Control can do it, but I might be missing something in the many many properties and settings the control has.
After a hint from pnuts. i've dug in an read up some more on the Chart Control....
I've created a 3D 'Manhattan' style chart. There's the datasource selects data with columns such as DayName, NumberOfOrders and WeekNo.
The chart should have clustering turned off and you need to use a special databinding method.
Chart1.DataBindCrossTable(ds.GetYearsOrdersByDay, "WeekNo", "DayName", "NumberOfOrders", null);
This creates several series based on the dataset and the parameters.
Basic markup
<asp:Chart ID="Chart1" runat="server" Height="600px" Width="700px">
<Series>
</Series>
<ChartAreas>
<asp:ChartArea Name="ChartArea1">
<Area3DStyle Enable3D="True" IsClustered="false" Perspective="20"/>
<AxisY Interval="100"></AxisY>
<AxisX IntervalOffset ="1.0" Interval ="1.0" >
<MajorGrid Enabled="true" Interval="1.0" IntervalOffset="0.5" />
</AxisX>
</asp:ChartArea>
</ChartAreas>
<Legends>
<asp:Legend Name="Legend1" Title="Number of Orders">
</asp:Legend>
</Legends>
</asp:Chart>

Resources