openseries 2.1.1__tar.gz → 2.1.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openseries
3
- Version: 2.1.1
3
+ Version: 2.1.2
4
4
  Summary: Tools for analyzing financial timeseries.
5
5
  License-Expression: BSD-3-Clause
6
6
  License-File: LICENSE.md
@@ -424,9 +424,6 @@ def _configure_figure_layout(
424
424
  add_logo: bool,
425
425
  vertical_legend: bool,
426
426
  title: str | None,
427
- mobile: bool = False,
428
- total_min_height: int | None = None,
429
- table_min_height: int | None = None,
430
427
  ) -> None:
431
428
  """Configure figure layout with logo, legend, and title.
432
429
 
@@ -436,14 +433,12 @@ def _configure_figure_layout(
436
433
  add_logo: Whether to add logo.
437
434
  vertical_legend: Whether to use vertical legend.
438
435
  title: Optional title for the figure.
439
- mobile: Whether this is a mobile layout. Defaults to False.
440
- total_min_height: Minimum total height for mobile layout in pixels.
441
- table_min_height: Minimum height for table subplot in pixels.
442
436
  """
443
437
  fig, logo = load_plotly_dict()
444
438
 
445
439
  if add_logo:
446
- figure.add_layout_image(logo)
440
+ logo_copy = logo.copy()
441
+ figure.add_layout_image(logo_copy)
447
442
 
448
443
  figure.update_layout(fig.get("layout"))
449
444
  colorway: list[str] = cast("dict[str, list[str]]", fig["layout"]).get(
@@ -468,24 +463,6 @@ def _configure_figure_layout(
468
463
  "orientation": "h",
469
464
  }
470
465
 
471
- if mobile:
472
- if vertical_legend:
473
- legend = {
474
- "yanchor": "top",
475
- "y": 1.02,
476
- "xanchor": "left",
477
- "x": 0,
478
- "orientation": "h",
479
- }
480
- else:
481
- legend = {
482
- "yanchor": "top",
483
- "y": 1.02,
484
- "xanchor": "left",
485
- "x": 0,
486
- "orientation": "h",
487
- }
488
-
489
466
  layout_updates: dict[str, object] = {
490
467
  "legend": legend,
491
468
  "colorway": colorway[: copied.item_count],
@@ -493,59 +470,11 @@ def _configure_figure_layout(
493
470
  "margin": {"l": 50, "r": 50, "t": 80, "b": 50, "pad": 10},
494
471
  }
495
472
 
496
- if mobile and total_min_height is not None:
497
- layout_updates["height"] = total_min_height
498
- layout_updates["autosize"] = False
499
-
500
473
  figure.update_layout(**layout_updates)
501
474
 
502
- if mobile:
503
- figure.update_xaxes(
504
- gridcolor="#EEEEEE",
505
- automargin=True,
506
- tickangle=-45,
507
- row=1,
508
- col=1,
509
- )
510
- figure.update_xaxes(
511
- gridcolor="#EEEEEE",
512
- automargin=True,
513
- tickangle=-45,
514
- row=2,
515
- col=1,
516
- )
517
- figure.update_yaxes(
518
- tickformat=".2%",
519
- gridcolor="#EEEEEE",
520
- automargin=True,
521
- row=1,
522
- col=1,
523
- )
524
- figure.update_yaxes(
525
- tickformat=".2%",
526
- gridcolor="#EEEEEE",
527
- automargin=True,
528
- row=2,
529
- col=1,
530
- )
531
- if table_min_height is not None and total_min_height is not None:
532
- plot_height = 400
533
- bar_height = 350
534
- spacing = 0.08
535
- plot_domain_top = 1.0
536
- plot_domain_bottom = 1.0 - (plot_height / total_min_height)
537
- bar_domain_top = plot_domain_bottom - spacing
538
- bar_domain_bottom = bar_domain_top - (bar_height / total_min_height)
539
-
540
- figure.update_layout(
541
- yaxis_domain=[plot_domain_bottom, plot_domain_top],
542
- yaxis2_domain=[bar_domain_bottom, bar_domain_top],
543
- )
544
- title_size = 24
545
- else:
546
- figure.update_xaxes(gridcolor="#EEEEEE", automargin=True, tickangle=-45)
547
- figure.update_yaxes(tickformat=".2%", gridcolor="#EEEEEE", automargin=True)
548
- title_size = 36
475
+ figure.update_xaxes(gridcolor="#EEEEEE", automargin=True, tickangle=-45)
476
+ figure.update_yaxes(tickformat=".2%", gridcolor="#EEEEEE", automargin=True)
477
+ title_size = 36
549
478
 
550
479
  if title:
551
480
  figure.update_layout(
@@ -713,16 +642,95 @@ def _build_mobile_figure(
713
642
  col=1,
714
643
  )
715
644
 
716
- _configure_figure_layout(
717
- figure_mobile,
718
- copied,
719
- add_logo=add_logo,
720
- vertical_legend=vertical_legend,
721
- title=title,
722
- mobile=True,
723
- total_min_height=total_min_height,
645
+ fig, logo = load_plotly_dict()
646
+
647
+ if add_logo:
648
+ logo_copy = logo.copy()
649
+ logo_copy["x"] = 0.99
650
+ logo_copy["xanchor"] = "right"
651
+ figure_mobile.add_layout_image(logo_copy)
652
+
653
+ figure_mobile.update_layout(fig.get("layout"))
654
+ colorway: list[str] = cast("dict[str, list[str]]", fig["layout"]).get(
655
+ "colorway",
656
+ [],
657
+ )
658
+
659
+ if vertical_legend:
660
+ legend = {
661
+ "yanchor": "bottom",
662
+ "y": -0.04,
663
+ "xanchor": "right",
664
+ "x": 0.98,
665
+ "orientation": "v",
666
+ }
667
+ else:
668
+ legend = {
669
+ "yanchor": "bottom",
670
+ "y": -0.2,
671
+ "xanchor": "right",
672
+ "x": 0.98,
673
+ "orientation": "h",
674
+ }
675
+
676
+ layout_updates: dict[str, object] = {
677
+ "legend": legend,
678
+ "colorway": colorway[: copied.item_count],
679
+ "autosize": False,
680
+ "height": total_min_height,
681
+ "margin": {"l": 50, "r": 50, "t": 80, "b": 50, "pad": 10},
682
+ }
683
+
684
+ figure_mobile.update_layout(**layout_updates)
685
+
686
+ figure_mobile.update_xaxes(
687
+ gridcolor="#EEEEEE",
688
+ automargin=True,
689
+ tickangle=-45,
690
+ row=1,
691
+ col=1,
692
+ )
693
+ figure_mobile.update_xaxes(
694
+ gridcolor="#EEEEEE",
695
+ automargin=True,
696
+ tickangle=-45,
697
+ row=2,
698
+ col=1,
699
+ )
700
+ figure_mobile.update_yaxes(
701
+ tickformat=".2%",
702
+ gridcolor="#EEEEEE",
703
+ automargin=True,
704
+ row=1,
705
+ col=1,
706
+ )
707
+ figure_mobile.update_yaxes(
708
+ tickformat=".2%",
709
+ gridcolor="#EEEEEE",
710
+ automargin=True,
711
+ row=2,
712
+ col=1,
713
+ )
714
+
715
+ plot_height = 400
716
+ bar_height = 350
717
+ spacing = 0.08
718
+ plot_domain_top = 1.0
719
+ plot_domain_bottom = 1.0 - (plot_height / total_min_height)
720
+ bar_domain_top = plot_domain_bottom - spacing
721
+ bar_domain_bottom = bar_domain_top - (bar_height / total_min_height)
722
+
723
+ figure_mobile.update_layout(
724
+ yaxis_domain=[plot_domain_bottom, plot_domain_top],
725
+ yaxis2_domain=[bar_domain_bottom, bar_domain_top],
724
726
  )
725
727
 
728
+ title_size = 24
729
+ if title:
730
+ figure_mobile.update_layout(
731
+ {"title": {"text": f"<b>{title}</b><br>", "font": {"size": title_size}}},
732
+ )
733
+
726
734
  return figure_mobile
727
735
 
728
736
 
@@ -830,7 +838,10 @@ def _generate_responsive_html_string(
830
838
  """
831
839
  desktop_style = "width:100%;"
832
840
  mobile_style = "width:100%; display:none;"
833
- match_media = 'window.matchMedia("(max-width: 960px)").matches'
841
+ match_media = (
842
+ '(window.matchMedia("(max-width: 960px)").matches || '
843
+ '"ontouchstart" in window || navigator.maxTouchPoints > 0)'
844
+ )
834
845
  desktop_get = f'document.getElementById("{div_id_desktop}_container")'
835
846
  mobile_get = f'document.getElementById("{div_id_mobile}_container")'
836
847
 
@@ -847,7 +858,7 @@ def _generate_responsive_html_string(
847
858
  f"</div>\n"
848
859
  "<style>\n"
849
860
  "body { overflow-y: auto; }\n"
850
- "@media (max-width: 960px) {\n"
861
+ "@media (max-width: 960px), (pointer: coarse), (hover: none) {\n"
851
862
  " .plotly-desktop { display: none !important; }\n"
852
863
  " .plotly-mobile { display: block !important; "
853
864
  "overflow: visible !important; }\n"
@@ -871,13 +882,55 @@ def _generate_responsive_html_string(
871
882
  " .plotly-mobile [style*='overflow'] { "
872
883
  "overflow: visible !important; overflow-y: visible !important; }\n"
873
884
  "}\n"
874
- "@media (min-width: 961px) {\n"
885
+ "@media (min-width: 961px) and (pointer: fine) and (hover: hover) {\n"
875
886
  " .plotly-desktop { display: block !important; }\n"
876
887
  " .plotly-mobile { display: none !important; }\n"
888
+ " .plotly-desktop .js-plotly-plot { "
889
+ "overflow: hidden !important; overflow-y: hidden !important; "
890
+ "overflow-x: hidden !important; }\n"
891
+ " .plotly-desktop .js-plotly-plot > div { "
892
+ "overflow: hidden !important; overflow-y: hidden !important; "
893
+ "overflow-x: hidden !important; max-height: 100% !important; }\n"
894
+ " .plotly-desktop .js-plotly-plot svg { "
895
+ "overflow: hidden !important; }\n"
896
+ " .plotly-desktop * { "
897
+ "overflow-y: hidden !important; }\n"
898
+ ' .plotly-desktop [style*="overflow"] { '
899
+ "overflow: hidden !important; overflow-y: hidden !important; }\n"
900
+ " .plotly-desktop .scrollbar-kit { "
901
+ "display: none !important; visibility: hidden !important; "
902
+ "opacity: 0 !important; }\n"
903
+ " .plotly-desktop .scrollbar-slider { "
904
+ "display: none !important; visibility: hidden !important; "
905
+ "opacity: 0 !important; }\n"
906
+ " .plotly-desktop .scrollbar-glyph { "
907
+ "display: none !important; visibility: hidden !important; "
908
+ "opacity: 0 !important; }\n"
877
909
  "}\n"
878
910
  "</style>\n"
879
911
  "<script>\n"
880
912
  "(function() {\n"
913
+ " function adjustLogoPosition(container) {\n"
914
+ " if (!container) return;\n"
915
+ " var plots = container.querySelectorAll('.js-plotly-plot');\n"
916
+ " plots.forEach(function(plot) {\n"
917
+ " var svg = plot.querySelector('svg');\n"
918
+ " if (!svg) return;\n"
919
+ " var images = svg.querySelectorAll('image[xref=\"paper\"]');\n"
920
+ " images.forEach(function(img) {\n"
921
+ " var isNarrow = window.matchMedia("
922
+ "'(max-width: 960px)').matches;\n"
923
+ " if (isNarrow) {\n"
924
+ " img.setAttribute('x', '0.99');\n"
925
+ " img.setAttribute('xanchor', 'right');\n"
926
+ " } else {\n"
927
+ " img.setAttribute('x', '0.01');\n"
928
+ " img.removeAttribute('xanchor');\n"
929
+ " }\n"
930
+ " });\n"
931
+ " });\n"
932
+ " }\n"
933
+ "\n"
881
934
  " function updateLayout() {\n"
882
935
  f" var isMobile = {match_media};\n"
883
936
  f" var desktopContainer = {desktop_get};\n"
@@ -900,12 +953,71 @@ def _generate_responsive_html_string(
900
953
  'mobileContainer.style.display = "none";\n'
901
954
  " disableTableScrolling(desktopContainer);\n"
902
955
  " setTimeout(function() { "
903
- "adjustTableSize(desktopContainer); }, 100);\n"
956
+ "adjustTableSize(desktopContainer); "
957
+ "adjustLogoPosition(desktopContainer); }, 100);\n"
904
958
  " }\n"
959
+ " adjustLogoPosition(desktopContainer);\n"
905
960
  " }\n"
906
961
  "\n"
907
962
  " function adjustTableSize(container) {\n"
908
963
  " if (!container) return;\n"
964
+ " \n"
965
+ " function forceNoScroll() {\n"
966
+ " var scrollbarKits = container.querySelectorAll("
967
+ "'.scrollbar-kit');\n"
968
+ " scrollbarKits.forEach(function(el) {\n"
969
+ " el.style.setProperty('display', 'none', "
970
+ "'important');\n"
971
+ " el.style.setProperty('visibility', 'hidden', "
972
+ "'important');\n"
973
+ " el.style.setProperty('opacity', '0', 'important');\n"
974
+ " });\n"
975
+ " \n"
976
+ " var scrollbarSliders = container.querySelectorAll("
977
+ "'.scrollbar-slider');\n"
978
+ " scrollbarSliders.forEach(function(el) {\n"
979
+ " el.style.setProperty('display', 'none', "
980
+ "'important');\n"
981
+ " el.style.setProperty('visibility', 'hidden', "
982
+ "'important');\n"
983
+ " el.style.setProperty('opacity', '0', 'important');\n"
984
+ " });\n"
985
+ " \n"
986
+ " var scrollbarGlyphs = container.querySelectorAll("
987
+ "'.scrollbar-glyph');\n"
988
+ " scrollbarGlyphs.forEach(function(el) {\n"
989
+ " el.style.setProperty('display', 'none', "
990
+ "'important');\n"
991
+ " el.style.setProperty('visibility', 'hidden', "
992
+ "'important');\n"
993
+ " el.style.setProperty('opacity', '0', 'important');\n"
994
+ " });\n"
995
+ " \n"
996
+ " var allElements = container.querySelectorAll('*');\n"
997
+ " allElements.forEach(function(el) {\n"
998
+ " var computed = window.getComputedStyle(el);\n"
999
+ " if (computed.overflowY === 'auto' || "
1000
+ "computed.overflowY === 'scroll' || computed.overflow === 'auto' || "
1001
+ "computed.overflow === 'scroll') {\n"
1002
+ " el.style.setProperty('overflow', 'hidden', "
1003
+ "'important');\n"
1004
+ " el.style.setProperty('overflow-y', 'hidden', "
1005
+ "'important');\n"
1006
+ " el.style.setProperty('overflow-x', 'hidden', "
1007
+ "'important');\n"
1008
+ " }\n"
1009
+ " if (el.scrollHeight > el.clientHeight && "
1010
+ "el.clientHeight > 0) {\n"
1011
+ " el.style.setProperty('max-height', "
1012
+ "el.clientHeight + 'px', 'important');\n"
1013
+ " el.style.setProperty('overflow', 'hidden', "
1014
+ "'important');\n"
1015
+ " el.style.setProperty('overflow-y', 'hidden', "
1016
+ "'important');\n"
1017
+ " }\n"
1018
+ " });\n"
1019
+ " }\n"
1020
+ " \n"
909
1021
  " var plots = container.querySelectorAll('.js-plotly-plot');\n"
910
1022
  " plots.forEach(function(plot) {\n"
911
1023
  " var svg = plot.querySelector('svg');\n"
@@ -914,89 +1026,197 @@ def _generate_responsive_html_string(
914
1026
  " if (!tableGroup) return;\n"
915
1027
  " var plotRect = plot.getBoundingClientRect();\n"
916
1028
  " if (plotRect.height === 0) return;\n"
917
- " setTimeout(function() {\n"
1029
+ " \n"
1030
+ " function adjustTable() {\n"
918
1031
  " try {\n"
919
- " var bbox = tableGroup.getBBox();\n"
920
- " if (bbox.height === 0) return;\n"
921
- " var availableHeight = plotRect.height - 60;\n"
922
- " var currentHeight = bbox.height;\n"
923
- " if (currentHeight > availableHeight && "
924
- "availableHeight > 0) {\n"
925
- " var scaleFactor = availableHeight / "
926
- "currentHeight;\n"
927
- " var minScale = 0.4;\n"
928
- " var maxScale = 1.0;\n"
929
- " scaleFactor = Math.max(minScale, "
930
- "Math.min(maxScale, scaleFactor));\n"
931
- " var existingTransform = "
1032
+ " forceNoScroll();\n"
1033
+ " \n"
1034
+ " var availableHeight = plotRect.height - 100;\n"
1035
+ " if (availableHeight <= 0) return;\n"
1036
+ " \n"
1037
+ " var rows = tableGroup.querySelectorAll("
1038
+ "'g[class*=\"row\"]');\n"
1039
+ " if (rows.length === 0) return;\n"
1040
+ " \n"
1041
+ " var rowCount = rows.length;\n"
1042
+ " var calculatedRowHeight = availableHeight / rowCount;\n"
1043
+ " var minRowHeight = 18;\n"
1044
+ " var maxRowHeight = 35;\n"
1045
+ " var rowHeight = Math.max(minRowHeight, "
1046
+ "Math.min(maxRowHeight, calculatedRowHeight));\n"
1047
+ " \n"
1048
+ " var baseFontSize = 12;\n"
1049
+ " var fontScale = rowHeight / 25;\n"
1050
+ " var fontSize = baseFontSize * fontScale;\n"
1051
+ " var minFontSize = 9;\n"
1052
+ " var maxFontSize = 14;\n"
1053
+ " fontSize = Math.max(minFontSize, "
1054
+ "Math.min(maxFontSize, fontSize));\n"
1055
+ " \n"
1056
+ " rows.forEach(function(row, rowIndex) {\n"
1057
+ " var yPos = rowIndex * rowHeight;\n"
1058
+ " var rects = row.querySelectorAll('rect');\n"
1059
+ " var texts = row.querySelectorAll('text');\n"
1060
+ " \n"
1061
+ " rects.forEach(function(rect) {\n"
1062
+ " var currentHeight = "
1063
+ "parseFloat(rect.getAttribute('height') || '25');\n"
1064
+ " if (currentHeight > 0) {\n"
1065
+ " rect.setAttribute('height', "
1066
+ "rowHeight.toString());\n"
1067
+ " var currentY = "
1068
+ "parseFloat(rect.getAttribute('y') || '0');\n"
1069
+ " var rowBaseY = Math.floor(currentY / "
1070
+ "currentHeight) * rowHeight;\n"
1071
+ " rect.setAttribute('y', "
1072
+ "rowBaseY.toString());\n"
1073
+ " }\n"
1074
+ " });\n"
1075
+ " \n"
1076
+ " texts.forEach(function(text) {\n"
1077
+ " text.setAttribute('font-size', "
1078
+ "fontSize.toString());\n"
1079
+ " });\n"
1080
+ " });\n"
1081
+ " \n"
1082
+ " var existingTransform = "
932
1083
  "tableGroup.getAttribute('transform') || '';\n"
933
- " var translateMatch = "
1084
+ " var translateMatch = "
934
1085
  "existingTransform.match(/translate\\(([^)]+)\\)/);\n"
935
- " var translate = translateMatch ? "
1086
+ " var translate = translateMatch ? "
936
1087
  "translateMatch[0] : 'translate(0,0)';\n"
937
- " var scaleTransform = translate + ' scale(' + "
938
- "scaleFactor + ')';\n"
939
- " tableGroup.setAttribute('transform', "
940
- "scaleTransform);\n"
941
- " } else if (currentHeight <= availableHeight) {\n"
942
- " var existingTransform = "
943
- "tableGroup.getAttribute('transform') || '';\n"
944
- " var translateMatch = "
945
- "existingTransform.match(/translate\\(([^)]+)\\)/);\n"
946
- " var translate = translateMatch ? "
947
- "translateMatch[0] : 'translate(0,0)';\n"
948
- " tableGroup.setAttribute('transform', "
949
- "translate);\n"
950
- " }\n"
1088
+ " tableGroup.setAttribute('transform', translate);\n"
1089
+ " \n"
1090
+ " forceNoScroll();\n"
951
1091
  " } catch (e) {\n"
952
1092
  " console.log('Table adjustment error:', e);\n"
953
1093
  " }\n"
954
- " }, 300);\n"
1094
+ " }\n"
1095
+ " \n"
1096
+ " setTimeout(adjustTable, 200);\n"
1097
+ " setTimeout(adjustTable, 600);\n"
1098
+ " setTimeout(adjustTable, 1200);\n"
1099
+ " setTimeout(adjustTable, 2000);\n"
955
1100
  " });\n"
956
1101
  " }\n"
957
1102
  "\n"
958
1103
  " function disableTableScrolling(container) {\n"
959
1104
  " if (!container) return;\n"
1105
+ " var isDesktop = container.classList && "
1106
+ "container.classList.contains('plotly-desktop');\n"
1107
+ " var overflowValue = isDesktop ? 'hidden' : 'visible';\n"
960
1108
  " var plots = container.querySelectorAll('.js-plotly-plot');\n"
961
1109
  " plots.forEach(function(plot) {\n"
962
1110
  " var allElements = plot.querySelectorAll('*');\n"
963
1111
  " allElements.forEach(function(el) {\n"
964
- " var style = window.getComputedStyle(el);\n"
965
- " var overflow = style.overflow;\n"
966
- " var overflowY = style.overflowY;\n"
967
- " if (overflow === 'auto' || overflow === 'scroll' || "
1112
+ " if (el.tagName === 'DIV' || el.tagName === 'SVG') {\n"
1113
+ " var style = window.getComputedStyle(el);\n"
1114
+ " var overflow = style.overflow;\n"
1115
+ " var overflowY = style.overflowY;\n"
1116
+ " if (overflow === 'auto' || overflow === 'scroll' || "
968
1117
  "overflowY === 'auto' || overflowY === 'scroll') {\n"
969
- " el.style.setProperty('overflow', 'visible', "
970
- "'important');\n"
971
- " el.style.setProperty('overflow-y', 'visible', "
972
- "'important');\n"
973
- " el.style.setProperty('overflow-x', 'visible', "
974
- "'important');\n"
1118
+ " el.style.setProperty('overflow', "
1119
+ "overflowValue, 'important');\n"
1120
+ " el.style.setProperty('overflow-y', "
1121
+ "overflowValue, 'important');\n"
1122
+ " el.style.setProperty('overflow-x', "
1123
+ "overflowValue, 'important');\n"
1124
+ " }\n"
975
1125
  " }\n"
976
1126
  " });\n"
977
- " plot.style.setProperty('overflow', 'visible', 'important');\n"
978
- " plot.style.setProperty('overflow-y', 'visible', "
1127
+ " plot.style.setProperty('overflow', overflowValue, "
1128
+ "'important');\n"
1129
+ " plot.style.setProperty('overflow-y', overflowValue, "
979
1130
  "'important');\n"
980
1131
  " var plotDivs = plot.querySelectorAll('div');\n"
981
1132
  " plotDivs.forEach(function(div) {\n"
982
- " div.style.setProperty('overflow', 'visible', "
1133
+ " div.style.setProperty('overflow', overflowValue, "
983
1134
  "'important');\n"
984
- " div.style.setProperty('overflow-y', 'visible', "
1135
+ " div.style.setProperty('overflow-y', overflowValue, "
985
1136
  "'important');\n"
986
1137
  " });\n"
987
1138
  " var svgs = plot.querySelectorAll('svg');\n"
988
1139
  " svgs.forEach(function(svg) {\n"
989
- " svg.style.setProperty('overflow', 'visible', "
1140
+ " svg.style.setProperty('overflow', overflowValue, "
990
1141
  "'important');\n"
991
- " svg.setAttribute('overflow', 'visible');\n"
1142
+ " svg.setAttribute('overflow', overflowValue);\n"
992
1143
  " });\n"
993
1144
  " });\n"
994
1145
  " }\n"
995
1146
  "\n"
996
1147
  " function setupScrollObserver(container) {\n"
997
1148
  " if (!container) return;\n"
1149
+ " var isDesktop = container.classList && "
1150
+ "container.classList.contains('plotly-desktop');\n"
1151
+ " \n"
1152
+ " function preventScrollbars() {\n"
1153
+ " if (isDesktop) {\n"
1154
+ " var scrollbarKits = container.querySelectorAll("
1155
+ "'.scrollbar-kit');\n"
1156
+ " scrollbarKits.forEach(function(el) {\n"
1157
+ " el.style.setProperty('display', 'none', "
1158
+ "'important');\n"
1159
+ " el.style.setProperty('visibility', 'hidden', "
1160
+ "'important');\n"
1161
+ " el.style.setProperty('opacity', '0', 'important');\n"
1162
+ " });\n"
1163
+ " \n"
1164
+ " var scrollbarSliders = container.querySelectorAll("
1165
+ "'.scrollbar-slider');\n"
1166
+ " scrollbarSliders.forEach(function(el) {\n"
1167
+ " el.style.setProperty('display', 'none', "
1168
+ "'important');\n"
1169
+ " el.style.setProperty('visibility', 'hidden', "
1170
+ "'important');\n"
1171
+ " el.style.setProperty('opacity', '0', 'important');\n"
1172
+ " });\n"
1173
+ " \n"
1174
+ " var scrollbarGlyphs = container.querySelectorAll("
1175
+ "'.scrollbar-glyph');\n"
1176
+ " scrollbarGlyphs.forEach(function(el) {\n"
1177
+ " el.style.setProperty('display', 'none', "
1178
+ "'important');\n"
1179
+ " el.style.setProperty('visibility', 'hidden', "
1180
+ "'important');\n"
1181
+ " el.style.setProperty('opacity', '0', 'important');\n"
1182
+ " });\n"
1183
+ " \n"
1184
+ " var plots = container.querySelectorAll('.js-plotly-plot');\n"
1185
+ " plots.forEach(function(plot) {\n"
1186
+ " var allElements = plot.querySelectorAll('*');\n"
1187
+ " allElements.forEach(function(el) {\n"
1188
+ " if (el.tagName === 'DIV' || "
1189
+ "el.tagName === 'SVG') {\n"
1190
+ " var style = window.getComputedStyle(el);\n"
1191
+ " if (style.overflow === 'auto' || "
1192
+ "style.overflow === 'scroll' || style.overflowY === 'auto' || "
1193
+ "style.overflowY === 'scroll') {\n"
1194
+ " el.style.setProperty('overflow', "
1195
+ "'hidden', 'important');\n"
1196
+ " el.style.setProperty('overflow-y', "
1197
+ "'hidden', 'important');\n"
1198
+ " el.style.setProperty('overflow-x', "
1199
+ "'hidden', 'important');\n"
1200
+ " }\n"
1201
+ " }\n"
1202
+ " });\n"
1203
+ " plot.style.setProperty('overflow', 'hidden', "
1204
+ "'important');\n"
1205
+ " var svg = plot.querySelector('svg');\n"
1206
+ " if (svg) {\n"
1207
+ " svg.style.setProperty('overflow', 'hidden', "
1208
+ "'important');\n"
1209
+ " svg.setAttribute('overflow', 'hidden');\n"
1210
+ " }\n"
1211
+ " });\n"
1212
+ " adjustTableSize(container);\n"
1213
+ " } else {\n"
1214
+ " disableTableScrolling(container);\n"
1215
+ " }\n"
1216
+ " }\n"
1217
+ " \n"
998
1218
  " var observer = new MutationObserver(function(mutations) {\n"
999
- " disableTableScrolling(container);\n"
1219
+ " preventScrollbars();\n"
1000
1220
  " });\n"
1001
1221
  " observer.observe(container, {\n"
1002
1222
  " childList: true,\n"
@@ -1004,6 +1224,7 @@ def _generate_responsive_html_string(
1004
1224
  " attributes: true,\n"
1005
1225
  " attributeFilter: ['style', 'class']\n"
1006
1226
  " });\n"
1227
+ " preventScrollbars();\n"
1007
1228
  " return observer;\n"
1008
1229
  " }\n"
1009
1230
  "\n"
@@ -1014,6 +1235,7 @@ def _generate_responsive_html_string(
1014
1235
  " if (desktopContainer && "
1015
1236
  'desktopContainer.style.display !== "none") {\n'
1016
1237
  " adjustTableSize(desktopContainer);\n"
1238
+ " adjustLogoPosition(desktopContainer);\n"
1017
1239
  " }\n"
1018
1240
  " }, 100);\n"
1019
1241
  " });\n"
@@ -1031,8 +1253,8 @@ def _generate_responsive_html_string(
1031
1253
  " }\n"
1032
1254
  " if (desktopContainer && "
1033
1255
  'desktopContainer.style.display !== "none") {\n'
1034
- " disableTableScrolling(desktopContainer);\n"
1035
1256
  " adjustTableSize(desktopContainer);\n"
1257
+ " adjustLogoPosition(desktopContainer);\n"
1036
1258
  " if (!desktopContainer._scrollObserver) {\n"
1037
1259
  " desktopContainer._scrollObserver = "
1038
1260
  "setupScrollObserver(desktopContainer);\n"
@@ -1139,12 +1361,11 @@ def report_html(
1139
1361
  plotfile = dirpath / filename
1140
1362
 
1141
1363
  _configure_figure_layout(
1142
- figure,
1143
- copied,
1364
+ figure=figure,
1365
+ copied=copied,
1144
1366
  add_logo=add_logo,
1145
1367
  vertical_legend=vertical_legend,
1146
1368
  title=title,
1147
- mobile=False,
1148
1369
  )
1149
1370
 
1150
1371
  figure_mobile = _build_mobile_figure(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "openseries"
3
- version = "2.1.1"
3
+ version = "2.1.2"
4
4
  description = "Tools for analyzing financial timeseries."
5
5
  authors = [
6
6
  { name = "Martin Karrin", email = "martin.karrin@captor.se" },
@@ -67,18 +67,17 @@ pre-commit = ">=4.5.0"
67
67
  pytest = ">=9.0.2"
68
68
  pytest-cov = ">=7.0.0"
69
69
  pytest-xdist = ">=3.8.0"
70
- ruff = "0.14.8"
70
+ ruff = "0.14.9"
71
71
  types-openpyxl = ">=3.1.2"
72
72
  scipy-stubs = ">=1.14.1.0"
73
73
  types-python-dateutil = ">=2.8.2"
74
74
  types-requests = ">=2.20.0"
75
75
 
76
76
  [tool.poetry.group.docs.dependencies]
77
- myst-parser = ">=4.0.1"
78
- sphinx = ">=8.2.3"
77
+ sphinx = ">=9.0.4"
79
78
  sphinx-autobuild = ">=2025.8.25"
80
- sphinx-autodoc-typehints = ">=3.5.2"
81
- sphinx-rtd-theme = ">=3.0.2"
79
+ sphinx-autodoc-typehints = ">=3.6.0"
80
+ sphinx-rtd-theme = ">=3.1.0rc1"
82
81
 
83
82
  [build-system]
84
83
  requires = ["poetry-core>=2.2.1"]
File without changes
File without changes