%22%22%22Interactive%20PV-capacity%20explorer%20(marimo%20notebook).%0A%0ARun%3A%20%20%20%20python%20-m%20marimo%20edit%20pv.py%0AExport%3A%20python%20-m%20marimo%20export%20html%20pv.py%20-o%20docs%2Fpv.html%0A%22%22%22%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.23.5%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_intro(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20PV%20explorer%20%C2%B7%20Marktstammdatenregister%0A%0A%20%20%20%20Interactive%20choropleth%20of%20installed%20**photovoltaic**%20capacity%20per%20German%0A%20%20%20%20county.%20Drag%20the%20date%20slider%20to%20step%20through%20history%2C%20toggle%20the%0A%20%20%20%20installation-type%20filter%20to%20isolate%20rooftop%20vs.%20ground-mount%20vs.%20balcony%0A%20%20%20%20plants.%20If%20no%20local%20data%20are%20present%2C%20a%20synthetic%20demo%20dataset%20is%20used.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_imports()%3A%0A%20%20%20%20from%20datetime%20import%20date%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20mastr_plot%0A%0A%20%20%20%20return%20date%2C%20mastr_plot%0A%0A%0A%40app.cell%0Adef%20_data(mastr_plot%2C%20mo)%3A%0A%20%20%20%20df%2C%20demo%20%3D%20mastr_plot.load_records()%0A%20%20%20%20units%2C%20units_demo%20%3D%20mastr_plot.load_admin_units()%0A%20%20%20%20banner%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%22%3E%20**Demo%20mode**%20%E2%80%94%20no%20%60data-*.json%60%20or%20%60germany_kreise.gpkg%60%20was%20found%2C%20%22%0A%20%20%20%20%20%20%20%20%22so%20synthetic%20plants%20on%20a%20coarse%20grid%20are%20shown.%22%0A%20%20%20%20%20%20%20%20if%20(demo%20or%20units_demo)%0A%20%20%20%20%20%20%20%20else%20%22%3E%20Loaded%20**real**%20MaStR%20records%20and%20OSM%20kreise%20polygons.%22%0A%20%20%20%20)%0A%20%20%20%20banner%0A%20%20%20%20return%20df%2C%20units%0A%0A%0A%40app.cell%0Adef%20_controls(date%2C%20df%2C%20mo)%3A%0A%20%20%20%20min_d%20%3D%20df%5B%22install_date%22%5D.min().date()%20if%20df%5B%22install_date%22%5D.notna().any()%20else%20date(2005%2C%201%2C%201)%0A%20%20%20%20max_d%20%3D%20date.today()%0A%20%20%20%20date_slider%20%3D%20mo.ui.date(%0A%20%20%20%20%20%20%20%20start%3Dmin_d%2C%20stop%3Dmax_d%2C%20value%3Ddate(2023%2C%201%2C%201)%2C%20label%3D%22Snapshot%20date%22%0A%20%20%20%20)%0A%20%20%20%20install_types%20%3D%20%5B%22(all)%22%5D%20%2B%20sorted(%0A%20%20%20%20%20%20%20%20t%20for%20t%20in%20df%5B%22installation_type%22%5D.dropna().unique().tolist()%0A%20%20%20%20)%0A%20%20%20%20type_filter%20%3D%20mo.ui.dropdown(%0A%20%20%20%20%20%20%20%20options%3Dinstall_types%2C%20value%3D%22(all)%22%2C%20label%3D%22Installation%20type%22%0A%20%20%20%20)%0A%20%20%20%20bin_count%20%3D%20mo.ui.slider(start%3D3%2C%20stop%3D10%2C%20step%3D1%2C%20value%3D7%2C%20label%3D%22Color%20bins%22)%0A%20%20%20%20cmap_picker%20%3D%20mo.ui.dropdown(%0A%20%20%20%20%20%20%20%20options%3D%5B%22viridis%22%2C%20%22plasma%22%2C%20%22magma%22%2C%20%22cividis%22%2C%20%22YlOrRd%22%5D%2C%0A%20%20%20%20%20%20%20%20value%3D%22YlOrRd%22%2C%20label%3D%22Colormap%22%2C%0A%20%20%20%20)%0A%20%20%20%20scale_picker%20%3D%20mo.ui.radio(%0A%20%20%20%20%20%20%20%20options%3D%5B%22jenks%22%2C%20%22linear%22%2C%20%22log%22%5D%2C%20value%3D%22jenks%22%2C%20label%3D%22Color%20scale%22%0A%20%20%20%20)%0A%20%20%20%20controls%20%3D%20mo.hstack(%0A%20%20%20%20%20%20%20%20%5Bdate_slider%2C%20type_filter%2C%20bin_count%2C%20cmap_picker%2C%20scale_picker%5D%2C%20gap%3D2%0A%20%20%20%20)%0A%20%20%20%20controls%0A%20%20%20%20return%20bin_count%2C%20cmap_picker%2C%20date_slider%2C%20scale_picker%2C%20type_filter%0A%0A%0A%40app.cell%0Adef%20_filtered(df%2C%20type_filter)%3A%0A%20%20%20%20pv%20%3D%20df%5Bdf%5B%22energy_type%22%5D%20%3D%3D%20%22Solare%20Strahlungsenergie%22%5D.copy()%0A%20%20%20%20if%20type_filter.value%20!%3D%20%22(all)%22%3A%0A%20%20%20%20%20%20%20%20pv%20%3D%20pv%5Bpv%5B%22installation_type%22%5D%20%3D%3D%20type_filter.value%5D%0A%20%20%20%20pv%0A%20%20%20%20return%20(pv%2C)%0A%0A%0A%40app.cell%0Adef%20_map(%0A%20%20%20%20bin_count%2C%0A%20%20%20%20cmap_picker%2C%0A%20%20%20%20date_slider%2C%0A%20%20%20%20mastr_plot%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20pv%2C%0A%20%20%20%20scale_picker%2C%0A%20%20%20%20units%2C%0A)%3A%0A%20%20%20%20agg%2C%20active%20%3D%20mastr_plot.aggregate_by_unit(%0A%20%20%20%20%20%20%20%20pv%2C%20units%2C%20plot_date%3Ddate_slider.value%2C%20energy_type%3D%22Solare%20Strahlungsenergie%22%0A%20%20%20%20)%0A%20%20%20%20bins%20%3D%20mastr_plot.jenks_bins(%0A%20%20%20%20%20%20%20%20agg%5B%22power_gw%22%5D%5Bagg%5B%22power_gw%22%5D%20%3E%200%5D.to_numpy()%2C%20k%3Dbin_count.value%0A%20%20%20%20)%0A%20%20%20%20fig%20%3D%20mastr_plot.plot_choropleth(%0A%20%20%20%20%20%20%20%20agg%2C%20plot_date%3Ddate_slider.value%2C%0A%20%20%20%20%20%20%20%20title%3Df%22PV%20capacity%20%E2%80%94%20%7Bdate_slider.value.isoformat()%7D%5Cn%7Blen(active)%3A%2C%7D%20plants%20active%22%2C%0A%20%20%20%20%20%20%20%20bins%3Dbins%2C%20cmap%3Dcmap_picker.value%2C%20scale%3Dscale_picker.value%2C%0A%20%20%20%20)%0A%20%20%20%20mo.mpl.interactive(fig)%0A%20%20%20%20return%20active%2C%20agg%0A%0A%0A%40app.cell%0Adef%20_stats(active%2C%20agg%2C%20mo)%3A%0A%20%20%20%20total_gw%20%3D%20float(agg%5B%22power_gw%22%5D.sum())%0A%20%20%20%20private_share%20%3D%20float(active%5B%22is_private%22%5D.mean())%20if%20len(active)%20else%200.0%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22%22%22%0A%20%20%20%20%20%20%20%20%23%23%20Summary%0A%0A%20%20%20%20%20%20%20%20-%20**Active%20plants%3A**%20%7Blen(active)%3A%2C%7D%0A%20%20%20%20%20%20%20%20-%20**Total%20installed%20capacity%3A**%20%7Btotal_gw%3A%2C.2f%7D%20GW%0A%20%20%20%20%20%20%20%20-%20**Private-owner%20share%3A**%20%7Bprivate_share*100%3A%2C.1f%7D%25%0A%20%20%20%20%20%20%20%20-%20**Counties%20covered%3A**%20%7B(agg%5B'power_gw'%5D%20%3E%200).sum()%3A%2C%7D%20%2F%20%7Blen(agg)%3A%2C%7D%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_growth(mo%2C%20pv)%3A%0A%20%20%20%20growth_monthly%20%3D%20(%0A%20%20%20%20%20%20%20%20pv.assign(month%3Dpv%5B%22install_date%22%5D.dt.to_period(%22M%22))%0A%20%20%20%20%20%20%20%20.groupby(%22month%22)%5B%22power%22%5D.sum().div(1e6).cumsum()%0A%20%20%20%20)%0A%20%20%20%20growth_monthly.index%20%3D%20growth_monthly.index.to_timestamp()%0A%20%20%20%20import%20matplotlib.pyplot%20as%20growth_plt%0A%20%20%20%20growth_fig%2C%20growth_ax%20%3D%20growth_plt.subplots(figsize%3D(9%2C%203.4)%2C%20dpi%3D120)%0A%20%20%20%20growth_ax.fill_between(growth_monthly.index%2C%20growth_monthly.values%2C%20color%3D%22%23f59e0b%22%2C%20alpha%3D0.35)%0A%20%20%20%20growth_ax.plot(growth_monthly.index%2C%20growth_monthly.values%2C%20color%3D%22%23b45309%22%2C%20linewidth%3D2)%0A%20%20%20%20growth_ax.set_ylabel(%22Cumulative%20PV%20%5BGW%5D%22)%0A%20%20%20%20growth_ax.set_title(%22Cumulative%20PV%20capacity%20over%20time%22)%0A%20%20%20%20growth_ax.grid(alpha%3D0.3)%0A%20%20%20%20growth_fig.tight_layout()%0A%20%20%20%20mo.mpl.interactive(growth_fig)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_import_mo()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
c2ba93a57ec106acad18d306d34e24cc