{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 2. Renewable PPAs\n", "This example demonstrates a the renewable `Generator` class of NEMGLO and the PPA features within. It shows how to extract historical AEMO data of the NEM, define load characteristics (as per Example 1) and further PPA structures, then running the optimiser to find the operational load behaviour.\n", "\n", "This example uses plotly == 5.6.0 to plot results. Install with... pip install plotly==5.6.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Install Packages\n", "For standard use of NEMGLO we can use from nemglo import * to import `nemglo` functionality. This example also uses plotly to generate charts, with the optional setting defining where to render charts." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# NEMGLO Packages\n", "from nemglo import *\n", "\n", "# Generic Packages\n", "import pandas as pd\n", "import plotly.graph_objects as go\n", "from plotly.subplots import make_subplots" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# Display plotly chart in a browser (optional)\n", "import plotly.io as pio\n", "pio.renderers.default = \"browser\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load Historical AEMO data\n", "Create a nemosis_data object to retrieve historical data for the simulation. nemosis_data class requires a defined interval length and cache folder." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "inputdata = nemosis_data(intlength=30, local_cache=r'E:\\TEMPCACHE')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we define the simulation period by start and end dispatch intervals, as well as the region for which we are modelling the load in. Additionally we specify here one or two generators we wish to extract dispatch traces for." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "start = \"02/01/2020 00:00\"\n", "end = \"09/01/2020 00:00\"\n", "region = 'VIC1'\n", "duid_1 = 'NUMURSF1'\n", "duid_2 = 'ARWF1'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we can optionally check the AEMO defined information about these generators, namely their registered capacity (MW). Although in the load optimisation we can set any desired sizings for these plants." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Retrieving static table Generators and Scheduled Loads.\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Station NameRegionFuel Source - DescriptorDUIDReg Cap (MW)
11Ararat Wind FarmVIC1WindARWF1241.59
364Numurkah Solar FarmVIC1SolarNUMURSF1112.00
\n", "
" ], "text/plain": [ " Station Name Region Fuel Source - Descriptor DUID \\\n", "11 Ararat Wind Farm VIC1 Wind ARWF1 \n", "364 Numurkah Solar Farm VIC1 Solar NUMURSF1 \n", "\n", " Reg Cap (MW) \n", "11 241.59 \n", "364 112.00 " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "inputdata._download_geninfo()\n", "inputdata._info[(inputdata._info['DUID'].isin([duid_1, duid_2]))]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The defined parameters are set by using functions set_ of the `nemosis_data` class." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "inputdata.set_dates(start, end)\n", "inputdata.set_region(region)\n", "inputdata.set_unit(duid_1, duid_2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Price data can now be loaded as per Example 1. Additionally we now have VRE generator trace data, which is the historical dispatch data (MW) scaled by the noted AEMO registered capacities (MW) to get a percentage capacity factor trace as below." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Compiling data for table DISPATCHPRICE.\n", "Returning DISPATCHPRICE.\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TimePrices
02020-01-02 00:30:0067.094337
12020-01-02 01:00:0065.526907
22020-01-02 01:30:0050.028502
32020-01-02 02:00:0040.664717
42020-01-02 02:30:0043.609028
.........
3312020-01-08 22:00:0044.572158
3322020-01-08 22:30:0051.387228
3332020-01-08 23:00:0044.822428
3342020-01-08 23:30:0044.136238
3352020-01-09 00:00:0049.485932
\n", "

336 rows × 2 columns

\n", "
" ], "text/plain": [ " Time Prices\n", "0 2020-01-02 00:30:00 67.094337\n", "1 2020-01-02 01:00:00 65.526907\n", "2 2020-01-02 01:30:00 50.028502\n", "3 2020-01-02 02:00:00 40.664717\n", "4 2020-01-02 02:30:00 43.609028\n", ".. ... ...\n", "331 2020-01-08 22:00:00 44.572158\n", "332 2020-01-08 22:30:00 51.387228\n", "333 2020-01-08 23:00:00 44.822428\n", "334 2020-01-08 23:30:00 44.136238\n", "335 2020-01-09 00:00:00 49.485932\n", "\n", "[336 rows x 2 columns]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "prices = inputdata.get_prices()\n", "prices" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Compiling data for table DISPATCHLOAD.\n", "Returning DISPATCHLOAD.\n", "Compiling data for table DISPATCH_UNIT_SCADA.\n", "Returning DISPATCH_UNIT_SCADA.\n", "ERROR DISCREPENCY between SCADAVALUE and INITIALMW. Assuming INITIALMW\n", "Retrieving static table Generators and Scheduled Loads.\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TimeARWF1NUMURSF1
02020-01-02 00:30:000.4246860.0
12020-01-02 01:00:000.3109950.0
22020-01-02 01:30:000.2644290.0
32020-01-02 02:00:000.2346260.0
42020-01-02 02:30:000.1981320.0
............
3312020-01-08 22:00:000.2651190.0
3322020-01-08 22:30:000.2998880.0
3332020-01-08 23:00:000.3077530.0
3342020-01-08 23:30:000.3487310.0
3352020-01-09 00:00:000.3294840.0
\n", "

336 rows × 3 columns

\n", "
" ], "text/plain": [ " Time ARWF1 NUMURSF1\n", "0 2020-01-02 00:30:00 0.424686 0.0\n", "1 2020-01-02 01:00:00 0.310995 0.0\n", "2 2020-01-02 01:30:00 0.264429 0.0\n", "3 2020-01-02 02:00:00 0.234626 0.0\n", "4 2020-01-02 02:30:00 0.198132 0.0\n", ".. ... ... ...\n", "331 2020-01-08 22:00:00 0.265119 0.0\n", "332 2020-01-08 22:30:00 0.299888 0.0\n", "333 2020-01-08 23:00:00 0.307753 0.0\n", "334 2020-01-08 23:30:00 0.348731 0.0\n", "335 2020-01-09 00:00:00 0.329484 0.0\n", "\n", "[336 rows x 3 columns]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vre = inputdata.get_vre_traces()\n", "vre" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a planner object for this modelling session\n", "For every use case of NEMGLO, a `nemglo.planner.Plan` object is required. This must be created with a unique identifier, in this case called **\"P2G\"**. The first step is then to load market prices for the simulation period for which the load will be optimised for. The function load_market_prices stores these required values." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "P2G = Plan(identifier = \"P2G\")\n", "P2G.load_market_prices(prices)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create an Electrolyser object + define its operating characteristics\n", "A load must be defined and linked to the `Plan` object in order to model it's behaviour. For creating components in `NEMGLO`, they must be defined as belonging to a `Plan` class. Similarly to `Plan`, all components must have a unique identifer which has been called **H2E** here for the Electrolyser. Following this we defined the operating characteristics as per Example 1, and add the electrolyser operation to the model." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "h2e = Electrolyser(P2G, identifier='H2E')\n", "\n", "h2e.load_h2_parameters_preset(capacity = 100.0,\n", " maxload = 100.0,\n", " minload = 10.0,\n", " offload = 0.0,\n", " electrolyser_type = 'PEM',\n", " sec_profile = 'fixed',\n", " h2_price_kg = 5.0)\n", "\n", "h2e.add_electrolyser_operation()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create an Generator object + define the RE trace data & PPA structure\n", "The `Generator` component is created just like the Electrolyser, parsing the `Plan` object and using a unique identifier for this Generator." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "solar = Generator(P2G, identifier=\"SF\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To define the parameters of our new Generator **SF**, we call the `load_vre_parameters` function specifying the 'duid', desired 'capacity', 'trace' using the vre dataframe we extracted from the `nemosis_data` module earlier, 'ppa_strike' price and optionally a 'ppa_floor' price. Note we only parse the 'Time' and duid columns of the vre dataframe, we do not want to use the other generator data here for the wind farm!" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "solar.load_vre_parameters(duid = 'NUMURSF1',\n", " capacity = 100.0,\n", " trace = vre[['Time', 'NUMURSF1']],\n", " ppa_strike = 30.0,\n", " ppa_floor=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we can implement this component in the model by using `add_ppa_contract`" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "solar.add_ppa_contract()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running the optimisation\n", "As per Example 1..." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OPTIMISATION COMPLETE, Obj Value: -610452.4214854483\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "P2G.optimise()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### View planner results\n", "The results can also be extracted within python through a number of functions. Specific to the VRE `Generator` component, we find:\n", "\n", "- The timeseries data for the vre availability in MW with `get_vre_availability`. Note this is simply the VRE input trace scaled by the defined `load_vre_parameters` capacity value." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " interval value time\n", "0 0 0.0 2020-01-02 00:30:00\n", "1 1 0.0 2020-01-02 01:00:00\n", "2 2 0.0 2020-01-02 01:30:00\n", "3 3 0.0 2020-01-02 02:00:00\n", "4 4 0.0 2020-01-02 02:30:00\n", "The maximum capacity factor was: 89.3 %\n", "The average capacity factor was: 29.7 %\n" ] } ], "source": [ "result_solar = P2G.get_vre_availability(identifier=\"SF\")\n", "print(result_solar.head())\n", "print(\"The maximum capacity factor was: {:.1f} %\".format(result_solar['value'].max()))\n", "print(\"The average capacity factor was: {:.1f} %\".format(result_solar['value'].mean()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- A breakdown of cost components and the total cost per dispatch interval using the `get_costs` function of the `Plan`.\n", "\n", "```{tip} The column names returned in get_costs are standardized across the pacakge based on the identifiers given for each components and default variable names which can be found in the [Naming Convention](../../naming.md)\n", "```" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timeintervaltotal_costH2E-h2_producedH2E-mw_loadSF-ppa_cfd
02020-01-02 00:30:000-433.161955-3787.8787883354.7168330.0
12020-01-02 01:00:001-511.533455-3787.8787883276.3453330.0
22020-01-02 01:30:002-1286.453705-3787.8787882501.4250830.0
32020-01-02 02:00:003-1754.642955-3787.8787882033.2358330.0
42020-01-02 02:30:004-1607.427371-3787.8787882180.4514170.0
.....................
3312020-01-08 22:00:00331-1559.270871-3787.8787882228.6079170.0
3322020-01-08 22:30:00332-1218.517371-3787.8787882569.3614170.0
3332020-01-08 23:00:00333-1546.757371-3787.8787882241.1214170.0
3342020-01-08 23:30:00334-1581.066871-3787.8787882206.8119170.0
3352020-01-09 00:00:00335-1313.582205-3787.8787882474.2965830.0
\n", "

336 rows × 6 columns

\n", "
" ], "text/plain": [ " time interval total_cost H2E-h2_produced H2E-mw_load \\\n", "0 2020-01-02 00:30:00 0 -433.161955 -3787.878788 3354.716833 \n", "1 2020-01-02 01:00:00 1 -511.533455 -3787.878788 3276.345333 \n", "2 2020-01-02 01:30:00 2 -1286.453705 -3787.878788 2501.425083 \n", "3 2020-01-02 02:00:00 3 -1754.642955 -3787.878788 2033.235833 \n", "4 2020-01-02 02:30:00 4 -1607.427371 -3787.878788 2180.451417 \n", ".. ... ... ... ... ... \n", "331 2020-01-08 22:00:00 331 -1559.270871 -3787.878788 2228.607917 \n", "332 2020-01-08 22:30:00 332 -1218.517371 -3787.878788 2569.361417 \n", "333 2020-01-08 23:00:00 333 -1546.757371 -3787.878788 2241.121417 \n", "334 2020-01-08 23:30:00 334 -1581.066871 -3787.878788 2206.811917 \n", "335 2020-01-09 00:00:00 335 -1313.582205 -3787.878788 2474.296583 \n", "\n", " SF-ppa_cfd \n", "0 0.0 \n", "1 0.0 \n", "2 0.0 \n", "3 0.0 \n", "4 0.0 \n", ".. ... \n", "331 0.0 \n", "332 0.0 \n", "333 0.0 \n", "334 0.0 \n", "335 0.0 \n", "\n", "[336 rows x 6 columns]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result_costs = P2G.get_costs()\n", "result_costs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again, calling the earlier results from Example 1 so we can plot a combination of output results." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "result_load = P2G.get_load()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plotting results\n", "Constructing a chart in plotly of `result_solar`, `result_load` and `price` produces the below." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "fig = go.Figure()\n", "fig.update_layout(title='NEMGLO Electrolyser with PPA Example 2 - Operation Timeseries
VIC: Jan-2020
', titlefont=dict(size=24),\n", " margin=dict(l=20, r=20, t=60, b=0),\n", " xaxis=dict(title=\"Time\", showgrid=False, mirror=True, titlefont=dict(size=18), \\\n", " tickfont=dict(size=18), tickangle=-45, tickformat=\"%d-%b\", domain=[0, 1]),\n", " yaxis=dict(title=\"Generator / Load Dispatch (MW)\", showgrid=False, range=[-10,140], mirror=True, titlefont=dict(size=18),\\\n", " tickfont=dict(size=18), tickvals=[i for i in range(-20, 140, 20)]),\n", " yaxis2=dict(title=\"Price ($/MWh)\", showgrid=False, gridcolor='slategrey', range=[-250,150], mirror=True, \\\n", " titlefont=dict(size=18),tickfont=dict(size=18), anchor=\"x\", overlaying=\"y\", side=\"right\", color=\"FireBrick\"),\n", " legend=dict(xanchor='center',x=0.55, y=-0.25, orientation='h', font=dict(size=18)),\n", " template=\"simple_white\",\n", " font_family=\"Times New Roman\",\n", " xaxis_showgrid=True,\n", " yaxis_showgrid=True,\n", " width=1000,\n", " height=600)\n", "fmt_timestamps = [dt.strftime(prices['Time'][i], \"%d-%b %H:%M\") for i in range(len(prices))]\n", "fig.add_trace(go.Scatter(x=prices['Time'], y=prices['Prices'],name=\"Price ($/MWh)\", \\\n", " line={'color':'FireBrick'}, yaxis=\"y2\"))\n", "fig.add_trace(go.Scatter(x=result_load['time'], y=result_load['value'],name='Load (MW)', \\\n", " line={'color':'Purple'}))\n", "fig.add_trace(go.Scatter(x=result_solar['time'], y=result_solar['value'], name=f'{duid_1} (MW)', \\\n", " line={'color':'darkorange'}, yaxis=\"y\"))\n", "\n", "for ser in fig['data']:\n", " ser['text'] = [dt.strftime(prices['Time'][i], \"%d-%b %H:%M\") for i in range(len(prices))]\n", " ser['hovertemplate'] = 'Time: %{text}
Value: %{y}'\n", "\n", "fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{include} example_2_plt_1.html \n", "```" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "time = result_costs['time']\n", "energy = result_costs['H2E-mw_load'].mul(-1)\n", "h2 = result_costs['H2E-h2_produced'].mul(-1)\n", "ppa = result_costs['SF-ppa_cfd'].mul(-1)\n", "total = result_costs['total_cost'].mul(-1)\n", "\n", "fig = go.Figure()\n", "fig.update_layout(title='NEMGLO Electrolyser with PPA Example 2 - Revenue Timeseries
VIC: Jan-2020
', titlefont=dict(size=24),\n", " margin=dict(l=20, r=20, t=60, b=0),\n", " xaxis=dict(title=\"Time\", showgrid=True, mirror=True, titlefont=dict(size=18), \\\n", " tickfont=dict(size=18), tickangle=-45, tickformat=\"%d-%b\", domain=[0, 1]),\n", " yaxis=dict(title=\"Revenue ($)\", showgrid=True, mirror=True, titlefont=dict(size=18),\\\n", " tickfont=dict(size=18),),\n", " legend=dict(xanchor='center',x=0.55, y=-0.25, orientation='h', font=dict(size=18)),\n", " template=\"simple_white\",\n", " font_family=\"Times New Roman\",\n", " width=1000,\n", " height=600)\n", "fmt_timestamps = [dt.strftime(prices['Time'][i], \"%d-%b %H:%M\") for i in range(len(prices))]\n", "\n", "fig.add_trace(go.Scatter(x=time, y=energy, name=\"Energy Spot Revenue\", line={'color':'firebrick'}, yaxis=\"y\"))\n", "fig.add_trace(go.Scatter(x=time, y=[ppa[i] + energy[i] for i in range(min(len(ppa),len(energy)))], \\\n", " name=f'Net Energy Revenue ($)', line={'color':'firebrick', 'dash': 'dash'}, yaxis=\"y\"))\n", "fig.add_trace(go.Scatter(x=time, y=ppa, name=f'{duid_1} PPA Revenue', line={'color':'darkorange'}, yaxis=\"y\"))\n", "fig.add_trace(go.Scatter(x=time, y=h2, name=\"H2 Production Revenue\", line={'color':'purple'}, yaxis=\"y\"))\n", "fig.add_trace(go.Scatter(x=time, y=total, name=\"Total Revenue\", line={'color':'black'}, yaxis=\"y\"))\n", "\n", "for ser in fig['data']:\n", " ser['text'] = [dt.strftime(prices['Time'][i], \"%d-%b %H:%M\") for i in range(len(prices))]\n", " ser['hovertemplate'] = 'Time: %{text}
Value: %{y}'\n", "\n", "fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{include} example_2_plt_2.html \n", "```" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "fig = go.Figure(go.Waterfall(\n", " orientation = \"v\",\n", " measure = [\"relative\", \"relative\", \"relative\", \"total\"],\n", " x = [\"Hydrogen Benefit\", \"Energy\", \"PPA\", \"Total\"],\n", " textposition = \"outside\",\n", " textfont = dict(family=\"Times New Roman\", size=18),\n", " text = [\"{}k\".format(int(np.ceil(sum(h2)/1000))), \n", " \"{}k\".format(int(np.ceil(sum(energy)/1000))),\n", " \"{}k\".format(int(np.ceil(sum(ppa)/1000))),\n", " \"{}k\".format(int(np.ceil(sum(total)/1000))),],\n", " y = [sum(h2), sum(energy), sum(ppa), sum(total), -20, 0],\n", " connector = {\"line\":{\"color\":\"slategrey\"}},\n", " increasing=dict(marker=dict(color=\"ForestGreen\")),\n", " decreasing = dict(marker = dict(color=\"firebrick\")),\n", "))\n", "\n", "fig.update_layout(\n", " title='NEMGLO Electrolyser with PPA Example 2
Operational Profit
VIC: Jan-2020
', titlefont=dict(size=24),\n", " margin=dict(l=20, r=20, t=120, b=0),\n", " xaxis=dict(title=\"Cost Component\", showgrid=False, mirror=True, titlefont=dict(size=18), \\\n", " tickfont=dict(size=18), tickangle=0, tickformat=\"%d-%b\", domain=[0, 1]),\n", " yaxis=dict(title=\"Revenue / Cost ($)\", showgrid=True, mirror=True, titlefont=dict(size=18), \\\n", " tickfont=dict(size=18), range=[0,1.5*10**6]),\n", " template=\"simple_white\",\n", " font_family=\"Times New Roman\",\n", " width=600,\n", " height=600)\n", "\n", "fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{include} example_2_plt_3.html \n", "```" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.9.12 ('nempy')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" }, "vscode": { "interpreter": { "hash": "4aab49ac747d4948ee2428bd46f4ac833ef94a37ecb38233c747c75e4d05fe4b" } } }, "nbformat": 4, "nbformat_minor": 2 }