I've read some articles about the weekend problem with teechart and the suggestions are the foolowing steps:
TChart1.Series(0).XValues.DateTime = False
Use continuous numbers as Xvalues
replace the X label with datetime.
The problem is: I draw the real time candlesticks according to the date,hour and minute and I must keep TChart1.Series(0).XValues.DateTime = True
So are there any ways to get rid of the null weekend (not only the weekend, even some time in a day as from 5:15 to 6:00 need to be removed) so that the candlesticks are shown continuously (the Xvalues must keep datetime style all the time)?
thanks.
(BTW, I use Teechart2011 Eval & VB6)
TeeChart draws each point according to its X and Y values in the associated axes.
You can work with Break Axis tool to obtain a discontinuous effect in an axis, but the easiest way to draw the points continuously in the horizontal axis is having continuous X values. So I'd suggest you to use the TChart1.Series(i).asCandle.AddCandle XVal, OpenVal, HighVal, LowVal, CloseVal, Label, clTeeColor function, being:
XVal: TChart1.Series(i).Count, instead of the date retrieved from the system
Label: the date retrieved from the system, converted to string
If this doesn't solve the problem because you still think you must have DateTime XValues, please explain why.
Taking your snipped of code from here, I've created a simple example that seems to work fine for me here. Find it below:
Private Sub Form_Load()
Dim month, day, year, hour, minute, second, nums As Integer
Dim tmpDate As Date
month = 6
day = 7
year = 2012
hour = 6
minute = 15
second = 0
nums = 10
TChart1.Aspect.View3D = False
TChart1.AddSeries scCandle
TChart1.Axis.Bottom.Labels.Angle = 90
For i = 1 To nums
tmpDate = (DateValue(day & "," & month & "," & year) + TimeValue(hour & ":" & minute & ":" & second))
If Not IsWeekend(tmpDate) Then
With TChart1.Series(0)
.asCandle.AddCandle .Count, 5, 15, 0, 10, tmpDate, clTeeColor
End With
End If
day = day + 1
Next i
End Sub
Public Function IsWeekend(InputDate As Date) As Boolean
Select Case Weekday(InputDate)
Case vbSaturday, vbSunday
IsWeekend = True
Case Else
IsWeekend = False
End Select
End Function
Related
I'm wondering if it's possible to define a custom ordering or format for the xAxis in highcharts. My dataset has a date time which would be used for the xAxis however my client has specified that it should show the 'Period' on the xAxis. A period is specified as a 30 minute slice - meaning there are 48 periods in a day.
The range of the data is from a period on the previous day to the current day with that period. For example 06/03/2017 Period 11 (10:00) to 07/03/2017 Period 11, the xAxis should look like so:
Currently I've attempted to do this by fiddling with the actual dateTime of each point, so that it is set to Y-m-d H:i:{Period} and then using the dateFormat to only show seconds on the xAxis. However this leaves a gap in data between 2017-03-06 23:59:{Period 48} and 2017-03-07 00:00:{Period 11}
Assuming your series-data is arranged as pairs of [<timestamp in milliseconds>, <value>] you can leave your data alone and simple do calculations and presentation of the label.
To show the labels as we want we use xAxis.labels.formatter (and possibly tickInterval to space them as we want). For example:
xAxis: {
type: 'datetime',
labels: {
formatter: function() {
return createLabelFromTimestamp(this.value);
}
},
tickInterval: 1800000
}
The calculation of the period number (as described in question) can be done for example like this:
function createLabelFromTimestamp(timestamp) {
var hms = timestamp % (1800000 * 48);
var period = hms / 1800000;
// if 0-th period, show date instead
if(period == 0) {
var date = new Date(timestamp);
return date.toDateString();
}
// otherwise show period number
else {
return period;
}
}
We simply modulo away the day and divide to find what 30-minute segment we are in.
See this JSFiddle example of it in action.
I used configured Highstock's "tickPositioner" to set ticks dynamically for different ranges of data. For example, if the range is 1 hour max => 1 tick every 10 minutes. Here is some code of the function I put in tickPositioner (which is in xAxis config):
if (xDataRange <= oneHour) {
// If range is 1 hour max => 1 tick every 10 minutes
increment = oneMinute*10;
positions.info.unitName = "minute";
} else if (xDataRange > oneHour && xDataRange <= oneDay) {
// If range is between 1 hour and 1 day => 1 tick every hour
increment = oneHour;
positions.info.unitName = "hour";
} else { ... }
Here is an illustrating fiddle : http://jsfiddle.net/E6GHC/124/
(I know that the range choices are not the best here.)
The QUESTION: I would like to do the same with the minorTicks.
As you can see in the Fiddle, when you click on the month button the ticks are positionned each week and minorTicks are each day. But this is static configuration (minorTickInterval: oneDay).
I have some ideas and I have tried them and nothing seems to work out..
So if someone have any suggestion ? I would be veryyy thankful.
The perfect thing would have been to be have to set/update the minorTickInterval in tickPositioner function.
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.
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)!
I am plotting a Line Chart, The Problem is in my data some points have zero Value. If I do AddNull For that it don't show the X-axis Value for the same. Can anyone share a example of Using a AddNULL and Add in the same series Impact.
E.g I have a Series having 11 X- Pts, The Series Data is (0,0,0,0,0,10,0,0,0,0,0)
The Point with value 10 should be shown at 5th place but in my case it is displayed at Position 0.
I recommend you use method SetNull or AddNullXY to make null, the values you want and set the property TreatNull to DontPaint because the null values aren't visible. I have made a simple code for you, where I use method SetNull to add nulls in your series:
Private Sub Form_Load()
TChart1.Aspect.View3D = False
TChart1.AddSeries scLine
TChart1.AddSeries scLine
TChart1.Series(0).asLine.Pointer.Visible = True
TChart1.Series(1).asLine.Pointer.Visible = True
Dim i As Integer
For i = 0 To 19
TChart1.Series(0).AddXY i, Rnd, "", vbBlue
If i = 5 Then
TChart1.Series(1).AddXY i, 10, "", vbRed
Else
TChart1.Series(1).AddXY i,0, "", vbRed
End If
Next i
For i = 0 To TChart1.Series(1).Count - 1
If i <> 5 Then
TChart1.Series(1).SetNull (i)
End If
Next i
TChart1.Series(1).asLine.TreatNulls = tnDontPaint
End Sub
Could you tell us if previous works as you want?
Thanks,