Left axis for HorizontalBarChart of Charts are clipped from the top - swift

When setting up a horizontal bar chart, I'm actually getting a weird issue where the labels of the leftAxis are clipped.
See screenshot:
Here's the code I've used to set up my horizontal bar
func prepareHorizontalBarChart() {
horizontalBarChartView.zoomOut()
horizontalBarChartView.fitBars = true
horizontalBarChartView.xAxis.drawGridLinesEnabled = false // disable horizontal grid lines
horizontalBarChartView.chartDescription?.enabled = false
horizontalBarChartView.xAxis.labelPosition = .bottom
horizontalBarChartView.leftAxis.spaceTop = 0.0
horizontalBarChartView.rightAxis.enabled = false
horizontalBarChartView.leftAxis.axisMinimum = 0
horizontalBarChartView.leftAxis.labelPosition = .insideChart
horizontalBarChartView.leftAxis.granularity = 1.0
horizontalBarChartView.leftAxis.granularityEnabled = true
horizontalBarChartView.extraRightOffset = 10.0
horizontalBarChartView.legend.enabled = false
horizontalBarChartView.xAxis.avoidFirstLastClippingEnabled = true
horizontalBarChartView.xAxis.granularity = 1.0
horizontalBarChartView.xAxis.granularityEnabled = true
horizontalBarChartView.xAxis.drawLabelsEnabled = true
horizontalBarChartView.rightAxis.labelFont = UIFont.systemFont(ofSize: 20)
reloadData()
}

I think in Horizontal Bar chart label is cliping on top edges so for that we need to add extra space in Chart view port with below property.
horiBarChartView.extraTopOffset = 10
will add 10px extra space from top.
Before extra space (default behaviour):
After 10px extra space:
Hope this will help you to solve your problem.

Related

Word VBS script add border cell

I have a simple VBS script below that opens Word and creates a table with 4 cells, I need to add a bottom border only for the cell with TEXT inside and not for the entire table, any ideas?
Set objWord = CreateObject("Word.Application")
objword.visible = true
Set objDoc = objWord.Documents.Add()
Set objSelection = objWord.Selection
Set objRange = objDoc.Range()
objDoc.Tables.Add objRange,2,2
Set objTable = objDoc.Tables(1)
objTable.Cell(2,1).Range.Font.Name = "Arial"
objTable.Cell(2,1).Range.Text = "TEXT"
objTable.Cell(2,1).Borders(-3).LineStyle = 1 'wdLineStyleSingle

IOS Charts positioning of gridlines

I am struggling to find out how to set gridlines on my chart to specific points on the x axis and to centre labels on the lines corresponding to the time of day. I have a simple chart, the data represents a day with about 280 data points (one for every 5 minute period). I want to show gridlines at times of the day equal to 03:00, 06:00, 12:00, 15:00, 18:00 and 21:00 and show the corresponding labels centred below the gridlines. I have have also tried LimitLines, which works for placing the vertical lines at the correct points, but there does not seem to be the ability to align the time labels with the centre of the limit lines.
I know this can be done because I have seen screenshots on-line showing time labels centred on gridlines (or limitlines) for specific periods on the day, but I've spent hours looking for how to do this an I'm drawing a blank.
My code below (note the commented out failed attempt to get limitlines to work).
let tideHeights = LineChartDataSet(entries: dataEntries)
tideHeights.drawCirclesEnabled = false
tideHeights.colors = [NSUIColor.black]
//let timings = ["00:00", "03:00", "06:00", "12:00", "15:00", "18:00", "21:00"]
let data = LineChartData(dataSet: tideHeights)
lineChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: dataPoints)
//lineChartView.xAxis.drawGridLinesEnabled = false
//let gridLine = values.count / timings.count
//var xPos = 0
//for label in timings {
//let limitLine = ChartLimitLine(limit: Double(xPos), label: label)
//limitLine.labelPosition = .bottomLeft
//limitLine.lineWidth = 0.5
//limitLine.lineColor = .black
//limitLine.valueTextColor = .black
//lineChartView.xAxis.addLimitLine(limitLine)
//xPos += gridLine
//}
lineChartView.xAxis.labelCount = 7
lineChartView.xAxis.labelPosition = .bottom
lineChartView.xAxis.granularity = 1
lineChartView.xAxis.avoidFirstLastClippingEnabled = true
lineChartView.legend.enabled = false
lineChartView.data = data
The output is below, the gridlines are at system set positions, how can I control where they are placed?
Update:
After applying the very helpful suggestion by Stephan Schlecht, I am still getting strange results. With lineChartView.xAxis.setLabelCount(9, force: true) I get:
and with lineChartView.xAxis.setLabelCount(4, force: true) I get:
It seems for some reason that the 1st gridline after the Axis is ignored.
Code is:
lineChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: dataPoints)
let marker = ChartMarker()
marker.setMinuteInterval(interval: 5)
marker.chartView = lineChartView
lineChartView.marker = marker
lineChartView.xAxis.setLabelCount(4, force: true)
lineChartView.xAxis.avoidFirstLastClippingEnabled = true
lineChartView.xAxis.labelPosition = .bottom
lineChartView.leftAxis.labelPosition = .insideChart
lineChartView.rightAxis.drawLabelsEnabled = false
lineChartView.legend.enabled = false
lineChartView.data = data
lineChartView.data?.highlightEnabled = true
Update 2
To reproduce, I have the following class which creates the data (btw, it is a stub class, eventually it will contain a paid api, so for now I generate the data for test purposes:
class TideHeights {
var tideHeights = [Double]()
var tideTimes = [Date]()
var strTimes = [String]()
var intervalMins = 5
init (intervalMins: Int) {
self.intervalMins = intervalMins
let slots = 24 * 60.0 / Double(intervalMins)
let seconds = 24 * 60 * 60.0 / slots
let radians = 2 * Double.pi / slots
let endDate = Date().endOfDay
var date = Date().startOfDay
var radianOffset = 0.0
repeat {
tideHeights.append(sin(radianOffset) + 1)
tideTimes.append(date)
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HH:mm"
strTimes.append(timeFormatter.string(from: date))
date = date.advanced(by: seconds)
radianOffset += radians
} while date <= endDate
}
}
this class is instantiated and used to draw the graph in the following two functions in ViewController.
func drawChart() -> Void {
let tideData = TideHeights(intervalMins: 5)
lineChartView.dragEnabled = true
lineChartView.setScaleEnabled(false)
lineChartView.pinchZoomEnabled = false
setChartValues(dataPoints: tideData.strTimes, values: tideData.tideHeights)
}
func setChartValues(dataPoints: [String], values: [Double]) -> Void {
//initialise and load array of chart data entries for drawing
var dataEntries: [ChartDataEntry] = []
for i in 0..<values.count {
let dataEntry = ChartDataEntry(x: Double(i), y: values[i])
dataEntries.append(dataEntry)
}
let tideHeights = LineChartDataSet(entries: dataEntries)
tideHeights.drawCirclesEnabled = false
tideHeights.colors = [NSUIColor.black]
let gradientColors = [ChartColorTemplates.colorFromString("#72E700").cgColor,
ChartColorTemplates.colorFromString("#724BEB").cgColor]
let gradient = CGGradient(colorsSpace: nil, colors: gradientColors as CFArray, locations: nil)!
tideHeights.fillAlpha = 0.7
tideHeights.fill = Fill(linearGradient: gradient, angle: 90)
tideHeights.drawFilledEnabled = true
let data = LineChartData(dataSet: tideHeights)
lineChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: dataPoints)
let marker = ChartMarker()
marker.setMinuteInterval(interval: 5)
marker.chartView = lineChartView
lineChartView.marker = marker
lineChartView.xAxis.setLabelCount(4, force: true)
lineChartView.xAxis.avoidFirstLastClippingEnabled = true
lineChartView.xAxis.labelPosition = .bottom
lineChartView.leftAxis.labelPosition = .insideChart
lineChartView.rightAxis.drawLabelsEnabled = false
lineChartView.legend.enabled = false
lineChartView.data = data
lineChartView.data?.highlightEnabled = true
}
The documentation says:
setLabelCount(int count, boolean force): Sets the number of labels for
the y-axis. Be aware that this number is not fixed (if force == false)
and can only be approximated. If force is enabled (true), then the
exact specified label-count is drawn – this can lead to uneven numbers
on the axis.
see https://weeklycoding.com/mpandroidchart-documentation/axis-general/
Remark: although the y-axis is mentioned in the documentation of the function, it can actually be applied to both axes.
So instead of
lineChartView.xAxis.labelCount = 7
use
lineChartView.xAxis.setLabelCount(9, force: true)
Note: you need 9 label counts not 7.
Test
If one combines a sine wave of 288 points with your code above
for i in 0...288 {
let val = sin(Double(i) * 2.0 * Double.pi / 288.0) + 1
dataEntries.append(ChartDataEntry(x: Double(i), y: val))
}
and forces the label count = 9 as shown, then it looks like this:
Stephan was correct in his answer to this question. To force gridlines and alignment, use setLabelCount(x, force: true) the additional complexity related to my specific project and the data contained in the labels.

How do i stop clipping of limit line text in ios-charts?

I have a requirement for drawing the limit line which is near to the top of the chart and I want to keep limit line label on top right. Is there any way, it can not be truncated. Please see my output.
enter image description here
try limitline.labelPosition = ChartLimitLabelPositionRightBottom;
if you want keep labelPosition on top right,
you may can try set yourYAxis.spaceTop = x;
if x == 0, the maxValue will match the top of the chart,
if x == 1, the maxValue will match the centerY of the chart,
sorry, I can't express myself well, but, just try it.
hope it works.
The default renderer is little bit messed up. Subclass it (YAxisRenderer) and override method: renderLimitLines. Copy the content from original renderer and replace lines:
var clippingRect = viewPortHandler.contentRect
clippingRect.origin.y -= l.lineWidth / 2.0
clippingRect.size.height += l.lineWidth
with:
var clippingRect = viewPortHandler.contentRect
clippingRect.origin.y -= l.lineWidth / 2.0 + l.valueFont.lineHeight
clippingRect.size.height += l.lineWidth + l.valueFont.lineHeight
Now, as you have it prepared, you need to set your new axis renderer for
let yAxisRenderer = CenteredLimitLineYAxisRenderer(
viewPortHandler: chart.viewPortHandler,
yAxis: chart.leftAxis,
transformer: chart.getTransformer(forAxis: .left)
)
chart.leftYAxisRenderer = yAxisRenderer

B4a Listview TwoLines Vertical Centering

i need to use ListView1.TwoLinesAndBitmap
and i have strange problem to set lable,SecondLabel,imageview in center Vertically
as i see all examples set the itemheight to something like : 60dip
but when i test listview in some Hight resolution and density Device like Lenovo 10 inch tablet the height of itemheight will be very small
so i decide to use percent of Y as itemheight
here is my code : **********
ListView1.TwoLinesAndBitmap.ItemHeight = 10%y
ListView1.TwoLinesAndBitmap.ImageView.Height = ListView1.TwoLinesAndBitmap.ItemHeight - 20dip
ListView1.TwoLinesAndBitmap.ImageView.Width = ListView1.TwoLinesAndBitmap.ImageView.Height
ListView1.TwoLinesAndBitmap.ImageView.Gravity = Gravity.CENTER
ListView1.TwoLinesAndBitmap.Label.TextColor = Colors.Black
ListView1.TwoLinesAndBitmap.Label.Left = ListView1.Left
ListView1.TwoLinesAndBitmap.Label.Width = ListView1.Width
ListView1.TwoLinesAndBitmap.Label.Height = ListView1.TwoLinesLayout.ItemHeight/2
ListView1.TwoLinesAndBitmap.Label.Gravity = Gravity.CENTER + Gravity.CENTER_VERTICAL
ListView1.TwoLinesAndBitmap.Label.TextSize = ListView1.TwoLinesAndBitmap.ItemHeight * 170/1000dip
ListView1.TwoLinesAndBitmap.SecondLabel.Left = ListView1.Left
ListView1.TwoLinesAndBitmap.SecondLabel.Width = ListView1.Width
ListView1.TwoLinesAndBitmap.SecondLabel.Height = ListView1.TwoLinesLayout.ItemHeight/2
ListView1.TwoLinesAndBitmap.SecondLabel.Gravity = Gravity.CENTER + Gravity.CENTER_VERTICAL
ListView1.TwoLinesAndBitmap.SecondLabel.TextSize = ListView1.TwoLinesAndBitmap.ItemHeight * 150/1000dip
i try to center all items in center verticaly but as i attach an image blow there is problems in all three devices ( Sony V , Lenovo tablet , AVD ) and none of them load nice
in sony V :
-lable load on top
-SecondLabel load on bottom
- imageview not Center in vertical
in Lenovo Yoga :
-lable load on top
-SecondLabel load right after label on top
- imageview not center vertical
in avd Emulator :
-lable load on top with a little nicer space from top
-SecondLabel on the bottom (0 position) !!
i`m very confused and try to change various options but no luck at all
Here is the screenshot i take of all 3 devices :
http://i58.tinypic.com/650k1u.jpg
Try this replacements and additions;
ListView1.TwoLinesAndBitmap.ImageView.Left = (ListView1.Width - ListView1.TwoLinesAndBitmap.ImageView.Width)/2
ListView1.TwoLinesAndBitmap.Label.Left = 0
ListView1.TwoLinesAndBitmap.SecondLabel.Left = 0
ListView1.TwoLinesAndBitmap.SecondLabel.Top = ListView1.TwoLinesLayout.ItemHeight/2

Failing to draw on a Gtk.DrawingArea

I'm not able to draw, i've already read tutorials, i can't find the problem.
I simply have a correct UI drawed by Glade. Then i want to draw, for example 50 drawing areas. So i create a Grid with 50 cells; for each cell there is a vertical box (with a drawing area and a label inside each one). But i can't seen anything drawed.
class collega_GUI:
def __init__(self):
try:
self.__builder = Gtk.Builder()
self.__builder.add_from_file('UI2.glade')
self.__Grid = Gtk.Grid()
self.__Grid.set_margin_left(20)
self.__Grid.set_margin_right(20)
self.__Grid.set_row_spacing(10)
self.__Grid.set_column_spacing(15)
self.__Grid.set_column_homogeneous(True)
self.__GridBox = self.__builder.get_object('box11')
self.__GridBox.pack_end(self.__Grid, 1, 1, 20)
indirizzi_ip = []
for i in range(50):
indirizzi_ip.append(str(i))
cpu_info = {}
for ip in indirizzi_ip:
cpu_info[ip] = dict()
left = 0
right = 0
for ip in indirizzi_ip:
cpu_info[ip]['drawing_area'] = Gtk.DrawingArea()
cpu_info[ip]['drawing_area'].set_size_request(100, 100)
cpu_info[ip]['drawing_area'].set_name(ip)
box = Gtk.VBox(False, 5)
box.add(cpu_info[ip]['drawing_area'])
label = Gtk.Label(ip)
box.add(label)
self.__Grid.attach(box, left, right, 1, 1) #object,left,right,top,bottom
cpu_info[ip]['drawing_area'].connect("draw", self.__draw)
label.show()
cpu_info[ip]['drawing_area'].show() #the draw should start now!
box.show()
# 5 drawing areas in a row
left += 1
if left == 5:
right += 1
left = 0
self.__builder.get_object('Azioni_Window').show()
Gtk.main()
except Exception as xe:
logging.error('%s' % str(xe))
sys.exit()
def __draw(self, widget, context):
context.set_source_rgb(0.9, 0, 0.1) #rosso
context.set_source_rgb(0.1, 0.9, 0) #verde
context.set_source_rgb(0.8, 0.7, 0) #giallo
context.set_source_rgb(0.8, 0.7, 0.8) #inattivo
context.rectangle(0, 0, widget.get_allocated_width(), widget.get_allocated_height())
context.fill()
if __name__=='__main__':
try:
UINX=collega_GUI()
except Exception:
sys.exit()
You're missing
self.__Grid.show()
And hence nothing in the grid is shown.
In general it's easier to just call show_all() on some top-level container rather than trying to remember to show() every individual widget.