customeranalytics 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. customeranalytics/__init__.py +319 -0
  2. customeranalytics/configs.py +480 -0
  3. customeranalytics/data_storage_configurations/__init__.py +245 -0
  4. customeranalytics/data_storage_configurations/data_access.py +165 -0
  5. customeranalytics/data_storage_configurations/data_works_pipeline.py +207 -0
  6. customeranalytics/data_storage_configurations/es_create_index.py +544 -0
  7. customeranalytics/data_storage_configurations/logger.py +36 -0
  8. customeranalytics/data_storage_configurations/query_es.py +157 -0
  9. customeranalytics/data_storage_configurations/reports.py +684 -0
  10. customeranalytics/data_storage_configurations/schedule_data_integration.py +355 -0
  11. customeranalytics/docs/queries.yaml +245 -0
  12. customeranalytics/docs/web_configs.yaml +2 -0
  13. customeranalytics/exploratory_analysis/__init__.py +109 -0
  14. customeranalytics/exploratory_analysis/churn.py +232 -0
  15. customeranalytics/exploratory_analysis/cohorts.py +535 -0
  16. customeranalytics/exploratory_analysis/descriptive_statistics.py +470 -0
  17. customeranalytics/exploratory_analysis/funnels.py +407 -0
  18. customeranalytics/exploratory_analysis/product_analytics.py +340 -0
  19. customeranalytics/exploratory_analysis/promotion_analytics.py +299 -0
  20. customeranalytics/exploratory_analysis/rfm.py +202 -0
  21. customeranalytics/exploratory_analysis/sample_data/sample_data_avg_order_count_per_promo_per_cust.csv +99 -0
  22. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_1_search.csv +2 -0
  23. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_2_search.csv +46 -0
  24. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_3_search.csv +2 -0
  25. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_4_search.csv +2 -0
  26. customeranalytics/exploratory_analysis/sample_data/sample_data_churn.csv +2 -0
  27. customeranalytics/exploratory_analysis/sample_data/sample_data_churn_weekly.csv +10 -0
  28. customeranalytics/exploratory_analysis/sample_data/sample_data_client_feature_predicted.csv +1590 -0
  29. customeranalytics/exploratory_analysis/sample_data/sample_data_client_kpis.csv +7060 -0
  30. customeranalytics/exploratory_analysis/sample_data/sample_data_clvrfm_anomaly.csv +561 -0
  31. customeranalytics/exploratory_analysis/sample_data/sample_data_clvsegments_amount.csv +8 -0
  32. customeranalytics/exploratory_analysis/sample_data/sample_data_customer_journey.csv +18 -0
  33. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_clv.csv +103 -0
  34. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_downloads.csv +68 -0
  35. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_1_to_2.csv +66 -0
  36. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_2_to_3.csv +64 -0
  37. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_3_to_4.csv +55 -0
  38. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_dimension_values.csv +199 -0
  39. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_funnel.csv +36 -0
  40. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_funnel_downloads.csv +68 -0
  41. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_inorganic_ratio.csv +6070 -0
  42. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_orders.csv +57 -0
  43. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_organic_orders.csv +64 -0
  44. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_products_of_sales.csv +12574 -0
  45. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_promotion_discount.csv +64 -0
  46. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_promotion_revenue.csv +6070 -0
  47. customeranalytics/exploratory_analysis/sample_data/sample_data_dcohort_anomaly.csv +6 -0
  48. customeranalytics/exploratory_analysis/sample_data/sample_data_dcohort_anomaly_2.csv +118 -0
  49. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver.csv +47 -0
  50. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver_kpis.csv +2 -0
  51. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver_weekday_hour.csv +25 -0
  52. customeranalytics/exploratory_analysis/sample_data/sample_data_dfunnel_anomaly.csv +118 -0
  53. customeranalytics/exploratory_analysis/sample_data/sample_data_dimension_kpis.csv +199 -0
  54. customeranalytics/exploratory_analysis/sample_data/sample_data_dorders_anomaly.csv +85 -0
  55. customeranalytics/exploratory_analysis/sample_data/sample_data_frequency_clusters.csv +6 -0
  56. customeranalytics/exploratory_analysis/sample_data/sample_data_frequency_recency.csv +3740 -0
  57. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_funnel.csv +25 -0
  58. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_funnel_downloads.csv +25 -0
  59. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_inorganic_ratio.csv +2353 -0
  60. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_orders.csv +25 -0
  61. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_organic_orders.csv +2353 -0
  62. customeranalytics/exploratory_analysis/sample_data/sample_data_inorganic_orders_per_promotion_per_day.csv +6070 -0
  63. customeranalytics/exploratory_analysis/sample_data/sample_data_kpis.csv +2 -0
  64. customeranalytics/exploratory_analysis/sample_data/sample_data_monetary_clusters.csv +6 -0
  65. customeranalytics/exploratory_analysis/sample_data/sample_data_monetary_frequency.csv +3740 -0
  66. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_funnel.csv +5 -0
  67. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_funnel_downloads.csv +5 -0
  68. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_orders.csv +4 -0
  69. customeranalytics/exploratory_analysis/sample_data/sample_data_most_combined_products.csv +11 -0
  70. customeranalytics/exploratory_analysis/sample_data/sample_data_most_ordered_categories.csv +11 -0
  71. customeranalytics/exploratory_analysis/sample_data/sample_data_most_ordered_products.csv +11 -0
  72. customeranalytics/exploratory_analysis/sample_data/sample_data_order_and_payment_amount_differences.csv +91 -0
  73. customeranalytics/exploratory_analysis/sample_data/sample_data_prepare.csv +101 -0
  74. customeranalytics/exploratory_analysis/sample_data/sample_data_prepare_weekday_hour.csv +25 -0
  75. customeranalytics/exploratory_analysis/sample_data/sample_data_product_kpis.csv +201 -0
  76. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_amount_accept.csv +11 -0
  77. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_amount_reject.csv +7 -0
  78. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_orders_accept.csv +11 -0
  79. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_orders_reject.csv +11 -0
  80. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_comparison.csv +91 -0
  81. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_kpis.csv +99 -0
  82. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_number_of_customer.csv +99 -0
  83. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_amount_accept.csv +81 -0
  84. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_amount_reject.csv +11 -0
  85. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_orders_accept.csv +55 -0
  86. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_orders_reject.csv +37 -0
  87. customeranalytics/exploratory_analysis/sample_data/sample_data_purchase_amount_distribution.csv +22 -0
  88. customeranalytics/exploratory_analysis/sample_data/sample_data_recency_clusters.csv +6 -0
  89. customeranalytics/exploratory_analysis/sample_data/sample_data_recency_monetary.csv +3740 -0
  90. customeranalytics/exploratory_analysis/sample_data/sample_data_rfm.csv +2001 -0
  91. customeranalytics/exploratory_analysis/sample_data/sample_data_ride.csv +101 -0
  92. customeranalytics/exploratory_analysis/sample_data/sample_data_ride_weekday_hour.csv +25 -0
  93. customeranalytics/exploratory_analysis/sample_data/sample_data_segmentation.csv +11 -0
  94. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_daily_before_after_amount.csv +10 -0
  95. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_daily_before_after_orders.csv +9 -0
  96. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_monthly_before_after_amount.csv +10 -0
  97. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_monthly_before_after_orders.csv +11 -0
  98. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_weekly_before_after_amount.csv +10 -0
  99. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_weekly_before_after_orders.csv +10 -0
  100. customeranalytics/exploratory_analysis/sample_data/sample_data_user_counts_per_order_seq.csv +47 -0
  101. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_order_per_user.csv +13 -0
  102. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_payment_amount.csv +13 -0
  103. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_session_per_user.csv +13 -0
  104. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_downloads.csv +13 -0
  105. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_1_to_2.csv +13 -0
  106. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_2_to_3.csv +13 -0
  107. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_3_to_4.csv +12 -0
  108. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_funnel.csv +25 -0
  109. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_funnel_downloads.csv +25 -0
  110. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_orders.csv +10 -0
  111. customeranalytics/ml_process/__init__.py +64 -0
  112. customeranalytics/ml_process/ab_test.py +615 -0
  113. customeranalytics/ml_process/anomaly_detection.py +456 -0
  114. customeranalytics/ml_process/clv_prediction.py +301 -0
  115. customeranalytics/ml_process/customer_segmentation.py +354 -0
  116. customeranalytics/ml_process/delivery_analytics.py +754 -0
  117. customeranalytics/utils.py +186 -0
  118. customeranalytics/web/app/__init__.py +37 -0
  119. customeranalytics/web/app/base/__init__.py +9 -0
  120. customeranalytics/web/app/base/forms.py +16 -0
  121. customeranalytics/web/app/base/models.py +43 -0
  122. customeranalytics/web/app/base/routes.py +126 -0
  123. customeranalytics/web/app/base/static/assets/css/app.css +20 -0
  124. customeranalytics/web/app/base/static/assets/fonts/Inter-Black.woff +0 -0
  125. customeranalytics/web/app/base/static/assets/fonts/Inter-Black.woff2 +0 -0
  126. customeranalytics/web/app/base/static/assets/fonts/Inter-BlackItalic.woff +0 -0
  127. customeranalytics/web/app/base/static/assets/fonts/Inter-BlackItalic.woff2 +0 -0
  128. customeranalytics/web/app/base/static/assets/fonts/Inter-Bold.woff +0 -0
  129. customeranalytics/web/app/base/static/assets/fonts/Inter-Bold.woff2 +0 -0
  130. customeranalytics/web/app/base/static/assets/fonts/Inter-BoldItalic.woff +0 -0
  131. customeranalytics/web/app/base/static/assets/fonts/Inter-BoldItalic.woff2 +0 -0
  132. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBold.woff +0 -0
  133. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBold.woff2 +0 -0
  134. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBoldItalic.woff +0 -0
  135. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBoldItalic.woff2 +0 -0
  136. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLight-BETA.woff +0 -0
  137. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLight-BETA.woff2 +0 -0
  138. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLightItalic-BETA.woff +0 -0
  139. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLightItalic-BETA.woff2 +0 -0
  140. customeranalytics/web/app/base/static/assets/fonts/Inter-Italic.woff +0 -0
  141. customeranalytics/web/app/base/static/assets/fonts/Inter-Italic.woff2 +0 -0
  142. customeranalytics/web/app/base/static/assets/fonts/Inter-Light-BETA.woff +0 -0
  143. customeranalytics/web/app/base/static/assets/fonts/Inter-Light-BETA.woff2 +0 -0
  144. customeranalytics/web/app/base/static/assets/fonts/Inter-LightItalic-BETA.woff +0 -0
  145. customeranalytics/web/app/base/static/assets/fonts/Inter-LightItalic-BETA.woff2 +0 -0
  146. customeranalytics/web/app/base/static/assets/fonts/Inter-Medium.woff +0 -0
  147. customeranalytics/web/app/base/static/assets/fonts/Inter-Medium.woff2 +0 -0
  148. customeranalytics/web/app/base/static/assets/fonts/Inter-MediumItalic.woff +0 -0
  149. customeranalytics/web/app/base/static/assets/fonts/Inter-MediumItalic.woff2 +0 -0
  150. customeranalytics/web/app/base/static/assets/fonts/Inter-Regular.woff +0 -0
  151. customeranalytics/web/app/base/static/assets/fonts/Inter-Regular.woff2 +0 -0
  152. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBold.woff +0 -0
  153. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBold.woff2 +0 -0
  154. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBoldItalic.woff +0 -0
  155. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBoldItalic.woff2 +0 -0
  156. customeranalytics/web/app/base/static/assets/fonts/Inter-Thin-BETA.woff +0 -0
  157. customeranalytics/web/app/base/static/assets/fonts/Inter-Thin-BETA.woff2 +0 -0
  158. customeranalytics/web/app/base/static/assets/fonts/Inter-ThinItalic-BETA.woff +0 -0
  159. customeranalytics/web/app/base/static/assets/fonts/Inter-ThinItalic-BETA.woff2 +0 -0
  160. customeranalytics/web/app/base/static/assets/fonts/Inter-italic.var.woff2 +0 -0
  161. customeranalytics/web/app/base/static/assets/fonts/Inter-upright.var.woff2 +0 -0
  162. customeranalytics/web/app/base/static/assets/fonts/Inter.var.woff2 +0 -0
  163. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.eot +0 -0
  164. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.svg +3570 -0
  165. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.ttf +0 -0
  166. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.woff +0 -0
  167. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.woff2 +0 -0
  168. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.eot +0 -0
  169. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.svg +801 -0
  170. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.ttf +0 -0
  171. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.woff +0 -0
  172. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.woff2 +0 -0
  173. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.eot +0 -0
  174. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.svg +5028 -0
  175. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.ttf +0 -0
  176. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.woff +0 -0
  177. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.woff2 +0 -0
  178. customeranalytics/web/app/base/static/assets/img/avatars/avatar-1.png +0 -0
  179. customeranalytics/web/app/base/static/assets/img/avatars/avatar-2.png +0 -0
  180. customeranalytics/web/app/base/static/assets/img/avatars/avatar-3.png +0 -0
  181. customeranalytics/web/app/base/static/assets/img/avatars/avatar-4.png +0 -0
  182. customeranalytics/web/app/base/static/assets/img/avatars/avatar-5.png +0 -0
  183. customeranalytics/web/app/base/static/assets/img/avatars/info.jpeg +0 -0
  184. customeranalytics/web/app/base/static/assets/img/icons/customanality.png +0 -0
  185. customeranalytics/web/app/base/static/assets/img/icons/icon-48x48.png +0 -0
  186. customeranalytics/web/app/base/static/assets/js/app.js +2 -0
  187. customeranalytics/web/app/base/static/assets/js/app.js.LICENSE +566 -0
  188. customeranalytics/web/app/base/static/assets/js/app.js.LICENSE.txt +556 -0
  189. customeranalytics/web/app/base/static/assets/js/modules/bootstrap.js +15 -0
  190. customeranalytics/web/app/base/static/assets/js/modules/chartjs.js +4 -0
  191. customeranalytics/web/app/base/static/assets/js/modules/feather.js +8 -0
  192. customeranalytics/web/app/base/static/assets/js/modules/flatpickr.js +4 -0
  193. customeranalytics/web/app/base/static/assets/js/modules/moment.js +4 -0
  194. customeranalytics/web/app/base/static/assets/js/modules/sidebar.js +23 -0
  195. customeranalytics/web/app/base/static/assets/js/modules/theme.js +16 -0
  196. customeranalytics/web/app/base/templates/accounts/login.html +81 -0
  197. customeranalytics/web/app/base/templates/accounts/register.html +80 -0
  198. customeranalytics/web/app/base/templates/includes/footer.html +28 -0
  199. customeranalytics/web/app/base/templates/includes/navigation.html +51 -0
  200. customeranalytics/web/app/base/templates/includes/scripts.html +3 -0
  201. customeranalytics/web/app/base/templates/includes/sidebar.html +146 -0
  202. customeranalytics/web/app/base/templates/layouts/base-fullscreen.html +36 -0
  203. customeranalytics/web/app/base/templates/layouts/base.html +84 -0
  204. customeranalytics/web/app/base/util.py +30 -0
  205. customeranalytics/web/app/home/__init__.py +9 -0
  206. customeranalytics/web/app/home/forms.py +1039 -0
  207. customeranalytics/web/app/home/models.py +438 -0
  208. customeranalytics/web/app/home/profiles.py +310 -0
  209. customeranalytics/web/app/home/routes.py +386 -0
  210. customeranalytics/web/app/home/search.py +288 -0
  211. customeranalytics/web/app/home/static/assets/img/avatars/avatar-1.png +0 -0
  212. customeranalytics/web/app/home/static/assets/img/avatars/avatar-2.png +0 -0
  213. customeranalytics/web/app/home/static/assets/img/avatars/avatar-3.png +0 -0
  214. customeranalytics/web/app/home/static/assets/img/avatars/avatar-4.png +0 -0
  215. customeranalytics/web/app/home/static/assets/img/avatars/avatar-5.png +0 -0
  216. customeranalytics/web/app/home/static/assets/img/icons/customanality.png +0 -0
  217. customeranalytics/web/app/home/static/assets/img/icons/icon-48x48.png +0 -0
  218. customeranalytics/web/app/home/templates/abtest-product.html +280 -0
  219. customeranalytics/web/app/home/templates/abtest-promotion.html +362 -0
  220. customeranalytics/web/app/home/templates/abtest-segments.html +298 -0
  221. customeranalytics/web/app/home/templates/add-data-delivery.html +184 -0
  222. customeranalytics/web/app/home/templates/add-data-product.html +177 -0
  223. customeranalytics/web/app/home/templates/add-data-purchase.html +392 -0
  224. customeranalytics/web/app/home/templates/anomaly.html +261 -0
  225. customeranalytics/web/app/home/templates/clv.html +211 -0
  226. customeranalytics/web/app/home/templates/cohorts.html +308 -0
  227. customeranalytics/web/app/home/templates/customer-segmentation.html +308 -0
  228. customeranalytics/web/app/home/templates/data-es.html +152 -0
  229. customeranalytics/web/app/home/templates/data-execute.html +397 -0
  230. customeranalytics/web/app/home/templates/delivery.html +404 -0
  231. customeranalytics/web/app/home/templates/funnel-customer.html +240 -0
  232. customeranalytics/web/app/home/templates/funnel-session.html +236 -0
  233. customeranalytics/web/app/home/templates/index.html +524 -0
  234. customeranalytics/web/app/home/templates/index2.html +515 -0
  235. customeranalytics/web/app/home/templates/page-403.html +46 -0
  236. customeranalytics/web/app/home/templates/page-404.html +45 -0
  237. customeranalytics/web/app/home/templates/page-500.html +45 -0
  238. customeranalytics/web/app/home/templates/pages-blank.html +33 -0
  239. customeranalytics/web/app/home/templates/pages-sign-in.html +67 -0
  240. customeranalytics/web/app/home/templates/pages-sign-up.html +61 -0
  241. customeranalytics/web/app/home/templates/product.html +203 -0
  242. customeranalytics/web/app/home/templates/profile.html +1009 -0
  243. customeranalytics/web/app/home/templates/rfm.html +254 -0
  244. customeranalytics/web/app/home/templates/search.html +167 -0
  245. customeranalytics/web/app/home/templates/settings.html +205 -0
  246. customeranalytics/web/app/home/templates/stats-desc.html +230 -0
  247. customeranalytics/web/app/home/templates/stats-purchase.html +221 -0
  248. customeranalytics/web/config.py +30 -0
  249. customeranalytics/web/db.sqlite3 +0 -0
  250. customeranalytics/web/run.py +30 -0
  251. customeranalytics-0.1.dist-info/METADATA +1102 -0
  252. customeranalytics-0.1.dist-info/RECORD +254 -0
  253. customeranalytics-0.1.dist-info/WHEEL +4 -0
  254. customeranalytics-0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1039 @@
1
+ import sys, os, inspect
2
+ currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
3
+ parentdir = os.path.dirname(currentdir)
4
+ sys.path.insert(0, parentdir)
5
+
6
+ import pandas as pd
7
+ from numpy import array, mean, std
8
+ import json
9
+
10
+ from os.path import join, dirname, exists
11
+ from os import listdir
12
+ import plotly.graph_objs as go
13
+ import plotly
14
+ from screeninfo import get_monitors
15
+ from sqlalchemy import create_engine, MetaData
16
+
17
+ from customeranalytics.utils import convert_to_day, abspath_for_sample_data
18
+ from customeranalytics.configs import time_periods, descriptive_stats, abtest_promotions, \
19
+ abtest_products, abtest_segments, delivery_metrics
20
+
21
+ engine = create_engine('sqlite://///' + join(abspath_for_sample_data(), "web", 'db.sqlite3'),
22
+ connect_args={'check_same_thread': False})
23
+ metadata = MetaData()
24
+ con = engine.connect()
25
+
26
+
27
+ """
28
+ charts Dictionary:
29
+ each chart related to each page is stored in chats.
30
+ When need to be visualize, related page of chart is merged with stored data on Charts class
31
+ """
32
+ charts = {
33
+ # index.html charts and KPIs
34
+ "index": {
35
+ # charts - orders_monthly, orders_hourly, orders_weekly, orders_daily, segmentation
36
+ "charts":
37
+ {'monthly_orders': {'trace': go.Scatter(mode="lines+markers+text",
38
+ line=dict(color='firebrick', width=4),
39
+ textposition="bottom center",
40
+ textfont=dict(
41
+ family="sans serif",
42
+ size=30,
43
+ color="crimson")),
44
+ 'layout': go.Layout()},
45
+ 'hourly_orders': {'trace': go.Scatter(mode="lines+markers+text",
46
+ line=dict(color='firebrick', width=4),
47
+ textposition="bottom center",
48
+ textfont=dict(
49
+ family="sans serif",
50
+ size=30,
51
+ color="crimson")),
52
+ 'layout': go.Layout()},
53
+ 'weekly_orders': {'trace': go.Scatter(mode="lines+markers+text",
54
+ line=dict(color='firebrick', width=4),
55
+ textposition="bottom center",
56
+ textfont=dict(
57
+ family="sans serif",
58
+ size=30,
59
+ color="crimson")),
60
+ 'layout': go.Layout()},
61
+ 'daily_orders': {'trace': go.Scatter(mode="lines+markers+text",
62
+ line=dict(color='firebrick', width=4),
63
+ textposition="bottom center",
64
+ textfont=dict(
65
+ family="sans serif",
66
+ size=30,
67
+ color="crimson")),
68
+ 'layout': go.Layout()},
69
+ 'segmentation': {'trace': go.Treemap(
70
+ marker_colorscale='Blues',
71
+ textinfo="label+value+percent parent+percent entry", parents=[""] * 7),
72
+ 'layout': go.Layout(width=1000,
73
+ margin=dict(l=1, r=1, t=1, b=1),
74
+ height=400)},
75
+ "customer_journey": {'trace': go.Scatter(x=[], y=[],
76
+ marker=dict(size=[], color=[]), mode='markers', name='markers'),
77
+ 'layout': go.Layout()},
78
+ "most_ordered_products": {'trace': go.Bar(x=[], y=[]), 'layout': go.Layout()},
79
+ "most_ordered_categories": {'trace': go.Bar(x=[], y=[]), 'layout': go.Layout()},
80
+ "churn": {'trace': go.Pie(labels=[], values=[]), 'layout': go.Layout()},
81
+ "churn_weekly": {'trace': go.Bar(x=[], y=[]), 'layout': go.Layout()},
82
+ },
83
+ ## TODO organic - promoted ratio
84
+ # KPIs - total_orders, total_visits, total_unique_visitors. index.html left top
85
+ "kpis": {"kpis": ['total_orders', 'total_visitors', 'total_revenue', 'total_discount',
86
+ 'since_last_week_orders', 'since_last_week_revenue',
87
+ 'since_last_week_total_visitors', 'since_last_week_total_discount']}},
88
+ # index2.html of Charts and KPIs
89
+ "index2": {
90
+ # charts - rfm
91
+ "charts": {"rfm": {"trace": go.Scatter3d(mode='markers',
92
+ marker=dict(color=None,
93
+ size=12,
94
+ colorscale='delta',
95
+ opacity=0.8)),
96
+ "layout": go.Layout(width=1000,
97
+ margin=dict(l=1, r=1, t=1, b=1),
98
+ height=600,
99
+ scene=dict(
100
+ xaxis_title='recency',
101
+ yaxis_title='monetary',
102
+ zaxis_title='frequency'))
103
+ },
104
+
105
+ "daily_clv": {'trace': go.Scatter(mode="lines+markers+text", fill='tozeroy'),
106
+ 'layout': go.Layout()},
107
+ "user_counts_per_order_seq": {'trace': go.Bar(),
108
+ 'layout': go.Layout(
109
+ xaxis_title="X Axis Title",
110
+ yaxis_title="Y Axis Title",
111
+ margin=dict(r=1, t=1))},
112
+
113
+
114
+ "purchase_amount_distribution": {'trace': go.Bar(x=[], y=[]), 'layout': go.Layout()},
115
+ "daily_funnel": {'trace': go.Scatter(mode="lines+markers+text",
116
+ line=dict(color='firebrick', width=4),
117
+ textposition="bottom center",
118
+ textfont=dict(
119
+ family="sans serif",
120
+ size=30,
121
+ color="crimson")),
122
+ 'layout': go.Layout(legend=dict(
123
+ orientation="h",
124
+ yanchor="bottom",
125
+ y=1.02,
126
+ xanchor="right",
127
+ x=1
128
+ ))},
129
+ "weekly_cohort_downloads": {'trace': go.Heatmap(z=[], x=[], y=[],
130
+ colorscale='Viridis', opacity=0.9,
131
+ showlegend=False, ygap=2, xgap=2,
132
+ hoverongaps=None, showscale=False),
133
+ 'annotation': go.Annotation(text=[], x=[], y=[],
134
+ xref='x1', yref='y1', showarrow=False),
135
+ 'layout': go.Layout(paper_bgcolor='rgba(0,0,0,0)',
136
+ plot_bgcolor='rgba(0,0,0,0)',
137
+ width=1000,
138
+ margin=dict(l=1, r=1, t=1, b=1),
139
+ height=600,
140
+ annotations=[])}
141
+ },
142
+ # not any recent KPIs for now
143
+ "kpis": {}
144
+ },
145
+ "funnel": {
146
+ # charts - Funnel Daily, Monthly, Weekly
147
+ "charts": {_f: {'trace': go.Scatter(mode="lines+markers+text",
148
+ line=dict(color='firebrick', width=4),
149
+ textposition="bottom center",
150
+ textfont=dict(
151
+ family="sans serif",
152
+ size=30,
153
+ color="crimson")),
154
+ 'layout': go.Layout(legend=dict(
155
+ orientation="h",
156
+ yanchor="bottom",
157
+ y=1.02,
158
+ xanchor="right",
159
+ x=1
160
+ ))}
161
+ for _f in ['daily_funnel', 'hourly_funnel', 'weekly_funnel', 'monthly_funnel',
162
+ 'daily_funnel_downloads', 'hourly_funnel_downloads',
163
+ 'weekly_funnel_downloads', 'monthly_funnel_downloads']},
164
+ # not any recent KPIs for now
165
+ "kpis": {}
166
+ },
167
+ "cohort": {
168
+ # charts - Cohorts From 1, 2, 3 to 2, 3 ,4 Downloads to 1st Orders, daily, Weekly
169
+ "charts": {_c: {'trace': go.Heatmap(z=[], x=[], y=[], colorscale='Viridis', opacity=0.9,
170
+ showlegend=False, ygap=2, xgap=2, hoverongaps=None, showscale=False),
171
+ 'annotation': go.Annotation(text=[], x=[], y=[], xref='x1', yref='y1', showarrow=False),
172
+ 'layout': go.Layout(paper_bgcolor='rgba(0,0,0,0)',
173
+ plot_bgcolor='rgba(0,0,0,0)',
174
+ width=1000, margin=dict(l=1, r=1, t=1, b=1), height=600,
175
+ annotations=[])}
176
+ for _c in ['daily_cohort_downloads', 'daily_cohort_from_1_to_2',
177
+ 'daily_cohort_from_2_to_3', 'daily_cohort_from_3_to_4',
178
+ 'weekly_cohort_downloads', 'weekly_cohort_from_1_to_2',
179
+ 'weekly_cohort_from_2_to_3', 'weekly_cohort_from_3_to_4']},
180
+ # not any recent KPIs for now
181
+ "kpis": {}
182
+ },
183
+ "stats": {
184
+ # Descriptive Statistics
185
+ "charts": {_f: {'trace': go.Scatter(mode="lines+markers+text",
186
+ line=dict(color='firebrick', width=4),
187
+ textposition="bottom center",
188
+ textfont=dict(
189
+ family="sans serif",
190
+ size=20,
191
+ color="crimson")),
192
+ 'layout': go.Layout(legend=dict(
193
+ orientation="h",
194
+ yanchor="bottom",
195
+ y=1.02,
196
+ xanchor="right",
197
+ x=1
198
+ ))}
199
+ for _f in ['daily_orders', 'weekly_orders', 'monthly_orders', 'hourly_orders']},
200
+ # not any recent KPIs for now
201
+ "kpis": {}
202
+ },
203
+ "descriptive": {
204
+ # Descriptive Statistics
205
+ "charts": {_f: {'trace': go.Scatter(mode="lines+markers+text",
206
+ line=dict(color='firebrick', width=4),
207
+ textfont=dict(
208
+ family="sans serif",
209
+ size=8,
210
+ color="crimson")),
211
+ 'layout': go.Layout(legend=dict(
212
+ orientation="h",
213
+ yanchor="bottom",
214
+ y=1.02,
215
+ xanchor="right",
216
+ x=1
217
+ ))} if _f.split("_")[0] == 'weekly' else
218
+ {'trace': go.Bar(x=[], y=[]), 'layout': go.Layout()}
219
+ for _f in ["weekly_average_session_per_user",
220
+ "weekly_average_order_per_user", "purchase_amount_distribution",
221
+ "weekly_average_payment_amount"]},
222
+
223
+
224
+ "kpis": {}
225
+ },
226
+ "abtest-promotion": {
227
+ # Descriptive Statistics
228
+ "charts": {_f: {'trace': go.Bar(),
229
+ 'layout': go.Layout(
230
+ legend=dict(
231
+ orientation="h",
232
+ yanchor="bottom",
233
+ y=1.02,
234
+ xanchor="right",
235
+ x=1),
236
+ margin=dict(r=1, t=1))} if _f not in ["order_and_payment_amount_differences",
237
+ "promotion_comparison"] else
238
+ {'trace': go.Scatter(x=[], y=[], marker=dict(size=[], color=[]), mode='markers', name='markers'),
239
+ 'layout': go.Layout(margin=dict(l=1, r=1, t=1, b=1))}
240
+ for _f in ["order_and_payment_amount_differences", "promotion_comparison",
241
+ "promotion_usage_before_after_amount_accept", "promotion_usage_before_after_amount_reject",
242
+ "promotion_usage_before_after_orders_accept", "promotion_usage_before_after_orders_reject"]},
243
+ "kpis": {}
244
+ },
245
+ "abtest-product": {
246
+ # Descriptive Statistics
247
+ "charts": {_f: {'trace': go.Bar(),
248
+ 'layout': go.Layout(
249
+ legend=dict(
250
+ orientation="h",
251
+ yanchor="bottom",
252
+ y=1.02,
253
+ xanchor="right",
254
+ x=1),
255
+ margin=dict(r=1, t=1))} if _f not in ["order_and_payment_amount_differences",
256
+ "promotion_comparison"] else
257
+ {'trace': go.Scatter(x=[], y=[], marker=dict(size=[], color=[]), mode='markers', name='markers'),
258
+ 'layout': go.Layout(margin=dict(l=1, r=1, t=1, b=1))}
259
+ for _f in ["product_usage_before_after_amount_accept",
260
+ "product_usage_before_after_amount_reject",
261
+ "product_usage_before_after_orders_accept",
262
+ "product_usage_before_after_orders_reject"]},
263
+ "kpis": {}
264
+ },
265
+ "abtest-segments": {
266
+ # Descriptive Statistics
267
+ "charts": {_f: {'trace': go.Bar(),
268
+ 'layout': go.Layout(
269
+ legend=dict(
270
+ orientation="h",
271
+ yanchor="bottom",
272
+ y=1.02,
273
+ xanchor="right",
274
+ x=1),
275
+ margin=dict(r=1, t=1))} for _f in
276
+ ['segments_change_weekly_before_after_orders', 'segments_change_weekly_before_after_amount',
277
+ 'segments_change_daily_before_after_orders', 'segments_change_daily_before_after_amount',
278
+ 'segments_change_monthly_before_after_orders', 'segments_change_monthly_before_after_amount']},
279
+ "kpis": {}
280
+ },
281
+ "product_analytic": {
282
+ # product analytics
283
+ "charts": {
284
+ "most_combined_products": {'trace': go.Bar(x=[], y=[]), 'layout': go.Layout()},
285
+ "most_ordered_products": {'trace': go.Bar(x=[], y=[]), 'layout': go.Layout()},
286
+ "most_ordered_categories": {'trace': go.Bar(x=[], y=[]), 'layout': go.Layout()},
287
+ },
288
+ # not any recent KPIs for now
289
+ "kpis": {}
290
+ },
291
+ "rfm": {
292
+ # charts - rfm
293
+ "charts": {"rfm": {"trace": go.Scatter3d(mode='markers',
294
+ marker=dict(color=None,
295
+ size=12,
296
+ colorscale='delta',
297
+ opacity=0.8)),
298
+ "layout": go.Layout(width=1000,
299
+ margin=dict(l=1, r=1, t=1, b=1),
300
+ height=600,
301
+ scene=dict(
302
+ xaxis_title='recency',
303
+ yaxis_title='monetary',
304
+ zaxis_title='frequency'))
305
+ },
306
+ 'frequency_recency': {'trace': go.Scatter(y=[], x=[],
307
+ mode='markers',
308
+ marker=dict(
309
+ size=16,
310
+ color=[],
311
+ colorscale='Viridis', # one of plotly colorscales
312
+ showscale=False
313
+ )),
314
+ "layout": go.Layout(margin=dict(l=1, r=1, t=1, b=1))},
315
+ 'monetary_frequency': {'trace': go.Scatter(y=[], x=[],
316
+ mode='markers',
317
+ marker=dict(
318
+ size=16,
319
+ color=[],
320
+ colorscale='Viridis', # one of plotly colorscales
321
+ showscale=False
322
+ )),
323
+ "layout": go.Layout(margin=dict(l=1, r=1, t=1, b=1))},
324
+ 'recency_monetary': {'trace': go.Scatter(y=[], x=[],
325
+ mode='markers',
326
+ marker=dict(
327
+ size=16,
328
+ color=[],
329
+ colorscale='Viridis', # one of plotly colorscales
330
+ showscale=False
331
+ )),
332
+ "layout": go.Layout(margin=dict(l=1, r=1, t=1, b=1))}
333
+
334
+ },
335
+ # not any recent KPIs for now
336
+ "kpis": {}
337
+ },
338
+ "customer-segmentation": {
339
+ "charts": {'segmentation': {'trace': go.Treemap(marker_colorscale='Blues',
340
+ textinfo="label+value+percent parent+percent entry",
341
+ parents=[""] * 7),
342
+ 'layout': go.Layout(width=1000,
343
+ margin=dict(l=1, r=1, t=1, b=1),
344
+ height=400)}
345
+ ,
346
+ 'recency_clusters': {'trace': go.Scatter(y=[], x=[],
347
+ hovertemplate='Segment %{marker.color}: <br>Client Count: %{y} </br>Recency : %{x}',
348
+ mode='markers',
349
+ marker=dict(
350
+ size=[],
351
+ color=[],
352
+ showscale=False
353
+ )),
354
+ 'layout': go.Layout(margin=dict(l=1, r=1, t=1, b=1))
355
+ }
356
+ ,
357
+ 'frequency_clusters': {'trace': go.Scatter(y=[], x=[],
358
+ hovertemplate='Segment %{marker.color}: <br>Client Count: %{y} </br>Frequency : %{x}',
359
+ mode='markers',
360
+ marker=dict(
361
+ size=[],
362
+ color=[],
363
+ showscale=False
364
+ )),
365
+ 'layout': go.Layout(margin=dict(l=1, r=1, t=1, b=1))
366
+ },
367
+ 'monetary_clusters': {'trace': go.Scatter(y=[], x=[],
368
+ hovertemplate='Segment %{marker.color}: <br>Client Count: %{y} </br>Monetary : %{x}',
369
+ mode='markers',
370
+ marker=dict(
371
+ size=[],
372
+ color=[],
373
+ showscale=False
374
+ )),
375
+ 'layout': go.Layout(margin=dict(l=1, r=1, t=1, b=1))
376
+ }
377
+ },
378
+ "kpis": {}
379
+ },
380
+ "clv": {
381
+ "charts": {'daily_clv': {'trace': go.Scatter(mode="lines+markers+text", fill='tozeroy'),
382
+ 'layout': go.Layout()},
383
+ 'clvsegments_amount': {'trace': go.Pie(labels=[], values=[], hole=.3), 'layout': go.Layout()}
384
+ },
385
+ "kpis": {}
386
+ },
387
+ "anomaly": {"charts":{"dfunnel_anomaly": {'trace': [go.Scatter(name="anomaly score (0 - 1)", x=[], y=[],
388
+ marker=dict(color="blue")),
389
+ go.Bar(name="outlier detection (0/1)", x=[], y=[],
390
+ marker=dict(color='#FECB52'))],
391
+ 'layout': go.Layout()},
392
+ "dcohort_anomaly_2": {'trace': [go.Scatter(name="anomaly score", x=[], y=[],
393
+ marker=dict(color="blue")),
394
+ go.Bar(name="outlier detection (0/1)", x=[], y=[],
395
+ marker=dict(color='#FECB52'))],
396
+ 'layout': go.Layout()},
397
+ "dcohort_anomaly": {'trace': go.Scatter(name=None, x=[], y=[], marker=dict(color="red")),
398
+ 'layout': go.Layout()},
399
+ "dorders_anomaly": {'trace': go.Bar(name=None, x=[], y=[]), 'layout': go.Layout()},
400
+ "clvrfm_anomaly": {'trace': go.Scatter(name=None, x=[], y=[], mode='markers'), 'layout': go.Layout()}},
401
+ "kpis": {}},
402
+
403
+
404
+ "search_product": {"charts": {_f: {'trace': go.Bar(),
405
+ 'layout': go.Layout(
406
+ legend=dict(
407
+ orientation="h",
408
+ yanchor="bottom",
409
+ y=1.02,
410
+ xanchor="right",
411
+ x=1),
412
+ margin=dict(r=1, t=1))} if _f != "chart_2_search" else
413
+ {'trace': go.Scatter(mode="lines+markers+text",
414
+ line=dict(color='firebrick', width=4),
415
+ textposition="bottom center",
416
+ textfont=dict(
417
+ family="sans serif",
418
+ size=30,
419
+ color="crimson")),
420
+ 'layout': go.Layout()}
421
+ for _f in ["chart_{}_search".format(str(i)) for i in range(2, 5)]},
422
+
423
+
424
+
425
+
426
+ "kpis": {"chart_1_search": ['average_product_sold_per_user_kpi', 'total_product_revenue_kpi',
427
+ 'total_product_discount_kpi', 'total_product_cust_kpi']}},
428
+
429
+
430
+ "search_promotion": {"charts": {_f:
431
+ {'trace': go.Scatter(mode="lines+markers+text",
432
+ line=dict(color='firebrick', width=4),
433
+ textposition="bottom center",
434
+ textfont=dict(
435
+ family="sans serif",
436
+ size=30,
437
+ color="crimson")),
438
+ 'layout': go.Layout()}
439
+ for _f in ["chart_{}_search".format(str(i)) for i in range(2, 5)]},
440
+
441
+ "kpis": {"chart_1_search": ['order_count', 'total_revenue',
442
+ 'total_discount', 'client_count']}},
443
+
444
+ "search_client": {"charts": {_f: {'trace': go.Scatter(mode="lines+markers+text",
445
+ line=dict(color='firebrick', width=4),
446
+ textposition="bottom center",
447
+ textfont=dict(
448
+ family="sans serif",
449
+ size=30,
450
+ color="crimson")),
451
+ 'layout': go.Layout()}
452
+ for _f in ["chart_{}_search".format(str(i)) for i in range(2, 5)]},
453
+
454
+ "kpis": {"chart_1_search": ['order_count', 'frequency', 'monetary', 'recency']}},
455
+
456
+ "search_dimension": {"charts": {_f: {'trace': go.Scatter(mode="lines+markers+text",
457
+ line=dict(color='firebrick', width=4),
458
+ textposition="bottom center",
459
+ textfont=dict(
460
+ family="sans serif",
461
+ size=30,
462
+ color="crimson")),
463
+ 'layout': go.Layout()}
464
+ for _f in ["chart_{}_search".format(str(i)) for i in range(2, 5)]},
465
+
466
+ "kpis": {"chart_1_search": ['order_count', 'payment_amount', 'discount_amount', 'client_count']}},
467
+
468
+ "delivery": {"charts": {_f: {'trace': go.Heatmap(z=[], x=[], y=[],
469
+ colorscale='Viridis', opacity=0.9,
470
+ showlegend=False, ygap=2, xgap=2,
471
+ hoverongaps=None, showscale=False) if 'weekday' in _f.split("_") else
472
+ go.Densitymapbox(lat=[], lon=[], z=[], radius=10, showscale=False),
473
+ 'layout':
474
+ go.Layout(paper_bgcolor='rgba(0,0,0,0)',
475
+ plot_bgcolor='rgba(0,0,0,0)',
476
+ # width=1400,
477
+ margin=dict(l=50, r=50, t=1, b=50) # ,
478
+ # height=450
479
+ )
480
+ if 'weekday' in _f.split("_") else
481
+
482
+ go.Layout(mapbox_style="stamen-terrain",
483
+ margin=dict(l=1, r=1, t=1, b=1),
484
+ mapbox=dict(center=dict(lat=0.0, lon=0.0),
485
+ zoom=10)),
486
+ }
487
+ for _f in [i for i in ['deliver', 'prepare', 'ride']] +
488
+ [i + '_weekday_hour' for i in ['deliver', 'prepare', 'ride']]},
489
+
490
+ "kpis": {
491
+ "deliver_kpis": ['deliver', 'ride', 'returns', 'prepare', 'total_locations']}}
492
+ }
493
+
494
+
495
+ class SampleData:
496
+ """
497
+ This enables us to visualize dashboards when there is no initial data has been created yet.
498
+ These sample data comes from the sample data_folder default in the library.
499
+ """
500
+ kpis = {}
501
+ folder = join(abspath_for_sample_data(), "exploratory_analysis", 'sample_data', '')
502
+ for f in listdir(dirname(folder)):
503
+ if f.split(".")[1] == 'csv':
504
+ kpis["_".join(f.split(".")[0].split("_")[2:])] = None
505
+
506
+ folder = join(abspath_for_sample_data(), "exploratory_analysis", 'sample_data', '')
507
+ for f in listdir(dirname(folder)):
508
+ if f.split(".")[1] == 'csv':
509
+ _kpi_name = "_".join(f.split(".")[0].split("_")[2:])
510
+
511
+ _data = pd.read_csv(join(folder, f))
512
+ if 'date' in list(_data.columns):
513
+ _data['date'] = _data['date'].apply(lambda x: convert_to_day(x))
514
+ kpis["_".join(f.split(".")[0].split("_")[2:])] = _data
515
+
516
+
517
+ class RealData:
518
+ """
519
+ After the scheduling process is done,
520
+ reports are created on the temporary folder with a folder name 'build_in_reports'.
521
+ This collects all reports of created .csv files from 'build_in_reports'.
522
+ Each dimension and whole data ('main' folder name) will be stored separately.
523
+ Each dimension of reports will be created as .csv file.
524
+ """
525
+ kpis = {}
526
+ try:
527
+ es_tag = pd.read_sql("SELECT * FROM es_connection", con).to_dict('resutls')[-1]
528
+ folder = join(es_tag['directory'], "build_in_reports", "")
529
+ except: es_tag, folder = {}, []
530
+
531
+ def get_report_dimensions(self):
532
+ """
533
+
534
+ """
535
+ dimensions = ['There is no available report. Please execute Schedule Data Process']
536
+ try:
537
+ es_tag = pd.read_sql("SELECT * FROM es_connection", con).to_dict('records')[-1]
538
+ if exists(join(es_tag['directory'], "build_in_reports")):
539
+ _dims = listdir(dirname(join(es_tag['directory'], "build_in_reports")))
540
+ if len(_dims) != 0:
541
+ _dims = listdir(dirname(join(es_tag['directory'], "build_in_reports", "")))
542
+ if len(_dims) != 0:
543
+ dimensions = _dims
544
+ return dimensions
545
+ except: return dimensions
546
+
547
+ def check_for_the_report(self, report_name, index='main', date=None):
548
+ """
549
+ checks for 'build_in_reports' while platform is running.
550
+ """
551
+ try:
552
+ es_tag = pd.read_sql("SELECT * FROM es_connection", con).to_dict('records')[-1]
553
+ _path = join(es_tag['directory'], "build_in_reports", index, report_name + ".csv")
554
+ if date is not None:
555
+ _path = join(es_tag['directory'], "build_in_reports", index, date, report_name + ".csv")
556
+ return exists(_path)
557
+ except Exception as e:
558
+ return False
559
+
560
+ def fetch_report(self, report_name, index='main', date=None):
561
+ """
562
+ checks for 'build_in_reports' while platform is running and collect the selected report.
563
+ """
564
+ try:
565
+ es_tag = pd.read_sql("SELECT * FROM es_connection", con).to_dict('records')[-1]
566
+ file_path = join(es_tag['directory'], "build_in_reports", index, report_name + ".csv")
567
+ if date is not None:
568
+ date_file_path = join(es_tag['directory'], "build_in_reports", index, date, report_name + ".csv")
569
+ file_path = date_file_path if exists(date_file_path) else file_path
570
+ return pd.read_csv(file_path)
571
+ except: return False
572
+
573
+ # this will collect the report in the 'build_in_reports'.
574
+ # whole data of reports will be stored in 'main' folder. dimensions are stored seperatelly
575
+ try:
576
+ for index in listdir(dirname(folder)):
577
+ _folder = join(es_tag['directory'], "build_in_reports", index, "")
578
+ kpis[index] = {}
579
+ for f in listdir(dirname(_folder)):
580
+ try:
581
+ kpis[index][f.split(".")[0]] = pd.read_csv(join(_folder, f))
582
+ except Exception as e:
583
+ print(e)
584
+ except Exception as e: print(e)
585
+
586
+
587
+ def cohort_human_readable_form(cohort, tp):
588
+ """
589
+ cohorts data is manipulated in or order to convert more readable format.
590
+ """
591
+ cohort_updated = pd.DataFrame()
592
+ cohort_days = [int(i) for i in list(set(list(cohort.columns)) - set([tp]))]
593
+
594
+ dates = list(zip(list(range(len(list(cohort[tp])))), reversed(list(cohort[tp]))))
595
+ days_back = 15
596
+ while len(cohort_updated) == 0:
597
+ if days_back <= max(cohort_days):
598
+ cohort_updated = cohort[[tp] + [str(i) for i in list(range(days_back+1))]]
599
+ _days = list(map(lambda x: x[1], filter(lambda x: x[0] <= days_back, dates)))
600
+ cohort_updated = cohort_updated[cohort_updated[tp].isin(_days)]
601
+ days_back -= 1
602
+
603
+ cohort_updated = cohort_updated.sort_values(by=tp, ascending=True)
604
+ return cohort_updated
605
+
606
+
607
+ class Charts:
608
+ """
609
+ Collecting Charts for Dashboards;
610
+ There are 2 types of data sets for Charts;
611
+ sample_data; these are built-in .csv file in exploratory_analysis/sample_data folder
612
+ real_data; created from exploratory_analysis reports and ml_processes after creating a real data connection
613
+ After collecting the real data by using **charts** dictionary,
614
+ template of the chart related to page (.html) and its data merge and sending to render_template.
615
+ """
616
+ def __init__(self, samples, real):
617
+ """
618
+ The main perspective here to store each chart serialized .json file into the self.graph_json
619
+ e.g. index.html has segmentation chart
620
+ self.graph_json['charts']['segmentation'] = {'trace': [], 'layout': {}}
621
+ If each chart needs any specific change pls check **charts** dictionary.
622
+ :param samples: built-in data sets in .csv format, converted to pandas data-frame
623
+ :param reals: created ports in .csv format, converted to pandas data-frame
624
+ """
625
+ self.samples = samples
626
+ self.reals = real
627
+ self.graph_json = {}
628
+ self.data_type = {}
629
+ self.filters = {}
630
+ self.monitor = get_monitors()[0]
631
+ self.descriptive_stats = descriptive_stats
632
+ self.abtest_promotions = abtest_promotions
633
+ self.abtest_products = abtest_products
634
+ self.abtest_segments = abtest_segments
635
+ self.delivery_metrics = delivery_metrics
636
+
637
+ def get_data(self, chart, index, date):
638
+ """
639
+ checks both sample and real data. If there is real data for the related KPI or chart fetches from sample_data.
640
+ :param chart: e.g. rfm, segmentation, ...
641
+ :return:
642
+ """
643
+ try:
644
+ if chart not in list(self.reals.kpis.keys()):
645
+ if not self.reals.check_for_the_report(report_name=chart, index=index, date=date):
646
+ return self.samples[chart], False
647
+ else:
648
+ return self.reals.fetch_report(report_name=chart, index=index), True
649
+ else: return self.samples[chart], False
650
+ except Exception as e:
651
+ print(e)
652
+ return self.samples[chart], False
653
+
654
+ def get_widths_heights(self, target, chart):
655
+ if chart == 'segmentation':
656
+ if self.monitor.height == 1080 and self.monitor.width == 1920:
657
+ width, height = 720, 450
658
+ if self.monitor.height == 1050 and self.monitor.width == 1680:
659
+ width, height = 1000, 400
660
+ if chart == 'rfm':
661
+ if self.monitor.height == 1080 and self.monitor.width == 1920:
662
+ width, height = 700, 600
663
+ if self.monitor.height == 1050 and self.monitor.width == 1680:
664
+ width, height = 1000, 600
665
+ if chart in ['segmentation', 'rfm']:
666
+ charts[target]['charts'][chart]['layout']['width'] = width
667
+ charts[target]['charts'][chart]['layout']['height'] = height
668
+
669
+ def decide_trace_type(self, trace, chart):
670
+ if len(set(['funnel', 'distribution', 'clv']) & set(chart.split("_"))) != 0:
671
+ return trace if type(trace) == list else [trace]
672
+ else:
673
+ if 'weekday' not in chart.split("_") and len(self.delivery_metrics & set(chart.split("_"))) != 0:
674
+ return trace if type(trace) == list else [trace]
675
+ else:
676
+ if type(trace) == list:
677
+ return trace
678
+ else:
679
+ return [trace]
680
+
681
+ def ab_test_of_trace(self, data, chart):
682
+ """
683
+ "order_and_payment_amount_differences",
684
+ "promotion_comparison",
685
+ "promotion / product _usage_before_after_amount_accept",
686
+ "promotion / product _usage_before_after_amount_reject",
687
+ "promotion / product _usage_before_after_orders_accept",
688
+ "promotion / product _usage_before_after_orders_reject"
689
+
690
+ "segments_change_weekly_before_after_orders"
691
+ "segments_change_weekly_before_after_amount"
692
+ "segments_change_daily_before_after_orders"
693
+ "segments_change_daily_before_after_amount"
694
+ "segments_change_monthly_before_after_orders"
695
+ "segments_change_monthly_before_after_amount"
696
+ """
697
+ _trace = []
698
+ if chart.split("_")[1] in ['usage', 'change']:
699
+ _type = -2 if chart.split("_")[1] == 'usage' else -1
700
+ _name = 'order count' if chart.split("_")[_type] == 'orders' else 'purchase amount'
701
+ names = ["before average "+_name+" per c.", "after average "+_name+" per c."]
702
+ indicator = chart.split("_")[0] + 's' if chart.split("_")[1] == 'usage' else chart.split("_")[0]
703
+ _trace = [
704
+ go.Bar(name=names[0], x=data[indicator], y=data['mean_control']),
705
+ go.Bar(name=names[1], x=data[indicator], y=data['mean_validation'])
706
+ ]
707
+
708
+ if chart == 'order_and_payment_amount_differences':
709
+ data = data.rename(columns={"diff": "Difference of Order (Before Vs After)",
710
+ "diff_amount": "Difference of Payment Amount (Before Vs After)"})
711
+ _trace = go.Scatter(x=data['Difference of Order (Before Vs After)'],
712
+ y=data['Difference of Payment Amount (Before Vs After)'],
713
+ mode='markers',
714
+ marker=dict(color=list(range(len(data))),
715
+ colorscale='Rainbow'))
716
+ if chart == 'promotion_comparison':
717
+ _trace = go.Scatter(x=data['accept_Ratio'],
718
+ y=data['total_effects'],
719
+ text=data['1st promo'],
720
+ marker=dict(size=data['total_negative_effects'],
721
+ color=list(range(len(data))),
722
+ colorscale='Rainbow'),
723
+ mode='markers',
724
+ name='markers')
725
+ return _trace
726
+
727
+ def get_trace(self, trace, chart, index, date, target):
728
+ """
729
+ fill more variables on charts dictionary. At this process, data sets are stored in the trace.
730
+
731
+ :param trace: e.g. [{go.Scatter()}]
732
+ :param chart: e.g. rfm, segmentation, ...
733
+ :param index: by default 'main'. it is the dimension filter for charts
734
+ :param date: by default the latest date. it is the date filter for charts
735
+ :return:
736
+ """
737
+ _data, is_real_data = self.get_data(chart, index, date) # collect data
738
+ # data for line chart daily(sum), weekly(sum), houry(average), monthly(sum)
739
+ if chart in ["_".join([t, 'orders']) for t in time_periods]:
740
+ try:
741
+ _t = 'date' if chart.split("_")[0] not in list(_data.columns) else chart.split("_")[0]
742
+ _data = _data.sort_values(by=_t, ascending=True)
743
+ _data['orders'] = _data['orders'].apply(lambda x: round(float(x), 2))
744
+ trace['x'] = list(_data[_t])
745
+ trace['y'] = list(_data['orders'])
746
+ if _t not in ['daily', 'weekly']:
747
+ trace['text'] = list(_data['orders'])
748
+ except Exception as e:
749
+ print(e)
750
+ # from the customer segmentation Human readable segments with their sizes
751
+ if chart == 'segmentation':
752
+ trace['labels'] = list(_data['segments'])
753
+ trace['values'] = list(_data['value'])
754
+ # sampled clients of numerical recency, monetary and frequency values
755
+ if chart == 'rfm':
756
+ trace['x'] = list(_data['recency'])
757
+ trace['y'] = list(_data['monetary'])
758
+ trace['z'] = list(_data['frequency'])
759
+ trace['marker']['color'] = list(_data['segments_numeric']) # segments are numerical values.
760
+ if 'funnel' in chart.split("_"):
761
+ _tp = list(set(list(_data.columns)) & set(time_periods))[0]
762
+ trace = []
763
+ for _a in set(list(_data.columns)) - set(time_periods):
764
+ trace += [go.Scatter(x=list(_data[_tp]),
765
+ y=list(_data[_a]),
766
+ mode="lines+markers+text",
767
+ name=_a,
768
+ line=dict( width=4),
769
+ textposition="bottom center",
770
+ textfont=dict(
771
+ family="sans serif",
772
+ size=30))]
773
+ if 'cohort' in chart.split("_"):
774
+ _t = chart.split("_")[0]
775
+ _t_str = ' day' if _t == 'daily' else ' week'
776
+ _data = cohort_human_readable_form(_data, _t)
777
+ z = array(_data[_data.columns[1:]]).tolist()
778
+ x = [str(col) + _t_str for col in list(_data.columns)][1:]
779
+ y = [str(ts)[0:10] for ts in list(_data[_data.columns[0]])]
780
+ trace['z'], trace['x'], trace['y'] = z, x, y
781
+ if chart in self.descriptive_stats:
782
+ if 'distribution' in chart.split("_"):
783
+ _data['payment_bins'] = _data['payment_bins'].apply(lambda x: round(float(x), 2))
784
+ _data['orders'] = _data['orders'].apply(lambda x: int(x))
785
+ _trace_updated = []
786
+ for _bin in _data.to_dict('records'):
787
+ _trace_updated.append(go.Bar(x=[_bin['payment_bins']], y=[_bin['orders']], showlegend=False))
788
+ trace = _trace_updated
789
+ else:
790
+ _t = 'weekly'
791
+ indicator = list(set(list(_data.columns)) - set([_t]))[0]
792
+ _data = _data.sort_values(by=_t, ascending=True)
793
+ _data[indicator] = _data[indicator].apply(lambda x: round(float(x), 2))
794
+ trace['x'] = list(_data[_t])
795
+ trace['y'] = list(_data[indicator])
796
+ trace['text'] = list(_data[indicator])
797
+ if chart in self.abtest_promotions + self.abtest_products + self.abtest_segments:
798
+ trace = self.ab_test_of_trace(_data, chart)
799
+ if chart == 'user_counts_per_order_seq':
800
+ trace['x'] = list(_data['order_seq_num'])
801
+ trace['y'] = list(_data['frequency'])
802
+ if chart == 'customer_journey':
803
+ _data = _data.reset_index().iloc[:-1]
804
+ _data['text'] = _data.apply(
805
+ lambda row: 'Customers Who have ' + str(int(row['index'])) + ' orders. Avg. Purchase Amount : ' + str(round(row['customers` average Purchase Value'], 2)) + " || Avg. Duration between last and recent order :" + str(round(row['hourly order differences'], 2)), axis=1)
806
+ trace = go.Scatter(x=_data['index'],
807
+ y=_data['hourly order differences'],
808
+ text=_data['text'],
809
+ marker=dict(size=_data['customers` average Purchase Value'],
810
+ color=list(range(len(_data))), colorscale='Rainbow'),
811
+ mode='markers',
812
+ name='markers')
813
+ if 'most' in chart.split("_"):
814
+ x_column = 'products' if 'products' in chart.split("_") else 'category'
815
+ trace['x'], trace['y'] = list(_data[x_column]), list(_data['order_count'])
816
+ if 'recency' in chart.split("_") or 'frequency' in chart.split("_") or 'monetary' in chart.split("_"):
817
+ if 'clusters' in chart.split("_"):
818
+ _segment_column = chart.split("_")[0] + '_segment'
819
+ trace['x'] = list(_data[chart.split("_")[0]])
820
+ trace['y'] = list(_data['client_count'])
821
+ trace['marker']['size'] = [s * 16 for s in list(_data[_segment_column])]
822
+ trace['marker']['color'] = list(_data[_segment_column])
823
+ else:
824
+ trace['x'] = list(_data[chart.split("_")[0]])
825
+ trace['y'] = list(_data[chart.split("_")[1]])
826
+ trace['marker']['color'] = list(_data['segments_numeric']) # segments are numerical values.
827
+ if 'clv' in chart.split("_"):
828
+ trace = []
829
+ for data_type in ["prediction", "actual"]:
830
+ _data_dt = _data.query("data_type == @data_type")
831
+ trace.append(go.Scatter(x=list(_data_dt['date']), y=list(_data_dt['payment_amount']), name=data_type,
832
+ mode="lines+markers+text", fill='tozeroy'))
833
+ if chart == 'clvsegments_amount':
834
+ trace['labels'] = list(_data['segments'])
835
+ trace['values'] = list(_data['payment_amount'])
836
+ if chart in ['dfunnel_anomaly', 'dcohort_anomaly_2']:
837
+ trace[0]['x'] = list(_data['daily'])
838
+ trace[0]['y'] = list(_data['Anomaly Score Download to First Order'])
839
+ trace[1]['x'] = list(_data['daily'])
840
+ trace[1]['y'] = list(_data['outlier'])
841
+ if chart == 'dcohort_anomaly':
842
+ _days = list(set(_data.columns) - {'days'})
843
+ _colors = list(map(lambda x: 'red' if x.split("_")[-1] == 'outlier' else 'blue', _days))
844
+ _days_updated = list(map(lambda x: x.split("_")[0] if x.split("_")[-1] == 'outlier' else x, _days))
845
+ trace = []
846
+ for col1, col2, color in zip(_days, _days_updated, _colors):
847
+ _trace = go.Scatter(x=list(_data['days']), y=list(_data[col1]), name=col2, marker={'color': color})
848
+ trace.append(_trace)
849
+ if chart == 'dorders_anomaly':
850
+ _trace = trace
851
+ trace = []
852
+ for _filter in ['no change', 'decrease', 'increase']:
853
+ __data = _data.query("anomalities == @_filter")
854
+ _trace = go.Bar(name=_filter, x=list(__data['daily']), y=list(__data['diff_perc']))
855
+ trace.append(_trace)
856
+ if chart == 'clvrfm_anomaly':
857
+ trace = []
858
+ clusters = sorted(list(_data['naming'].unique()))
859
+ _data['frequency_diff'] = _data['frequency_diff'].apply(lambda x: round(float(x), 2))
860
+ _data['monetary_diff'] = _data['monetary_diff'].apply(lambda x: round(float(x), 2))
861
+ for cluster in clusters:
862
+ __data = _data.query("naming == @cluster")
863
+ _trace = go.Scatter(name=cluster, x=list(__data['monetary_diff']), y=list(__data['frequency_diff']),
864
+ mode='markers')
865
+ trace.append(_trace)
866
+ if chart == 'churn':
867
+ trace['labels'] = ['churn %', 'not churn %']
868
+ trace['values'] = [list(_data['churn'])[0], 1 - list(_data['churn'])[0]]
869
+ if chart == 'churn_weekly':
870
+ trace['x'] = list(_data['weekly'])
871
+ trace['y'] = list(_data['churn'])
872
+ if 'search' in chart.split("_"):
873
+ if target == 'search_product':
874
+ if chart == "chart_2_search":
875
+ trace['x'] = list(_data['daily'])
876
+ trace['y'] = list(_data['order_count'])
877
+ if chart == "chart_3_search":
878
+ trace = [
879
+ go.Bar(name='before', x=_data['products'], y=_data['mean_control']),
880
+ go.Bar(name='after', x=_data['products'], y=_data['mean_validation'])
881
+ ]
882
+ if chart == "chart_4_search":
883
+ trace = [
884
+ go.Bar(name='before', x=_data['products'], y=_data['mean_control']),
885
+ go.Bar(name='after', x=_data['products'], y=_data['mean_validation'])
886
+ ]
887
+ if target == 'search_promotion':
888
+ if chart == "chart_2_search":
889
+ trace['x'] = list(_data['daily'])
890
+ trace['y'] = list(_data['inorganic_ratio'])
891
+ if chart == "chart_3_search":
892
+ trace['x'] = list(_data['daily'])
893
+ trace['y'] = list(_data['total_revenue'])
894
+ if chart == "chart_4_search":
895
+ trace['x'] = list(_data['daily'])
896
+ trace['y'] = list(_data['total_discount'])
897
+
898
+ if target == 'search_client':
899
+ if chart == "chart_2_search":
900
+ trace['x'] = list(_data['date'])
901
+ trace['y'] = list(_data['payment_amount'])
902
+
903
+ if target == 'search_dimension':
904
+ if chart == "chart_2_search":
905
+ trace['x'] = list(_data['daily'])
906
+ trace['y'] = list(_data['order_count'])
907
+ if chart == "chart_3_search":
908
+ trace['x'] = list(_data['daily'])
909
+ trace['y'] = list(_data['payment_amount'])
910
+ if chart == "chart_4_search":
911
+ trace['x'] = list(_data['daily'])
912
+ trace['y'] = list(_data['client_count'])
913
+
914
+ if 'weekday' in chart.split("_"):
915
+ trace['x'] = [str(int(col)) for col in list(_data.columns)][1:]
916
+ trace['y'] = [str(int(ts)) + ':00 ' for ts in list(_data[_data.columns[0]])]
917
+ trace['z'] = array(_data[_data.columns[1:]]).tolist()
918
+
919
+ if 'weekday' not in chart.split("_") and len(self.delivery_metrics & set(chart.split("_"))) != 0:
920
+ trace['lat'] = list(_data['latitude'])
921
+ trace['lon'] = list(_data['longitude'])
922
+ trace['z'] = list(_data[chart.split("_")[0]])
923
+
924
+ return self.decide_trace_type(chart=chart, trace=trace), is_real_data
925
+
926
+ def get_centroids(self, data):
927
+ return [mean(list(data['latitude'])), mean(list(data['longitude']))]
928
+
929
+ def get_layout(self, layout, chart, index, date, annotation=None):
930
+ _data = self.get_data(chart, index, date)[0]
931
+ if 'cohort' in chart.split("_"):
932
+ _t = chart.split("_")[0]
933
+ _t_str = ' day' if _t == 'daily' else ' week'
934
+ _data = cohort_human_readable_form(_data, _t)
935
+ z = array(_data[_data.columns[1:]]).tolist()
936
+ x = [str(col) + _t_str for col in list(_data.columns)][1:]
937
+ y = [str(ts)[0:10] for ts in list(_data[_data.columns[0]])]
938
+ annotations = []
939
+ for n, row in enumerate(z):
940
+ for m, val in enumerate(row):
941
+ annotation['text'] = str(z[n][m])
942
+ try:
943
+ annotation['x'] = x[m]
944
+ except Exception as e:
945
+ print(e)
946
+ annotation['y'] = y[n]
947
+ annotations.append(annotation)
948
+ layout['annotations'] = annotations
949
+ if 'usage' in chart.split("_") or chart == 'customer_journey':
950
+ columns = ['mean_control', 'mean_validation']
951
+ columns = ['hourly order differences'] * 2 if chart == 'customer_journey' else columns
952
+ layout['yaxis'] = {"range": [
953
+ round(max(0, min(min(_data[columns[0]]), min(_data[columns[1]])) - 0.02), 2),
954
+ round(max(0, max(max(_data[columns[0]]), max(_data[columns[1]])) - 0.02), 2)]}
955
+ if 'change' in chart.split("_"):
956
+ columns = ['mean_control', 'mean_validation']
957
+ layout['yaxis'] = {"range": [
958
+ round(max(0, min(min(_data[columns[0]]), min(_data[columns[1]])) - 0.02), 2),
959
+ round(max(0, max(max(_data[columns[0]]), max(_data[columns[1]])) - 0.02), 2)]}
960
+ if chart == 'dfunnel_anomaly':
961
+ min_value = round(min(_data['Anomaly Score Download to First Order']) - 0.01, 2)
962
+ max_value = round(max(_data['Anomaly Score Download to First Order']) + 0.01, 2)
963
+ layout['yaxis'] = {"range": [min_value, max_value]}
964
+
965
+ if len(self.delivery_metrics & set(chart.split("_"))) != 0 and 'weekday' not in chart.split("_"):
966
+ _centroids = self.get_centroids(_data)
967
+ layout = go.Layout(mapbox_style="stamen-terrain",
968
+ mapbox=dict(center=dict(lat=_centroids[0], lon=_centroids[1]), zoom=10))
969
+
970
+ if 'change' in chart.split("_") or 'dfunnel' in chart.split("_"):
971
+ return layout
972
+ else:
973
+ if len(self.delivery_metrics & set(chart.split("_"))) != 0:
974
+ return layout
975
+ else:
976
+ return [layout] if 'usage' not in chart.split("_") else layout
977
+
978
+ def get_values(self, kpi, index, date):
979
+ """
980
+ get data related KPI
981
+ :param kpi: .e.g.total_orders, total_visitors, ...
982
+ :return: dictionary with KPIs in keys
983
+ """
984
+ _data, is_real_data = self.get_data(kpi, index, date)
985
+ return _data.to_dict('records')[0], is_real_data
986
+
987
+ def has_chart_annotation(self, chart, c):
988
+ if 'cohort' in chart.split("_"):
989
+ return c['annotation']
990
+ else: return None
991
+
992
+ def get_chart(self, target, index='main', date=None):
993
+ """
994
+ related to 'target', charts and KPIs are collected in order to show on-page.
995
+ The main aim here, fill the self.graph_json dictionary with serialized dictionaries.
996
+ :param target:
997
+ :return:
998
+ """
999
+ # collecting charts
1000
+ self.graph_json['charts'] = {}
1001
+ self.data_type = {}
1002
+ self.filters = {"dimensions": self.reals.get_report_dimensions()}
1003
+ for c in charts[target]['charts']:
1004
+ trace, is_real_data = self.get_trace(charts[target]['charts'][c]['trace'], c, index, date, target)
1005
+ self.get_widths_heights(chart=c, target=target)
1006
+ annotation = self.has_chart_annotation(chart=c, c=charts[target]['charts'][c])
1007
+ layout = self.get_layout(charts[target]['charts'][c]['layout'], c,
1008
+ annotation=annotation, index=index, date=date)
1009
+ self.data_type[c] = is_real_data
1010
+ self.graph_json['charts'][c] = {'trace': trace,
1011
+ 'layout': layout, 'is_real_data': is_real_data}
1012
+ # collecting KPIs
1013
+ self.graph_json['kpis'] = {}
1014
+ for k in charts[target]['kpis']:
1015
+ _obj, is_real_data = self.get_values(k, index, date)
1016
+ for _k in charts[target]['kpis'][k]:
1017
+ try:
1018
+ self.data_type[_k] = is_real_data
1019
+ self.graph_json['kpis'][_k] = '{:,}'.format(int(_obj[_k])).replace(",", ".")
1020
+ except Exception as e:
1021
+ print()
1022
+ return self.graph_json, self.data_type, self.filters
1023
+
1024
+ def get_individual_chart(self, target, chart, index='main', date=None):
1025
+ self.graph_json['charts'] = {}
1026
+ c = charts[target]['charts'][chart]
1027
+ trace, is_real_data = self.get_trace(c['trace'], chart, index, date, target)
1028
+ self.get_widths_heights(chart=chart, target=target)
1029
+ annotation = c['annotation'] if 'cohort' in chart.split("_") else None
1030
+ layout = self.get_layout(c['layout'], chart,
1031
+ annotation=annotation, index=index, date=date)
1032
+ self.data_type[chart] = is_real_data
1033
+ return {'trace': trace, 'layout': layout, 'is_real_data': is_real_data}
1034
+
1035
+ def get_json_format(self, chart):
1036
+ return json.dumps({"trace": chart['trace'],
1037
+ "layout": chart['layout']}, cls=plotly.utils.PlotlyJSONEncoder)
1038
+
1039
+