XDATA number of gear shifts

317 views
Skip to first unread message

Craig Dinger

unread,
Nov 10, 2025, 6:04:45 PM (12 days ago) Nov 10
to golden-cheetah-users
I am interested in using the number of shifts per activity. I believe this is in XDATA GEARS Front-NUM. How can I add a field to report the number of shifts for front and number of shifts for rear derailleurs in the activity? I'm not interested in how long I used each gear or anything else, just the number of shifts made with each derailleur. 

I did a search and found info about XDATA and shift graph. I followed the links re XDATA, but either I didn't understand it or it didn't cover what I am looking for. 


Thanks,

Craig

Ale Martinez

unread,
Nov 10, 2025, 7:37:58 PM (12 days ago) Nov 10
to golden-cheetah-users
El lunes, 10 de noviembre de 2025 a la(s) 8:04:45 p.m. UTC-3, cad...@gmail.com escribió:
I am interested in using the number of shifts per activity. I believe this is in XDATA GEARS Front-NUM. How can I add a field to report the number of shifts for front and number of shifts for rear derailleurs in the activity? I'm not interested in how long I used each gear or anything else, just the number of shifts made with each derailleur. 

I did a search and found info about XDATA and shift graph. I followed the links re XDATA, but either I didn't understand it or it didn't cover what I am looking for. 

If you want to add that information to an existing shifting User Chart you can use annotations, see https://github.com/GoldenCheetah/GoldenCheetah/wiki/UG_Special-Topics_Working-with-User-Charts#adding-annotations-to-the-chart, to compute the number of shifts you need to count the number of times an element of the shifting vector is different from the previous ones, there are several ways to do that, see https://github.com/GoldenCheetah/GoldenCheetah/wiki/UG_Special-Topics_Formula-Syntax-and-Expressions#working-with-vectors to learn the tools. 

Craig Dinger

unread,
Nov 11, 2025, 3:46:46 AM (12 days ago) Nov 11
to golden-cheetah-users
Thanks Ale. I will review the shifting vector option.

Craig

Ale Martinez

unread,
Nov 11, 2025, 6:37:49 AM (12 days ago) Nov 11
to golden-cheetah-users
Filter can be used to count changes in a vector v: count(v[ i>0 && v[i-1]<>v[i] ])

marcen

unread,
Nov 12, 2025, 6:47:00 AM (11 days ago) Nov 12
to golden-cheetah-users
Some time ago, I started working on a user chart for a  Shimano Di2 gear system. There is a tile with metrics that also includes the number of gear changes.  It should also be noted that the metrics and tables tile filters the values for AVG Front Shift Time, AVG Rear Shift Time, Duration min and Duration AVG. 
This is to prevent shift operations from being calculated  where several gears are shifted up or down at once.
The threshold value for this filter is adjustable. The relevant setting parameter is: minDurationThresholdSec.
Overview Di2 - Double.gchart

Pat Voi

unread,
Nov 13, 2025, 7:34:47 AM (10 days ago) Nov 13
to golden-cheetah-users
The usage graphs for a Shimano Di2 drivetrain are interesting. It seems to me that the durations in the graphs are not valid, is that right?
Message has been deleted

marcen

unread,
Nov 13, 2025, 8:34:06 AM (9 days ago) Nov 13
to golden-cheetah-users
Which tiles do you mean where the durations are incorrect? Can you explain in more detail what is invalid about the graphs?
Message has been deleted

Pat Voi

unread,
Nov 13, 2025, 12:40:29 PM (9 days ago) Nov 13
to golden-cheetah-users
I apologize that I did not translate everything, and I just noticed that the times are decimal.
Is it possible to directly convert the (decimal) result into hours?
Message has been deleted

marcen

unread,
Nov 13, 2025, 1:45:42 PM (9 days ago) Nov 13
to golden-cheetah-users

In the User Chart, time values on the Y-axis can only be displayed in decimal format (not as 01:04:02). Make sure that under Chart Settings → Axis, the Minutes setting is set to Continuous. Otherwise, the User Chart will display nothing. https://github.com/GoldenCheetah/GoldenCheetah/wiki/UG_Special-Topics_Working-with-User-Charts#axis-settings

Gear Ratio Shifts tile is the Y units wrong must be Quantity.

Yes, you can divide totalTimePerGear by 3600. To do this, edit the user chart:
https://github.com/GoldenCheetah/GoldenCheetah/wiki/UG_Special-Topics_Working-with-User-Charts#series-settings

I have another idea to make the display closer to a time format, but I still need to test if it works.

Pat Voi

unread,
Nov 13, 2025, 2:06:02 PM (9 days ago) Nov 13
to golden-cheetah-users
Thank you, it would be great if the duration were displayed in hourly format.

marcen

unread,
Nov 13, 2025, 2:40:59 PM (9 days ago) Nov 13
to golden-cheetah-users
The only format that works is the numeric schema like 0245.22, where:

1000 – 100 = hours
10 – 1 = minutes
everything after the decimal point = seconds

So 245.22 means 2 hours, 45 minutes, and 22 seconds.
Overview Di2 - Double.gchart

Poncho

unread,
Nov 13, 2025, 4:54:59 PM (9 days ago) Nov 13
to golden-che...@googlegroups.com
Nice chart, thanks for sharing :)

I think you could improve the performance a bit by using the store() and
fetch() functions. Doing the same computations only once and not for
every tile again.

This would also allow to set minDurationThresholdSec once and then use
it in different places.

Best regards,
Poncho

marcen

unread,
Nov 13, 2025, 6:22:17 PM (9 days ago) Nov 13
to golden-cheetah-users
Thanks for pointing that out. The gear ratio tiles, bars and pie charts are almost identical, only the X-axis is different. Those can be simplified. I'll have to take a closer look at the others to see where they overlap.

marcen

unread,
Nov 14, 2025, 9:57:50 AM (8 days ago) Nov 14
to golden-cheetah-users
Unfortunately, the store() and fetch() functions do not work reliably across different tiles. Each time GC is started, the tile that receives data via fetch() is empty.And when data is then displayed, it is not that of the currently selected activity.

Ale Martinez

unread,
Nov 14, 2025, 10:36:34 AM (8 days ago) Nov 14
to golden-cheetah-users
El viernes, 14 de noviembre de 2025 a la(s) 11:57:50 a.m. UTC-3, marcen escribió:
Unfortunately, the store() and fetch() functions do not work reliably across different tiles. Each time GC is started, the tile that receives data via fetch() is empty.And when data is then displayed, it is not that of the currently selected activity.

Variable scope is the athlete and they are not persistent across sessions, if you want they to work at the activity level you can add filename() to the variable name.

marcen

unread,
Nov 14, 2025, 3:27:37 PM (8 days ago) Nov 14
to golden-cheetah-users
Thank you for the hint. That fixes the issue of incorrect data being loaded. What it doesn't solve is that the activity does not store any data in store() the first time it is loaded, and the activity always needs to be loaded twice for store() to have data.

Ale Martinez

unread,
Nov 14, 2025, 5:46:06 PM (8 days ago) Nov 14
to golden-cheetah-users
El viernes, 14 de noviembre de 2025 a la(s) 5:27:37 p.m. UTC-3, marcen escribió:
Thank you for the hint. That fixes the issue of incorrect data being loaded. What it doesn't solve is that the activity does not store any data in store() the first time it is loaded, and the activity always needs to be loaded twice for store() to have data.

That is not an issue for me, it works as documented in my tests.
Can you post the minimum sample code to reproduce the problem in a KPI tile?

marcen

unread,
Nov 14, 2025, 7:01:50 PM (8 days ago) Nov 14
to golden-cheetah-users
I must have done something wrong. I can't reproduce the problem. I created a new overview with the two user chart tiles and it works as expected. The code was simply copied from the tiles that did not work. I have attached the overview where it doesn't work.
Overview Di2 - Double - mit Stor() Funktion.gchart

Ale Martinez

unread,
Nov 15, 2025, 3:23:38 PM (7 days ago) Nov 15
to golden-cheetah-users
El viernes, 14 de noviembre de 2025 a la(s) 9:01:50 p.m. UTC-3, marcen escribió:
I must have done something wrong. I can't reproduce the problem. I created a new overview with the two user chart tiles and it works as expected. The code was simply copied from the tiles that did not work. I have attached the overview where it doesn't work.

May be the problem is in the chart code but I don't plan to review that, store and fetch implementation is really simple: it just uses a Hash table with name as key for each open athlete (https://github.com/GoldenCheetah/GoldenCheetah/blob/a7200a31ff54f1f8a9cc8bf765fe699a02654638/src/Core/DataFilter.cpp#L6069-L6095), I would not expect the problem be there.

Poncho

unread,
Nov 15, 2025, 4:29:55 PM (7 days ago) Nov 15
to golden-che...@googlegroups.com
It's the order in which the charts appear in the .gchart file that makes
the difference between working and non- working versions.

I've tested it by editing the .gchart file in a text editor. Basically
reordering the values in the "config:" section by copy&pasting the
strings results in a working chart.

Ale Martinez

unread,
Nov 16, 2025, 10:35:27 AM (6 days ago) Nov 16
to golden-cheetah-users
El sábado, 15 de noviembre de 2025 a la(s) 6:29:55 p.m. UTC-3, Poncho escribió:
It's the order in which the charts appear in the .gchart file that makes
the difference between working and non- working versions.

I've tested it by editing the .gchart file in a text editor. Basically
reordering the values in the "config:" section by copy&pasting the
strings results in a working chart.

It tends to be a bad practice to depend on the order of computation since the user can change that without knowing the side effects, an easy way to avoid that is using a pattern like this for each chart/tile:

my-variable-name <- "my-variable-name"+filename();

if (fetch( my-variable-name  )=0) store(my-variable-name  , some-lengthy-computation-generating-a-numeric-value);

fetch(my-variable-name ); 

Craig Dinger

unread,
Nov 20, 2025, 1:22:13 PM (2 days ago) Nov 20
to golden-cheetah-users
A little more background on why I am attempting to obtain the number of shifts. I want to use this number along with the interval between charges to monitor battery degradation as a function of decreasing number of shifts between charges.  I have read and reread "UG_Special Topics_Formula Syntax and Expressions", unfortunately, I don't understand a fair amount of it. I have no computer programming/language background. I am trying to learn, but so far it is really frustrating. I think I understand the basic premise of what needs to be done, but fail miserably on how to accomplish it. 

My understanding is that shift data is stored in Raw Data -> GEARS -> "FRONT-NUM" AND "REAR-NUM". Additionally, this data is in XDATA(Front-Num) and XDATA(Rear-Num) . The data is a vector? In order to obtain the desired number of shift for the front derailleur, I need to count the number of times the value in Front-Num changes. Beyond that I am kind of lost. I'm not sure if I do this by creating a custom metric as below (which doesn't appear to work) or some other option. I copied the first section from the "Shimano DI2.gchart" so to only run the data if Front-Num contains data. The rest is my fumbling about. I'm trying to limit how much I ask for help, but I am really lost at the moment and need more guidance

{

relevant

{

if(length(xdata("GEARS","FRONT-NUM")) = 0)

{annotate(label,"No Gear data in this activity available."); }

else

{ xdata("GEARS","FRONT-NUM"); }

}


finalise

{

# --- Get Data ---

gearsFrontNum <- xdata("Gears", "Front-Num");

count(gearsFrontNum[ i>0 && gearsFrontNum[i-1]<>gearsFrontNum[i] ]);


}

}



Thanks,
Craig

Ale Martinez

unread,
Nov 20, 2025, 2:13:39 PM (2 days ago) Nov 20
to golden-cheetah-users
El jueves, 20 de noviembre de 2025 a la(s) 3:22:13 p.m. UTC-3, cad...@gmail.com escribió:
A little more background on why I am attempting to obtain the number of shifts. I want to use this number along with the interval between charges to monitor battery degradation as a function of decreasing number of shifts between charges.  I have read and reread "UG_Special Topics_Formula Syntax and Expressions", unfortunately, I don't understand a fair amount of it. I have no computer programming/language background. I am trying to learn, but so far it is really frustrating. I think I understand the basic premise of what needs to be done, but fail miserably on how to accomplish it. 

My understanding is that shift data is stored in Raw Data -> GEARS -> "FRONT-NUM" AND "REAR-NUM". Additionally, this data is in XDATA(Front-Num) and XDATA(Rear-Num) . The data is a vector? In order to obtain the desired number of shift for the front derailleur, I need to count the number of times the value in Front-Num changes. Beyond that I am kind of lost. I'm not sure if I do this by creating a custom metric as below (which doesn't appear to work) or some other option. I copied the first section from the "Shimano DI2.gchart" so to only run the data if Front-Num contains data. The rest is my fumbling about. I'm trying to limit how much I ask for help, but I am really lost at the moment and need more guidance

{

relevant

{

if(length(xdata("GEARS","FRONT-NUM")) = 0)

{annotate(label,"No Gear data in this activity available."); }

else

{ xdata("GEARS","FRONT-NUM"); }

}


finalise

{

# --- Get Data ---

gearsFrontNum <- xdata("Gears", "Front-Num");

count(gearsFrontNum[ i>0 && gearsFrontNum[i-1]<>gearsFrontNum[i] ]);


}

}


If you want just a number for the whole activity, a KPI tile would be a simpler option:

Screenshot 2025-11-20 160951.png 

Craig Dinger

unread,
Nov 20, 2025, 4:36:21 PM (2 days ago) Nov 20
to golden-cheetah-users
I'm not sure what I'm doing wrong, I set up a  Rear Shifts kpi with this (I changed the name but otherwise the same but the value is always "1". Front is the same except FD replaced RD. 


#Rear Shifts

{

RDNum <- xdata("Gears", "Rear-Num");

count(RDNum[ i>0 && RDNum[i-1]<>RDNum[i] ]);

}





Ale Martinez

unread,
Nov 20, 2025, 4:38:40 PM (2 days ago) Nov 20
to golden-cheetah-users
El jueves, 20 de noviembre de 2025 a la(s) 6:36:21 p.m. UTC-3, cad...@gmail.com escribió:
I'm not sure what I'm doing wrong, I set up a  Rear Shifts kpi with this (I changed the name but otherwise the same but the value is always "1". Front is the same except FD replaced RD. 

As I commented in my previous post, XData series names are case-sensitive, change them to match what you see in Raw Data tab (all uppercase).

Craig Dinger

unread,
Nov 20, 2025, 5:36:11 PM (2 days ago) Nov 20
to golden-cheetah-users
Thanks Ale,

Everything working as desired now. I had the "Front Shifts" with capitals and the "Rear Shifts" with a mix, not sure how or why, but glad you caught it. The ride I was looking at only had rear shifts so of course the "Front Shifts" was 1. 

Thanks again,

Craig

Ale Martinez

unread,
Nov 20, 2025, 6:12:40 PM (2 days ago) Nov 20
to golden-cheetah-users
Great! BTW, if you would want to accumulate those data across rides, you would need to learn another tool: https://github.com/GoldenCheetah/GoldenCheetah/wiki/UG_Special-Topics_Creating-User-Metrics
Reply all
Reply to author
Forward
0 new messages