19
19
20
20
# Declare all supported attributes, across all plot types
21
21
direct_attrables = (
22
- ["x" , "y" , "z" , "a" , "b" , "c" , "r" , "theta" , "size" , "base " ]
22
+ ["base" , " x" , "y" , "z" , "a" , "b" , "c" , "r" , "theta" , "size" , "x_start" , "x_end " ]
23
23
+ ["hover_name" , "text" , "names" , "values" , "parents" , "wide_cross" ]
24
24
+ ["ids" , "error_x" , "error_x_minus" , "error_y" , "error_y_minus" , "error_z" ]
25
25
+ ["error_z_minus" , "lat" , "lon" , "locations" , "animation_group" ]
@@ -610,7 +610,8 @@ def configure_cartesian_axes(args, fig, orders):
610
610
# Set x-axis titles and axis options in the bottom-most row
611
611
x_title = get_decorated_label (args , args ["x" ], "x" )
612
612
for xaxis in fig .select_xaxes (row = 1 ):
613
- xaxis .update (title_text = x_title )
613
+ if "is_timeline" not in args :
614
+ xaxis .update (title_text = x_title )
614
615
set_cartesian_axis_opts (args , xaxis , "x" , orders )
615
616
616
617
# Configure axis type across all x-axes
@@ -621,6 +622,9 @@ def configure_cartesian_axes(args, fig, orders):
621
622
if "log_y" in args and args ["log_y" ]:
622
623
fig .update_yaxes (type = "log" )
623
624
625
+ if "is_timeline" in args :
626
+ fig .update_xaxes (type = "date" )
627
+
624
628
return fig .layout
625
629
626
630
@@ -1354,6 +1358,7 @@ def build_dataframe(args, constructor):
1354
1358
if type (args .get ("color" , None )) == str and args ["color" ] == NO_COLOR :
1355
1359
no_color = True
1356
1360
args ["color" ] = None
1361
+
1357
1362
# now that things have been prepped, we do the systematic rewriting of `args`
1358
1363
1359
1364
df_output , wide_id_vars = process_args_into_dataframe (
@@ -1599,6 +1604,30 @@ def aggfunc_continuous(x):
1599
1604
return args
1600
1605
1601
1606
1607
+ def process_dataframe_timeline (args ):
1608
+ """
1609
+ Massage input for bar traces for px.timeline()
1610
+ """
1611
+ args ["is_timeline" ] = True
1612
+ if args ["x_start" ] is None or args ["x_end" ] is None :
1613
+ raise ValueError ("Both x_start and x_end are required" )
1614
+
1615
+ try :
1616
+ x_start = pd .to_datetime (args ["data_frame" ][args ["x_start" ]])
1617
+ x_end = pd .to_datetime (args ["data_frame" ][args ["x_end" ]])
1618
+ except TypeError :
1619
+ raise TypeError (
1620
+ "Both x_start and x_end must refer to data convertible to datetimes."
1621
+ )
1622
+
1623
+ # note that we are not adding any columns to the data frame here, so no risk of overwrite
1624
+ args ["data_frame" ][args ["x_end" ]] = (x_end - x_start ).astype ("timedelta64[ms]" )
1625
+ args ["x" ] = args ["x_end" ]
1626
+ del args ["x_end" ]
1627
+ args ["base" ] = args ["x_start" ]
1628
+ del args ["x_start" ]
1629
+
1630
+
1602
1631
def infer_config (args , constructor , trace_patch , layout_patch ):
1603
1632
attrs = [k for k in direct_attrables + array_attrables if k in args ]
1604
1633
grouped_attrs = []
@@ -1801,6 +1830,9 @@ def make_figure(args, constructor, trace_patch=None, layout_patch=None):
1801
1830
args = build_dataframe (args , constructor )
1802
1831
if constructor in [go .Treemap , go .Sunburst ] and args ["path" ] is not None :
1803
1832
args = process_dataframe_hierarchy (args )
1833
+ if constructor == "timeline" :
1834
+ constructor = go .Bar
1835
+ args = process_dataframe_timeline (args )
1804
1836
1805
1837
trace_specs , grouped_mappings , sizeref , show_colorbar = infer_config (
1806
1838
args , constructor , trace_patch , layout_patch
0 commit comments