Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line Chart ignores colors if mode is set to bezier. #4148

Closed
dtakeda opened this issue Sep 17, 2019 · 7 comments
Closed

Line Chart ignores colors if mode is set to bezier. #4148

dtakeda opened this issue Sep 17, 2019 · 7 comments

Comments

@dtakeda
Copy link

dtakeda commented Sep 17, 2019

What did you do?

Attempt to draw a line chart with a bezier curve with different colors.

What did you expect to happen?

A line chart with different colors.

What happened instead?

A line chart with the first color.

Screen Shot 2019-09-17 at 1 27 03 PM

Charts Environment

Charts version: 3.3.0
Xcode version: 10.3
Swift version:
Platform(s) running Charts:
macOS version running Xcode: 10.14.6

Demo Project

Using ChartsDemo-iOS-Swift

add the line
set.mode = .horizontalBezier // or the other bezier
after (line 87) in function setDataCount
set.setCircleColor(color)
in MultipleLinesChartViewController.swift

@dtakeda dtakeda changed the title Line Chart does ignores colors if the mode is bezier. Line Chart ignores colors if the mode is set to bezier. Sep 18, 2019
@dtakeda dtakeda changed the title Line Chart ignores colors if the mode is set to bezier. Line Chart ignores colors if mode is set to bezier. Sep 18, 2019
@dgaedcke
Copy link

dgaedcke commented Oct 18, 2019

I'm having this same problem!! Has anyone figured out how to subclass and solve it??

To be clear, I'm focused on the LINE color (not the values or valLabel color). See example chart at SO:
https://stackoverflow.com/questions/58458576/want-two-colors-when-using-mpandroidchart-line-chart-with-beizer-style

I'd be happy to fix and submit a PR if someone can coach me a bit.
And actually, now that I think about it, perhaps we need to manually insert zero points in the data-set as that is where the color-switch should happen ... but that will skew the x-axis and the bezier calculation ... hmmmm?? Might be over my head ...

@dgaedcke
Copy link

dgaedcke commented Oct 19, 2019

yes, I can subclass LineChartRenderer and implement my own drawHorizontalBezier() function
this should work

@liuxuan30
Copy link
Member

I‘m not sure if this is a bug.

        // get the color that is specified for this position from the DataSet
        let drawingColor = dataSet.colors.first!

the bezier line are using the first color of each data set, so it should be working. Can you check what color are you setting? IMO if you set each data set a color, it should be fine.

@dgaedcke
Copy link

I guess my issue was not clear ... I have ONE line (from one data-set) but I want it drawn in TWO colors.... green above zero, and red BELOW zero ... but I've got it working via my subclass. Thanks for your response!!

@liuxuan30
Copy link
Member

ok. FYI the linear lines supports colors per line segments. but for bezier, I think you are right that you need to override it to customize it.

@kevinOlivet
Copy link

dgaedcke, can you share your code of how you managed to get it working via your subclass?

@dgaedcke
Copy link

Here is my subclass:

`import Foundation
import Charts

let tsGreen = UIColor(red: 64/255, green: 196/255, blue: 152/255, alpha: 1)
let tsRed = UIColor(red: 234/255, green: 30/255, blue: 74/255, alpha: 1)
let tsYellow = UIColor(red: 234/255, green: 196/255, blue: 100/255, alpha: 1)

class ColoredLineChartRenderer: LineChartRenderer {
//
// var chartHeight:CGFloat = 0

private var myXBounds = BarLineScatterCandleBubbleRenderer.XBounds()
// added to support the commented "Color Section" code below
// min & maximum visible data geometry coordinate
private var minVisiblePoint = CGPoint.zero
private var maxVisiblePoint = CGPoint.zero

private struct ColorSection {
	// section of graph with specific color
	var min: CGFloat // In data geometry
	var max: CGFloat // In data geometry
	var strokeColor: UIColor

// var fillColor: UIColor { return strokeColor.withAlphaComponent(0.2) }

	static func topBottom() -> [ColorSection] {
		return [ColorSection(min: 0, max: 45, strokeColor: tsRed),
				ColorSection(min:55, max:100, strokeColor: tsGreen),
				ColorSection(min:45.1, max:54.9, strokeColor: tsYellow),
		]
	}
}
// end support for commented "Color Section" code

@objc override func drawHorizontalBezier(context gc: CGContext, dataSet: ILineChartDataSet)
{
	guard let dataProvider = dataProvider else { return }
	
	let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
	
	let phaseY = animator.phaseY
	myXBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator)
	
	// the path for the cubic-spline
	let cubicDrawPath = CGMutablePath()
	var valueToPixelMatrix = trans.valueToPixelMatrix
	
	gc.saveGState()
	gc.beginPath()
	
	if myXBounds.range >= 1 {
		var prev: ChartDataEntry! = dataSet.entryForIndex(myXBounds.min)
		var cur: ChartDataEntry! = prev
		
		if cur == nil { return }
		
		// let the spline start at zero
		cubicDrawPath.move(to: CGPoint(x: CGFloat(cur.x), y: CGFloat(cur.y * phaseY)), transform: valueToPixelMatrix)
		
		for j in myXBounds.dropFirst(1) {
			prev = cur
			cur = dataSet.entryForIndex(j)

// print("y: (cur.y) when x is (cur.x)")
// control point for curve
let cpx = CGFloat(prev.x + (cur.x - prev.x) / 2.0)
cubicDrawPath.addCurve(
to: CGPoint(
x: CGFloat(cur.x),
y: CGFloat(cur.y * phaseY)),
control1: CGPoint(
x: cpx,
y: CGFloat(prev.y * phaseY)),
control2: CGPoint(
x: cpx,
y: CGFloat(cur.y * phaseY)),
transform: valueToPixelMatrix)
} // end of for-loop

		// "Color Section" code
		// borrowed from this article:
		// https://stackoverflow.com/questions/51879693/how-to-change-stroke-and-path-color-on-uibezierpath-when-it-crosses-a-threshold
		
		let graphSize = CGSize(width: 600, height: 600)

		for band in ColorSection.topBottom() {
			let y0 = max(CGPoint(x: 0, y: band.min).applying(valueToPixelMatrix).y, 0)
			let y1 = min(CGPoint(x: 0, y: band.max).applying(valueToPixelMatrix).y, graphSize.height)
			gc.saveGState()	// ; do {
			gc.clip(to: CGRect(x: 0, y: y0, width: graphSize.width, height: y1 - y0))
			band.strokeColor.setStroke()
			gc.setLineWidth(4)
			gc.addPath(cubicDrawPath)
			gc.strokePath()
			gc.restoreGState()
		}
	}
	gc.restoreGState()
}

}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants