@@ -112,17 +112,19 @@ def _render_fig_to_png(figure, dpi=preview_dpi):
112112
113113 def _do_render (figure ):
114114 """Actually render the figure to the preview widget."""
115- render_dpi = int (figure .dpi )
116- fig_image .value = _render_fig_to_png (figure , dpi = render_dpi )
115+ # Always use preview_dpi for the live preview (fast).
116+ # The figure's own DPI is preserved for export/save.
117+ fig_image .value = _render_fig_to_png (figure , dpi = preview_dpi )
117118 n = len (editor .edits )
118119 w_in , h_in = figure .get_size_inches ()
119- dpi = int (figure .dpi )
120- px_w , px_h = int (w_in * dpi ), int (h_in * dpi )
120+ export_dpi = int (figure .dpi )
121+ px_w , px_h = int (w_in * export_dpi ), int (h_in * export_dpi )
121122 _render_state ['pending' ] = 0
122123 apply_btn .description = 'Apply'
123124 status_bar .value = (
124125 f'<span style="font-size:11px; color:#2ECC71">'
125- f'{ n } edit(s) — DPI: { dpi } → export size: { px_w } ×{ px_h } px</span>'
126+ f'{ n } edit(s) — DPI: { export_dpi } → '
127+ f'export size: { px_w } \u00d7 { px_h } px</span>'
126128 )
127129
128130 def _live_refresh (figure ):
@@ -272,8 +274,9 @@ def _on_ax_change(change):
272274 ylim_range .max = yl [1 ] + yr * 0.5
273275 ylim_range .step = yr / 50
274276 ylim_range .value = [yl [0 ], yl [1 ]]
275- # Rebuild style tab content
276- _rebuild_style_widgets ()
277+ # Rebuild style tab content (only if already loaded)
278+ if _tab_loaded .get (1 , False ):
279+ _rebuild_style_widgets ()
277280
278281 ax_selector .observe (_on_ax_change , names = 'value' )
279282
@@ -608,7 +611,8 @@ def _cb(change):
608611
609612 style_container .children = children
610613
611- _rebuild_style_widgets ()
614+ # NOTE: _rebuild_style_widgets() is deferred — called on first
615+ # tab switch to Style tab (see _on_tab_switch).
612616
613617 # ==================================================================
614618 # Tab 3: Layout (spines, grid, figsize, legend, axes limits, etc.)
@@ -1216,17 +1220,58 @@ def _live_code_update(figure):
12161220 editor .on_refresh (_live_code_update )
12171221
12181222 # ==================================================================
1219- # Assemble tabs
1223+ # Assemble tabs (with lazy loading for non-default tabs)
12201224 # ==================================================================
1225+ _loading_msg = widgets .HTML (
1226+ '<div style="padding:20px; color:#999; text-align:center">'
1227+ 'Loading...</div>'
1228+ )
1229+ _lazy_placeholders = {
1230+ 1 : widgets .VBox ([_loading_msg ]),
1231+ 2 : widgets .VBox ([widgets .HTML (
1232+ '<div style="padding:20px; color:#999; text-align:center">'
1233+ 'Loading...</div>' )]),
1234+ 3 : widgets .VBox ([widgets .HTML (
1235+ '<div style="padding:20px; color:#999; text-align:center">'
1236+ 'Loading...</div>' )]),
1237+ 4 : widgets .VBox ([widgets .HTML (
1238+ '<div style="padding:20px; color:#999; text-align:center">'
1239+ 'Loading...</div>' )]),
1240+ }
1241+ _tab_loaded = {0 : True , 1 : False , 2 : False , 3 : False , 4 : False }
1242+ _real_tabs = {
1243+ 1 : style_container ,
1244+ 2 : layout_tab ,
1245+ 3 : theme_tab ,
1246+ 4 : code_tab ,
1247+ }
1248+
12211249 tabs = widgets .Tab (children = [
1222- text_tab , style_container , layout_tab , theme_tab , code_tab ,
1250+ text_tab ,
1251+ _lazy_placeholders [1 ],
1252+ _lazy_placeholders [2 ],
1253+ _lazy_placeholders [3 ],
1254+ _lazy_placeholders [4 ],
12231255 ])
12241256 tabs .set_title (0 , 'Text' )
12251257 tabs .set_title (1 , 'Style' )
12261258 tabs .set_title (2 , 'Layout' )
12271259 tabs .set_title (3 , 'Theme' )
12281260 tabs .set_title (4 , 'Export' )
12291261
1262+ def _on_tab_switch (change ):
1263+ idx = change ['new' ]
1264+ if idx is not None and not _tab_loaded .get (idx , True ):
1265+ _tab_loaded [idx ] = True
1266+ children = list (tabs .children )
1267+ children [idx ] = _real_tabs [idx ]
1268+ tabs .children = children
1269+ # Build style widgets on first visit
1270+ if idx == 1 :
1271+ _rebuild_style_widgets ()
1272+
1273+ tabs .observe (_on_tab_switch , names = 'selected_index' )
1274+
12301275 panel_header = widgets .HBox (
12311276 [
12321277 widgets .HTML (
0 commit comments