Repository: wandb/wandb
Issue category: Bug Report

Issue:
[Bug]: Incorrect order in `runs.histories()`
### Describe the bug

`Runs` have a `order` attribute. However in the `Runs.histories()` method the order is not respected and the `runid` is used to sort instead (see [Relevant code](https://github.com/wandb/wandb/blob/v0.18.7/wandb/apis/public/runs.py#L236). I don't think this is desirable and also is undocumented behavior. I would recommend that the order specified in the `Runs` object is used or to not reorder  all so that it is preserved to match the order obtained when iterating over the `runs` object via the iterator interface.

wandb: 0.17.3
python 3.11.8
operating system: Ubuntu 22.04


Hints:
Hi @GuillaumeOpenAI! Thank you for writing in!

I have tried out something like this on my end:
```
import wandb

api = wandb.Api()

runs = api.runs("acyrtest/support-team-external-storage")

hist = runs.histories()
for hists in hist:
    print(hists)
```

and got this as the result, which is now sorted by run_id, and is sorted by creation date, just like it is in the W&B UI:
```
...
{'_runtime': 0.43318, '_timestamp': 1730926130.456495, 'test': 3, '_step': 3, 'run_id': 'ry7uzzqp'}
{'_runtime': 0.433185, '_timestamp': 1730926130.456522, 'test': 4, '_step': 4, 'run_id': 'ry7uzzqp'}
{'_runtime': 0.43319, '_timestamp': 1730926130.456544, 'test': 5, '_step': 5, 'run_id': 'ry7uzzqp'}
{'_runtime': 0.43322, '_timestamp': 1730926130.4565701, 'test': 6, '_step': 6, 'run_id': 'ry7uzzqp'}
{'_runtime': 0.433225, '_timestamp': 1730926130.456596, 'test': 7, '_step': 7, 'run_id': 'ry7uzzqp'}
{'_runtime': 0.433297, '_timestamp': 1730926130.4566169, 'test': 8, '_step': 8, 'run_id': 'ry7uzzqp'}
{'_runtime': 0.433305, '_timestamp': 1730926130.456641, 'test': 9, '_step': 9, 'run_id': 'ry7uzzqp'}
{'test': 0, '_step': 0, '_runtime': 0.33756, '_timestamp': 1730926195.386603, 'run_id': 'rdav159p'}
{'test': 1, '_step': 1, '_runtime': 0.337583, '_timestamp': 1730926195.386668, 'run_id': 'rdav159p'}
{'test': 2, '_step': 2, '_runtime': 0.337587, '_timestamp': 1730926195.3867, 'run_id': 'rdav159p'}
{'test': 3, '_step': 3, '_runtime': 0.337592, '_timestamp': 1730926195.3867269, 'run_id': 'rdav159p'}
{'test': 4, '_step': 4, '_runtime': 0.337597, '_timestamp': 1730926195.386753, 'run_id': 'rdav159p'}
{'test': 5, '_step': 5, '_runtime': 0.337613, '_timestamp': 1730926195.386775, 'run_id': 'rdav159p'}
{'test': 6, '_step': 6, '_runtime': 0.337673, '_timestamp': 1730926195.3867981, 'run_id': 'rdav159p'}
{'test': 7, '_step': 7, '_runtime': 0.337688, '_timestamp': 1730926195.386824, 'run_id': 'rdav159p'}
{'test': 8, '_step': 8, '_runtime': 0.337705, '_timestamp': 1730926195.386844, 'run_id': 'rdav159p'}
{'test': 9, '_step': 9, '_runtime': 0.337723, '_timestamp': 1730926195.3868642, 'run_id': 'rdav159p'}
{'_timestamp': 1730926993.72419, 'test': 0, '_step': 0, '_runtime': 0.340699, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.72425, 'test': 1, '_step': 1, '_runtime': 0.340727, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.724282, 'test': 2, '_step': 2, '_runtime': 0.340733, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.72431, 'test': 3, '_step': 3, '_runtime': 0.340739, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.7243352, 'test': 4, '_step': 4, '_runtime': 0.340757, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.724362, 'test': 5, '_step': 5, '_runtime': 0.340792, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.7243829, 'test': 6, '_step': 6, '_runtime': 0.34085, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.724406, 'test': 7, '_step': 7, '_runtime': 0.340863, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.724425, 'test': 8, '_step': 8, '_runtime': 0.340896, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730926993.724446, 'test': 9, '_step': 9, '_runtime': 0.340904, 'run_id': 'aesgkd8u'}
{'_timestamp': 1730927371.951988, 'test': 0, '_step': 0, '_runtime': 0.300452, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.952055, 'test': 1, '_step': 1, '_runtime': 0.30048, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.952088, 'test': 2, '_step': 2, '_runtime': 0.300486, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.952116, 'test': 3, '_step': 3, '_runtime': 0.300492, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.9521449, 'test': 4, '_step': 4, '_runtime': 0.300496, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.9521668, 'test': 5, '_step': 5, '_runtime': 0.300524, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.952188, 'test': 6, '_step': 6, '_runtime': 0.300585, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.9522078, 'test': 7, '_step': 7, '_runtime': 0.300596, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.952228, 'test': 8, '_step': 8, '_runtime': 0.300603, 'run_id': 'k633grbi'}
{'_timestamp': 1730927371.952248, 'test': 9, '_step': 9, '_runtime': 0.300609, 'run_id': 'k633grbi'}
...
```

In the example above you can tell the runs are not sorted by run_id but by the timestamp instead. 

Are you seeing a different behavior on your end?
My point is that they should be sorted by the order specified when the `runs` object is created.

When I iterate on my runs via a `for` loop or via `histories` I get a different ordering which is problematic as it's hard to match the `metadata` to the history of a run if the two methods return different orders
Gotcha thank you for the quick follow-up. 

I have gone ahead and sent the feedback over to our engineering team. I'll let you know when I get an update from them. 

Patch:
diff --git a/wandb/apis/public/runs.py b/wandb/apis/public/runs.py
index c605630e079..b29b5109f91 100644
--- a/wandb/apis/public/runs.py
+++ b/wandb/apis/public/runs.py
@@ -236,7 +236,6 @@ def histories(
             if not histories:
                 return pd.DataFrame()
             combined_df = pd.concat(histories)
-            combined_df.sort_values("run_id", inplace=True)
             combined_df.reset_index(drop=True, inplace=True)
             # sort columns for consistency
             combined_df = combined_df[(sorted(combined_df.columns))]
@@ -262,9 +261,9 @@ def histories(
                 histories.append(df)
             if not histories:
                 return pl.DataFrame()
-            combined_df = pl.concat(histories, how="align")
+            combined_df = pl.concat(histories, how="vertical")
             # sort columns for consistency
-            combined_df = combined_df.select(sorted(combined_df.columns)).sort("run_id")
+            combined_df = combined_df.select(sorted(combined_df.columns))
 
             return combined_df
 


Test patch: