QML Charts Calculate Difference between two points on X Axis - qt

I have a qml Line Chart with DateTime X Axis and I need to measure time difference(dx) between two points similar to this chart
Here is the Chart code with sample data
ChartView {
id:chart
title: "Line"
anchors.fill: parent
antialiasing: true
DateTimeAxis {
id: axisX
format: "hh:mm:ss,ms"
tickCount: 10
}
ValueAxis {
id: axisY
min: 0
max: 10
}
LineSeries {
id:series1
name: "LineSeries"
axisX: axisX
axisY: axisY
pointsVisible: true
XYPoint { x: Date.parse("2020-10-09 05:51:00:500"); y: 0 }
XYPoint { x: Date.parse("2020-10-09 05:51:00:600"); y: 2 }
XYPoint { x: Date.parse("2020-10-09 05:52:00:100"); y: 4 }
XYPoint { x: Date.parse("2020-10-09 05:53:00:20"); y: 5 }
XYPoint { x: Date.parse("2020-10-09 05:54:00:200"); y: 8 }
XYPoint { x: Date.parse("2020-10-09 05:55:00:100"); y: 7 }
XYPoint { x: Date.parse("2020-10-09 05:56:00:200"); y: 6 }
XYPoint { x: Date.parse("2020-10-09 05:57:00:400"); y: 2 }
}
}
Any idea how to achieve this using QML or C++?

I roughly did like this. You should adjust time difference handling better.
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
property int rectangeXPosition: 0
property int rectangleYPosition: 0
property int rWidth: 0
property int rHeight: 0
property int minuteDiff: 0
ChartView {
id:chart
title: "Line"
anchors.fill: parent
antialiasing: true
Rectangle
{
x: rectangeXPosition
y: rectangleYPosition
width: rWidth
height: rHeight
color: "red"
opacity: 0.2
Text {
anchors.left: parent.right
anchors.top: parent.top
text: minuteDiff + " minutes"
}
}
MouseArea
{
anchors.fill: parent
onPositionChanged:
{
rWidth = mouse.x - rectangeXPosition
rHeight = mouse.y - rectangleYPosition
var currentPoint = chart.mapToValue(Qt.point(mouse.x, mouse.y), series1)
var startPoint = chart.mapToValue(Qt.point(rectangeXPosition,rectangleYPosition),series1)
var dateTimeDiff = new Date(currentPoint.x - startPoint.x)
minuteDiff = dateTimeDiff.getMinutes()
}
onPressed:
{
var point = Qt.point(mouse.x, mouse.y);
rectangeXPosition = point.x
rectangleYPosition = point.y
}
onReleased:
{
rectangeXPosition = 0
rectangleYPosition = 0
rWidth = 0
rHeight = 0
}
}
DateTimeAxis {
id: axisX
format: "hh:mm:ss,ms"
tickCount: 10
}
ValueAxis {
id: axisY
min: 0
max: 10
}
LineSeries {
id:series1
name: "LineSeries"
axisX: axisX
axisY: axisY
pointsVisible: true
XYPoint { x: Date.parse("2020-10-09 05:51:00:500"); y: 0 }
XYPoint { x: Date.parse("2020-10-09 05:51:00:600"); y: 2 }
XYPoint { x: Date.parse("2020-10-09 05:52:00:100"); y: 4 }
XYPoint { x: Date.parse("2020-10-09 05:53:00:20"); y: 5 }
XYPoint { x: Date.parse("2020-10-09 05:54:00:200"); y: 8 }
XYPoint { x: Date.parse("2020-10-09 05:55:00:100"); y: 7 }
XYPoint { x: Date.parse("2020-10-09 05:56:00:200"); y: 6 }
XYPoint { x: Date.parse("2020-10-09 05:57:00:400"); y: 2 }
}
}
}

Related

Chartview - Drawing rectangles in the plotarea

I'm currently developping a qml application and I need to specify various area in the plotArea.
I'm drawing rectangles but my scatterseries dot are not visible because drawn behing the rectangle.
I tried to add transparency, or to set a z value somewhere but it is not giving a good result.
It is possible with qwidget qcharts and I'm looking to do the same in qml.
Here a working sample of code with my issue (if I comment the rectangles' part the dots are visible)
import QtQuick 2.15
import QtCharts 2.3
ChartView {
id: test
width: 600
height: 400
animationOptions: ChartView.NoAnimation
theme: ChartView.ChartThemeDark
legend.visible: false
ValueAxis {
id: axisX
min: 0
max: 100
}
ValueAxis {
id: axisY1
min: 0
max: 100
}
Rectangle {
id: rect1
color: "red"
border.width: 2
width: plotArea.width * 4 / 10
height: plotArea.height * 4/15
x: plotArea.x
y: plotArea.y
Text {
anchors.left: parent.left
anchors.leftMargin: 8
anchors.top: parent.top
anchors.topMargin: 8
text: qsTr("Rectangle 1")
}
}
Rectangle {
id: rect2
color: "orange"
border.width: 2
width: plotArea.width * 6 / 10
height: plotArea.height * 4 / 15
x: rect1.x + rect1.width
y: plotArea.y
Text {
anchors.left: parent.left
anchors.leftMargin: 8
anchors.top: parent.top
anchors.topMargin: 8
text: qsTr("Rectangle 2")
}
}
Rectangle {
id: rect3
color: "orange"
border.width: 2
width: plotArea.width * 4 / 10
height: plotArea.height * 7 / 15
x: plotArea.x
y: rect1.y + rect1.height
Text {
anchors.left: parent.left
anchors.leftMargin: 8
anchors.top: parent.top
anchors.topMargin: 8
text: qsTr("Rectangle 3")
}
}
Rectangle {
id: rect4
color: "green"
border.width: 2
width: plotArea.width * 6 / 10
height: plotArea.height * 7 / 15
x: rect3.x + rect3.width
y: rect3.y
Text {
anchors.left: parent.left
anchors.leftMargin: 8
anchors.top: parent.top
anchors.topMargin: 8
text: qsTr("Rectangle 4")
}
}
Rectangle {
id: rect5
color: "gray"
width: plotArea.width
height: plotArea.height * 4 / 15
x: plotArea.x
y: rect3.y + rect3.height
border.color: "black"
border.width: 2
}
ScatterSeries {
axisX: axisX
axisY: axisY1
color: "blue"
XYPoint {
x: 10
y: 10
}
XYPoint {
x: 98
y: 5
}
XYPoint {
x: 95
y: 89
}
XYPoint {
x: 5
y: 75
}
markerShape: ScatterSeries.MarkerShapeRectangle
}
}
I didn't find a solution on the documentation or online.
The closed question I found is Qml ChartView with sections for X Axis points but they was no answer
I found a solution by drawing AreaSeries.
import QtQuick 2.15
import QtCharts 2.3
ChartView {
id: test
width: 600
height: 400
animationOptions: ChartView.SeriesAnimations
theme: ChartView.ChartThemeDark
legend.visible: false
ValueAxis {
id: axisX
min: 0
max: 100
}
ValueAxis {
id: axisY1
min: 0
max: 100
}
AreaSeries{
axisX: axisX
axisY: axisY1
color: "red"
upperSeries: LineSeries {
XYPoint { x: 0; y: 50}
XYPoint { x: 75; y: 50}
}
lowerSeries: LineSeries {
XYPoint { x: 0; y: 0}
XYPoint { x: 75; y: 0}
}
}
AreaSeries{
axisX: axisX
axisY: axisY1
color: "orange"
upperSeries: LineSeries {
XYPoint { x: 75; y: 50}
XYPoint { x: 100; y: 50}
}
lowerSeries: LineSeries {
XYPoint { x: 75; y: 0}
XYPoint { x: 100; y: 0}
}
}
AreaSeries{
axisX: axisX
axisY: axisY1
color: "green"
upperSeries: LineSeries {
XYPoint { x: 0; y: 100}
XYPoint { x: 100; y: 100}
}
lowerSeries: LineSeries {
XYPoint { x: 0; y: 50}
XYPoint { x: 100; y: 50}
}
}
ScatterSeries {
axisX: axisX
axisY: axisY1
color: "blue"
XYPoint {
x: 10
y: 10
}
XYPoint {
x: 98
y: 5
}
XYPoint {
x: 95
y: 89
}
XYPoint {
x: 5
y: 75
}
markerShape: ScatterSeries.MarkerShapeRectangle
}
}

how to add PathLine to ShapePath with a Repeater?

UPDATE 1 - i can get it to work using Javascript - but that seems to be a little bit unoptimized (from 2-3% to 30% load with qmlscene.exe when activated) - complete recreation when the model changes (its not ever growing), is that the only way or is there a more "declarative" style available?
How can i add a PathLine to a ShapePath based on a Model?
i know how to use a Repeater from outside of Items but not how to implode them inside of Items
do i need some sort of Repeater-Delegate on pathElements?
and i don't want to use the LineSeries component
import QtQuick.Shapes 1.15
import QtQuick 2.15
Shape {
ListModel {
id: myPositions
ListElement { x: 0; y:38 }
ListElement { x: 10; y: 28 }
ListElement { x: 20; y: 30 }
ListElement { x: 30; y: 14 }
}
ShapePath {
strokeColor: "black"
strokeWidth: 1
fillColor: "transparent"
startX: 0
startY: 0
PathLine { x: 0; y: 38 }
PathLine { x: 10; y: 28 }
PathLine { x: 20; y: 30 }
PathLine { x: 30; y: 14 }
// Repeater {
// model: myPositions
// PathLine { x: model.x; y: model.y }
// }
}
}
UPDATE 1
import QtQuick.Shapes 1.15
import QtQuick 2.15
Shape {
ListModel {
id: myPositions
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Timer
{
interval: 100
running: true
repeat: true
property real myX: 0
onTriggered: {
myPositions.append({"x":myX, "y":getRandomInt(0,30)})
myX = myX + 10
}
}
function createPathLineElements(positionsModel, shapePath)
{
var pathElements = []
for (var i = 0; i < positionsModel.count; i++)
{
var pos = myPositions.get(i)
var pathLine = Qt.createQmlObject('import QtQuick 2.15; PathLine {}',
shapePath);
pathLine.x = pos.x
pathLine.y = pos.y
pathElements.push(pathLine)
}
return pathElements
}
ShapePath {
id: myPath
strokeColor: "black"
strokeWidth: 1
fillColor: "transparent"
startX: 0
startY: 0
pathElements: createPathLineElements(myPositions, myPath)
}
}
Use an Instantiator:
Shape {
ListModel {
id: myPositions
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Timer {
interval: 100
running: true
repeat: true
property real myX: 0
onTriggered: {
myPositions.append({"x":myX, "y":getRandomInt(0,30)})
myX = myX + 10
}
}
ShapePath {
id: myPath
fillColor: "transparent"
strokeColor: "red"
capStyle: ShapePath.RoundCap
joinStyle: ShapePath.RoundJoin
strokeWidth: 3
strokeStyle: ShapePath.SolidLine
}
Instantiator {
model: myPositions
onObjectAdded: myPath.pathElements.push(object)
PathLine {
x: model.x
y: model.y
}
}
}
You can't use repeater in that element.
The most performant way is to use QQuickItem in order to create a custom Item which draws incremental path.
Yet another simpler ways are:
1- Use PathSvg element and set its path runtime like below:
ShapePath {
fillColor: "transparent"
strokeColor: "red"
capStyle: ShapePath.RoundCap
joinStyle: ShapePath.RoundJoin
strokeWidth: 3
strokeStyle: ShapePath.SolidLine
PathSvg { id: ps; path: parent.p } //<== fill path property using js
property string p: ""
Component.onCompleted: {
for ( var i = 0; i < myModel.count; i++) {
p += "L %1 %2".arg(myModel.get(i).x).arg(myModel.get(i).y);
}
ps.path = p;
}
}
2- If you know steps, so you can pre-declare all PathLines and then set their values runtime. Just like a heart rate line on a health care monitor.

How to add text in plotting area of chartview in qml

How do I place text at specific (x,y) locations within the plotting area of a QML ChartView type?
For example, I would like to place text at the location XYPoint{x: -3; Y: 20}
I don't want to place at window's(x,y), i want to put at plotting area's (x,y)
I read documentation,but i don't find any property !!!!!!
//ChartView for plotting points
ChartView{
id:chrt
anchors.fill: parent
height: parent.height
width: parent.width
legend.visible: false
backgroundColor: "black"
//X- axis
ValueAxis{
id: x_axis
min: -5
max: 0
tickCount: 6
}
//Right Y axis
ValueAxis{
id:right_y_axis
min:0
max:40
tickCount: 5
}
//Left Y axis
ValueAxis{
id:left_y_axis
min:0
max:40
tickCount: 5
}
//Line series for wave 1
LineSeries{
id:l1
axisY: left_y_axis
axisX:x_axis
color: "yellow"
width: 1
}
//Line series for wave 2
LineSeries{
id:l2
axisYRight: right_y_axis
style: Qt.DashLine
color: "yellow"
width: 0.6
}
}
Ok, you can use ChartView.mapToPosition to calculate the global position of the specified point from a series (or some another point inside the series), for example:
ChartView{
id:chart
anchors.fill: parent
backgroundColor: "black"
LineSeries{
id: series
XYPoint { x: 10; y: 5 }
XYPoint { x: 10; y: 1 }
XYPoint { x: 15; y: 5 }
XYPoint { x: 20; y: 10 }
XYPoint { x: 25; y: 5 }
XYPoint { x: 30; y: 20 }
XYPoint { x: 40; y: 10 }
}
Text {
id: txt
text: "Hello"
color: "white"
}
onWidthChanged: updatePointPosition();
onHeightChanged: updatePointPosition();
function updatePointPosition()
{
var p = chart.mapToPosition(series.at(3), series);
txt.x = p.x;
txt.y = p.y;
}
}

Custom tooltip Tooltip in QML chartview

I have set a custom tooltip using the code
ChartView {
id: chart
anchors.fill: parent
antialiasing: true
ValueAxis {
id: axisY
tickCount: 3
}
DateTimeAxis{
id: xTime
gridVisible: false
}
ToolTip {
id: id_toolTip
contentItem: Text{
color: "#21be2b"
}
background: Rectangle {
border.color: "#21be2b"
}
}
SplineSeries{
id: chartseries
pointsVisible: true
pointLabelsVisible: false
useOpenGL: true
axisX: xTime
axisY: axisY
onClicked: {
id_toolTip.show("dd")
}
}
}
It gives an error when I click on the graph ..
TypeError: Property 'show' of object QQuickToolTip(0x37275d0) is not a function"
But below mentioned code will work.
chart.ToolTip.show("dd")
But I need custom tooltip
You can use the other properties as I show below:
ChartView {
id: chart
anchors.fill: parent
antialiasing: true
ValueAxis {
id: axisY
tickCount: 3
max: 4
min: 0
}
DateTimeAxis{
id: xTime
gridVisible: false
}
ToolTip {
id: id_tooltip
contentItem: Text{
color: "#21be2b"
text: id_tooltip.text
}
background: Rectangle {
border.color: "#21be2b"
}
}
SplineSeries{
id: chartseries
XYPoint { x: new Date('December 17, 1995 03:24:00').getTime() ; y: 0.0 }
XYPoint { x: new Date('December 18, 1995 04:25:00').getTime() ; y: 3.2 }
XYPoint { x: new Date('December 19, 1995 05:26:00').getTime() ; y: 2.4 }
XYPoint { x: new Date('December 20, 1995 06:27:00').getTime() ; y: 2.1 }
XYPoint { x: new Date('December 21, 1995 07:24:00').getTime() ; y: 0.0 }
XYPoint { x: new Date('December 22, 1995 08:25:00').getTime() ; y: 3.2 }
XYPoint { x: new Date('December 23, 1995 09:26:00').getTime() ; y: 2.4 }
XYPoint { x: new Date('December 24, 1995 10:27:00').getTime() ; y: 2.1 }
pointsVisible: true
pointLabelsVisible: false
useOpenGL: true
axisX: xTime
axisY: axisY
onClicked: {
var p = chart.mapToPosition(point)
var text = qsTr("x: %1, y: %2").arg(new Date(point.x).toLocaleDateString(Qt.locale("en_US"))).arg(point.y)
id_tooltip.x = p.x
id_tooltip.y = p.y - id_tooltip.height
id_tooltip.text = text
//id_tooltip.timeout = 1000
id_tooltip.visible = true
}
}
}
In the first case, id_toolTip.show("dd") , you try to call the show func of the instantiated version of QML::Tooltip whereas at the second case, chart.ToolTip.show("dd") you call the show function of the attached property Tooltip which exists for all the qml controls.
Acccording to the docs, if you don't provide a second parameter, then this means that show() is the func of the shared tooltip and not the one you instantiate. That might be the reason your code does not work.

QML-How to change color of one point in chartview?

How to change color of one particular point in chartview in qml.i.e now all x axis values are displaying in black color but i want odd number to be displayed in red color.I want as shown in image where label colors in y axis are of different colors.
here is my piece of code
ChartView {
id:chartView
width: 2*horizontalList.width
height:horizontalList.height
antialiasing: true
animationOptions: ChartView.SeriesAnimations
legend.visible:false
ValueAxis {
id: scaleAxisX
min: 0
max: pointsX.length
tickCount: pointsX.length+1
labelFormat: "%.0f"
titleVisible: false
gridVisible: true
}
ValueAxis {
id: scaleAxisY
min: 0
max: 1.0
tickCount: 6
//labelFormat: "%.0f"
titleVisible: false
gridVisible: false
labelsVisible: false
labelsColor: "#757575"
}
ScatterSeries {
id: scatterSeries
axisXTop: scaleAxisX
axisY: scaleAxisY
color: "black"
markerSize: 12
}
}
As shown in second image ,the top line with red circle is a X axis(valueAxis) of chartview.i want to make the number inside the red circle to be in red color.
You can add a different ScatterSeries with color value;
import QtQuick 2.0
import QtCharts 2.0
ChartView {
title: "Scatters"
anchors.fill: parent
antialiasing: true
ScatterSeries {
color: "black"
id: scatter1
name: "Scatter1"
XYPoint { x: 1; y: 1 }
XYPoint { x: 2; y: 2 }
XYPoint { x: 3; y: 3 }
XYPoint { x: 4; y: 4 }
}
ScatterSeries {
color: "red"
name: "Scatter2"
XYPoint { x: 1.5; y: 1.5 }
}
}

Resources