modyehab810/ReactPy_SuperStore_Analysis_Dashboard
0
1import reactpy2from reactpy import component, html, run, utils, use_state3import pandas as pd4import numpy as np5import plotly.express as px6from reactpy.backend.fastapi import configure, Options7from fastapi import FastAPI8from reactpy_router import route, simple, link9from reactpy_router.core import use_params10 11app = FastAPI()12 13 14@component15def my_router():16 return simple.router(17 route("/".home()),18 route("/locations".locations()),19 route("/customers".customers()),20 route("/TimeSeries".time_series()),21 route("/Logistics".logistics()),22 )23 24 25# ----------------------------------------------------------------26data__path = r"Sample_Store.csv"27 28df = pd.read_csv(data__path, encoding="unicode_escape")29 30df["Order_Date"] = pd.to_datetime(df["Order_Date"])31df["Ship_Date"] = pd.to_datetime(df["Ship_Date"])32 33df["Order_Month"] = df["Order_Date"].dt.month_name()34df["Order_Year"] = df["Order_Date"].dt.year35 36 37state_list = df["State"].unique().tolist()38state_list.insert(0, "All")39 40# Years41years_list = df["Order_Year"].unique().tolist()42years_list.insert(0, "All")43 44# Categoty45category_list = df["Category"].unique().tolist()46category_list.insert(0, "All")47 48# Main Function of Vizualizations49 50 51def create_chart_vizualization(the_data, chart_type="bar", xlabel="X_Label",52 ylabel="Y_Label", the_title="Chart Title",53 bar_colors=["#ADA2FF", "#C0DEFF",54 "#FCDDB0", "#FF9F9F"],55 title_size=25, hover_html_template="", height=600, showlegend=False):56 if chart_type == "bar":57 fig = px.bar(the_data,58 x=the_data.index,59 y=the_data,60 color=the_data.index,61 color_discrete_sequence=bar_colors,62 labels={"index": xlabel, "y": ylabel},63 text_auto="0.3s",64 title=the_title,65 height=height,66 template="plotly_dark"67 )68 69 fig.update_traces(70 textfont={71 "family": "tahoma",72 "size": 17,73 "color": "white"74 },75 marker=dict(line=dict(color='#111', width=2)),76 hovertemplate=hover_html_template,77 78 )79 80 elif chart_type == "pie":81 fig = px.pie(names=the_data.index,82 values=round(the_data),83 title=the_title,84 color_discrete_sequence=bar_colors,85 height=height,86 template="plotly_dark",87 )88 89 fig.update_traces(90 textfont={91 "family": "tahoma",92 "size": 17,93 "color": "white"94 },95 textinfo="label+value",96 hovertemplate=hover_html_template,97 marker=dict(line=dict(color='#111', width=2)),98 pull=[0.0, 0.0, 0.15]99 100 )101 102 elif chart_type == "line":103 fig = px.line(the_data,104 x=the_data.index.astype(str),105 y=the_data,106 color_discrete_sequence=["#ADA2FF"],107 labels={"y": ylabel, "x": xlabel},108 title=the_title,109 markers="o",110 height=height,111 template="plotly_dark"112 113 )114 115 fig.update_traces(116 marker=dict(size=12, line=dict(color='#111', width=1)),117 hovertemplate=hover_html_template,118 )119 120 fig.update_layout(121 showlegend=showlegend,122 title={123 "font": {124 "size": title_size,125 "family": "tahoma",126 }127 },128 hoverlabel={129 "bgcolor": "#123",130 "font_size": 17,131 "font_family": "tahoma"132 }133 )134 return fig135 136 137@component138def create_sales_category_chart(the_df):139 category_by_slaes = the_df.groupby("Category")["Sales"].sum()140 fig = px.pie(names=category_by_slaes.index,141 values=category_by_slaes,142 title="Total Sales By Category",143 color_discrete_sequence=["#ADA2FF",144 "#C0DEFF", "#FCDDB0", "#FF9F9F"],145 hole=0.43,146 template="plotly_dark"147 )148 149 fig.update_traces(150 textfont={151 "family": "tahoma",152 "size": 15,153 },154 textinfo="label+percent",155 hovertemplate="Category: %{label}<br>Sales: %{value:0.2s}",156 marker=dict(line=dict(color='#111', width=1)),157 )158 159 fig.update_layout(160 showlegend=False,161 title={162 "font": {163 "size": 25,164 "family": "tahoma",165 }166 },167 hoverlabel={168 "bgcolor": "#123",169 "font_size": 17,170 "font_family": "tahoma"171 }172 )173 return fig174 175 176state_filt = state_list[0]177years_filt = years_list[0]178category_filt = category_list[0]179form_data = {"state": "All", "year": "All", "category": "All"}180 181 182@component183def select_menu(the_state, the_year, the_category):184 global state_filt185 global years_filt186 global category_filt187 global form_data188 189 div_class = {190 "class": "flex max-full flex-col gap-y-1 p-2 rounded-md bg-black"191 }192 label_class = {193 "class": "block text-l font-md text-white text-left"194 }195 select_menu_class = "text-gray-300 mt-1 cursor-pointer block w-full py-2 px-3 bg-gray-700 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"196 197 state_filt, set_state_filt = use_state(state_list[0])198 years_filt, set_years_filt = use_state(years_list[0])199 category_filt, set_category_filt = use_state(category_list[0])200 form_data, set_form_data = use_state(201 {"state": "All", "year": "All", "category": "All"})202 203 select_states_options = html.select({204 "id": "states-select",205 "name": "states",206 "value": the_state,207 "class": select_menu_class,208 "on_change": lambda e: set_state_filt(e["target"]["value"]),209 }, [html.option({"value": i, "class": "text-white"}, i) for i in state_list],210 )211 212 select_years_options = html.select({213 "id": "years-select",214 "name": "years",215 "value": the_year,216 "class": select_menu_class,217 "on_change": lambda e: set_years_filt(e["target"]["value"]),218 }, [html.option({"value": i, "class": "text-white"}, i) for i in years_list],219 )220 221 select_category_options = html.select({222 "id": "category-select",223 "name": "category",224 "value": the_category,225 "class": select_menu_class,226 "on_change": lambda e: set_category_filt(e["target"]["value"]),227 }, [html.option({"value": i, "class": "text-white"}, i) for i in category_list],228 )229 230 @reactpy.event(prevent_default=False)231 def handle_submit(event):232 data = {}233 data["state"] = event["target"]["elements"][0]["value"]234 data["year"] = event["target"]["elements"][1]["value"]235 data["category"] = event["target"]["elements"][2]["value"]236 237 set_form_data(data)238 239 menus = html.form(240 {"class": "text-black py-0 sm:py-1", "on_submit": handle_submit},241 html.div(242 {"class": "max-full max-w-7xl px-0 lg:px-0"},243 html.dl(244 {"class": "grid grid-cols-1 xs:grid-cols-1 gap-x-3 gap-y-2 text-center lg:grid-cols-1"},245 html.div(246 div_class,247 html.label(248 label_class,249 f'States: ',250 html.span(251 {"class": "text-blue-300 font-bold"}, the_state)252 ),253 select_states_options254 ),255 html.div(256 div_class,257 html.label(258 label_class,259 f'Years: ',260 html.span(261 {"class": "text-blue-300 font-bold"}, the_year)262 ),263 select_years_options264 ),265 html.div(266 div_class,267 html.label(268 label_class,269 f'Category: ',270 html.span(271 {"class": "text-blue-300 font-bold"}, the_category)272 ),273 select_category_options274 ),275 276 ),277 278 html.br(),279 280 html.div(281 div_class,282 html.button({283 "id": "apply-filter",284 "type": "submit",285 "class": "h-16 w-full text-blue-400 hover:text-white border-2 border-blue-700 hover:bg-black focus:ring-4 focus:outline-none focus:ring-blue-300 font-bold rounded-lg text-lg px-5 py-2.5 text-center me-2 mb-2 dark:border-blue-500 dark:text-blue-500 dark:hover:text-white dark:hover:bg-blue-500 dark:focus:ring-blue-800"286 287 }, "Apply Filter"),288 289 ),290 ),291 )292 293 return menus294 295 296@component297def side_bar():298 299 side_bar = html.aside(300 {"id": "default-sidebar", "class": "relative bg-#0f1729 fixed top-0 left-0 z-40 w-full h-screen transition-transform -translate-x-full sm:translate-x-0",301 "aria-label": "Sidebar"},302 html.div(303 {"class": "h-full px-3 py-4 overflow-y-auto bg-gray-50 dark:bg-gray-800"},304 html.ul(305 {"class": "space-y-2 font-bold"},306 html.li(307 html.a(308 {309 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",310 "href": "/",311 "aria-current": "page"},312 313 html.span(314 {"class": "ms-3"},315 "Sales"316 317 )318 )319 ),320 html.li(321 html.a(322 {323 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",324 "href": "/locations",325 "aria-current": "page"},326 327 html.span(328 {"class": "ms-3"},329 "Locations"330 331 )332 )333 ),334 html.li(335 html.a(336 {337 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",338 "href": "/customers",339 "aria-current": "page"},340 341 html.span(342 {"class": "ms-3"},343 "Customers"344 345 )346 )347 ),348 html.li(349 html.a(350 {351 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",352 "href": "/TimeSeries",353 "aria-current": "page"},354 355 html.span(356 {"class": "ms-3"},357 "Time Series"358 359 )360 )361 ),362 html.li(363 html.a(364 {365 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",366 "href": "/Logistics",367 "aria-current": "page"},368 369 html.span(370 {"class": "ms-3"},371 "Logistics"372 373 )374 )375 ),376 html.hr(),377 html.br(),378 379 380 381 382 html.li(383 select_menu(form_data["state"], form_data["year"],384 form_data["category"]),385 ),386 387 388 )389 390 )391 )392 393 return side_bar394 395 396# ==================== Start Home Page Components =======================397@component398def create_home_cards(the_df, page_title):399 div_class = {400 "class": "flex max-w-xs sm:max-w flex-col gap-y-4 border-2 border-blue-300 p-5 rounded-md bg-black transition "401 "duration-300 ease-in-out hover:bg-gray-900"402 }403 404 dt_class = {405 "class": "ext-base leading-7 text-white font-tahoma font-bold"406 }407 408 dd_class = {409 "class": "order-first text-3xl font-tahoma font-bold tracking-tight text-white sm:text-3xl"410 }411 412 cards = html.section(413 {"class": "text-black py-2 sm:py-2"},414 html.div(415 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},416 html.h2(417 {"class": "text-6xl font-bold mb-8 text-center text-white"},418 page_title419 ),420 html.dl(421 {"class": "grid grid-cols-2 xs:grid-cols-1 sm:grid-cols-1 gap-x-8 gap-y-16 text-center lg:grid-cols-4"},422 html.div(423 div_class,424 html.dt(425 dt_class, "Total Sales"426 ),427 html.dd(428 dd_class,429 f'${the_df["Sales"].sum():,.0f}'430 )431 ),432 433 html.div(434 div_class,435 html.dt(436 dt_class, "Total Profit"437 ),438 html.dd(439 dd_class,440 f'${the_df["Profit"].sum():,.0f}'441 )442 ),443 html.div(444 div_class,445 html.dt(446 dt_class, "Total Volumes"447 ),448 html.dd(449 dd_class,450 f'{the_df["Quantity"].sum():,.0f}'451 )452 ),453 454 html.div(455 div_class,456 html.dt(457 dt_class, "Total Orders"458 ),459 html.dd(460 dd_class,461 f'{the_df["Customer_ID"].nunique():,.0f}'462 )463 )464 465 )466 467 ),468 )469 return cards470 471 472@component473def create_shipping_segment_chart(the_df):474 div_class = {475 "class": "flex max-auto flex-col gap-y-1 border-1 border-gray-800 p-2 rounded-md bg-black"476 }477 # Shipping Mode Bar Chart478 regions_sales = the_df.groupby(479 "Region")["Sales"].sum().sort_values(ascending=False)480 481 fig_regions_sales = create_chart_vizualization(regions_sales, chart_type="bar", xlabel="Region",482 ylabel="Sales",483 the_title="Total Sales Via Regions",484 bar_colors=[485 "#067fd6", "#01B075", "#705DDF", "#FF625B"],486 487 hover_html_template="Region: <b>%{x}</b><br># Total Sales: %{y:.3s}")488 489 fig_regions_sales = fig_regions_sales.to_html(include_plotlyjs='cdn', config={490 'displayModeBar': False})491 492 # Customers Segments Pie Chart493 segments = the_df.groupby("Segment")["Sales"].sum()494 495 fig_segments = create_chart_vizualization(segments, chart_type="pie",496 the_title="Sales By Customer Segmentation",497 bar_colors=[498 "#067fd6", "#01B075", "#705DDF", "#FF625B"],499 hover_html_template="Customer Segment: %{label}<br>Frequency: %{value:,.0f}<br>Frequency PCT(%): %{percent}")500 fig_segments = fig_segments.to_html(include_plotlyjs='cdn', config={501 'displayModeBar': False})502 503 chart = html.section(504 {"class": "text-black py-2 sm:py-3"},505 html.div(506 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},507 html.dl(508 {"class": "grid grid-cols-2 xs:grid-cols-1 sm:grid-cols-1 gap-x-1 gap-y-2 text-center lg:grid-cols-2"},509 html.div(510 div_class,511 utils.html_to_vdom(fig_regions_sales)512 ),513 514 html.div(515 div_class,516 utils.html_to_vdom(fig_segments)517 518 ),519 520 )521 ),522 )523 return chart524 525 526@component527def create_profit_year_chart(the_df):528 div_class = {529 "class": "flex max-auto flex-col gap-y-1 border-1 border-gray-800 p-2 rounded-md bg-black"530 }531 532 profit_via_year = round(the_df.groupby("Order_Year")["Profit"].sum())533 534 fig_profit_year = create_chart_vizualization(profit_via_year, chart_type="line", xlabel="Year",535 ylabel="Total Profit",536 the_title="Total Profit Via Years",537 hover_html_template="Year: <b>%{x}</b><br>Total Profit: %{y:,}", height=550)538 539 fig_profit_year = fig_profit_year.to_html(include_plotlyjs='cdn', config={540 'displayModeBar': False})541 542 chart = html.section(543 {"class": "text-black py-2 sm:py-4"},544 html.div(545 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},546 html.dl(547 {"class": "grid grid-cols-1 xs:grid-cols-1 gap-x-1 gap-y-2 text-center lg:grid-cols-1"},548 html.div(549 div_class,550 utils.html_to_vdom(fig_profit_year)551 ),552 )553 ),554 )555 return chart556# ==================== End Home Page Components =======================557 558# ==================== Start Locations Page Components =======================559 560 561@component562def select_menu_loc(the_state, the_year, the_category):563 global state_filt564 global years_filt565 global category_filt566 global form_data567 568 div_class = {569 "class": "flex max-full flex-col gap-y-1 p-2 rounded-md bg-black"570 }571 label_class = {572 "class": "block text-l font-md text-white text-left"573 }574 select_menu_class = "text-gray-300 mt-1 cursor-pointer block w-full py-2 px-3 bg-gray-700 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"575 576 state_filt, set_state_filt = use_state(state_list[0])577 years_filt, set_years_filt = use_state(years_list[0])578 category_filt, set_category_filt = use_state(category_list[0])579 form_data, set_form_data = use_state(580 {"state": "All", "year": "All", "category": "All"})581 582 select_states_options = html.select({583 "id": "states-select",584 "name": "states",585 "value": the_state,586 "class": select_menu_class,587 "on_change": lambda e: set_state_filt(e["target"]["value"]),588 }, [html.option({"value": i, "class": "text-white"}, i) for i in state_list],589 )590 591 select_years_options = html.select({592 "id": "years-select",593 "name": "years",594 "value": the_year,595 "class": select_menu_class,596 "on_change": lambda e: set_years_filt(e["target"]["value"]),597 }, [html.option({"value": i, "class": "text-white"}, i) for i in years_list],598 )599 600 select_category_options = html.select({601 "id": "category-select",602 "name": "category",603 "value": the_category,604 "class": select_menu_class,605 "on_change": lambda e: set_category_filt(e["target"]["value"]),606 }, [html.option({"value": i, "class": "text-white"}, i) for i in category_list],607 )608 609 @reactpy.event(prevent_default=False)610 def handle_submit(event):611 data = {}612 data["state"] = event["target"]["elements"][0]["value"]613 data["year"] = event["target"]["elements"][1]["value"]614 data["category"] = event["target"]["elements"][2]["value"]615 616 set_form_data(data)617 618 menus = html.form(619 {"class": "text-black py-0 sm:py-1", "on_submit": handle_submit},620 html.div(621 {"class": "max-full max-w-7xl px-0 lg:px-0"},622 html.dl(623 {"class": "grid grid-cols-1 xs:grid-cols-1 gap-x-3 gap-y-2 text-center lg:grid-cols-1"},624 html.div(625 {"style": {"display": "none"}},626 html.label(627 label_class,628 f'States: ',629 630 ),631 select_states_options632 ),633 html.div(634 div_class,635 html.label(636 label_class,637 f'Years: ',638 html.span(639 {"class": "text-blue-300 font-bold"}, the_year)640 ),641 select_years_options642 ),643 html.div(644 div_class,645 html.label(646 label_class,647 f'Category: ',648 html.span(649 {"class": "text-blue-300 font-bold"}, the_category)650 ),651 select_category_options652 ),653 654 ),655 656 html.br(),657 658 html.div(659 div_class,660 html.button({661 "id": "apply-filter",662 "type": "submit",663 "class": "h-16 w-full text-blue-400 hover:text-white border-2 border-blue-700 hover:bg-black focus:ring-4 focus:outline-none focus:ring-blue-300 font-bold rounded-lg text-lg px-5 py-2.5 text-center me-2 mb-2 dark:border-blue-500 dark:text-blue-500 dark:hover:text-white dark:hover:bg-blue-500 dark:focus:ring-blue-800"664 665 }, "Apply Filter"),666 667 ),668 ),669 )670 671 return menus672 673 674@component675def side_bar_loc():676 677 side_bar = html.aside(678 {"id": "default-sidebar", "class": "relative bg-#0f1729 fixed top-0 left-0 z-40 w-full h-screen transition-transform -translate-x-full sm:translate-x-0",679 "aria-label": "Sidebar"},680 html.div(681 {"class": "h-full px-3 py-4 overflow-y-auto bg-gray-50 dark:bg-gray-800"},682 html.ul(683 {"class": "space-y-2 font-bold"},684 html.li(685 html.a(686 {687 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",688 "href": "/",689 "aria-current": "page"},690 691 html.span(692 {"class": "ms-3"},693 "Sales"694 695 )696 )697 ),698 html.li(699 html.a(700 {701 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",702 "href": "/locations",703 "aria-current": "page"},704 705 html.span(706 {"class": "ms-3"},707 "Locations"708 709 )710 )711 ),712 html.li(713 html.a(714 {715 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",716 "href": "/customers",717 "aria-current": "page"},718 719 html.span(720 {"class": "ms-3"},721 "Customers"722 723 )724 )725 ),726 html.li(727 html.a(728 {729 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",730 "href": "/TimeSeries",731 "aria-current": "page"},732 733 html.span(734 {"class": "ms-3"},735 "Time Series"736 737 )738 )739 ),740 html.li(741 html.a(742 {743 "class": "flex items-center p-2 text-white rounded-lg dark:text-white hover:bg-blue-100 hover:text-black group",744 "href": "/Logistics",745 "aria-current": "page"},746 747 html.span(748 {"class": "ms-3"},749 "Logistics"750 751 )752 )753 ),754 html.hr(),755 html.br(),756 757 758 html.li(759 select_menu_loc(form_data["state"], form_data["year"],760 form_data["category"]),761 ),762 763 764 )765 766 )767 )768 769 return side_bar770 771 772@component773def create_locations_cards(the_df, page_title):774 div_class = {775 "class": "flex max-w-xs sm:max-w flex-col gap-y-4 border-2 border-blue-300 p-5 rounded-md bg-black transition "776 "duration-300 ease-in-out hover:bg-gray-900"777 }778 779 dt_class = {780 "class": "ext-base leading-7 text-white font-tahoma font-bold"781 }782 783 dd_class = {784 "class": "order-first text-3xl font-tahoma font-bold tracking-tight text-white sm:text-3xl"785 }786 787 cards = html.section(788 {"class": "text-black py-2 sm:py-2"},789 html.div(790 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},791 html.h2(792 {"class": "text-5xl font-bold mb-8 text-center text-white"},793 page_title794 ),795 html.dl(796 {"class": "grid grid-cols-3 xs:grid-cols-1 gap-x-8 gap-y-16 text-center lg:grid-cols-3"},797 html.div(798 div_class,799 html.dt(800 dt_class, "Regions"801 ),802 html.dd(803 dd_class,804 f'{the_df["Region"].nunique():,.0f}'805 )806 ),807 808 html.div(809 div_class,810 html.dt(811 dt_class, "States"812 ),813 html.dd(814 dd_class,815 f'{the_df["State"].nunique():,.0f}'816 )817 ),818 819 820 html.div(821 div_class,822 html.dt(823 dt_class, "Top Order State"824 ),825 html.dd(826 dd_class,827 the_df["State"].value_counts().idxmax()828 )829 )830 831 )832 833 ),834 )835 return cards836 837 838def create_top_10_states(the_data, chart_type="bar", xlabel="X_Label",839 ylabel="Y_Label", the_title="Chart Title",840 bar_colors=[841 "#067fd6", "#01B075", "#705DDF", "#FF625B"],842 title_size=25, hover_html_template="", orientation="h"):843 844 if chart_type == "bar":845 fig = px.bar(the_data,846 y=the_data.index,847 x=the_data,848 orientation=orientation,849 color=the_data.index,850 color_discrete_sequence=bar_colors,851 labels={"x": xlabel, "y": ylabel},852 text_auto="0.5s",853 title=the_title,854 height=600,855 template="plotly_dark"856 )857 858 fig.update_traces(859 textfont={860 "family": "tahoma",861 "size": 17,862 "color": "white"863 },864 marker=dict(line=dict(color='#111', width=2)),865 hovertemplate=hover_html_template,866 )867 868 fig.update_layout(869 showlegend=False,870 title={871 "font": {872 "size": title_size,873 "family": "tahoma",874 }875 },876 hoverlabel={877 "bgcolor": "#123",878 "font_size": 17,879 "font_family": "tahoma"880 }881 )882 return fig883 884 885def create_top_10_state_chart(the_df):886 div_class = {887 "class": "flex max-auto flex-col gap-y-1 border-1 border-gray-800 p-2 rounded-md bg-black"888 }889 # Shipping Mode Bar Chart890 top_10_states_sales = the_df.groupby("State")["Sales"].sum().nlargest(10)891 892 fig_top_10_states_sales = create_top_10_states(top_10_states_sales, chart_type="bar", orientation="h", xlabel="Total Sales",893 ylabel="State",894 the_title="Top 5 State Via Sales",895 bar_colors=["#067fd6"],896 897 hover_html_template="The State: <b>%{y}</b><br>Total Sales: %{x:.5s}")898 899 fig_top_10_states_sales = fig_top_10_states_sales.to_html(include_plotlyjs='cdn', config={900 'displayModeBar': False})901 902 chart = html.section(903 {"class": "text-black py-2 sm:py-3"},904 html.div(905 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},906 html.dl(907 {"class": "grid grid-cols-1 xs:grid-cols-1 sm:grid-cols-1 gap-x-1 gap-y-2 text-center lg:grid-cols-1"},908 html.div(909 div_class,910 utils.html_to_vdom(fig_top_10_states_sales)911 ),912 913 # html.div(914 # div_class,915 # utils.html_to_vdom(fig_segments)916 917 # ),918 919 )920 ),921 )922 return chart923# ==================== End Locations Page Components =======================924 925# ==================== Start Customers Page Components =======================926 927 928@component929def create_customers_cards(the_df, page_title):930 div_class = {931 "class": "flex max-w-xs sm:max-w flex-col gap-y-4 border-2 border-blue-300 p-5 rounded-md bg-black transition "932 "duration-300 ease-in-out hover:bg-gray-900"933 }934 935 dt_class = {936 "class": "ext-base leading-7 text-white font-tahoma font-bold"937 }938 939 dd_class = {940 "class": "order-first text-3xl font-tahoma font-bold tracking-tight text-white sm:text-3xl"941 }942 943 cards = html.section(944 {"class": "text-black py-2 sm:py-2"},945 html.div(946 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},947 html.h2(948 {"class": "text-5xl font-bold mb-8 text-center text-white"},949 page_title950 ),951 html.dl(952 {"class": "grid grid-cols-3 xs:grid-cols-1 gap-x-8 gap-y-16 text-center lg:grid-cols-3"},953 html.div(954 div_class,955 html.dt(956 dt_class, "AVG Sales Per Customer"957 ),958 html.dd(959 dd_class,960 f'${the_df.groupby("Customer_ID")["Sales"].sum().mean():,.2f}'961 )962 ),963 964 html.div(965 div_class,966 html.dt(967 dt_class, "AVG Profit Per Customer"968 ),969 html.dd(970 dd_class,971 f'${the_df.groupby("Customer_ID")["Profit"].sum().mean():,.2f}'972 )973 ),974 975 html.div(976 div_class,977 html.dt(978 dt_class, "Top Loyal Customers"979 ),980 html.dd(981 dd_class,982 the_df.drop_duplicates(subset="Order_ID")[983 "Customer_Name"].value_counts().idxmax()984 )985 )986 987 )988 989 ),990 )991 return cards992 993 994def create_customers_segment(the_df):995 the_df = the_df.drop_duplicates()996 997 customers_by_segemnt = the_df.drop_duplicates(998 "Customer_ID")["Segment"].value_counts()999 1000 fig = px.pie(names=customers_by_segemnt.index,1001 values=customers_by_segemnt,1002 title="Customers Popularity Via Segments",1003 color_discrete_sequence=[1004 "#067fd6", "#01B075", "#705DDF", "#FF625B"],1005 hole=0.43,1006 template="plotly_dark",1007 height=5001008 )1009 1010 fig.update_traces(1011 textfont={1012 "family": "tahoma",1013 "size": 16,1014 },1015 textinfo="label+percent",1016 hovertemplate="Segment: %{label}<br>Popularity PCT(%): %{percent}<br># Customers %{value:.2s}",1017 marker=dict(line=dict(color='#111', width=1)),1018 )1019 1020 fig.update_layout(1021 showlegend=False,1022 title={1023 "font": {1024 "size": 25,1025 "family": "tahoma",1026 }1027 },1028 hoverlabel={1029 "bgcolor": "#123",1030 "font_size": 17,1031 "font_family": "tahoma"1032 }1033 )1034 return fig1035 1036 1037@component1038def create_customers_charts(the_df):1039 div_class = {1040 "class": "flex max-auto flex-col gap-y-1 border-1 border-gray-800 p-2 rounded-md bg-black"1041 }1042 1043 customers_segment = create_customers_segment(the_df)1044 1045 fig_customers_segment = customers_segment.to_html(include_plotlyjs='cdn', config={1046 'displayModeBar': False})1047 1048 # Customer Evolution1049 customers_via_years = the_df.drop_duplicates(1050 "Customer_ID")["Order_Year"].value_counts().sort_index()1051 1052 customers_via_years = create_chart_vizualization(customers_via_years, chart_type="line", xlabel="Year",1053 ylabel="Total Customer",1054 the_title="The Increasing of Customers Via Years",1055 hover_html_template="Year: <b>%{x}</b><br>Total Customer: %{y:,}", height=500)1056 1057 fig_customers_via_years = customers_via_years.to_html(include_plotlyjs='cdn', config={1058 'displayModeBar': False})1059 1060 chart = html.section(1061 {"class": "text-black py-2 sm:py-3"},1062 html.div(1063 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},1064 html.dl(1065 {"class": "grid grid-cols-2 xs:grid-cols-1 sm:grid-cols-1 gap-x-1 gap-y-2 text-center lg:grid-cols-2"},1066 html.div(1067 div_class,1068 utils.html_to_vdom(fig_customers_via_years)1069 ),1070 1071 html.div(1072 div_class,1073 utils.html_to_vdom(fig_customers_segment)1074 1075 ),1076 1077 )1078 ),1079 )1080 return chart1081# ==================== End Customers Page Components =======================1082 1083# ==================== Start Time Series Page Components =======================1084 1085 1086@component1087def page_header(page_title):1088 title = html.section(1089 {"class": "text-black py-2 sm:py-2"},1090 html.div(1091 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},1092 html.h2(1093 {"class": "text-5xl font-bold mb-8 text-center text-white"},1094 page_title1095 ),1096 1097 ),1098 )1099 return title1100 1101 1102def create_line_chart(the_df, xlabel="X", ylabel="Y", title="Title", hover_html_template="Template"):1103 fig = px.line(the_df,1104 color_discrete_sequence=[1105 "#067fd6", "#01B075", "#705DDF", "#FF625B"],1106 labels={"index": xlabel, "value": ylabel,1107 "Order_Year": "Year"},1108 title=title,1109 markers="o",1110 height=500,1111 template="plotly_dark",1112 )1113 1114 fig.update_traces(1115 marker=dict(size=8, line=dict(color='#111', width=1)),1116 hovertemplate=hover_html_template,1117 )1118 1119 fig.update_layout(1120 showlegend=True,1121 title={1122 "font": {1123 "size": 25,1124 "family": "tahoma",1125 }1126 },1127 hoverlabel={1128 "bgcolor": "#123",1129 "font_size": 17,1130 "font_family": "tahoma"1131 }1132 )1133 return fig1134 1135 1136@component1137def create_slaes_via_months_charts(the_df):1138 div_class = {1139 "class": "flex max-auto flex-col gap-y-1 border-1 border-gray-800 p-2 rounded-md bg-black"1140 }1141 slaes_via_year_month = the_df.pivot_table(1142 index=the_df["Order_Date"].dt.month, columns="Order_Year", values="Sales", aggfunc="sum")1143 1144 months_name = ["Jan", "Feb", "Mar", "Apr",1145 "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]1146 1147 x = slaes_via_year_month.index1148 displayes_months_name = []1149 1150 for i in x:1151 displayes_months_name.append(months_name[i-1])1152 1153 slaes_via_year_month.index = displayes_months_name1154 1155 slaes_via_year_month = create_line_chart(slaes_via_year_month, xlabel="Month", ylabel="Sales",1156 title="Sales Via Month Per Each Year", hover_html_template="Month: <b>%{x}</b><br>Total Sales: %{y:.3s}")1157 1158 fig_slaes_via_year_month = slaes_via_year_month.to_html(include_plotlyjs='cdn', config={1159 'displayModeBar': False})1160 1161 chart = html.section(1162 {"class": "text-black py-2 sm:py-3"},1163 html.div(1164 {"class": "mx-auto max-w-7xl px-6 lg:px-8"},1165 html.dl(1166 {"class": "grid grid-cols-1 xs:grid-cols-1 sm:grid-cols-1 gap-x-1 gap-y-2 text-center lg:grid-cols-1"},1167 html.div(1168 div_class,1169 utils.html_to_vdom(fig_slaes_via_year_month)1170 )1171 )1172 ),1173 )1174 return chart1175 1176 1177@component1178def create_profit_via_months_charts(the_df):1179 div_class = {1180 "class": "flex max-auto flex-col gap-y-1 border-1 border-gray-800 p-2 rounded-md bg-black"1181 }1182 profit_via_year_month = the_df.pivot_table(1183 index=the_df["Order_Date"].dt.month, columns="Order_Year", values="Profit", aggfunc="sum")1184 1185 months_name = ["Jan", "Feb", "Mar", "Apr",1186 "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]1187 1188 x = profit_via_year_month.index1189 displayes_months_name = []1190 1191 for i in x:1192 displayes_months_name.append(months_name[i-1])1193 1194 profit_via_year_month.index = displayes_months_name1195 1196 profit_via_year_month = create_line_chart(profit_via_year_month, xlabel="Month", ylabel="Profit",1197 title="Profit Via Month Per Each Year", hover_html_template="Month: <b>%{x}</b><br>Total Profit: %{y:.3s}")1198 1199 fig_profit_via_year_month = profit_via_year_month.to_html(include_plotlyjs='cdn', config={1200 'displayModeBar': False})