Records are slight shifted on date plot created using coreplot library - ios

Here is a necessary code snippets,
X axis label formatter,
NSDateFormatter dateFormatter = new NSDateFormatter();
dateFormatter.DateFormat = "dd/MM";
var timeFormatter = new CPTTimeFormatter(dateFormatter);
timeFormatter.ReferenceDate = NSDate.FromTimeIntervalSinceNow(0);
x.LabelFormatter = timeFormatter;
Delegate method of getting records,
public override NSNumber NumberForPlot(CPTPlot plot, CPTPlotField forFieldEnum, nuint index)
{
if (forFieldEnum == CPTPlotField.ScatterPlotFieldX)
return new NSNumber((index + 1) * 86400);
Debug.WriteLine("{0}", Data[(int)index].Rate);
return Data[(int)index].Rate;
}
See attached screenshot for result looks like. You can see that markers are not aligned to X axis. First data point should display on “01/01” but it is displaying just before it. Same for all other points.
Let me know if anybody wish to look at any other part of code. I just need direction or clue what could lead to this record shifting. I have already looked at sample code provided in coreplot but didn't get any clue on this.
Edit:
Ranges are as below,
plotSpace.XRange = new CPTPlotRange(NSNumber.FromDouble(0).NSDecimalValue, NSNumber.FromDouble(86400 * 9).NSDecimalValue);
plotSpace.YRange = new CPTPlotRange(NSNumber.FromDouble(-1).NSDecimalValue, NSNumber.FromDouble(9).NSDecimalValue);
Also tried,
var space = graph.DefaultPlotSpace as CPTXYPlotSpace;
space.ScaleToFitPlots(new CPTPlot [] { dataSourceLinePlot });
Edit: Graph setup code

The problem is with the ReferenceDate for the time formatter. It is being initialized with the current date and time, so the offset will vary throughout the day depending on when the setup code runs. There are several ways to make an NSDate object that corresponds to a fixed time of day. The most straightforward is by using NSDateComponents.
Several of the Core Plot example apps, including the "Date Plot" demo in the Plot Gallery app, use this technique to generate reference dates.
Also, the automatic axis labeling policy doesn't work well with dates. It's picking tick locations that fall on "nice" numbers of seconds between ticks, but that doesn't correspond to even numbers of days. You should use the fixed interval policy (the default) or one of the ones that let you provide the tick locations directly.

Related

CorePlot x axis labels

OK, my final issue with getting my bar chart setup is how to print the X axis labels. I tried this:
if let axis = graph.axisSet as? CPTXYAxisSet, xAxis = axis.xAxis {
let dateLabels = self!.dates!.map {
CPTAxisLabel(text: NSDateFormatter.localizedStringFromDate($0, dateStyle: .ShortStyle, timeStyle: .NoStyle), textStyle: nil)
}
xAxis.axisLabels = Set(dateLabels)
}
I'm getting nothing displayed though. I looked at DatePlot sample but I don't want to do what it's doing as it incorrectly assumes that a day is 86,400 seconds long, and that will break multiple times. Also, my date offsets are in months, so that makes it even worse. Can't I just somehow provide the already formatted date string?
Seems strange to me that "axisLabels" would be a set, since a set is not ordered.
Each axis label has a tickLocation. Set the tick location to the bar location for that label in the same units used in the plot space and datasource. Since the label tick location is not related to its position in the array, we can use an unordered collection like a set.

UI Slider Time of Day Beyond Midnight?

So this is a unique situation. I have a double slider I made using swift to make a time range picker like the one Kayak has. Unfortunately mine needs to be a time range between 00:00 all the way to 04:00 the following morning.
It was easy to get it from 00:00 to 23:59 using a scale of 86340 seconds for my slider control. I simply plug that into this little function and out pops the correct range on both ends/knobs:
func getTimeStringFromSeconds(seconds: Double) -> String {
let dcFormatter = NSDateComponentsFormatter()
dcFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehavior.Pad
dcFormatter.allowedUnits = [NSCalendarUnit.Hour, NSCalendarUnit.Minute]
dcFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyle.Positional
return dcFormatter.stringFromTimeInterval(seconds)!
}
As you can see in the screenshot above though I have 100740 seconds instead as the scale. How can I get it to go beyond 23:59, then reset to 00:00 and go into the next day? I can make it go to 28:00 as seen above which would technically be 4am but I want it to start over and show 04:00, not 28:00. What's a good solution for this?
Just as a note, my only solution so far was a sort of hack to make the label say 0:00 by resetting the seconds to 0.00 once it goes over 86340. The scale is still 100740 but there's some math like the following to make the label say otherwise without messing with the value of the knob (upperValue):
if upperKnobLayer.highlighted {
upperValue += valueDelta
upperValue = max(min(maximumValue, upperValue), lowerValue)
var upperDouble = Double(round(upperValue))
if upperDouble > 86340.00 {
let newValue = upperDouble - 86340
upperDouble = 0.00 + newValue
}
upperTime = getTimeStringFromSeconds(upperDouble)
}
It would help to post the implementation of your picker but generally you want the sliders value type to be NSTimeIntervals. Then you can have a reference date which will be midnight 00:00 of today. You can use NSDate(timeIntervalSince:referenceDate) to then get an NSDate representing any date since that reference date which can be formatted accordingly and display to the screen. The added benefit of this way is that the actual day of the date will be correct if your timeInterval makes it spill over to the next day
How about normalizing to a day's worth of seconds.
return dcFormatter.stringFromTimeInterval(seconds % 86340)!

Get y-value of points along the generated line graph in Highcharts

I have two series of data--one consists of (Date, Rating), and the other is a list of events that happened on specific dates. The ultimate goal is to use the first series of data to construct a line graph to show how the rating has changed over time, which I've done successfully:
I now need to plot the second set of data using the dates as x-values (different dates than the first set), but want them to show up on the line--meaning I need to get the y-value of what that date would be if it were in the first set. I hope I explained that clearly; let me know if it's confusing.
I forgot I knew how to do algebra.
function getYValue(dataset, date){
//gets rating estimate for closest surrounding dates using algebraic fun-times
var point_1, point_2;
for (j = 0; j < dataset.length; j++){
if (dataset[j][0] > date) {
point_1 = dataset[j-1];
point_2 = dataset[j];
break;
}
}
var slope = (point_2[1] - point_1[1]) / (point_2[0] - point_1[0]);
var rating = slope * (date - point_2[0]) + point_2[1];
return rating;
}

MS Chart Control Range Bar

I am trying to somehow replicate the range bar chart here.
I've found this reference but I don't fully grasp the code.
What I have is a series of task (sometimes accomplished in different periods).
let d = [("task1", DateTime.Parse("11/01/2014 08:30"), DateTime.Parse("12/01/2014 10:30"));
("task2", DateTime.Parse("15/01/2014 09:30"), DateTime.Parse("16/01/2014 10:30"));
("task3", DateTime.Parse("11/01/2014 08:30"), DateTime.Parse("16/01/2014 10:30"))]
let chart = d |> FSharp.Charting.Chart.RangeBar
chart.ShowChart()
I am struggling to understand the logic of the API.
I have also tried:
let chart = new Windows.Forms.DataVisualization.Charting.Chart(Dock = DockStyle.Fill)
let area = new ChartArea("Main")
chart.ChartAreas.Add(area)
let mainForm = new Form(Visible = true, TopMost = true, Width = 700, Height = 500)
mainForm.Controls.Add(chart)
let seriesColumns = new Series("NameOfTheSerie")
seriesColumns.ChartType <- SeriesChartType.RangeBar
type SupportToChart(serieVals: Series) =
member this.addPointXY(lbl, [<ParamArray>] yVals: Object[]) =
serieVals.Points.AddXY(lbl, yVals) |> ignore
let supporter = SupportToChart(seriesColumns)
supporter.addPointXY("AAA", DateTime.Parse("11/01/2014 08:30"), DateTime.Parse("12/01/2014 10:30") )
which results in
System.ArgumentOutOfRangeException: You can only set 1 Y values for
this data point.
Has something changed in the API since then?
I'm not entirely sure that F# Charting is currently powerful enough to be able to reconstruct the above chart. However, one of the problems seems to be that it treats dates as float values (for some reason) and incorrectly guesses the ranges. You can at least see the chart if you use:
Chart.RangeBar(d)
|> Chart.WithYAxis(Min=41650.0, Max=41660.0)
Please submit this as an issue on GitHub. If you want to dig deeper into how F# Charting works and help us get this fixed, that would be amazing :-)
The trick is initializing the Series with
let serie = new Series("Range", yValues)
where yValues defines the max number of "Y-values".

iOS: Tapku Calendar: Need to select multiple dates

I've been checking the Tapku Calendar code for a bit and searched and read all the relevant questions and responses here however none seem to really offer the correct solution to the problem: How to select multiple dates, either programmatically or by tapping. Just a simple blue tile over two adjacent dates would make me happy :-) The post below seems to have a similar question however the answer does not work. The place in the code is not hit unless the month changes - not exactly what I am looking for. What would be great is a higher-level implementation of selectDate: that would select multiple dates. But just the right place to tweak in the library would be a great place to start is anyone is more familiar with the code. Much appreciated.
iOS: Tapku calendar library - allow selecting multiple dates for current month
So after a bit of stepping through code, I have this rudimentary method using a hammer. I adopted most of the code from TKCalendarMonthView.m->selectDay:day method. The method I created basically creates a new TKCalendarMonthTiles object and fills in the details and then adds subviews onto the main TKCalendarMonthTiles object (self). I tag the subviews so I can first get rid of them if they exist at the beginning of the method as I only want to select one additional day (you could leave the subviews attached if you want them to remain in the UI). I don't track the dates or store them or anything however this meets my needs.
The idea is to simply create a view with the correct tile image you want to use and one that contains the text label of the actual "date" like "14" then add those views as subviews to self. The borrowed code does all the calculations for "where" that date tile resides in the grid, so the view is drawn at the correct location. Code:
- (void)markDay:(int)day {
// First, remove any old subviews
[[self viewWithTag:42] removeFromSuperview];
[[self viewWithTag:43] removeFromSuperview];
int pre = firstOfPrev < 0 ? 0 : lastOfPrev - firstOfPrev + 1;
int tot = day + pre;
int row = tot / 7;
int column = (tot % 7)-1;
TKCalendarMonthTiles *deliveryTile = [[TKCalendarMonthTiles alloc] init];
deliveryTile.selectedImageView.image = [UIImage imageWithContentsOfFile:TKBUNDLE(#"TapkuLibrary.bundle/Images/calendar/MyDateTile.png")];
deliveryTile.currentDay.text = [NSString stringWithFormat:#"%d",day];
if(column < 0){
column = 6;
row--;
}
CGRect r = deliveryTile.selectedImageView.frame;
r.origin.x = (column*46);
r.origin.y = (row*44)-1;
deliveryTile.selectedImageView.frame = r;
deliveryTile.currentDay.frame = r;
[[deliveryTile selectedImageView] setTag:42];
[[deliveryTile currentDay] setTag:43];
[self addSubview:deliveryTile.selectedImageView];
[self addSubview:deliveryTile.currentDay];
} // markDay:
I call this method at the end of TKCalendarMonthView.m->selectDay:day as well as at the end of TKCalendarMonthView.m->-reactToTouch:down. Limited testing so far so good. Off to figure out why the timezone setting keeps thinking its tomorrow (I am in Pacific time zone).
Cheers, Michael

Resources