How to move the x-axis position using dc.js? - charts

I have this:
But I want the x axis to run along y=0, e.g.
And ideally I'd either have the tick labels on top i.e. in the blue bit, or where they were at the bottom of the chart.
EDIT: how the chart is created.
I'm using something like:
var
ndx = crossfilter(data),
dataDimension = ndx.dimension(d => d.period),
ordinals = data.map(d => d.period),
lossGroup = dataDimension.group().reduceSum(d => d.loss),
offsets = lossGroup.all().map(d => -d.value),
chart;
// The data is like {
// period: Date (start of period, e.g. month),
// start: Integer (number at start of period/end of last period)
// loss: Integer (number lost during period)
// gain: Integer (number gained during period)
// }
chart = dc.barChart(chartElement)
.dimension(dataDimension)
// The first group is the loss
.group(lossGroup)
.stack(dataDimension.group().reduceSum(d => d.start), 'carryforward')
.stack(dataDimension.group().reduceSum(d => d.gain), 'gain')
.stackLayout(d3.layout.stack().offset(layers => offsets))
.x(d3.scale.ordinal(ordinals).domain(ordinals))
.xUnits(dc.units.ordinal)
.elasticY(true)
.renderLabel(false)
// The first group is the loss
.title(item => 'Loss: ' + item.value)
.title('carryforward', item => 'Sustained: ' + item.value)
.title('gain', item => 'Gain: ' + item.value)
.renderTitle(true);
dc.renderAll();

Hmm, I guess you are using .stackLayout() to get the negative stacking. Since dc.js doesn't “look inside” this setting, I don't think there is anything built-in to offset the axis. You would probably need to use a pretransition handler to move it.
As for moving the tick labels, you could use .title() instead, like in this example. And then set the tick label to empty.
Best I can think of, not really an answer but more than a comment. :-)

Related

Power BI Create Continuous Line Chart at End of Position

I have a line chart which the dark blue line data point ends halfway through the chart, as no future data is yet available.
Is there a way to continue the line throughout the rest of the months on the date X Axis as a straight line with its current end position?
Current measure reads
Actuals = SELECTEDVALUE('Actual Hours'[Average Actual FTE])​
Chart
Dataset
EDIT
Updated Line Chart
New Measure Code
To continue the line you should fill blanks for future dates like this:
Actuals =
VAR _LastDate =
CALCULATE(
MAX('Table'[month]),
ALL('Table'),
NOT(ISBLANK('Table'[value]))
)
VAR _Value =
CALCULATE(
SUM('Table'[value]),
'Table'[month] = _LastDate
)
RETURN
SWITCH(
SUM('Table'[value]),
BLANK(), _Value,
SUM('Table'[value])
)
_LastDate defines last date with non-blank value and _Value gets value for this date. Inside RETURN we fill blanks with _Value and do nothing to non-blanks.
On my dummy data it looks like:

Scala Range contains (anything in another Range)?

I am trying to define a simple Scala method to determine if two rectangles overlap in any capacity. I believe the way to do this would be something along the lines of:
if (! (Range_of_rectangle1.contains(anything in Range_of_rectangle2) ) ) => false
And this would need to be done for both the x-axis and the y-axis...
But I'm new enough to Scala that I don't sure how to write something like someRange.contains( anything in another Range).
The code I have currently for determining the overlap sorta works but has some problems, as I will discuss:
First I define a Rectangle (and there is a reason that its a case class in my code, but that's unrelated to this task).
case class Rectangle (minx: Int, maxx: Int, miny: Int, maxy: Int)
Then I create the function to look if two rectangles overlap
def rectanglesOverlap(r1: Rectangle, r2:Rectangle): Boolean = {
r2 match {
//In English: if r2's minx OR miny are not anywhere in the range of r1's x-axis, then there's no overlap along the x-axis
//If the range of r1's x-axis does NOT contain anything from r2's x-axis, they don't overlap
case x_overlap1 if (! ( (r1.minx to r1.maxx).contains(r2.minx) || (r1.minx to r1.maxx).contains(r2.maxx) ) ) => false //where r1 is larger rectangle
case y_overlap1 if (! ( (r1.miny to r1.maxy).contains(r2.miny) || (r1.miny to r1.maxy).contains(r2.maxy) ) ) => false
//If the range of r2's x-axis does NOT contain anything from r1's x-axis, they don't overlap
case x_overlap2 if (! ( (r2.minx to r2.maxx).contains(r1.minx) || (r2.minx to r2.maxx).contains(r1.maxx) ) ) => false //where r2 is larger rectangle
case y_overlap2 if (! ( (r2.miny to r2.maxy).contains(r1.miny) || (r2.miny to r2.maxy).contains(r1.maxy) ) ) => false
case _ => true
}
}
So what the code tries to do is start with the x- and y-axis of one of the rectangles, and check if the other rectangle's minx/y OR maxx/y is in there....
See the problem?
When I tested it, I got "false" for this:
val q1 = Rectangle(1, 18, 1, 18)
val q2 = Rectangle(1,8,8,16)
scala> rectanglesOverlap(q1, q2)
res0: Boolean = false
And the reason for this is obvious. Its false because the q2 y-axis is 8-16 and neither q1 miny (1) or q1 maxy (18) fall within the 8-16 range. However, its clear that they overlap.
So know that I conceptually know what's wrong with my code, I'm trying to figure out how to programmatically do something like this:
someRange.contains( anything in another Range).
But my efforts of searching Google and Stack Overflow haven't yielded the proper solution. Help?
When you want to know where one collection overlaps another, you're looking for their "intersection".
someRange.intersect(anotherRange)
or
(1 to 18) intersect (8 to 16)
and to turn it into a Boolean
((1 to 18) intersect (8 to 16)).nonEmpty

Rx how to merge observables and only fire if all provided an onnext in a specified timeframe

I have a number of observable event streams that are all providing events with timestamps. I don't care about the events individually, I need to know when they all fired within a specified timeframe.
For example:
Button one was clicked (don't care)
Button two was clicked (don't care)
Button one was clicked and within 5 seconds button two was clicked (I need this)
I tried "and then when" but I get old events and can't figure out how to filter them out if it is not within the time window.
Thanks!
Edit:
I attempted to create a marble diagram to clarify what I am trying to achieve...
I have a bunch of random event streams represented in the top portion. Some events fire more often then others. I only want to capture the group of events that fired within a specified time window. In this example I used windows of 3 seconds. The events I want are highlighted in dark black all other events should be ignored. I hope this helps better explain the problem.
Is sequence important? If so, the usual way of dealing with "this and then that" is using flatMapLatest. You can achieve your other constraints by applying them to stream passed to flatMapLatest. Consider the following example:
const fromClick = x => Rx.Observable.fromEvent(document.getElementById(x), 'click');
const a$ = fromClick('button1');
const b$ = fromClick('button2');
const sub = a$.flatMapLatest(() => b$.first().timeout(5000, Rx.Observable.never()))
.subscribe(() => console.log('condition met'));
Here we're saying "for each click on button 1, start listening to button 2, and return either the first click or nothing (if we hit the timeout). Here's a working example: https://jsbin.com/zosipociti/edit?js,console,output
You want to use the Sample operator. I'm not sure if you want .NET or JS sample code, since you tagged both.
Edit:
Here's a .NET sample. metaSample is an observable of 10 child observables. Each of the child observables has numbers going from 1 to 99 with random time-gaps between each number. The time gaps are anywhere between 0 to 200 milliseconds.
var random = new Random();
IObservable<IObservable<int>> metaSample = Observable.Generate(1, i => i < 10, i => i + 1, i =>
Observable.Generate(1, j => j < 100, j => j + 1, j => j, j => TimeSpan.FromMilliseconds(random.Next(200))));
We then Sample each of the child operators every one second. This gives us the latest value that occurred in that one second window. We then merge those sampled streams together:
IObservable<int> joined = metaSample
.Select(o => o.Sample(TimeSpan.FromSeconds(1)))
.Merge();
A marble diagram for 5 of them could look like this:
child1: --1----2--3-4---5----6
child2: -1-23---4--5----6-7--8
child3: --1----2----3-4-5--6--
child4: ----1-2--34---567--8-9
child5: 1----2--3-4-5--------6-
t : ------1------2------3-
------------------------------
result: ------13122--45345--5768--
So the after 1 second, it grabs the latest from each child and dumps it, after 2 seconds the same. After 3 seconds, notice that child5 hasn't emitted anything, so there's only 4 numbers emitted. Obviously with our parameters that's impossible, but that's demonstrated as how Sample would work with no events.
This is the closest I have come to accomplishing this task... There has to be a cleaner way with groupjoin but I can't figure it out!
static void Main(string[] args)
{
var random = new Random();
var o1 = Observable.Interval(TimeSpan.FromSeconds(2)).Select(t => "A " + DateTime.Now.ToString("HH:mm:ss"));
o1.Subscribe(Console.WriteLine);
var o2 = Observable.Interval(TimeSpan.FromSeconds(3)).Select(t => "B " + DateTime.Now.ToString("HH:mm:ss"));
o2.Subscribe(Console.WriteLine);
var o3 = Observable.Interval(TimeSpan.FromSeconds(random.Next(3, 7))).Select(t => "C " + DateTime.Now.ToString("HH:mm:ss"));
o3.Subscribe(Console.WriteLine);
var o4 = Observable.Interval(TimeSpan.FromSeconds(random.Next(5, 10))).Select(t => "D " + DateTime.Now.ToString("HH:mm:ss"));
o4.Subscribe(Console.WriteLine);
var joined = o1
.CombineLatest(o2, (s1, s2)=> new { e1 = s1, e2 = s2})
.CombineLatest(o3, (s1, s2) => new { e1 = s1.e1, e2 = s1.e2, e3 = s2 })
.CombineLatest(o4, (s1, s2) => new { e1 = s1.e1, e2 = s1.e2, e3 = s1.e3, e4 = s2 })
.Sample(TimeSpan.FromSeconds(3));
joined.Subscribe(e => Console.WriteLine($"{DateTime.Now}: {e.e1} - {e.e2} - {e.e3} - {e.e4}"));
Console.ReadLine();
}

Scala : exclude some Dates

I have a list of dates that i want to ignore :
private val excludeDates = List(
new DateTime("2015-07-17"),
new DateTime("2015-07-20"),
new DateTime("2015-07-23")
)
But i always need to display four dates excluding my black Dates list and the weekends. So far with the following code, my counter is increased when i hit an ignored date and it make sens. So how i can jump to the next date until i hit 4 dates not in my black list and my Weekends ? Maybe with a while, but i dont know how to add it in my scala code :
1 to 4 map { endDate.minusDays(_)} diff excludeDates filter {
_.getDayOfWeek() match {
case DateTimeConstants.SUNDAY | DateTimeConstants.SATURDAY => false
case _ => true
}
}
You could use a Stream :
val blacklist = excludeDates.toSet
Stream.from(1)
.map(endDate.minusDays(_))
.filter(dt => ! blacklist.contains(dt))
.take(4)
.toList
In a quick and rough way I would do it like this
val upperLimit = 4 + excludeDates.length
(1 to upperLimit).map( endDate.minusDays ).filter( d => !excludeDates.contains(d) ).take(4)
In short you go from the end date backward at max the number of dates you need plus the size of the excluded dates, then you filter the sequence checking if the date is not the excluded list and finally you pick only the dates you need with .take( n )
Hope it helps :)

Custom axis labels with missing table rows

There is a Spreadsheet with two columns: Date, Integer. And some rows are missing.
When I insert chart manually, I see long horizontal line instead of missing rows.
But when I do this:
var sheet = SpreadsheetApp.openById(id).getSheets()[0];
var table = Charts.newDataTable().
addColumn(Charts.ColumnType.STRING, "Date").
addColumn(Charts.ColumnType.NUMBER, "asd");
sheet.getSheetValues(sheet.getLastRow() - 9, 1, 10, 2).forEach( function(line) {
var date = new Date(line[0]);
table.addRow( [
date.getDate() + " " + ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][date.getMonth()],
line[1]
] );
} );
var chart = Charts.newLineChart().
setDataTable(table).
setXAxisTitle("Date").
setYAxisTitle("asd").
setTitle("asd").
build();
var temp = "<img src=\'cid:asd\'/>";
MailApp.sendEmail("asd#gmail.com", "asd", temp, {
htmlBody: temp,
inlineImages: { asd: chart }
} );
the X axis is collapsed, because its values aren't actually Dates, because I reformatted them.
(red lines were made in mspaint to focus your attention)
What is a proper way to make it with horizontal line, like in Spreadsheet, and with customly formatted Dates, like in the image from email?
Whenever you do this it will take the regular behavior in this case make the connection between available values.
If you change the type of chart, it would illustrate missing values more appropriately; bars or other type of charts would illustrate in a better way missing values.