SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, iOS Chart, Android Chart and JavaScript Chart Components
SciChart Android ships with ~90Â Android Chart Examples which you can browse, play with, view the source-code and even export each SciChart Android Chart Example to a stand-alone Android Studio project. All of this is possible with the new and improved SciChart Android Examples Suite, which ships as part of our Android Charts SDK.
This example demonstrates how to use WaterfallRenderableSeries3D and WaterfallDataSeries3D Type to create the Waterfall Android Chart in 3D with SciChart Android, that renders a two-dimensional array as a series of slices. The Waterfall Plot initially looks like a series of “mountain” shapes that appear side by side.
The WaterfallRenderableSeries3D type provides a number of configurable chart types in SciChart Android 3D, including:
Please read more about The Waterfall 3D Chart Type in SciChart Android Documentation.
The full source code for the Android 3D Simple Waterfall example is included below (Scroll down!).
Did you know you can also view the source code from one of the following sources as well?
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2021. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales: sales@scichart.com
//
// Waterfall3DChartFragment.kt is part of SCICHART®, High Performance Scientific Charts
// For full terms and conditions of the license, see http://www.scichart.com/scichart-eula/
//
// This source code is protected by international copyright law. Unauthorized
// reproduction, reverse-engineering, or distribution of all or any portion of
// this source code is strictly prohibited.
//
// This source code contains confidential and proprietary trade secrets of
// SciChart Ltd., and should at no time be copied, transferred, sold,
// distributed or made available without express written permission.
//******************************************************************************
package com.scichart.examples.fragments.examples3d.basicChartTypes.kt
import android.view.View
import android.widget.AdapterView
import android.widget.CompoundButton
import com.scichart.charting.visuals.axes.AutoRange.Always
import com.scichart.charting3d.model.dataSeries.waterfall.WaterfallDataSeries3D
import com.scichart.charting3d.visuals.SciChartSurface3D
import com.scichart.charting3d.visuals.pointMarkers.SpherePointMarker3D
import com.scichart.charting3d.visuals.renderableSeries.data.GradientColorPalette
import com.scichart.charting3d.visuals.renderableSeries.data.SolidColorBrushPalette
import com.scichart.charting3d.visuals.renderableSeries.waterfall.WaterfallRenderableSeries3D
import com.scichart.drawing.utility.ColorUtil.*
import com.scichart.examples.R
import com.scichart.examples.data.DataManager
import com.scichart.examples.data.Radix2FFT
import com.scichart.examples.fragments.base.ExampleSingleChart3DBaseFragment
import com.scichart.examples.utils.ItemSelectedListenerBase
import com.scichart.examples.utils.ViewSettingsUtil
import com.scichart.examples.utils.scichartExtensions.*
import com.scichart.examples.utils.widgetgeneration.ImageViewWidget
import com.scichart.examples.utils.widgetgeneration.Widget
import java.util.*
import kotlin.math.log10
import kotlin.math.pow
import kotlin.math.sin
import kotlin.math.sqrt
class Waterfall3DChartFragment : ExampleSingleChart3DBaseFragment() {
private val gradientFillColorPalette = GradientColorPalette(
intArrayOf(Red, Orange, Yellow, GreenYellow, DarkGreen),
floatArrayOf(0f, .25f, .5f, .75f, 1f)
)
private val gradientStrokeColorPalette = GradientColorPalette(
intArrayOf(Crimson, DarkOrange, LimeGreen, LimeGreen),
floatArrayOf(0f, .33f, .67f, 1f)
)
private val transparentColorPalette = SolidColorBrushPalette(Transparent)
private val solidStrokeColorPalette = SolidColorBrushPalette(LimeGreen)
private val solidFillColorPalette = SolidColorBrushPalette(0xAA00BFFF.toInt())
private var currentFillColorPalette = 0 // by default YAxis
private var currentStrokeColorPalette = 0 // by default YAxis
private lateinit var rSeries: WaterfallRenderableSeries3D
override fun initExample(surface3d: SciChartSurface3D) {
surface3d.suspendUpdates {
xAxis = numericAxis3D()
yAxis = numericAxis3D()
zAxis = numericAxis3D { autoRange = Always }
renderableSeries {
waterfallRenderableSeries3D {
waterfallDataSeries3D<Double, Double, Double>(POINTS_PER_SLICE, SLICE_COUNT) {
startX = 10.0
stepX = 1.0
startZ = 1.0
fillDataSeries(this)
}
strokeThickness = 1f
sliceThickness = 0f
yColorMapping = gradientFillColorPalette
yStrokeColorMapping = gradientStrokeColorPalette
opacity = 0.8f
rSeries = this
}
}
chartModifiers {
pinchZoomModifier3D()
orbitModifier3D { receiveHandledEvents = true }
zoomExtentsModifier3D()
vertexSelectionModifier3D { receiveHandledEvents = true }
}
}
}
private fun fillDataSeries(ds: WaterfallDataSeries3D<Double, Double, Double>) {
val dataManager = DataManager.getInstance()
val count = POINTS_PER_SLICE * 2
val re = DoubleArray(count)
val im = DoubleArray(count)
for (sliceIndex in 0 until SLICE_COUNT) {
for (i in 0 until count) {
re[i] = 2.0 * sin(Math.PI * i / 10) +
5.0 * sin(Math.PI * i / 5) +
2.0 * dataManager.randomDouble
im[i] = -10.0
}
transform.run(re, im)
val scaleCoef = 1.5.pow(sliceIndex * 0.3) / 1.5.pow(SLICE_COUNT * 0.3)
for (pointIndex in 0 until POINTS_PER_SLICE) {
val reValue = re[pointIndex]
val imValue = im[pointIndex]
val mag = sqrt(reValue * reValue + imValue * imValue)
var yVal = (random.nextInt(10) + 10) * log10(mag / POINTS_PER_SLICE)
yVal = if (yVal < -25 || yVal > -5)
(if (yVal < -25) -25 else random.nextInt(9) - 6).toDouble()
else yVal
ds.updateYAt(pointIndex, sliceIndex, -yVal * scaleCoef)
}
}
}
override fun getToolbarItems(): List<Widget> = ArrayList<Widget>().apply {
add(ImageViewWidget.Builder().setId(R.drawable.example_toolbar_settings).setListener { openSettingsDialog() }.build())
}
private fun openSettingsDialog() {
val dialog = ViewSettingsUtil.createSettingsPopup(activity, R.layout.example_waterfall_3d_popup_layout)
ViewSettingsUtil.setUpSpinner(dialog, R.id.strokePaletteSelector, R.array.stroke_color_palette_list, currentStrokeColorPalette, object : ItemSelectedListenerBase() {
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
when (position) {
0 -> {
currentStrokeColorPalette = 0
rSeries.yStrokeColorMapping = gradientStrokeColorPalette
rSeries.zStrokeColorMapping = null
}
1 -> {
currentStrokeColorPalette = 1
rSeries.yStrokeColorMapping = null
rSeries.zStrokeColorMapping = gradientStrokeColorPalette
}
2 -> {
currentStrokeColorPalette = 2
rSeries.yStrokeColorMapping = solidStrokeColorPalette
rSeries.zStrokeColorMapping = solidStrokeColorPalette
}
3 -> {
currentStrokeColorPalette = 3
rSeries.yStrokeColorMapping = transparentColorPalette
rSeries.zStrokeColorMapping = transparentColorPalette
}
}
}
})
ViewSettingsUtil.setUpSpinner(dialog, R.id.fillPaletteSelector, R.array.fill_color_palette_list, currentFillColorPalette,
object : ItemSelectedListenerBase() {
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
when (position) {
0 -> {
currentFillColorPalette = 0
rSeries.yColorMapping = gradientFillColorPalette
rSeries.zColorMapping = null
}
1 -> {
currentFillColorPalette = 1
rSeries.yColorMapping = null
rSeries.zColorMapping = gradientFillColorPalette
}
2 -> {
currentFillColorPalette = 2
rSeries.yColorMapping = solidFillColorPalette
rSeries.zColorMapping = solidFillColorPalette
}
3 -> {
currentFillColorPalette = 3
rSeries.yColorMapping = transparentColorPalette
rSeries.zColorMapping = transparentColorPalette
}
}
}
})
ViewSettingsUtil.setUpCheckBox(dialog, R.id.showPointMarkers, rSeries.pointMarker != null) { _: CompoundButton?, isChecked: Boolean ->
rSeries.pointMarker = if (isChecked) SpherePointMarker3D().apply { fill = Blue; size = 5f } else null
}
ViewSettingsUtil.setUpCheckBox(dialog, R.id.isVolumetric, rSeries.sliceThickness > 0) { _: CompoundButton?, isChecked: Boolean ->
rSeries.sliceThickness = if (isChecked) 10f else 0f
}
dialog.show()
}
companion object {
private const val POINTS_PER_SLICE = 128
private const val SLICE_COUNT = 20
private val random = Random()
private val transform = Radix2FFT(POINTS_PER_SLICE)
}
}
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2021. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales: sales@scichart.com
//
// CreateWaterfall3DChartFragment.java is part of SCICHART®, High Performance Scientific Charts
// For full terms and conditions of the license, see http://www.scichart.com/scichart-eula/
//
// This source code is protected by international copyright law. Unauthorized
// reproduction, reverse-engineering, or distribution of all or any portion of
// this source code is strictly prohibited.
//
// This source code contains confidential and proprietary trade secrets of
// SciChart Ltd., and should at no time be copied, transferred, sold,
// distributed or made available without express written permission.
//******************************************************************************
package com.scichart.examples.fragments.examples3d.basicChartTypes;
import static com.scichart.charting.visuals.axes.AutoRange.Always;
import static com.scichart.drawing.utility.ColorUtil.Blue;
import static com.scichart.drawing.utility.ColorUtil.Crimson;
import static com.scichart.drawing.utility.ColorUtil.DarkGreen;
import static com.scichart.drawing.utility.ColorUtil.DarkOrange;
import static com.scichart.drawing.utility.ColorUtil.GreenYellow;
import static com.scichart.drawing.utility.ColorUtil.LimeGreen;
import static com.scichart.drawing.utility.ColorUtil.Orange;
import static com.scichart.drawing.utility.ColorUtil.Red;
import static com.scichart.drawing.utility.ColorUtil.Transparent;
import static com.scichart.drawing.utility.ColorUtil.Yellow;
import android.app.Dialog;
import android.view.View;
import android.widget.AdapterView;
import androidx.annotation.NonNull;
import com.scichart.charting3d.model.dataSeries.waterfall.WaterfallDataSeries3D;
import com.scichart.charting3d.visuals.SciChartSurface3D;
import com.scichart.charting3d.visuals.axes.NumericAxis3D;
import com.scichart.charting3d.visuals.renderableSeries.data.GradientColorPalette;
import com.scichart.charting3d.visuals.renderableSeries.data.SolidColorBrushPalette;
import com.scichart.charting3d.visuals.renderableSeries.waterfall.WaterfallRenderableSeries3D;
import com.scichart.core.framework.UpdateSuspender;
import com.scichart.examples.R;
import com.scichart.examples.data.DataManager;
import com.scichart.examples.data.Radix2FFT;
import com.scichart.examples.fragments.base.ExampleSingleChart3DBaseFragment;
import com.scichart.examples.utils.ItemSelectedListenerBase;
import com.scichart.examples.utils.ViewSettingsUtil;
import com.scichart.examples.utils.widgetgeneration.ImageViewWidget;
import com.scichart.examples.utils.widgetgeneration.Widget;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Waterfall3DChartFragment extends ExampleSingleChart3DBaseFragment {
private static final int POINTS_PER_SLICE = 128;
private static final int SLICE_COUNT = 20;
private final Random random = new Random();
private final Radix2FFT transform = new Radix2FFT(POINTS_PER_SLICE);
private final GradientColorPalette gradientFillColorPalette = new GradientColorPalette(
new int[]{Red, Orange, Yellow, GreenYellow, DarkGreen},
new float[]{0, .25f, .5f, .75f, 1});
private final GradientColorPalette gradientStrokeColorPalette = new GradientColorPalette(
new int[]{Crimson, DarkOrange, LimeGreen, LimeGreen},
new float[]{0, .33f, .67f, 1});
private final SolidColorBrushPalette transparentColorPalette = new SolidColorBrushPalette(Transparent);
private final SolidColorBrushPalette solidStrokeColorPalette = new SolidColorBrushPalette(LimeGreen);
private final SolidColorBrushPalette solidFillColorPalette = new SolidColorBrushPalette(0xAA00BFFF);
private int currentFillColorPalette = 0; // by default YAxis
private int currentStrokeColorPalette = 0; // by default YAxis
final WaterfallRenderableSeries3D rSeries = sciChart3DBuilder.newWaterfallSeries3D()
.withStrokeThickness(1f)
.withSliceThickness(0f)
.withYColorMapping(gradientFillColorPalette)
.withYStrokeColorMapping(gradientStrokeColorPalette)
.withOpacity(0.8f)
.build();
@Override
protected void initExample(@NonNull SciChartSurface3D surface3d) {
final NumericAxis3D xAxis = sciChart3DBuilder.newNumericAxis3D().build();
final NumericAxis3D yAxis = sciChart3DBuilder.newNumericAxis3D().build();
final NumericAxis3D zAxis = sciChart3DBuilder.newNumericAxis3D().withAutoRangeMode(Always).build();
final WaterfallDataSeries3D<Double, Double, Double> ds = new WaterfallDataSeries3D<>(Double.class, Double.class, Double.class, POINTS_PER_SLICE, SLICE_COUNT);
ds.setStartX(10d);
ds.setStepX(1d);
ds.setStartZ(1d);
fillDataSeries(ds);
rSeries.setDataSeries(ds);
UpdateSuspender.using(surface3d, () -> {
surface3d.setXAxis(xAxis);
surface3d.setYAxis(yAxis);
surface3d.setZAxis(zAxis);
surface3d.getRenderableSeries().add(rSeries);
surface3d.getChartModifiers().add(sciChart3DBuilder.newModifierGroup()
.withPinchZoomModifier3D().build()
.withOrbitModifier3D().withReceiveHandledEvents(true).build()
.withZoomExtentsModifier3D().build()
.withVertexSelectionModifier().withReceiveHandledEvents(true).build()
.build());
});
}
private void fillDataSeries(WaterfallDataSeries3D<Double, Double, Double> ds) {
final DataManager dataManager = DataManager.getInstance();
final int count = POINTS_PER_SLICE * 2;
final double[] re = new double[count];
final double[] im = new double[count];
for (int sliceIndex = 0; sliceIndex < SLICE_COUNT; sliceIndex++) {
for (int i = 0; i < count; i++) {
re[i] = 2d * Math.sin(Math.PI * i / 10) +
5d * Math.sin(Math.PI * i / 5) +
2d * dataManager.getRandomDouble();
im[i] = -10d;
}
transform.run(re, im);
final double scaleCoef = Math.pow(1.5, sliceIndex * 0.3) / Math.pow(1.5, SLICE_COUNT * 0.3);
for (int pointIndex = 0; pointIndex < POINTS_PER_SLICE; pointIndex++) {
final double reValue = re[pointIndex];
final double imValue = im[pointIndex];
final double mag = Math.sqrt(reValue * reValue + imValue * imValue);
double yVal = (random.nextInt(10) + 10) * Math.log10(mag / POINTS_PER_SLICE);
yVal = (yVal < -25 || yVal > -5)
? (yVal < -25) ? -25 : random.nextInt(9) - 6
: yVal;
ds.updateYAt(pointIndex, sliceIndex, -yVal * scaleCoef);
}
}
}
@NonNull
@Override
public List<Widget> getToolbarItems() {
return new ArrayList<Widget>() {{
add(new ImageViewWidget.Builder().setId(R.drawable.example_toolbar_settings).setListener(v -> openSettingsDialog()).build());
}};
}
private void openSettingsDialog() {
final Dialog dialog = ViewSettingsUtil.createSettingsPopup(getActivity(), R.layout.example_waterfall_3d_popup_layout);
ViewSettingsUtil.setUpSpinner(dialog, R.id.strokePaletteSelector, R.array.stroke_color_palette_list, currentStrokeColorPalette, new ItemSelectedListenerBase() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0: // YAxis
currentStrokeColorPalette = 0;
rSeries.setYStrokeColorMapping(gradientStrokeColorPalette);
rSeries.setZStrokeColorMapping(null);
break;
case 1: // ZAxis
currentStrokeColorPalette = 1;
rSeries.setYStrokeColorMapping(null);
rSeries.setZStrokeColorMapping(gradientStrokeColorPalette);
break;
case 2: // Solid
currentStrokeColorPalette = 2;
rSeries.setYStrokeColorMapping(solidStrokeColorPalette);
rSeries.setZStrokeColorMapping(solidStrokeColorPalette);
break;
case 3: // None
currentStrokeColorPalette = 3;
rSeries.setYStrokeColorMapping(transparentColorPalette);
rSeries.setZStrokeColorMapping(transparentColorPalette);
break;
}
}
});
ViewSettingsUtil.setUpSpinner(dialog, R.id.fillPaletteSelector, R.array.fill_color_palette_list, currentFillColorPalette, new ItemSelectedListenerBase() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0: // YAxis
currentFillColorPalette = 0;
rSeries.setYColorMapping(gradientFillColorPalette);
rSeries.setZColorMapping(null);
break;
case 1: // ZAxis
currentFillColorPalette = 1;
rSeries.setYColorMapping(null);
rSeries.setZColorMapping(gradientFillColorPalette);
break;
case 2: // Solid
currentFillColorPalette = 2;
rSeries.setYColorMapping(solidFillColorPalette);
rSeries.setZColorMapping(solidFillColorPalette);
break;
case 3: // None
currentFillColorPalette = 3;
rSeries.setYColorMapping(transparentColorPalette);
rSeries.setZColorMapping(transparentColorPalette);
break;
}
}
});
ViewSettingsUtil.setUpCheckBox(dialog, R.id.showPointMarkers, rSeries.getPointMarker() != null, (buttonView, isChecked) -> {
rSeries.setPointMarker(isChecked
? sciChart3DBuilder.newSpherePointMarker3D().withFill(Blue).withSize(5f).build()
: null);
});
ViewSettingsUtil.setUpCheckBox(dialog, R.id.isVolumetric, rSeries.getSliceThickness() > 0, (buttonView, isChecked) -> {
rSeries.setSliceThickness(isChecked ? 10f: 0f);
});
dialog.show();
}
}