Comments (12)
How can I use null values?
If null is parsed as Y value, the following exception is thrown:
Unhandled Exception: type 'Null' is not a subtype of type 'double'
My use case requires valid X values with null Y values
from fl_chart.
Definitely but I think it conveys the proper feeling from the business logic side. The users didn't chart something that they were supposed to do, which caused the problem.
We could offer settings to interpolate with a dashed line and/or a pure null option:
Interpolated with a dashed line:
I would be happy to help with this feature if we go with flutter for our project
from fl_chart.
@yongjhih nulls should be in the next release
from fl_chart.
Hello @imaNNeoFighT,
Thanks for the library! It's great so far. Is it possible to get real nullable coordinates added without having to create multiple instances of lines? This is a standard feature of a lot of different charting libraries.
In almost all of them the best practice is:
{ x: 5, y: null },
{ x: 6, y: null }
See:
- https://google.github.io/charts/flutter/example/line_charts/simple_nulls
- https://formidable.com/open-source/victory/gallery/victory-line-with-null-data/
from fl_chart.
That's what I did for null spots:
Skip null spots:
() {
return LineChart(LineChartData(
lineBarsData: LineChartBarData(/* ... */).listWith(spots.splitByNull()),
minX: spots.map((it) => it.x).min(), // optional: Avoid trimming to keep the original range of x-axis
maxX: spots.map((it) => it.x).max(), // optional: Avoid trimming to keep the original range of x-axis
// ...
));
}
extension LineChartBarDataX<T extends LineChartBarData> on T {
/// Skip spots while [spots] contain null y
List<T> listWith(Iterable<List<FlSpot>> lists) {
final data = this;
return lists.map((spots) => data.copyWith(spots: spots)).toList();
}
}
extension IterableFlSpotX<T extends FlSpot> on Iterable<T> {
Iterable<List<T>> splitByNull() => splitBy((it) => it.y == null);
}
/// ref. https://github.com/yongjhih/dartx/blob/77ef87a/lib/src/iterable.dart#L1012
extension IterableX<T> on Iterable<T> {
Iterable<List<E>> splitBy(bool test(E it)) {
final lists = fold<List<List<E>>>([[]], (that, it) {
if (!test(it)) {
that.last.add(it);
} else {
if (that.last.isNotEmpty) {
that.add([]);
}
}
return that;
});
return lists.where((it) => it.isNotEmpty);
}
}
Interpolate with the dashes for null spots:
() {
return LineChart(LineChartData(
lineBarsData: LineChartBarData(/* ... */).listDashableWith(spots),
minX: spots.map((it) => it.x).min(), // optional: Avoid trimming to keep the original range of x-axis
maxX: spots.map((it) => it.x).max(), // optional: Avoid trimming to keep the original range of x-axis
// ...
));
}
extension LineChartBarDataX<T extends LineChartBarData> on T {
/// Skip spots while [spots] contain null y
List<T> listWith(Iterable<List<FlSpot>> lists) {
final data = this;
return lists.map((spots) => data.copyWith(spots: spots)).toList();
}
/// Return simple dashed [T]
T dashed({
List<int> dashArray = const [1, 2],
double opacity = 0.5,
}) {
return copyWith(
dashArray: dashArray,
belowBarData: belowBarData?.copyWith(
colors: belowBarData?.colors?.map((it) => it. opacityFactor(opacity))?.toList(),
));
}
/// Dashed [spots] while which contain null y
List<T> listDashableWith(Iterable<FlSpot> spots, {
List<int> dashArray = const [1, 2],
double opacity = 0.5,
}) {
final repeatedSpots = spots.repeatByNull();
final _dashed = dashed(dashArray: dashArray, opacity: opacity);
if (repeatedSpots.isNotEmpty) {
return repeatedSpots.map((it) => it.first.dashed ? _dashed.copyWith(spots: it) : copyWith(spots: it)).toList();
} else {
final values = spots.map((it) => it.x);
return <T>[
_dashed.copyWith(spots: <FlSpot>[
FlSpot(values.min() ?? 0, 0),
FlSpot(values.max() ?? 0, 0),
])
];
}
}
}
extension IterableFlSpotX<T extends FlSpot> on Iterable<T> {
Iterable<List<T>> splitByNull() => splitBy((it) => it.y == null);
}
extension IterableFlSpotsX on Iterable<FlSpot> {
Iterable<List<FlSpotDashable>> repeatByNull() =>
map((it) => FlSpotDashable(it.x, it.y))
.repeatBy((it) => it.y == null, (that, it) => FlSpotDashable(that.x, that.y, dashed: true))
.where((it) => it.isNotEmpty);
}
class FlSpotDashable extends FlSpot {
const FlSpotDashable(double x, double y, {this.dashed = false}) : super(x, y);
final bool dashed;
@override
FlSpotDashable copyWith({
double x,
double y,
bool dashed = false
}) {
return FlSpotDashable(
x ?? this.x,
y ?? this.y,
dashed: dashed ?? this.dashed,
);
}
@override
String toString() {
return "{x: ${x}, y: ${y}, dashed: $dashed}";
}
}
extension BarAreaDataX<T extends BarAreaData> on T {
BarAreaData copyWith({
bool show,
List<Color> colors,
Offset gradientFrom,
Offset gradientTo,
List<double> gradientColorStops,
BarAreaSpotsLine spotsLine,
double cutOffY,
bool applyCutOffY,
}) => BarAreaData(
show: show ?? this.show ?? false,
colors: colors ?? this.colors ?? const [Colors.blueGrey],
gradientFrom: gradientFrom ?? this.gradientFrom ?? const Offset(0, 0),
gradientTo: gradientTo ?? this.gradientTo ?? const Offset(1, 0),
gradientColorStops: gradientColorStops ?? this.gradientColorStops,
spotsLine: spotsLine ?? this.spotsLine ?? const BarAreaSpotsLine(),
cutOffY: cutOffY ?? this.cutOffY,
applyCutOffY: applyCutOffY ?? this.applyCutOffY ?? false,
);
}
/// ref. https://github.com/yongjhih/dartx/blob/77ef87a/lib/src/iterable.dart#L1012
extension IterableX<T> on Iterable<T> {
Iterable<List<E>> splitBy(bool test(E it)) {
final lists = fold<List<List<E>>>([[]], (that, it) {
if (!test(it)) {
that.last.add(it);
} else {
if (that.last.isNotEmpty) {
that.add([]);
}
}
return that;
});
return lists.where((it) => it.isNotEmpty);
}
Iterable<List<T>> repeatBy(bool test(T it), T repeat(T repeater, T element)) {
if (isEmpty) {
return [[]];
}
final lists = skip(1).fold<List<List<T>>>([[first]], (that, it) {
if (test(it)) { // it == null
// repeating for current
if (test(that.last.last)) { // it == null && last == null
// skip
} else { // it == null && last != null
// repeat by repeater
that.add([repeat(that.last.last, it), it]);
}
} else { // it != null
if (test(that.last.last)) { // it != null && last == null
that.last.last = repeat(it, that.last.last);
that.add([it]);
} else { // it != null && last != null
that.last.add(it);
}
}
return that;
});
if (test(lists.last.last)) { // it != null && last == null
final repeater = lists.last.lastOrNullWhere((it) => !test(it));
if (repeater != null) {
lists.last.last = repeat(repeater, lists.last.last);
}
}
return lists.where((it) => it.every((that) => !test(that)));
}
}
extension ColorX<T extends Color> on T {
Color opacityFactor(double factor) =>
withOpacity(opacity * factor);
}
I'm still looking for this project will support the nullable spots by itself.
from fl_chart.
You can have multiple bars on the LineChart, then make two separted and combine them in your chart,
from fl_chart.
check LineBarsData , you can have multiple LineChartBarData
from fl_chart.
Got it! Thank you!
from fl_chart.
Okay fine, we need this in the line chart, but It is weird when we have rounded line chart
from fl_chart.
Nice, we will consider it.
Thanks for reporting!
from fl_chart.
Implemented in 0.8.6, check it out!
from fl_chart.
How can I use null values? If null is parsed as Y value, the following exception is thrown:
Unhandled Exception: type 'Null' is not a subtype of type 'double'
My use case requires valid X values with null Y values
FlSpot.nullSpot
from fl_chart.
Related Issues (20)
- Miss touched section in Pie chart
- Drag points on the line chart to adjust values and UI? HOT 1
- Error: The setter 'textScaler' isn't defined for the class 'RenderScatterChart'. HOT 6
- LineChart with multiple lines: Get single point on hovering/tapping a line
- Allow to define a border to scatter chart ScatterSpot HOT 2
- Disable tooltip values auto-sorting HOT 3
- TextScaler' not found HOT 3
- PieChart not fully draw in ios devices when have only one section HOT 8
- flchart No data appears in the square box HOT 2
- The graph does not appear when I touch it. HOT 1
- Vertical Line Configuration? HOT 3
- No Gradient for VerticalLine and HorizontalLine HOT 1
- Add waterfall chart to library
- Enhancement of Data Point Interaction Capabilities for Improved Analytical Depth HOT 1
- Pie chart sections all black iff one sections was once 100% (360 degrees) HOT 4
- Some lines in bar chart slide to the right, others move vertically HOT 1
- preventCurveOverShooting troubles HOT 2
- The named parameter 'swapAnimationDuration' isn't defined. (has been renamed to duration) HOT 1
- [LineChart] How to access to the desire barData in `getTouchedSpotIndicator`?
- Manage z-index for Scatter Chart
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fl_chart.