@@ -1254,13 +1254,13 @@ def expert_elevation_profile_plot(
1254
1254
1255
1255
# Plot
1256
1256
if color in ["ele" , "speed" , "pace" , "vertical_drop" , "ascent_rate" , "ascent_speed" ]:
1257
- axes .scatter (self .dataframe ["distance_from_start" ].values ,
1257
+ axes .scatter (self .dataframe ["distance_from_start" ].values / 1000 ,
1258
1258
self .dataframe ["ele" ].values ,
1259
1259
s = size ,
1260
1260
c = self .dataframe [color ],
1261
1261
cmap = cmap ) # .values to avoid -> Multi-dimensional indexing (e.g. `obj[:, None]`) is no longer supported. Convert to a numpy array before indexing instead.
1262
1262
else :
1263
- axes .scatter (self .dataframe ["distance_from_start" ].values ,
1263
+ axes .scatter (self .dataframe ["distance_from_start" ].values / 1000 ,
1264
1264
self .dataframe ["ele" ].values ,
1265
1265
s = size ,
1266
1266
color = color ) # .values to avoid -> Multi-dimensional indexing (e.g. `obj[:, None]`)
@@ -1269,6 +1269,10 @@ def expert_elevation_profile_plot(
1269
1269
if grid :
1270
1270
axes .grid ()
1271
1271
1272
+ # Axis labels
1273
+ axes .set_xlabel ("Distance [km]" )
1274
+ axes .set_ylabel ("Elevation [m]" )
1275
+
1272
1276
def expert_data_table (
1273
1277
self ,
1274
1278
axes : Axes ,
@@ -1289,12 +1293,12 @@ def expert_data_table(
1289
1293
cell_text = [
1290
1294
[f"{ self .distance ()/ 1000 :.2f} km" ],
1291
1295
[f"{ self .ascent ():.2f} m" ],
1292
- [" " ],
1293
- [" " ],
1294
- [" " ],
1295
- [" " ],
1296
- [" " ],
1297
- [" " ]
1296
+ [f" { self . descent ():.2f } m " ],
1297
+ [f" { self . total_elapsed_time () } " ],
1298
+ [f" { self . avg_speed ():.2f } km/h " ],
1299
+ [f" { self . avg_moving_speed ():.2f } km/h " ],
1300
+ [f" { self . max_speed ():.2f } km/h " ],
1301
+ [f" { self . moving_time () } " ]
1298
1302
]
1299
1303
1300
1304
axes .table (cellText = cell_text ,
@@ -1304,6 +1308,39 @@ def expert_data_table(
1304
1308
bbox = bbox )
1305
1309
axes .axis ("off" )
1306
1310
1311
+ def expert_ascent_rate_graph (
1312
+ self ,
1313
+ axes : Axes ):
1314
+ ascent_rates = [None , 1 , 5 , 10 , 20 ]
1315
+ nb_ascent_rates = [0 for i in ascent_rates ]
1316
+ nb_points = 0
1317
+
1318
+ # Move to a Gpx method?
1319
+ for track in self .gpx .tracks :
1320
+ for track_segment in track .trkseg :
1321
+ nb_points += len (track_segment .trkpt )
1322
+ for track_point in track_segment .trkpt :
1323
+ i = len (ascent_rates )- 1
1324
+ while i > 0 and track_point .ascent_rate < ascent_rates [i ]:
1325
+ i -= 1
1326
+ nb_ascent_rates [i ] += 1
1327
+
1328
+ percent_ascent_rate = [(nb * 100 ) / nb_points for nb in nb_ascent_rates ]
1329
+
1330
+ y_pos = range (1 , len (ascent_rates )+ 1 )
1331
+ y_labels = [f"{ x } %" if x is not None else "" for x in ascent_rates ]
1332
+ rects = axes .barh (y = y_pos ,
1333
+ width = percent_ascent_rate ,
1334
+ color = ["green" , "yellow" , "orange" , "red" , "black" ])
1335
+ large_percentiles = [f"{ p :.1f} %" if p > 40 else '' for p in percent_ascent_rate ]
1336
+ small_percentiles = [f"{ p :.1f} %" if p <= 40 else '' for p in percent_ascent_rate ]
1337
+ axes .bar_label (rects , small_percentiles ,
1338
+ padding = 5 , color = 'black' , fontweight = 'bold' )
1339
+ axes .bar_label (rects , large_percentiles ,
1340
+ padding = - 40 , color = 'white' , fontweight = 'bold' )
1341
+ axes .set_yticks (y_pos , labels = y_labels )
1342
+ axes .set_title ("Ascent rate" )
1343
+
1307
1344
def expert_plot (
1308
1345
self ,
1309
1346
figsize : Tuple [int , int ] = (14 ,8 ),
@@ -1327,12 +1364,14 @@ def expert_plot(
1327
1364
elevation_profile_color : str = "#101010" ,
1328
1365
elevation_profile_cmap : Optional [mpl .colors .Colormap ] = None ,
1329
1366
elevation_profile_colorbar : bool = False ,
1367
+ ascent_rate_graph_position : Optional [Tuple [int , int ]] = (0 ,1 ), # None
1330
1368
shared_color : str = "#101010" ,
1331
1369
shared_cmap : Optional [mpl .colors .Colormap ] = None ,
1332
1370
shared_colorbar : bool = False ,
1333
1371
data_table_position : Optional [Tuple [int , int ]] = (1 ,1 ), # None
1334
1372
title : Optional [str ] = None ,
1335
1373
title_fontsize : int = 20 ,
1374
+ watermark : bool = False ,
1336
1375
file_path : Optional [str ] = None ):
1337
1376
# Create dataframe containing data from the GPX file
1338
1377
self .dataframe = self .to_dataframe (projection = True ,
@@ -1396,7 +1435,7 @@ def expert_plot(
1396
1435
cmap = elevation_profile_cmap ,
1397
1436
colorbar = elevation_profile_colorbar )
1398
1437
else :
1399
- logging .error (f"Invalid map position: no subplot { elevation_profile_position } in a { subplot } array of plots" )
1438
+ logging .error (f"Invalid elevation profile position: no subplot { elevation_profile_position } in a { subplot } array of plots" )
1400
1439
return
1401
1440
1402
1441
# Handle data table plot
@@ -1409,12 +1448,24 @@ def expert_plot(
1409
1448
self .expert_data_table (axs [data_table_position [0 ], data_table_position [1 ]],
1410
1449
bbox = bbox )
1411
1450
else :
1412
- logging .error (f"Invalid map position: no subplot { elevation_profile_position } in a { subplot } array of plots" )
1451
+ logging .error (f"Invalid data table position: no subplot { data_table_position } in a { subplot } array of plots" )
1452
+ return
1453
+
1454
+ # Handle ascent rate bar graph
1455
+ if ascent_rate_graph_position is not None :
1456
+ if (True ): # Check if ascent_rate_graph_position is correct
1457
+ # Plot bar graph on subplot
1458
+ self .expert_ascent_rate_graph (axs [ascent_rate_graph_position [0 ], ascent_rate_graph_position [1 ]])
1459
+ else :
1460
+ logging .error (f"Invalid ascent rate graph position: no subplot { ascent_rate_graph_position } in a { subplot } array of plots" )
1413
1461
return
1414
1462
1415
1463
# Add title
1416
1464
if title is not None :
1417
- fig .suptitle (title , fontsize = title_fontsize )
1465
+ if watermark :
1466
+ fig .suptitle (title + "\n [made with ezGPX]" , fontsize = title_fontsize )
1467
+ else :
1468
+ fig .suptitle (title , fontsize = title_fontsize )
1418
1469
1419
1470
# MAKE FUNCTION ??
1420
1471
# Save or display plot
0 commit comments