File size: 36,529 Bytes
eef5e54
 
 
 
 
d434262
e810060
2222455
eef5e54
 
 
 
 
 
 
 
 
d434262
eef5e54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f4cf720
eef5e54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d434262
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d87a0ac
 
d434262
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e810060
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2222455
d434262
 
5250382
d434262
 
 
1f62e70
d434262
 
 
 
 
 
eef5e54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import requests
import json
import pickle


#################################################################### PAGE CONFIGURATION ####################################################################
st.set_page_config(page_title="Getaround Project Dashboard", page_icon="๐Ÿšฆ", layout="wide")


#################################################################### SIDEBAR MENU ####################################################################

st.sidebar.title("Navigation")
page = st.sidebar.radio("Go to", ["๐Ÿ  Home/Introduction", "๐Ÿ“Š Delays Analysis", "๐Ÿ’ธ Price Prediction", "๐ŸŽ‰ The End & Thank You"])

e = st.sidebar.empty()
e.write("")
st.sidebar.write("Made with ๐Ÿ’–๐Ÿ’—โค๏ธโ€๐Ÿ”ฅ by Youenn PATAT")
e = st.sidebar.empty()
e.write("")
st.sidebar.image("Aventurine_3.png", use_container_width=True)
st.sidebar.markdown("ยซ ๐Ÿฅ‚ Cheers, dear reader! ๐Ÿทยป")


#################################################################### Loading data ####################################################################
####################################################################       &      ####################################################################
#################################################################### Cleaning data ####################################################################
@st.cache_data 
def load_data():
    data = pd.read_excel("https://full-stack-assets.s3.eu-west-3.amazonaws.com/Deployment/get_around_delay_analysis.xlsx")
    return data
    
@st.cache_data 
def load_data_price():
    data_price = pd.read_csv("https://full-stack-assets.s3.eu-west-3.amazonaws.com/Deployment/get_around_pricing_project.csv", index_col=0)
    return data_price

data_load_state = st.text('Loading data...')
data = load_data()
data_price = load_data_price()
data_load_state.text("")

mean_rental_per_day = data_price["rental_price_per_day"].mean()

# Count the number of entries with delay_at_checkout_in_minutes > mean + 3*std and < mean - 3*std
mean_delay_checkout = data["delay_at_checkout_in_minutes"].mean()
std_delay_checkout = data["delay_at_checkout_in_minutes"].std()
outliers = data[(data['delay_at_checkout_in_minutes'] > (mean_delay_checkout + 3* std_delay_checkout)) |
                 (data['delay_at_checkout_in_minutes'] < (mean_delay_checkout - 3* std_delay_checkout))]
# Get the count of such entries
num_outliers = len(outliers)
# Filter out and remove the outliers
data = data[(data['delay_at_checkout_in_minutes'] <= (mean_delay_checkout + 3* std_delay_checkout)) & (data['delay_at_checkout_in_minutes'] >= (mean_delay_checkout - 3* std_delay_checkout)) | (data['delay_at_checkout_in_minutes'].isna())]
# We keep the Nan values to keep information of the cancel state of the rental, if not all the cancel state would be removed
# Define a function to categorize delays
def categorize_delay(delay):
    if pd.isna(delay):
        return "Unknown"
    elif delay <= 0:
        return "Early or in time"
    elif delay < 60:
        return "< 1 hour"
    elif delay < 120:
        return "1 to 2 hours"
    elif delay < 180:
        return "2 to 3 hours"
    elif delay < 360:
        return "3 to 6 hours"
    elif delay < 720:
        return "6 to 12 hours"
    elif delay < 1440:
        return "12 to 24 hours"
    else:
        return "1 day or more"
# Apply function to create the new column
data["checkout_delay_category"] = data["delay_at_checkout_in_minutes"].apply(categorize_delay)

#################################################################### HOME PAGE ####################################################################

if page == "๐Ÿ  Home/Introduction":
    st.title("Welcome to the Getaround Project Dashboard โŒš๐Ÿš—โŒš")
    st.image("https://lever-client-logos.s3.amazonaws.com/2bd4cdf9-37f2-497f-9096-c2793296a75f-1568844229943.png", use_container_width=True)
    st.image("https://imgcdn.stablediffusionweb.com/2024/4/2/85a87b99-264f-4692-b507-7d84b2e4c351.jpg", use_container_width=True)
    st.markdown("""

    ## Introduction

    This project aims to analyze the impact of a new feature of threshold to deal with problematic cases when there are delays at the check-out for a rental.

    

    ๐ŸŸ  **What you'll find in this app**:

    * ๐Ÿ“Š Data insights on rental delays & affected revenue.

    * ๐Ÿ“‰ Strategies to mitigate issues.

    * ๐ŸŽฏ Conclusion & recommendations.

    

    **Use the sidebar** to navigate between pages. ๐Ÿš€

                

    In this first page, you will find out the presentation of data and first views of it. In the **Delays Analysis** page, you will find the analysis of the problem and answers. 

    And in the last page, some thanking and link for my other works.

    """)

    st.subheader("๐Ÿ“Œ - Basic analysis and view of data",  divider="orange")

    # diplay raw data for delays
    st.write("Raw Data")
    if st.checkbox('Show raw data'):
        st.subheader('Raw data')
        st.write(data) 

    
    # Calculate the value counts of each delay category
    delay_counts = data['checkout_delay_category'].value_counts()
    # Calculate the percentage of each category
    delay_percentages = (delay_counts / delay_counts.sum()) * 100

    st.markdown("""

    Firstly, we want to check the proportion of check-in type (`mobile` or `connect`) and the proportion of the rentals' states (`ended` or `canceled`).

    """)

    col1, col2 = st.columns([1, 2])
    with col1:
        #visualisation of the percentage of the mobile vs connect check rental
        checkin_counts = data["checkin_type"].value_counts().reset_index()
        checkin_counts.columns = ["checkin_type", "count"]
        fig1 = px.pie(checkin_counts, 
                    names="checkin_type", 
                    values="count", 
                    title="Check-in Type Distribution",
                    color_discrete_sequence=["#3CB371", "#FFA500"])
        fig1.update_traces(textfont_color="black")
        st.plotly_chart(fig1, use_container_width=True, key="1")


    # Add text in the second column
    with col2:
        #visualisation of the percentage of the mobile vs connect check rental
        cancel_counts = data["state"].value_counts().reset_index()
        cancel_counts.columns = ["state", "count"]
        fig2 = px.pie(cancel_counts, 
                    names="state", 
                    values="count", 
                    title="Proportion of rentals' states",
                    color_discrete_sequence=["#3CB371", "#FFA500"])
        fig2.update_traces(textfont_color="black")
        st.plotly_chart(fig2, use_container_width=True, key="2")

    st.markdown("""

    So, we see that the majority of check-in are made by mobile, only 20% are made by the connected car. 

    Moreover, in our case, with that dataset, we see that rentals are cancels for 15% of rentals.

    """)

    st.markdown("""

                Now let's check the distribution of checkout delays in function of category of time.

                """)
    # Count occurrences of each category
    delay_counts = data["checkout_delay_category"].value_counts().reset_index()
    delay_counts.columns = ["Category", "Count"]
    delay_counts["Percentage"] = (delay_counts["Count"] / delay_counts["Count"].sum()) * 100
    # Define custom colors
    custom_colors = {
        "Early or in time": "#FFA500",  # Orange
    }
    # Assign green as the default color
    for category in delay_counts["Category"]:
        if category not in custom_colors:
            custom_colors[category] = "#3CB371"  # Green
    # Create a bar chart
    fig3 = px.bar(
        delay_counts, 
        x="Category", 
        y="Count", 
        title="Distribution of Checkout Delays", 
        labels={"Category": "Checkout Delay Category", "Count": "Number of Rentals"},
        color="Category",
        text=delay_counts["Percentage"].apply(lambda x: f"{x:.1f}%"),
        color_discrete_map=custom_colors,
    )
    fig3.update_traces(textfont_color="black")
    fig3.update_xaxes(showgrid=False, tickfont=dict(color='black'))
    fig3.update_yaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'))
    fig3.update_layout(xaxis_title="", yaxis_title="", title_font=dict(weight="bold"), showlegend=False, xaxis=dict(zeroline=True,zerolinecolor="black",zerolinewidth=2), plot_bgcolor="#BDDFD6")
    st.plotly_chart(fig3, use_container_width=True, theme=None)
    st.markdown("""

                There is only 32.6% of rental checkout that are early or in time, without delay. 

                For 23.4% we don't have informations. And the majoruty of delays are less than 2 hours.

                """)

    # Count occurrences of each category grouped by checkin_type
    delay_counts = data.groupby(["checkout_delay_category", "checkin_type"]).size().reset_index(name="Count")
    delay_counts["Percentage"] = (delay_counts["Count"] / delay_counts["Count"].sum()) * 100
    # Create a grouped bar chart
    fig4 = px.bar(
        delay_counts, 
        x="checkout_delay_category", 
        y="Count", 
        color="checkin_type",
        title="Distribution of Checkout Delays by Check-in Type", 
        labels={"checkout_delay_category": "Checkout Delay Category", "Count": "Number of Rentals", "checkin_type": "Check-in Type"},
        barmode="group",  # Groups bars side by side
        #text="Count",
        text=delay_counts["Percentage"].apply(lambda x: f"{x:.1f}%"),
        color_discrete_sequence=["#FFA500", "#3CB371"]
    )
    # Improve layout by setting custom order for x-axis
    fig4.update_traces(textfont_color="black")
    fig4.update_xaxes(showgrid=False, tickfont=dict(color='black'))
    fig4.update_yaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'))
    fig4.update_layout(xaxis_title="", yaxis_title="", title_font=dict(weight="bold"), xaxis=dict(zeroline=True,zerolinecolor="black",zerolinewidth=2), plot_bgcolor="#BDDFD6")
    fig4.update_layout(xaxis={'categoryorder':'array', 'categoryarray': [
        "Early or in time", "< 1 hour", "1 to 2 hours", "2 to 3 hours",
        "3 to 6 hours", "6 to 12 hours", "12 to 24 hours", "1 day or more", "Unknown"
    ]})
    st.plotly_chart(fig4, use_container_width=True,  theme=None)
    st.markdown("""

                There is much more delay problem with mobile checkin type than connect.

                """)
    
    st.markdown("""

                Great ! Now for the following analysis, go to the next page "**๐Ÿ“Š Delays Analysis**" !

                """)    

#################################################################### DELAYS ANALYSIS ####################################################################

elif page == "๐Ÿ“Š Delays Analysis":
    st.title("Analysis & Insights ๐Ÿ“Š")
    st.markdown("""

    Here, we analyze the delay problematic and how to solve it with threshold and a certain scope.

    

    **Key Findings**:

    - ๐Ÿš— A minimum delay of **X minutes** reduces scheduling conflicts.

    - ๐Ÿ’ฐ Potential revenue impact: **Y% of total revenue**.

    - โœ… Solving **Z% of problematic cases** with the policy.



    *Visuals and explanations go here.*

                

    In the following, we will focus on the next steps and questions:

                * How often are drivers late for the next check-in? How does it impact the next driver?

                * Which share of our ownerโ€™s revenue would potentially be affected by the feature?

                * How many rentals would be affected by the feature depending on the threshold and scope we choose?

                * How many problematic cases will it solve depending on the chosen threshold and scope?

    """)

    st.subheader("๐Ÿ“Œ - How often are drivers late for the next check-in? How does it impact the next driver?",  divider="orange")

    st.markdown("""

                So, for the first question, here's the visualization of the check-out that are `late`, `early or in time` and the `unknown` data.

                """)
    
    # Count occurrences of category & group category as simple "late", "in time" or "unknown"
    delay_drivers = data["checkout_delay_category"].apply(lambda x: "Early or in time" if x == "Early or in time"
                                                                    else "Unkonwn" if x == "Unknown"
                                                                    else "Late").value_counts().reset_index()
    delay_drivers.columns = ["Category", "Count"]
    delay_drivers["Percentage"] = (delay_drivers["Count"] / delay_drivers["Count"].sum()) * 100
    # Create a bar chart
    fig5 = px.bar(
        delay_drivers, 
        x="Category", 
        y="Count", 
        labels={"Category": "Checkout Delay Category", "Count": "Number of Rentals"},
        title="Distribution of Checkout Delays", 
        text=delay_drivers["Percentage"].apply(lambda x: f"{x:.1f}%"),
        color_discrete_sequence=["#FFA500"],
    )
    fig5.update_traces(textfont_color="black")
    fig5.update_xaxes(showgrid=False, tickfont=dict(color='black'))
    fig5.update_yaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'))
    fig5.update_layout(xaxis_title="", yaxis_title="", title_font=dict(weight="bold"), showlegend=False, xaxis=dict(zeroline=True,zerolinecolor="black",zerolinewidth=2), plot_bgcolor="#BDDFD6")
    st.plotly_chart(fig5, use_container_width=True, theme=None)

    # Count occurrences of each category
    delay_counts = data["checkout_delay_category"].value_counts().reset_index()
    delay_counts.columns = ["Category", "Count"]
    delay_counts["Percentage"] = (delay_counts["Count"] / delay_counts["Count"].sum()) * 100
    # Define custom colors
    custom_colors = {
        "Early or in time": "#FFA500",  # Orange
    }
    # Assign green as the default color
    for category in delay_counts["Category"]:
        if category not in custom_colors:
            custom_colors[category] = "#3CB371"  # Green
    # Create a bar chart
    fig6 = px.bar(
        delay_counts, 
        x="Category", 
        y="Count", 
        title="Distribution of Checkout Delays", 
        labels={"Category": "Checkout Delay Category", "Count": "Number of Rentals"},
        color="Category",
        text=delay_counts["Percentage"].apply(lambda x: f"{x:.1f}%"),
        color_discrete_map=custom_colors,
    )
    fig6.update_traces(textfont_color="black")
    fig6.update_xaxes(showgrid=False, tickfont=dict(color='black'))
    fig6.update_yaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'))
    fig6.update_layout(xaxis_title="", yaxis_title="", title_font=dict(weight="bold"), showlegend=False, xaxis=dict(zeroline=True,zerolinecolor="black",zerolinewidth=2), plot_bgcolor="#BDDFD6")
    st.plotly_chart(fig6, use_container_width=True, theme=None)

    st.markdown("""

                Only 32.6% of the check-out are early or in time, whereas almost half of the check-out (44%) are late.

                """)
    
    st.markdown("""

                Now, for the 2nd question, let's see how delays impact the next driver.

                """)
    
    mean_delay_impact = data["time_delta_with_previous_rental_in_minutes"].mean()
    min_delay_impact = data["time_delta_with_previous_rental_in_minutes"].min()
    max_delay_impact = data["time_delta_with_previous_rental_in_minutes"].max()

    st.markdown("#### Delay impacting informations on the next driver ๐Ÿš˜:")

    st.write(f"โ–ช๏ธ*Average delay impacting next driver:* {mean_delay_impact:.2f} minutes")
    st.write(f"โ–ช๏ธ*Minimum delay impacting next driver:* {min_delay_impact:.2f} minutes")
    st.write(f"โ–ช๏ธ*Maximum delay impacting next driver:* {max_delay_impact:.2f} minutes")

    delay_impact = data

    delay_impact["delta-late_checkout"] = delay_impact["time_delta_with_previous_rental_in_minutes"] - delay_impact["delay_at_checkout_in_minutes"]
    #if negative delta - late checkout, it means that the new rental cannot do its check-in
    negative_delay_impact = delay_impact[delay_impact["delta-late_checkout"] < 0]
    late_checkout = delay_drivers[delay_drivers["Category"] == "Late"]["Count"][0]
    nb_problematic_checkin_late = len(negative_delay_impact)
    # percentage calculation
    problematic_delays_rate = nb_problematic_checkin_late*100/late_checkout
    st.write(f"โ–ช๏ธAmong all the delays ({late_checkout}), {problematic_delays_rate:.3f}% \n of delays caused problems to the next rental because the checkout\n was made later than the new rental checkin.")

    # Calculate the average duration of problematic delays
    average_problematic_delay = negative_delay_impact['delay_at_checkout_in_minutes'].mean()
    # Calculate the average duration of non-problematic delays
    average_non_problematic_delay = data[data['delay_at_checkout_in_minutes'] > 0]['delay_at_checkout_in_minutes'].mean()
    # Compare the averages
    st.write(f"โ–ช๏ธAverage Duration of Problematic Delays: {average_problematic_delay:.0f} minutes")
    st.write(f"โ–ช๏ธAverage Duration of Non-Problematic Delays: {average_non_problematic_delay:.0f} minutes")
    
    delay_impact["problematic_delay"] = delay_impact["delta-late_checkout"] < 0
    delay_impact["problematic_delay"].value_counts()

    fig7 = px.histogram(delay_impact, x="problematic_delay", color_discrete_sequence=["#FFA500"], title="Proportion of problematic delays"
                )
    fig7.update_xaxes(
        categoryorder='array',
        categoryarray=["Problematic", "Non-Problematic"],
        showgrid=False, tickfont=dict(color='black')
    )
    fig7.update_yaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'))
    fig7.add_annotation(x=3, y=10000,text=f"Avg Delay: {average_problematic_delay:.2f} min",showarrow=False)
    fig7.add_annotation(x=2, y=10000,text=f"Avg Delay: {average_non_problematic_delay:.2f} min",showarrow=False)
    fig7.update_layout(
        xaxis=dict(
            tickmode='array',
            tickvals=[True, False],
            ticktext=["Problematic Delay", "Non Problematic Delay"],
            zeroline=True,zerolinecolor="black",zerolinewidth=2
        ),
        xaxis_title="",
        yaxis_title="",
        title_font=dict(weight="bold"),
        showlegend=False,
        plot_bgcolor="#BDDFD6"
    )
    fig7.update_traces(textfont_color="black")
    st.plotly_chart(fig7, use_container_width=True, theme=None)

    st.markdown("""

                For the majority of cases, it poses no problem to have delay, but for 2.857% of the case it is problematic for the following rental.

                """)
    
    st.subheader("๐Ÿ“Œ - Which share of our ownerโ€™s revenue would potentially be affected by the feature?",  divider="orange")

    # Define the treshold of minimum time between 2 locations (minutes)
    thresholds = [30, 60, 90, 120, 180, 360, 720, 1440]  # Example : 1 hour

    data["mean_price_per_rental"] = mean_rental_per_day

    treshold_data = data
    percentage_revenue_impacted = []
    percentage_revenue_impacted_displaying = {}

    for threshold in thresholds:
        treshold_data[f"affected_rentals_{threshold}"] = data["time_delta_with_previous_rental_in_minutes"] <= threshold
        affected_rentals = data[data["time_delta_with_previous_rental_in_minutes"] <= threshold]
        affected_revenue = affected_rentals["mean_price_per_rental"].sum()
        total_revenue = data["mean_price_per_rental"].sum()
        revenue_impact = (affected_revenue / total_revenue) * 100
        percentage_revenue_impacted.append(revenue_impact)
        percentage_revenue_impacted_displaying[threshold] = round(revenue_impact, 3)

    col1, col2 = st.columns([1, 2])
    with col1:
        # Select a threshold
        selected_threshold = st.selectbox("Select a threshold โณ (in minutes):", thresholds, key="selectbox_1")
        # Display impacted revenue percentage
        st.metric(label="๐Ÿ’ฐ Impacted Revenue", value=f"{percentage_revenue_impacted_displaying[selected_threshold]}%")
    
    with col2:
        affected_counts = [treshold_data[f"affected_rentals_{threshold}"].value_counts().get(True, 0) for threshold in thresholds]
        affected_rentals_plot = pd.DataFrame({"Threshold (min)": thresholds, "Affected rentals": affected_counts})

        fig8 = px.line(affected_rentals_plot, x="Threshold (min)", y="Affected rentals", text="Affected rentals",
                    title="Number of rentals affected by the treshold",
                    color_discrete_sequence=["#3CB371"],)
        fig8.update_traces(textposition='top center', textfont_color="black")
        fig8.update_xaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'), showline=True, linewidth=2, linecolor='black')
        fig8.update_yaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'))
        fig8.update_layout(xaxis_title="", yaxis_title="", title_font=dict(weight="bold"), showlegend=False, xaxis=dict(zeroline=True,zerolinecolor="black",zerolinewidth=2), plot_bgcolor="#BDDFD6")
        st.plotly_chart(fig8, use_container_width=True, theme=None)

    
    st.subheader("๐Ÿ“Œ - How many rentals would be affected by the feature depending on the threshold and scope we choose?",  divider="orange")

    all_affected_list = []
    all_affected_display = {}
    connect_affected_list = []
    connect_affected_display = {}
    all_affected_percentage = {}
    connect_affected_percentage = {}

    for threshold in thresholds:
        all_rentals = len(data)
        all_affected = data[data["time_delta_with_previous_rental_in_minutes"] <= threshold].shape[0]
        all_affected_list.append(all_affected)
        connect_affected = data[(data["time_delta_with_previous_rental_in_minutes"] <= threshold) & 
                                (data["checkin_type"] == "connect")].shape[0]
        connect_affected_list.append(connect_affected)
        all_affected_display[threshold] = all_affected
        connect_affected_display[threshold] = connect_affected
        all_affected_percentage[threshold] = (all_affected / all_rentals) * 100
        connect_affected_percentage[threshold] = (connect_affected / all_rentals) * 100

    # Select a threshold
    selected_threshold = st.selectbox("Select a threshold โณ (in minutes):", thresholds, key="selectbox_2")
    # Add a title before metrics
    st.markdown(f"#### ๐Ÿš— Rentals Affected by the {selected_threshold}-Minutes Threshold")

    col1, col2 = st.columns(2)
    # Display metrics side by side
    with col1:
        st.metric(label="๐Ÿ“ฒ All check-ins affected in number โ‡ฉ", value=f"{all_affected_display[selected_threshold]}")
        st.metric(label="๐Ÿ“ฒ All check-ins affected in % โ‡ฉ", value=f"{all_affected_percentage[selected_threshold]:.3f}")

    with col2:
        st.metric(label="๐Ÿ›œ Connect check-ins affected in number โ‡ฉ", value=f"{connect_affected_display[selected_threshold]}")
        st.metric(label="๐Ÿ›œ Connect check-ins affected in % โ‡ฉ", value=f"{connect_affected_percentage[selected_threshold]:.3f}")

    data_affected = pd.DataFrame({ "thresholds" : thresholds,
                 "all_affected" : all_affected_list,
                 "connect_affected" : connect_affected_list})
    
    fig9 = px.scatter(data_affected, x='thresholds', y='all_affected',
                    color_discrete_sequence=["#FFA500"],
                    labels={'all_affected': 'All Affected'},
                    title="Rentals affected by Thresholds in function of the type of check-in")
    # Add a line for 'all_affected'
    fig9.add_trace(go.Scatter(x=data_affected['thresholds'], y=data_affected['all_affected'],
        mode='lines+markers+text', line=dict(color='#FFA500'), name='All Affected', text=data_affected['all_affected']))

    fig9.add_trace(go.Scatter(x=data_affected['thresholds'], y=data_affected['connect_affected'], 
                        mode='lines+markers+text', marker_color='#3CB371', name='Connect Affected',
                        text=data_affected['connect_affected'],))  # Texte ร  afficher sur les marqueurs
    fig9.update_traces(textposition='top center', textfont_color="black")
    fig9.update_xaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'), showline=True, linewidth=2, linecolor='black')
    fig9.update_yaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'))
    fig9.update_layout(xaxis_title="", yaxis_title="", title_font=dict(weight="bold"), showlegend=True, xaxis=dict(zeroline=True,zerolinecolor="black",zerolinewidth=2), plot_bgcolor="#BDDFD6")
    st.plotly_chart(fig9, use_container_width=True, theme=None)

    st.markdown("""

                There are less rentals affected with the scope only on connected check-in than all 

                (mobile + connect) check-in. Moreover, as it could be expected, more rentals are 

                impacted with an increasing of the threshold choice.""")
    
    st.subheader("๐Ÿ“Œ - How many problematic cases will it solve depending on the chosen threshold and scope?",  divider="orange")

    solved_cases_all_list = []
    solved_cases_connect_list = []

    for threshold, i in zip(thresholds, range(len(thresholds))):

        problematic_cases = negative_delay_impact[(negative_delay_impact["delay_at_checkout_in_minutes"] <= threshold)]
        problematic_connectec_case = negative_delay_impact[(negative_delay_impact["delay_at_checkout_in_minutes"] <= threshold) & 
                                                        (negative_delay_impact["checkin_type"] == "connect")]
        total_problems_cases = len(negative_delay_impact)
        total_connect_pb_cases = len(negative_delay_impact[negative_delay_impact["checkin_type"] == "connect"])

        solved_cases = problematic_cases.shape[0]
        solved_cases_all_list.append(solved_cases)
        solved_cases_connect = problematic_connectec_case.shape[0]
        solved_cases_connect_list.append(solved_cases_connect)

        percentage_solved_all = (solved_cases / total_problems_cases) * 100
        percentage_connect_solved = (solved_cases_connect / total_connect_pb_cases) * 100

    # Convert to DataFrame
    df_solved_cases = pd.DataFrame({
        "Threshold (minutes)": thresholds,
        "Solved Cases (All Check-ins)": solved_cases_all_list,
        "Solved Cases (Connect Check-ins)": solved_cases_connect_list,
        "Revenue Impacted (%)": percentage_revenue_impacted
    })

    # Select a threshold with a slider
    selected_threshold = st.selectbox("Select a threshold โณ (in minutes):", thresholds, key="selectbox_3")

    # Get values for selected threshold
    selected_data = df_solved_cases[df_solved_cases["Threshold (minutes)"] == selected_threshold].iloc[0]

    # Display Metrics in Two Columns
    col1, col2, col3 = st.columns(3)
    with col1:
        st.metric(label="๐Ÿ“ฒ All Check-ins Solved", value=f"{selected_data['Solved Cases (All Check-ins)']}")
    with col2:
        st.metric(label="๐Ÿ›œ Connect Check-ins Solved", value=f"{selected_data['Solved Cases (Connect Check-ins)']}")
    with col3:
        st.metric(label="๐Ÿ’ฐ Revenue Impacted", value=f"{selected_data['Revenue Impacted (%)']:.2f} %")

    # Create the figure
    fig10 = go.Figure()
    # Add line for "All Check-ins"
    fig10.add_trace(go.Scatter(
        x=thresholds, 
        y=solved_cases_all_list, 
        mode="lines+markers", 
        name="Solved Cases (All Check-ins)", 
        marker=dict(color="#FFA500")
    ))
    # Add line for "Connect Check-ins"
    fig10.add_trace(go.Scatter(
        x=thresholds, 
        y=solved_cases_connect_list, 
        mode="lines+markers", 
        name="Solved Cases (Connect Check-ins)", 
        marker=dict(color="#3CB371")
    ))
    # Add vertical dashed lines with text annotations
    for i, threshold in enumerate(thresholds):
        max_y_value = solved_cases_all_list[i]  # Ensure line stops at "Solved Cases (All Check-ins)"
        
        # Add dashed line from y=0 to y=max_y_value
        fig10.add_trace(go.Scatter(
            x=[threshold, threshold],  # Vertical line at threshold
            y=[0, max_y_value],  # Stop at max_y_value
            mode="lines",
            line=dict(color="red", width=1.5, dash="dash"),
            name="Revenue Impact Annotation" if i == 0 else None,  # Show legend only once
            showlegend=(i == 0)
        ))
        # Add text annotation slightly above the dashed line
        fig10.add_annotation(
            x=threshold, 
            y=max_y_value + 20,  # Position slightly above the dashed line
            text=f"{percentage_revenue_impacted[i]:.2f}%",  # Format percentage
            showarrow=False,
            font=dict(size=10, color="red"),
            align="center",
        )
    fig10.update_traces(textposition='top center', textfont_color="black")
    fig10.update_xaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'), showline=True, linewidth=2, linecolor='black')
    fig10.update_yaxes(showgrid=True, gridcolor='#A9A9A9', tickfont=dict(color='black'))
    fig10.update_layout(title="Number of Problematic Cases Solved by Threshold",xaxis_title="",yaxis_title="", title_font=dict(weight="bold"),showlegend=True, xaxis=dict(zeroline=True,zerolinecolor="black",zerolinewidth=2), plot_bgcolor="#BDDFD6")
    st.plotly_chart(fig10, use_container_width=True, theme=None)

    st.markdown("""

                #### ๐Ÿ“Š Data Table""")
    st.dataframe(df_solved_cases)

    st.markdown("""

                Now, we can see the problematic cases solved in function of the check-in type (connect or all {mobile๐Ÿ“ฒ + connect๐Ÿ›œ}) 

                with the impacted revenue percentage of each threshold. For me the best choice to solve problem without too much 

                economical impact is to choose the threshold of **180** or **360** minutes, for the scope of all check-in type.""")

    st.markdown("""

                โœจ Thanks for reading all the way through! I hope you enjoyed it and found it interesting.

                Go to the last page, `The End & Thank You`, for a little surprise and links to my other worksโ€ผ๏ธ

                """)
#################################################################### Price prediction ####################################################################

elif page == "๐Ÿ’ธ Price Prediction":
    st.title("Price Prediction for a Rental ๐Ÿ’ธ๐Ÿ’ถ")
    st.markdown("""

    Here, you can choose the parameters of a car and with a connection to my API, you can have a day price prediction of the car.

    

    ๐ŸŸ  **What you'll find in this page**:

    * ๐ŸŽ๏ธ Object to select your car's characteristics?

    * ๐Ÿ’ธ A price prediction for one rental day.

                """)
    
    st.write("Select the car parameters below and get an estimated rental price!")

    # Define API URL
    api_url = "https://hyraxuna-api-getaround.hf.space/predict"

    # Define input fields for car parameters
    car_model = st.selectbox("Car Brand:", ['Citroรซn','Peugeot','PGO','Renault','Audi','BMW','Mercedes','Opel','Volkswagen','Ferrari','Mitsubishi','Nissan','SEAT','Subaru','Toyota','other'])
    mileage = st.slider("Mileage (km):", 0, 600000, 50000, step=1000)
    engine_power = st.slider("Engine Power (HP):", 0, 1000, 100, step=5)
    fuel = st.selectbox("Fuel Type:", ['diesel','petrol','other'])
    paint_color = st.selectbox("Paint Color:", ['black','grey','white','red','silver','blue','beige','brown','other'])
    car_type = st.selectbox("Car Type:", ['convertible','coupe','estate','hatchback','sedan','subcompact','suv','van'])

    # Boolean Features
    private_parking_available = st.checkbox("Private Parking Available")
    has_gps = st.checkbox("GPS Included")
    has_air_conditioning = st.checkbox("Air Conditioning")
    automatic_car = st.checkbox("Automatic Transmission")
    has_getaround_connect = st.checkbox("Getaround Connect Available")
    has_speed_regulator = st.checkbox("Speed Regulator Installed")
    winter_tires = st.checkbox("Winter Tires Installed")

    # Button to Predict
    if st.button("๐Ÿ” Predict Rental Price"):
        st.subheader("๐Ÿ’ถ Prediction Results")

        # Prepare input data as JSON
        input_data = {
                    "model_key": car_model, 
                    "mileage": mileage,
                    "engine_power": engine_power,
                    "fuel": fuel,
                    "paint_color": paint_color,
                    "car_type": car_type,
                    "private_parking_available": private_parking_available,
                    "has_gps": has_gps,
                    "has_air_conditioning": has_air_conditioning,
                    "automatic_car": automatic_car,
                    "has_getaround_connect": has_getaround_connect,
                    "has_speed_regulator": has_speed_regulator,
                    "winter_tires": winter_tires
                }

        headers = {"Content-Type": "application/json"}

        try:
            # API Request
            response = requests.post(api_url, data=json.dumps(input_data), headers=headers)
            result = response.json()

            if response.status_code == 200:
                predicted_price = result.get("prediction")
                st.success(f"๐Ÿ’ฐ Estimated Rental Price: **{predicted_price} โ‚ฌ per day**")
            else:
                st.error("โš ๏ธ Error fetching prediction. Please check API or try again.")
        
        except Exception as e:
            st.error(f"โš ๏ธ API Request Failed: {e}")

#################################################################### END & THANK YOU PAGE ####################################################################

elif page == "๐ŸŽ‰ The End & Thank You":
    st.title("Thank You for Exploring! ๐ŸŽ‰")

     # Create two columns
    col1, col2 = st.columns([1, 2])  # Adjust column ratio (1:2 for image & text)

    # Add an image in the first column
    with col1:
        st.image("ChibiElf1.png", use_container_width=True) 

    # Add text in the second column
    with col2:
        st.markdown("""

        **Final Thoughts**

        - ๐Ÿš€ This analysis helps optimize the rental platform.

        - ๐Ÿ”Ž Finding the right balance between user experience and revenue impact is key.

        

        **๐Ÿ™ Thank you for your time!**

        

        ๐Ÿ“ฉ Feel free to reach out for more insights.

                    

        Here are the links for my other works on **Github** & **Linkedin**:

        """)

        # Define the GitHub and LinkedIn URLs
        github_url = "https://github.com/HyraXuna?tab=repositories"
        linkedin_url = "https://www.linkedin.com/in/youenn-patat-46b59b246/"

        # Display clickable images for GitHub and LinkedIn
        st.markdown(
            f"""

            <div style="display: flex; justify-content: center; gap: 20px;">

                <a href="{github_url}" target="_blank">

                    <img src="https://cdn-icons-png.flaticon.com/512/25/25231.png" width="40">

                </a>

                <a href="{linkedin_url}" target="_blank">

                    <img src="https://cdn-icons-png.flaticon.com/512/174/174857.png" width="40">

                </a>

            </div>

            """,
            unsafe_allow_html=True
        )

    st.balloons()  # ๐ŸŽˆ Fun effect for celebration!

### Footer 
st.markdown("---")

st.markdown(
    """

    <div style="text-align: center;">

        <p>If you want to see more, check out my <strong>Github</strong> ๐Ÿ“–</p>

        <a href="https://github.com/HyraXuna?tab=repositories" target="_blank">

            <img src="https://cdn-icons-png.flaticon.com/512/25/25231.png" width="40">

        </a>

    </div>

    """,
    unsafe_allow_html=True
)

st.markdown("---")