Instruction:
Can you tell what is the following Python 3 function doing
def draw_port_label(context, port, transparency, fill, label_position, show_additional_value=False,
                    additional_value=None, only_extent_calculations=False):
    """Draws a normal label indicating the port name.

    :param context: Draw Context
    :param port: The PortView
    :param transparency: Transparency of the text
    :param fill: Whether the label should be filled or not
    :param label_position: Side on which the label should be drawn
    :param show_additional_value: Whether to show an additional value (for data ports)
    :param additional_value: The additional value to be shown
    :param only_extent_calculations: Calculate only the extends and do not actually draw
    """
    c = context
    cairo_context = c
    if isinstance(c, CairoBoundingBoxContext):
        cairo_context = c._cairo

    # Gtk TODO
    # c.set_antialias(Antialias.GOOD)

    text = port.name
    label_color = get_col_rgba(port.fill_color, transparency)
    text_color = port.text_color
    port_height = port.port_size[1]

    port_position = c.get_current_point()

    layout = PangoCairo.create_layout(cairo_context)
    layout.set_text(text, -1)

    font_name = constants.INTERFACE_FONT
    font = FontDescription(font_name + " " + str(FONT_SIZE))
    layout.set_font_description(font)

    ink_extents, logical_extents = layout.get_extents()
    extents = [extent / float(SCALE) for extent in [logical_extents.x, logical_extents.y,
                                                    logical_extents.width, logical_extents.height]]
    real_text_size = extents[2], extents[3]
    desired_height = port_height
    scale_factor = real_text_size[1] / desired_height

    # margin is the distance between the text and the border line
    margin = desired_height / 2.5
    arrow_height = desired_height
    # The real_text_size dimensions are rotated by 90 deg compared to the label, as the label is drawn upright
    text_size = desired_height, real_text_size[0] / scale_factor,
    text_size_with_margin = text_size[0] + 2 * margin, text_size[1] + 2 * margin + arrow_height
    port_distance = desired_height
    port_offset = desired_height / 2.

    if label_position is SnappedSide.RIGHT:
        label_angle = deg2rad(-90)
        text_angle = 0
    elif label_position is SnappedSide.BOTTOM:
        label_angle = 0
        text_angle = deg2rad(-90)
    elif label_position is SnappedSide.LEFT:
        label_angle = deg2rad(90)
        text_angle = 0
    else:  # label_position is SnappedSide.TOP:
        label_angle = deg2rad(180)
        text_angle = deg2rad(90)

    # Draw (filled) outline of label
    c.move_to(*port_position)
    c.save()
    c.rotate(label_angle)
    draw_label_path(c, text_size_with_margin[0], text_size_with_margin[1], arrow_height, port_distance, port_offset)
    c.restore()

    c.set_line_width(port_height * .03)
    c.set_source_rgba(*label_color)
    label_extents = c.stroke_extents()
    if label_extents[0] == 0:
        label_extents = c.fill_extents()

    if only_extent_calculations:
        c.new_path()
    else:
        if fill:
            c.fill_preserve()
        c.stroke()

        # Move to the upper left corner of the desired text position
        c.save()
        c.move_to(*port_position)
        c.rotate(label_angle)
        c.rel_move_to(0, port_distance + arrow_height + 2 * margin)
        c.scale(1. / scale_factor, 1. / scale_factor)
        c.rel_move_to(-real_text_size[1] / 2 - extents[1], real_text_size[0] - extents[0])
        c.restore()

        # Show text in correct orientation
        c.save()
        c.rotate(text_angle)
        c.scale(1. / scale_factor, 1. / scale_factor)
        # Correction for labels positioned right: as the text is mirrored, the anchor point must be moved
        if label_position is SnappedSide.RIGHT:
            c.rel_move_to(-real_text_size[0], -real_text_size[1])
        c.set_source_rgba(*get_col_rgba(text_color, transparency))
        PangoCairo.update_layout(cairo_context, layout)
        PangoCairo.show_layout(cairo_context, layout)
        c.restore()

    if show_additional_value:
        value_text = limit_value_string_length(additional_value)
        value_layout = PangoCairo.create_layout(cairo_context)
        value_layout.set_text(value_text, -1)
        value_layout.set_font_description(font)

        ink_extents, logical_extents = value_layout.get_extents()
        extents = [extent / float(SCALE) for extent in [logical_extents.x, logical_extents.y,
                                                        logical_extents.width, logical_extents.height]]
        value_text_size = extents[2], real_text_size[1]

        # Move to the upper left corner of the additional value box
        c.save()
        c.move_to(*port_position)
        c.rotate(label_angle)
        c.rel_move_to(-text_size_with_margin[0] / 2., text_size_with_margin[1] + port_distance)
        # Draw rectangular path
        c.rel_line_to(text_size_with_margin[0], 0)
        c.rel_line_to(0, value_text_size[0] / scale_factor + 2 * margin)
        c.rel_line_to(-text_size_with_margin[0], 0)
        c.close_path()
        c.restore()

        value_extents = c.stroke_extents()

        if only_extent_calculations:
            c.new_path()
        else:
            # Draw filled outline
            c.set_source_rgba(*get_col_rgba(gui_config.gtk_colors['DATA_VALUE_BACKGROUND']))
            c.fill_preserve()
            c.set_source_rgb(*gui_config.gtk_colors['BLACK'].to_floats())
            c.stroke()

            # Move to the upper left corner of the desired text position
            c.save()
            c.move_to(*port_position)
            c.rotate(label_angle)
            c.rel_move_to(0, margin + text_size_with_margin[1] + port_distance)
            c.scale(1. / scale_factor, 1. / scale_factor)
            c.rel_move_to(-real_text_size[1] / 2., value_text_size[0])
            c.restore()

            # Show text in correct orientation
            c.save()
            c.rotate(text_angle)
            c.scale(1. / scale_factor, 1. / scale_factor)
            # Correction for labels positioned right: as the text is mirrored, the anchor point must be moved
            if label_position is SnappedSide.RIGHT:
                c.rel_move_to(-value_text_size[0] - margin * scale_factor, -real_text_size[1])
            c.set_source_rgba(*get_col_rgba(gui_config.gtk_colors['SCOPED_VARIABLE_TEXT']))
            PangoCairo.update_layout(cairo_context, value_layout)
            PangoCairo.show_layout(cairo_context, value_layout)
            c.restore()

        label_extents = min(label_extents[0], value_extents[0]), min(label_extents[1], value_extents[1]), \
                        max(label_extents[2], value_extents[2]), max(label_extents[3], value_extents[3])

    return label_extents

Response: Draws a normal label indicating the port name.


Instruction:
Can you implement a function in Python 3 that
draws the path for an upright label on the Cairo context.

Response:
def draw_label_path(context, width, height, arrow_height, distance_to_port, port_offset):
    """Draws the path for an upright label

    :param context: The Cairo context
    :param float width: Width of the label
    :param float height: Height of the label
    :param float distance_to_port: Distance to the port related to the label
    :param float port_offset: Distance from the port center to its border
    :param bool draw_connection_to_port: Whether to draw a line from the tip of the label to the port
    """
    c = context
    # The current point is the port position

    # Mover to outer border of state
    c.rel_move_to(0, port_offset)
    # Draw line to arrow tip of label
    c.rel_line_to(0, distance_to_port)

    # Line to upper left corner
    c.rel_line_to(-width / 2., arrow_height)
    # Line to lower left corner
    c.rel_line_to(0, height - arrow_height)
    # Line to lower right corner
    c.rel_line_to(width, 0)
    # Line to upper right corner
    c.rel_line_to(0, -(height - arrow_height))
    # Line to center top (tip of label)
    c.rel_line_to(-width / 2., -arrow_height)
    # Close path
    c.close_path()


Instruction:
Can you generate the documentation for the following Python 3 function
def prepare_destruction(self, recursive=True):
        self.destruction_signal.emit()
        try:
            self.unregister_observer(self)
        except KeyError:  # Might happen if the observer was already unregistered
            pass
        if recursive:

            if self.state_copy:
                self.state_copy.prepare_destruction(recursive)
                self.state_copy = None
            else:
                if self.state_copy_initialized:
                    logger.verbose("Multiple calls of prepare destruction for {0}".format(self))

            # The next lines are commented because not needed and create problems if used why it is an open to-do
            # for port in self.input_data_ports[:] + self.output_data_ports[:] + self.outcomes[:]:
            #     if port.core_element is not None:
            #         # TODO setting data ports None in a Library state cause gtkmvc3 attribute getter problems why?
            #         port.prepare_destruction()

        del self.input_data_ports[:]
        del self.output_data_ports[:]
        del self.outcomes[:]
        self.state = None

Response: Prepares the model for destruction.


Instruction:
Given the following Python 3 function, write the documentation
def _load_input_data_port_models(self):
        if not self.state_copy_initialized:
            return
        self.input_data_ports = []
        for input_data_port_m in self.state_copy.input_data_ports:
            new_ip_m = deepcopy(input_data_port_m)
            new_ip_m.parent = self
            new_ip_m.data_port = input_data_port_m.data_port
            self.input_data_ports.append(new_ip_m)

Response: Reloads the input data port models directly from the state copy


Instruction:
Write a Python 3 script for
reloading the output data port models directly from the state copy

Response:
def _load_output_data_port_models(self):
        """Reloads the output data port models directly from the the state"""
        if not self.state_copy_initialized:
            return
        self.output_data_ports = []
        for output_data_port_m in self.state_copy.output_data_ports:
            new_op_m = deepcopy(output_data_port_m)
            new_op_m.parent = self
            new_op_m.data_port = output_data_port_m.data_port
            self.output_data_ports.append(new_op_m)


Instruction:
Can you implement a function in Python 3 that
reloads the income model directly from the state copy

Response:
def _load_income_model(self):
        """Reloads the income model directly from the state"""
        if not self.state_copy_initialized:
            return
        self.income = None
        income_m = deepcopy(self.state_copy.income)
        income_m.parent = self
        income_m.income = income_m.income
        self.income = income_m


Instruction:
Can you create a Python 3 function that
reloads the outcome models directly from the state copy

Response:
def _load_outcome_models(self):
        """Reloads the outcome models directly from the state"""
        if not self.state_copy_initialized:
            return
        self.outcomes = []
        for outcome_m in self.state_copy.outcomes:
            new_oc_m = deepcopy(outcome_m)
            new_oc_m.parent = self
            new_oc_m.outcome = outcome_m.outcome
            self.outcomes.append(new_oc_m)


Instruction:
Implement a Python 3 function for
checking if content of library is to be shown

Response:
def show_content(self):
        """Check if content of library is to be shown

        Content is shown, if the uppermost state's meta flag "show_content" is True and the library hierarchy depth
        (up to MAX_VISIBLE_LIBRARY_HIERARCHY level) is not to high.

        :return: Whether the content is to be shown
        :rtype: bool
        """
        current_hierarchy_depth = self.state.library_hierarchy_depth
        max_hierarchy_depth = global_gui_config.get_config_value("MAX_VISIBLE_LIBRARY_HIERARCHY", 2)
        if current_hierarchy_depth >= max_hierarchy_depth:
            return False
        if current_hierarchy_depth > 1:
            uppermost_lib_state = self.state.get_uppermost_library_root_state().parent
            uppermost_lib_state_m = self.get_state_machine_m().get_state_model_by_path(uppermost_lib_state.get_path())
        else:
            uppermost_lib_state_m = self
        uppermost_lib_meta = uppermost_lib_state_m.meta
        return False if 'show_content' not in uppermost_lib_meta['gui'] else uppermost_lib_meta['gui']['show_content']


Instruction:
How would you explain what the following Python 3 function does
def prepare_destruction(self):
        if self.core_element is None:
            logger.verbose("Multiple calls of prepare destruction for {0}".format(self))
        self.destruction_signal.emit()
        try:
            self.unregister_observer(self)
        except KeyError:  # Might happen if the observer was already unregistered
            pass
        super(StateElementModel, self).prepare_destruction()

Response: Prepares the model for destruction. Unregisters the model from observing itself.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def model_changed(self, model, prop_name, info):
        if self.parent is not None:
            self.parent.model_changed(model, prop_name, info)

Response: This method notifies the parent state about changes made to the state element


Instruction:
Can you generate a brief explanation for the following Python 3 code
def meta_changed(self, model, prop_name, info):
        if self.parent is not None:
            msg = info.arg
            # Add information about notification to the signal message
            notification = Notification(model, prop_name, info)
            msg = msg._replace(notification=notification)
            info.arg = msg
            self.parent.meta_changed(model, prop_name, info)

Response: This method notifies the parent state about changes made to the meta data


Instruction:
Can you tell what is the following Python 3 function doing
def on_config_value_changed(self, config_m, prop_name, info):
        config_key = info['args'][1]

        if config_key in ["EXECUTION_TICKER_ENABLED"]:
            self.check_configuration()

Response: Callback when a config value has been changed


Instruction:
Given the following Python 3 function, write the documentation
def disable(self):

        self.ticker_text_label.hide()
        if self.current_observed_sm_m:
            self.stop_sm_m_observation(self.current_observed_sm_m)

Response: Relieve all state machines that have no active execution and hide the widget


Instruction:
Here you have a function in Python 3, explain what it does
def on_state_execution_status_changed_after(self, model, prop_name, info):
        from rafcon.gui.utils.notification_overview import NotificationOverview
        from rafcon.core.states.state import State

        def name_and_next_state(state):
            assert isinstance(state, State)
            if state.is_root_state_of_library:
                return state.parent.parent, state.parent.name
            else:
                return state.parent, state.name

        def create_path(state, n=3, separator='/'):
            next_parent, name = name_and_next_state(state)
            path = separator + name
            n -= 1
            while n > 0 and isinstance(next_parent, State):
                next_parent, name = name_and_next_state(next_parent)
                path = separator + name + path
                n -= 1
            if isinstance(next_parent, State):
                path = separator + '..' + path
            return path

        if 'kwargs' in info and 'method_name' in info['kwargs']:
            overview = NotificationOverview(info)
            if overview['method_name'][-1] == 'state_execution_status':
                active_state = overview['model'][-1].state
                assert isinstance(active_state, State)

                path_depth = rafcon.gui.singleton.global_gui_config.get_config_value("EXECUTION_TICKER_PATH_DEPTH", 3)

                message = self._fix_text_of_label + create_path(active_state, path_depth)
                if rafcon.gui.singleton.main_window_controller.view is not None:
                    self.ticker_text_label.set_text(message)
                else:
                    logger.warn("Not initialized yet")

Response: Show current execution status in the widget


Instruction:
Explain what the following Python 3 code does
def register_observer(self):
        self.execution_engine.add_observer(self, "start", notify_before_function=self.on_start)
        self.execution_engine.add_observer(self, "pause", notify_before_function=self.on_pause)
        self.execution_engine.add_observer(self, "stop", notify_before_function=self.on_stop)

Response: Register all observable which are of interest


Instruction:
Can you generate the documentation for the following Python 3 function
def register_states_of_state_machine(self, state_machine):
        root = state_machine.root_state
        root.add_observer(self, "state_execution_status",
                          notify_after_function=self.on_state_execution_status_changed_after)
        self.recursively_register_child_states(root)

Response: This function registers all states of state machine.


Instruction:
Make a summary of the following Python 3 code
def recursively_register_child_states(self, state):
        self.logger.info("Execution status observer add new state {}".format(state))
        if isinstance(state, ContainerState):
            state.add_observer(self, "add_state",
                               notify_after_function=self.on_add_state)
            for state in list(state.states.values()):
                self.recursively_register_child_states(state)
                state.add_observer(self, "state_execution_status",
                                   notify_after_function=self.on_state_execution_status_changed_after)

        if isinstance(state, LibraryState):
            self.recursively_register_child_states(state.state_copy)
            state.add_observer(self, "state_execution_status",
                               notify_after_function=self.on_state_execution_status_changed_after)

Response: A function tha registers recursively all child states of a state


Instruction:
Make a summary of the following Python 3 code
def on_add_state_machine_after(self, observable, return_value, args):
        self.logger.info("Execution status observer register new state machine sm_id: {}".format(args[1].state_machine_id))
        self.register_states_of_state_machine(args[1])

Response: This method is called when a state machine is added to the state machine manager


Instruction:
Explain what the following Python 3 code does
def on_state_execution_status_changed_after(self, observable, return_value, args):
        self.logger.info("Execution status has changed for state '{0}' to status: {1}"
                         "".format(observable.get_path(by_name=True), observable.state_execution_status))

Response: This function is called when the state machine execution status of a state machine has changed after the state machine execution status of a state machine is created.


Instruction:
Here you have a function in Python 3, explain what it does
def run(self):

        try:
            self._initialize_hierarchy()
            while self.child_state is not self:
                # print("hs1", self.name)
                self.handling_execution_mode = True
                execution_mode = singleton.state_machine_execution_engine.handle_execution_mode(self, self.child_state)

                # in the case of starting the sm from a specific state not the transitions define the logic flow
                # but the the execution_engine.run_to_states; thus, do not alter the next state in this case
                if not self._start_state_modified:
                    # check if e.g. the state machine was paused and the next state was modified (e.g. removed)
                    self.check_if_child_state_was_modified()

                self.handling_execution_mode = False
                if self.state_execution_status is not StateExecutionStatus.EXECUTE_CHILDREN:
                    self.state_execution_status = StateExecutionStatus.EXECUTE_CHILDREN

                # print("hs2", self.name)

                self.backward_execution = False
                if self.preempted:
                    if self.last_transition and self.last_transition.from_outcome == -2:
                        logger.debug("Execute preemption handling for '{0}'".format(self.child_state))
                    else:
                        break
                elif execution_mode == StateMachineExecutionStatus.BACKWARD:
                    break_loop = self._handle_backward_execution_before_child_execution()
                    if break_loop:
                        break
                # This is only the case if this hierarchy-state is started in backward mode,
                # but the user directly switches to the forward execution mode
                if self.child_state is None:
                    break

                # print("hs3", self.name)

                self._execute_current_child()

                if self.backward_execution:
                    # print("hs4", self.name)
                    break_loop = self._handle_backward_execution_after_child_execution()
                    if break_loop:
                        # print("hs4.1", self.name)
                        break
                else:
                    # print("hs5", self.name)
                    break_loop = self._handle_forward_execution_after_child_execution()
                    if break_loop:
                        break
                # print("hs6", self.name)
            return self._finalize_hierarchy()

        except Exception as e:
            logger.error("{0} had an internal error: {1}\n{2}".format(self, str(e), str(traceback.format_exc())))
            self.output_data["error"] = e
            self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE
            self.child_state = None
            self.last_child = None
            return self.finalize(Outcome(-1, "aborted"))

Response: This function executes all the child states and stores the output data for the next state.


Instruction:
Can you create a Python 3 function that
sets up all data after receiving a backward execution step from the execution engine

Response:
def _handle_backward_execution_before_child_execution(self):
        """ Sets up all data after receiving a backward execution step from the execution engine
        :return: a flag to indicate if normal child state execution should abort
        """
        self.backward_execution = True
        last_history_item = self.execution_history.pop_last_item()
        if last_history_item.state_reference is self:
            # if the the next child_state in the history is self exit this hierarchy-state
            if self.child_state:
                # do not set the last state to inactive before executing the new one
                self.child_state.state_execution_status = StateExecutionStatus.INACTIVE
            return True
        assert isinstance(last_history_item, ReturnItem)
        self.scoped_data = last_history_item.scoped_data
        self.child_state = last_history_item.state_reference
        return False


Instruction:
Can you generate the documentation for the following Python 3 function
def _execute_current_child(self):

        self.child_state.input_data = self.get_inputs_for_state(self.child_state)
        self.child_state.output_data = self.create_output_dictionary_for_state(self.child_state)

        # process data of last state
        if self.last_error:
            self.child_state.input_data['error'] = copy.deepcopy(self.last_error)
        self.last_error = None
        if self.last_child:
            # do not set the last state to inactive before executing the new one
            self.last_child.state_execution_status = StateExecutionStatus.INACTIVE

        self.child_state.generate_run_id()
        if not self.backward_execution:  # only add history item if it is not a backward execution
            self.execution_history.push_call_history_item(
                self.child_state, CallType.EXECUTE, self, self.child_state.input_data)
        self.child_state.start(self.execution_history, backward_execution=self.backward_execution,
                               generate_run_id=False)

        self.child_state.join()

        # this line is important to indicate the parent the current execution status
        # it may also change during the execution of an hierarchy state
        # e.g. a hierarchy state may be started in forward execution mode but can leave in backward execution mode
        # print(self.child_state)
        # print(self.child_state.backward_execution)
        self.backward_execution = self.child_state.backward_execution
        # for h in self.execution_history._history_items:
        #     print(h)

        if self.preempted:
            if self.backward_execution:
                # this is the case if the user backward step through its state machine and stops it
                # as preemption behaviour in backward mode is not defined, set the state to forward mode
                # to ensure clean state machine shutdown
                self.backward_execution = False

        # set last_error and self.last_child
        if self.child_state.final_outcome is not None:  # final outcome can be None if only one state in a
            # hierarchy state is executed and immediately backward executed
            if self.child_state.final_outcome.outcome_id == -1:  # if the child_state aborted save the error
                self.last_error = ""
                if 'error' in self.child_state.output_data:
                    self.last_error = self.child_state.output_data['error']
        self.last_child = self.child_state

Response: This function processes all data for a child state and executes it.


Instruction:
Can you generate the documentation for the following Python 3 function
def _handle_backward_execution_after_child_execution(self):
        self.child_state.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE
        # the item popped now from the history will be a CallItem and will contain the scoped data,
        # that was valid before executing the child_state
        last_history_item = self.execution_history.pop_last_item()
        assert isinstance(last_history_item, CallItem)
        # copy the scoped_data of the history from the point before the child_state was executed
        self.scoped_data = last_history_item.scoped_data

        # this is a look-ahead step to directly leave this hierarchy-state if the last child_state
        # was executed; this leads to the backward and forward execution of a hierarchy child_state
        # having the exact same number of steps
        last_history_item = self.execution_history.get_last_history_item()
        if last_history_item.state_reference is self:
            last_history_item = self.execution_history.pop_last_item()
            assert isinstance(last_history_item, CallItem)
            self.scoped_data = last_history_item.scoped_data
            self.child_state.state_execution_status = StateExecutionStatus.INACTIVE
            return True
        return False

Response: Cleanup the former child state execution and prepare for the next state execution in the backward execution case.


Instruction:
Write a Python 3 script to
rotate tab labels of a given GTK Notebook container by 90 degrees and makes them detachable.

Response:
def rotate_and_detach_tab_labels(self):
        """Rotates tab labels of a given notebook by 90 degrees and makes them detachable.

        :param notebook: GTK Notebook container, whose tab labels are to be rotated and made detachable
        """
        icons = {'Libraries': constants.SIGN_LIB, 'States Tree': constants.ICON_TREE,
                 'Global Variables': constants.ICON_GLOB, 'Modification History': constants.ICON_HIST,
                 'Execution History': constants.ICON_EHIST, 'network': constants.ICON_NET}
        for notebook in self.left_bar_notebooks:
            for i in range(notebook.get_n_pages()):
                child = notebook.get_nth_page(i)
                tab_label = notebook.get_tab_label(child)
                tab_label_text = tab_label.get_text()
                notebook.set_tab_label(child, gui_helper_label.create_tab_header_label(tab_label_text, icons))
                notebook.set_tab_reorderable(child, True)
                notebook.set_tab_detachable(child, True)


Instruction:
Write a Python 3 script for
finding tab with label tab_label in list of notebooks and set it to the current page.

Response:
def bring_tab_to_the_top(self, tab_label):
        """Find tab with label tab_label in list of notebooks and set it to the current page.

        :param tab_label: String containing the label of the tab to be focused
        """
        found = False
        for notebook in self.left_bar_notebooks:
            for i in range(notebook.get_n_pages()):
                if gui_helper_label.get_notebook_tab_title(notebook, i) == gui_helper_label.get_widget_title(tab_label):
                    found = True
                    break
            if found:
                notebook.set_current_page(i)
                break


Instruction:
Can you generate the documentation for the following Python 3 function
def add_transitions_from_selected_state_to_parent():
    task_string = "create transition"
    sub_task_string = "to parent state"

    selected_state_m, msg = get_selected_single_state_model_and_check_for_its_parent()
    if selected_state_m is None:
        logger.warning("Can not {0} {1}: {2}".format(task_string, sub_task_string, msg))
        return
    logger.debug("Check to {0} {1} ...".format(task_string, sub_task_string))
    state = selected_state_m.state
    parent_state = state.parent

    # find all possible from outcomes
    from_outcomes = get_all_outcomes_except_of_abort_and_preempt(state)

    # find lowest valid outcome id
    possible_oc_ids = [oc_id for oc_id in state.parent.outcomes.keys() if oc_id >= 0]
    possible_oc_ids.sort()
    to_outcome = state.parent.outcomes[possible_oc_ids[0]]

    oc_connected_to_parent = [oc for oc in from_outcomes if is_outcome_connect_to_state(oc, parent_state.state_id)]
    oc_not_connected = [oc for oc in from_outcomes if not state.parent.get_transition_for_outcome(state, oc)]
    if all(oc in oc_connected_to_parent for oc in from_outcomes):
        logger.info("Remove transition {0} because all outcomes are connected to it.".format(sub_task_string))
        for from_outcome in oc_connected_to_parent:
            transition = parent_state.get_transition_for_outcome(state, from_outcome)
            parent_state.remove(transition)
    elif oc_not_connected:
        logger.debug("Create transition {0} ... ".format(sub_task_string))
        for from_outcome in from_outcomes:
            parent_state.add_transition(state.state_id, from_outcome.outcome_id,
                                        parent_state.state_id, to_outcome.outcome_id)
    else:
        if remove_transitions_if_target_is_the_same(from_outcomes):
            logger.info("Removed transitions origin from outcomes of selected state {0}"
                        "because all point to the same target.".format(sub_task_string))
            return add_transitions_from_selected_state_to_parent()
        logger.info("Will not create transition {0}: Not clear situation of connected transitions."
                    "There will be no transitions to other states be touched.".format(sub_task_string))

    return True

Response: Generates the default success transition of a state to its parent success


Instruction:
Can you create a Python 3 function that
generates the outcome transitions from outcomes with positive outcome_id to the closest next state

Response:
def add_transitions_to_closest_sibling_state_from_selected_state():
    """ Generates the outcome transitions from outcomes with positive outcome_id to the closest next state

    :return:
    """
    task_string = "create transition"
    sub_task_string = "to closest sibling state"
    selected_state_m, msg = get_selected_single_state_model_and_check_for_its_parent()
    if selected_state_m is None:
        logger.warning("Can not {0} {1}: {2}".format(task_string, sub_task_string, msg))
        return
    logger.debug("Check to {0} {1} ...".format(task_string, sub_task_string))
    state = selected_state_m.state
    parent_state = state.parent

    # find closest other state to connect to -> to_state
    closest_sibling_state_tuple = gui_helper_meta_data.get_closest_sibling_state(selected_state_m, 'outcome')
    if closest_sibling_state_tuple is None:
        logger.info("Can not {0} {1}: There is no other sibling state.".format(task_string, sub_task_string))
        return
    distance, sibling_state_m = closest_sibling_state_tuple
    to_state = sibling_state_m.state

    # find all possible from outcomes
    from_outcomes = get_all_outcomes_except_of_abort_and_preempt(state)

    from_oc_not_connected = [oc for oc in from_outcomes if not state.parent.get_transition_for_outcome(state, oc)]
    # all ports not connected connect to next state income
    if from_oc_not_connected:
        logger.debug("Create transition {0} ...".format(sub_task_string))
        for from_outcome in from_oc_not_connected:
            parent_state.add_transition(state.state_id, from_outcome.outcome_id, to_state.state_id, None)
    # no transitions are removed if not all connected to the same other state
    else:
        target = remove_transitions_if_target_is_the_same(from_outcomes)
        if target:
            target_state_id, _ = target
            if not target_state_id == to_state.state_id:
                logger.info("Removed transitions from outcomes {0} "
                            "because all point to the same target.".format(sub_task_string.replace('closest ', '')))
                add_transitions_to_closest_sibling_state_from_selected_state()
            else:
                logger.info("Removed transitions from outcomes {0} "
                            "because all point to the same target.".format(sub_task_string))
            return True
        logger.info("Will not {0} {1}: Not clear situation of connected transitions."
                    "There will be no transitions to other states be touched.".format(task_string, sub_task_string))

    return True


Instruction:
Can you create a Python 3 function that
adds coordinates to nodes based on provided geom

Response:
def add_coordinates(network):
    """
    Add coordinates to nodes based on provided geom

    Parameters
    ----------
    network : PyPSA network container

    Returns
    -------
    Altered PyPSA network container ready for plotting
    """
    for idx, row in network.buses.iterrows():
        wkt_geom = to_shape(row['geom'])
        network.buses.loc[idx, 'x'] = wkt_geom.x
        network.buses.loc[idx, 'y'] = wkt_geom.y

    return network


Instruction:
Here you have a function in Python 3, explain what it does
def plot_line_loading(
        network,
        timesteps=range(1,2),
        filename=None,
        boundaries=[],
        arrows=False):
    """
    Plots line loading as a colored heatmap.

    Line loading is displayed as relative to nominal capacity in %.

    Parameters
    ----------
    network : PyPSA network container
        Holds topology of grid including results from powerflow analysis
    timesteps : range
        Defines which timesteps are considered. If more than one, an
        average line loading is calculated.
    filename : str
        Specify filename
        If not given, figure will be show directly
    boundaries : list
        If given, the colorbar is fixed to a given min and max value
    arrows : bool
        If True, the direction of the power flows is displayed as
        arrows.
    """
    # TODO: replace p0 by max(p0,p1) and analogously for q0
    # TODO: implement for all given snapshots

    # calculate relative line loading as S/S_nom
    # with S = sqrt(P^2 + Q^2)
    cmap = plt.cm.jet
    array_line = [['Line'] * len(network.lines), network.lines.index]
    array_link = [['Link'] * len(network.links), network.links.index]

    if network.lines_t.q0.empty:

        loading_lines = pd.Series((network.lines_t.p0.mul(
            network.snapshot_weightings, axis=0).loc[network.snapshots[
            timesteps]].abs().sum() / (network.lines.s_nom_opt)).data,
            index=array_line)

    else:
        loading_lines = pd.Series(((network.lines_t.p0.mul(
                network.snapshot_weightings, axis=0)\
                    .loc[network.snapshots[timesteps]].abs().sum() ** 2 +\
                    network.lines_t.q0.mul(
                            network.snapshot_weightings, axis=0)\
                    .loc[network.snapshots[timesteps]].abs().sum() ** 2).\
                    apply(sqrt) / (network.lines.s_nom_opt)).data, index =
                            array_line)

    # Aviod covering of bidirectional links
    network.links['linked_to'] = 0
    for i,  row in network.links.iterrows():
        if not (network.links.index[(network.links.bus0 == row['bus1']) &
                                  (network.links.bus1 == row['bus0']) &
                                  (network.links.length == row['length']
                                  )]).empty:

            l = network.links.index[(network.links.bus0 == row['bus1']) &
                                  (network.links.bus1 == row['bus0']) &
                                  (network.links.length == row['length'])]

            network.links.set_value(i, 'linked_to',l.values[0])

    network.links.linked_to = network.links.linked_to.astype(str)
    link_load = network.links_t.p0[network.links.index[
            network.links.linked_to == '0']]

    for i, row in network.links[network.links.linked_to != '0'].iterrows():
        load = pd.DataFrame(index = network.links_t.p0.index,
                            columns = ['to', 'from'])
        load['to'] = network.links_t.p0[row['linked_to']]
        load['from'] = network.links_t.p0[i]
        link_load[i] = load.abs().max(axis = 1)

    loading_links = pd.Series((link_load.mul(
            network.snapshot_weightings, axis=0).loc[network.snapshots[
            timesteps]].abs().sum()[network.links.index] / (
        network.links.p_nom_opt)).data, index=array_link).dropna()

    load_links_rel = (loading_links/
                      network.snapshot_weightings\
                            [network.snapshots[timesteps]].sum())* 100

    load_lines_rel = (loading_lines / network.snapshot_weightings\
                            [network.snapshots[timesteps]].sum()) * 100

    loading = load_lines_rel.append(load_links_rel)

    ll = network.plot(line_colors=loading, line_cmap=cmap,
                      title="Line loading", line_widths=0.55)
    # add colorbar, note mappable sliced from ll by [1]

    if not boundaries:
        v = np.linspace(min(loading), max(loading), 101)
        boundaries = [min(loading), max(loading)]

    else:
        v = np.linspace(boundaries[0], boundaries[1], 101)

    cb = plt.colorbar(ll[1], boundaries=v,
                      ticks=v[0:101:10])
    cb_Link = plt.colorbar(ll[2], boundaries=v,
                      ticks=v[0:101:10])

    cb.set_clim(vmin=boundaries[0], vmax=boundaries[1])

    cb_Link.set_clim(vmin=boundaries[0], vmax=boundaries[1])

    cb_Link.remove()

    cb.set_label('Line loading in %')

    if arrows:
        ax = plt.axes()
        path = ll[1].get_segments()
        x_coords_lines = np.zeros([len(path)])
        cmap = cmap
        colors = cmap(ll[1].get_array() / 100)
        for i in range(0, len(path)):
            x_coords_lines[i] = network.buses.loc[str(
                network.lines.iloc[i, 2]), 'x']
            color = colors[i]
            if (x_coords_lines[i] == path[i][0][0] and load_lines_rel[i] >= 0):
                arrowprops = dict(arrowstyle="->", color=color)
            else:
                arrowprops = dict(arrowstyle="<-", color=color)
            ax.annotate(
                "",
                xy=abs(
                    (path[i][0] - path[i][1]) * 0.51 - path[i][0]),
                xytext=abs(
                    (path[i][0] - path[i][1]) * 0.49 - path[i][0]),
                arrowprops=arrowprops,
                size=10)

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()

Response: Plots the line loading of the given time series.


Instruction:
Explain what the following Python 3 code does
def plot_line_loading_diff(networkA, networkB, timestep=0):

    # new colormap to make sure 0% difference has the same color in every plot
    def shiftedColorMap(
            cmap,
            start=0,
            midpoint=0.5,
            stop=1.0,
            name='shiftedcmap'):
        '''
        Function to offset the "center" of a colormap. Useful for
        data with a negative min and positive max and you want the
        middle of the colormap's dynamic range to be at zero

        Input
        -----
          cmap : The matplotlib colormap to be altered
          start : Offset from lowest point in the colormap's range.
              Defaults to 0.0 (no lower ofset). Should be between
              0.0 and `midpoint`.
          midpoint : The new center of the colormap. Defaults to
              0.5 (no shift). Should be between 0.0 and 1.0. In
              general, this should be  1 - vmax/(vmax + abs(vmin))
              For example if your data range from -15.0 to +5.0 and
              you want the center of the colormap at 0.0, `midpoint`
              should be set to  1 - 5/(5 + 15)) or 0.75
          stop : Offset from highets point in the colormap's range.
              Defaults to 1.0 (no upper ofset). Should be between
              `midpoint` and 1.0.
        '''
        cdict = {
            'red': [],
            'green': [],
            'blue': [],
            'alpha': []
        }

        # regular index to compute the colors
        reg_index = np.linspace(start, stop, 257)

        # shifted index to match the data
        shift_index = np.hstack([
            np.linspace(0.0, midpoint, 128, endpoint=False),
            np.linspace(midpoint, 1.0, 129, endpoint=True)
        ])

        for ri, si in zip(reg_index, shift_index):
            r, g, b, a = cmap(ri)

            cdict['red'].append((si, r, r))
            cdict['green'].append((si, g, g))
            cdict['blue'].append((si, b, b))
            cdict['alpha'].append((si, a, a))

        newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
        plt.register_cmap(cmap=newcmap)

        return newcmap

    # calculate difference in loading between both networks
    loading_switches = abs(
        networkA.lines_t.p0.mul(networkA.snapshot_weightings, axis=0).\
        loc[networkA.snapshots[timestep]].to_frame())
    loading_switches.columns = ['switch']
    loading_noswitches = abs(
        networkB.lines_t.p0.mul(networkB.snapshot_weightings, axis=0).\
        loc[networkB.snapshots[timestep]].to_frame())
    loading_noswitches.columns = ['noswitch']
    diff_network = loading_switches.join(loading_noswitches)
    diff_network['noswitch'] = diff_network['noswitch'].fillna(
        diff_network['switch'])
    diff_network[networkA.snapshots[timestep]] \
        = diff_network['switch'] - diff_network['noswitch']

    # get switches
    new_buses = pd.Series(index=networkA.buses.index.values)
    new_buses.loc[set(networkA.buses.index.values) -
                  set(networkB.buses.index.values)] = 0.1
    new_buses = new_buses.fillna(0)

    # plot network with difference in loading and shifted colormap
    loading = (diff_network.loc[:, networkA.snapshots[timestep]] /
               (networkA.lines.s_nom)) * 100
    midpoint = 1 - max(loading) / (max(loading) + abs(min(loading)))
    shifted_cmap = shiftedColorMap(
        plt.cm.jet, midpoint=midpoint, name='shifted')
    ll = networkA.plot(line_colors=loading, line_cmap=shifted_cmap,
                       title="Line loading", bus_sizes=new_buses,
                       bus_colors='blue', line_widths=0.55)

    cb = plt.colorbar(ll[1])
    cb.set_label('Difference in line loading in % of s_nom')

Response: Plot difference in line loading between two networks.


Instruction:
Can you implement a function in Python 3 that
plots relative or absolute network extension of AC - and DC - lines.

Response:
def network_expansion(network, method = 'rel', ext_min=0.1,
                      ext_width=False, filename=None, boundaries=[]):
    """Plot relative or absolute network extension of AC- and DC-lines.

    Parameters
    ----------
    network: PyPSA network container
        Holds topology of grid including results from powerflow analysis
    method: str
        Choose 'rel' for extension relative to s_nom and 'abs' for
        absolute extensions.
    ext_min: float
        Choose minimum relative line extension shown in plot in p.u..
    ext_width: float or bool
        Choose if line_width respects line extension. Turn off with 'False' or
        set linear factor to decremise extension line_width.
    filename: str or None
        Save figure in this direction
    boundaries: array
       Set boundaries of heatmap axis

    """

    cmap = plt.cm.jet

    overlay_network = network.copy()
    overlay_network.lines = overlay_network.lines[
                            overlay_network.lines.s_nom_extendable & ((
                                    overlay_network.lines.s_nom_opt -
                                  overlay_network.lines.s_nom_min) /
                                overlay_network.lines.s_nom >= ext_min)]
    overlay_network.links = overlay_network.links[
                            overlay_network.links.p_nom_extendable & ((
                                    overlay_network.links.p_nom_opt -
                                  overlay_network.links.p_nom_min)/
                                 overlay_network.links.p_nom >= ext_min)]

    for i, row in overlay_network.links.iterrows():
        linked = overlay_network.links[(row['bus1'] ==
                overlay_network.links.bus0) & (
                        row['bus0'] == overlay_network.links.bus1)]
        if not linked.empty:
            if row['p_nom_opt'] < linked.p_nom_opt.values[0]:
                overlay_network.links.p_nom_opt[i] = linked.p_nom_opt.values[0]

    array_line = [['Line'] * len(overlay_network.lines),
                  overlay_network.lines.index]

    array_link = [['Link'] * len(overlay_network.links),
                  overlay_network.links.index]

    if method == 'rel':

        extension_lines = pd.Series((100 *
                                 (overlay_network.lines.s_nom_opt -
                                  overlay_network.lines.s_nom_min) /
                                overlay_network.lines.s_nom).data,
                                index=array_line)

        extension_links = pd.Series((100 *
                                 (overlay_network.links.p_nom_opt -
                                  overlay_network.links.p_nom_min)/
                                 (overlay_network.links.p_nom)).data,
                                index=array_link)
    if method == 'abs':
        extension_lines = pd.Series(
                                 (overlay_network.lines.s_nom_opt -
                                  overlay_network.lines.s_nom_min).data,
                                index=array_line)

        extension_links = pd.Series(
                                 (overlay_network.links.p_nom_opt -
                                  overlay_network.links.p_nom_min).data,
                                index=array_link)

    extension = extension_lines.append(extension_links)

    # Plot whole network in backgroud of plot
    network.plot(
            line_colors=pd.Series("grey", index = [['Line'] * len(
                    network.lines), network.lines.index]).append(
            pd.Series("grey", index = [['Link'] * len(network.links),
                  network.links.index])),
            bus_sizes=0,
            line_widths=pd.Series(0.5, index = [['Line'] * len(network.lines),
                  network.lines.index]).append(
            pd.Series(0.55, index = [['Link'] * len(network.links),
                  network.links.index])))

    if not ext_width:
        line_widths= pd.Series(0.8, index = array_line).append(
                pd.Series(0.8, index = array_link))

    else:
        line_widths= 0.5 + (extension / ext_width)

    ll = overlay_network.plot(
        line_colors=extension,
        line_cmap=cmap,
        bus_sizes=0,
        title="Optimized AC- and DC-line expansion",
        line_widths=line_widths)

    if not boundaries:
        v = np.linspace(min(extension), max(extension), 101)
        boundaries = [min(extension), max(extension)]

    else:
        v = np.linspace(boundaries[0], boundaries[1], 101)

    if not extension_links.empty:
        cb_Link = plt.colorbar(ll[2], boundaries=v,
                      ticks=v[0:101:10])
        cb_Link.set_clim(vmin=boundaries[0], vmax=boundaries[1])

        cb_Link.remove()

    cb = plt.colorbar(ll[1], boundaries=v,
                      ticks=v[0:101:10], fraction=0.046, pad=0.04)

    cb.set_clim(vmin=boundaries[0], vmax=boundaries[1])

    if method == 'rel':
        cb.set_label('line expansion relative to s_nom in %')
    if method == 'abs':
        cb.set_label('line expansion in MW')
    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()


Instruction:
Write a Python 3 script for
plotting relative network expansion derivation of AC - and DC - lines.

Response:
def network_expansion_diff (networkA, networkB, filename=None, boundaries=[]):
    """Plot relative network expansion derivation of AC- and DC-lines.

    Parameters
    ----------
    networkA: PyPSA network container
        Holds topology of grid including results from powerflow analysis
    networkB: PyPSA network container
        Holds topology of grid including results from powerflow analysis
    filename: str or None
        Save figure in this direction
    boundaries: array
       Set boundaries of heatmap axis

    """

    cmap = plt.cm.jet

    array_line = [['Line'] * len(networkA.lines), networkA.lines.index]

    extension_lines = pd.Series(100 *\
                                 ((networkA.lines.s_nom_opt - \
                                    networkB.lines.s_nom_opt)/\
                                    networkA.lines.s_nom_opt  ).values,\
                                index=array_line)

    array_link = [['Link'] * len(networkA.links), networkA.links.index]

    extension_links = pd.Series(100 *
                                 ((networkA.links.p_nom_opt -\
                                    networkB.links.p_nom_opt)/\
                                    networkA.links.p_nom_opt).values,\
                                index=array_link)

    extension = extension_lines.append(extension_links)

    ll = networkA.plot(
        line_colors=extension,
        line_cmap=cmap,
        bus_sizes=0,
        title="Derivation of AC- and DC-line extension",
        line_widths=2)

    if not boundaries:
        v = np.linspace(min(extension), max(extension), 101)
        boundaries = [min(extension).round(0), max(extension).round(0)]

    else:
        v = np.linspace(boundaries[0], boundaries[1], 101)

    if not extension_links.empty:
        cb_Link = plt.colorbar(ll[2], boundaries=v,
                      ticks=v[0:101:10])
        cb_Link.set_clim(vmin=boundaries[0], vmax=boundaries[1])

        cb_Link.remove()

    cb = plt.colorbar(ll[1], boundaries=v,
                      ticks=v[0:101:10], fraction=0.046, pad=0.04)

    cb.set_clim(vmin=boundaries[0], vmax=boundaries[1])
    cb.set_label('line extension derivation  in %')

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()


Instruction:
How would you code a function in Python 3 to
plot loading of lines in equivalten full load hours.

Response:
def full_load_hours(network, boundaries=[], filename=None, two_cb=False):
    """Plot loading of lines in equivalten full load hours.

    Parameters
    ----------
    network: PyPSA network container
        Holds topology of grid including results from powerflow analysis
    filename: str or None
        Save figure in this direction
    boundaries: array
       Set boundaries of heatmap axis
    two_cb: bool
        Choose if an extra colorbar for DC-lines is plotted

    """
    cmap = plt.cm.jet

    array_line = [['Line'] * len(network.lines), network.lines.index]

    load_lines = pd.Series(abs((network.lines_t.p0.mul(
                                network.snapshot_weightings, axis=0).sum() /
                                (network.lines.s_nom))).data, index=array_line)

    array_link = [['Link'] * len(network.links), network.links.index]

    load_links = pd.Series(abs((network.links_t.p0.mul(
                                network.snapshot_weightings, axis=0).sum() /
                                (network.links.p_nom))).data, index=array_link)

    load_hours = load_lines.append(load_links)

    ll = network.plot(line_colors=load_hours, line_cmap=cmap, bus_sizes=0,
                      title="Full load-hours of lines", line_widths=2)

    if not boundaries:
        cb = plt.colorbar(ll[1])
        cb_Link = plt.colorbar(ll[2])
    elif boundaries:
        v = np.linspace(boundaries[0], boundaries[1], 101)

        cb_Link = plt.colorbar(ll[2], boundaries=v,
                               ticks=v[0:101:10])
        cb_Link.set_clim(vmin=boundaries[0], vmax=boundaries[1])

        cb = plt.colorbar(ll[1], boundaries=v,
                          ticks=v[0:101:10])
        cb.set_clim(vmin=boundaries[0], vmax=boundaries[1])

    if two_cb:
        cb_Link.set_label('Number of full-load hours of DC-lines')
        cb.set_label('Number of full-load hours of AC-lines')

    else:
        cb.set_label('Number of full-load hours')

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()


Instruction:
Write a Python 3 function for
plotting maximal reactive line load.

Response:
def plot_q_flows(network):
    """Plot maximal reactive line load.

    Parameters
    ----------
    network: PyPSA network container
        Holds topology of grid including results from powerflow analysis

    """
    cmap_line = plt.cm.jet

    q_flows_max = abs(network.lines_t.q0.abs().max()/(network.lines.s_nom))

    ll = network.plot(line_colors = q_flows_max, line_cmap = cmap_line)
    boundaries = [min(q_flows_max), max(q_flows_max)]
    v = np.linspace(boundaries[0], boundaries[1], 101)

    cb = plt.colorbar(ll[1], boundaries=v,
                      ticks=v[0:101:10])

    cb.set_clim(vmin=boundaries[0], vmax=boundaries[1])


Instruction:
Write a Python 3 function for
plotting maximum loading of each line.

Response:
def max_load(network, boundaries=[], filename=None, two_cb=False):

    """Plot maximum loading of each line.

    Parameters
    ----------
    network: PyPSA network container
        Holds topology of grid including results from powerflow analysis
    filename: str or None
        Save figure in this direction
    boundaries: array
       Set boundaries of heatmap axis
    two_cb: bool
        Choose if an extra colorbar for DC-lines is plotted

    """

    cmap_line = plt.cm.jet
    cmap_link = plt.cm.jet
    array_line = [['Line'] * len(network.lines), network.lines.index]
    array_link = [['Link'] * len(network.links), network.links.index]

    if network.lines_t.q0.empty:
        load_lines = pd.Series((abs(network.lines_t.p0).max(
                ) / (network.lines.s_nom) * 100).data, index=array_line)

    else: load_lines = pd.Series(((network.lines_t.p0**2 +
                           network.lines_t.q0 ** 2).max().apply(sqrt)/
                           (network.lines.s_nom) * 100).data, index=array_line)

    load_links = pd.Series((abs(network.links_t.p0.max(
                ) / (network.links.p_nom)) * 100).data, index=array_link)

    max_load = load_lines.append(load_links)

    ll = network.plot(
        line_colors=max_load,
        line_cmap={
            'Line': cmap_line,
            'Link': cmap_link},
        bus_sizes=0,
        title="Maximum of line loading",
        line_widths=2)

    if not boundaries:
        boundaries = [min(max_load), max(max_load)]

    v = np.linspace(boundaries[0], boundaries[1], 101)

    cb = plt.colorbar(ll[1], boundaries=v,
                      ticks=v[0:101:10])

    cb.set_clim(vmin=boundaries[0], vmax=boundaries[1])

    cb_Link = plt.colorbar(ll[2], boundaries=v,
                               ticks=v[0:101:10])
    cb_Link.set_clim(vmin=boundaries[0], vmax=boundaries[1])

    if two_cb:
        # cb_Link.set_label('Maximum load of DC-lines %')
        cb.set_label('Maximum load of AC-lines %')

    else:
        cb.set_label('Maximum load in %')
    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()


Instruction:
Can you implement a function in Python 3 that
plots number of hours with line loading in selected range.

Response:
def load_hours(network, min_load=0.9, max_load=1, boundaries=[0, 8760]):

    """Plot number of hours with line loading in selected range.

    Parameters
    ----------
    network: PyPSA network container
        Holds topology of grid including results from powerflow analysis
    min_load: float
        Choose lower bound of relative load
    max_load: float
        Choose upper bound of relative load
    boundaries: array
       Set boundaries of heatmap axis

    """

    cmap_line = plt.cm.jet
    cmap_link = plt.cm.jet
    array_line = [['Line'] * len(network.lines), network.lines.index]

    load_lines = pd.Series(((abs(network.lines_t.p0[(
        abs(network.lines_t.p0.mul(network.snapshot_weightings, axis=0)) /
        network.lines.s_nom_opt >= min_load) &
                                                    (
        abs(network.lines_t.p0.mul(network.snapshot_weightings, axis=0)) /
        network.lines.s_nom_opt <= max_load)]) /
                            abs(network.lines_t.p0[(
                                abs(network.lines_t.p0) /
                                network.lines.s_nom_opt >= min_load) &
                                (abs(network.lines_t.p0) /
                                 network.lines.s_nom_opt <= max_load)]))
                            .sum()).data, index=array_line)

    array_link = [['Link'] * len(network.links), network.links.index]

    load_links = pd.Series(((abs(network.links_t.p0[(
        abs(network.links_t.p0.mul(network.snapshot_weightings, axis=0)) /
        network.links.p_nom_opt >= min_load) &
                                                    (
        abs(network.links_t.p0.mul(network.snapshot_weightings, axis=0)) /
        network.links.p_nom_opt <= max_load)]) /
                             abs(network.links_t.p0[(
                                abs(network.links_t.p0) /
                                network.links.p_nom_opt >= min_load) &
                                (abs(network.links_t.p0) /
                                 network.links.p_nom_opt <= max_load)]))
                            .sum()).data, index=array_link)

    load_hours = load_lines.append(load_links)

    ll = network.plot(
        line_colors=load_hours,
        line_cmap={
            'Line': cmap_line,
            'Link': cmap_link},
        bus_sizes=0,
        title="Number of hours with more then 90% load",
        line_widths=2)

    v1 = np.linspace(boundaries[0], boundaries[1], 101)
    v = np.linspace(boundaries[0], boundaries[1], 101)
    cb_Link = plt.colorbar(ll[2], boundaries=v1,
                           ticks=v[0:101:10])
    cb_Link.set_clim(vmin=boundaries[0], vmax=boundaries[1])

    cb = plt.colorbar(ll[1], boundaries=v,
                      ticks=v[0:101:10])
    cb.set_clim(vmin=boundaries[0], vmax=boundaries[1])

    cb.set_label('Number of hours')


Instruction:
Can you implement a function in Python 3 that
plots residual load summed of all exisiting buses.

Response:
def plot_residual_load(network):
    """ Plots residual load summed of all exisiting buses.

    Parameters
    ----------
    network : PyPSA network containter
    """

    renewables = network.generators[
        network.generators.carrier.isin(['wind_onshore', 'wind_offshore',
                                         'solar', 'run_of_river',
                                         'wind'])]
    renewables_t = network.generators.p_nom[renewables.index] * \
        network.generators_t.p_max_pu[renewables.index].mul(
                network.snapshot_weightings, axis=0)
    load = network.loads_t.p_set.mul(network.snapshot_weightings, axis=0).\
    sum(axis=1)
    all_renew = renewables_t.sum(axis=1)
    residual_load = load - all_renew
    plot = residual_load.plot(
        title = 'Residual load',
        drawstyle='steps',
        lw=2,
        color='red',
        legend=False)
    plot.set_ylabel("MW")
    # sorted curve
    sorted_residual_load = residual_load.sort_values(
        ascending=False).reset_index()
    plot1 = sorted_residual_load.plot(
            title='Sorted residual load',
            drawstyle='steps',
            lw=2,
            color='red',
            legend=False)
    plot1.set_ylabel("MW")


Instruction:
Can you implement a function in Python 3 that
plots the stacked sum of generators grouped by carrier type.

Response:
def plot_stacked_gen(network, bus=None, resolution='GW', filename=None):
    """
    Plot stacked sum of generation grouped by carrier type

    Parameters
    ----------
    network : PyPSA network container
    bus: string
        Plot all generators at one specific bus. If none,
        sum is calulated for all buses
    resolution: string
        Unit for y-axis. Can be either GW/MW/KW

    Returns
    -------
    Plot
    """
    if resolution == 'GW':
        reso_int = 1e3
    elif resolution == 'MW':
        reso_int = 1
    elif resolution == 'KW':
        reso_int = 0.001

    # sum for all buses
    if bus is None:
        p_by_carrier = pd.concat([network.generators_t.p[network.generators
                         [network.generators.control != 'Slack'].index],
                         network.generators_t.p.mul(
                         network.snapshot_weightings, axis=0)
                         [network.generators[network.generators.control ==
                         'Slack'].index]
                         .iloc[:, 0].apply(lambda x: x if x > 0 else 0)],
                         axis=1)\
                         .groupby(network.generators.carrier, axis=1).sum()
        load = network.loads_t.p.sum(axis=1)
        if hasattr(network, 'foreign_trade'):
            trade_sum = network.foreign_trade.sum(axis=1)
            p_by_carrier['imports'] = trade_sum[trade_sum > 0]
            p_by_carrier['imports'] = p_by_carrier['imports'].fillna(0)
    # sum for a single bus
    elif bus is not None:
        filtered_gens = network.generators[network.generators['bus'] == bus]
        p_by_carrier = network.generators_t.p.mul(network.snapshot_weightings,
            axis=0).groupby(filtered_gens.carrier, axis=1).abs().sum()
        filtered_load = network.loads[network.loads['bus'] == bus]
        load = network.loads_t.p.mul(network.snapshot_weightings, axis=0)\
            [filtered_load.index]

    colors = coloring()
#    TODO: column reordering based on available columns

    fig, ax = plt.subplots(1, 1)

    fig.set_size_inches(12, 6)
    colors = [colors[col] for col in p_by_carrier.columns]
    if len(colors) == 1:
        colors = colors[0]
    (p_by_carrier / reso_int).plot(kind="area", ax=ax, linewidth=0,
                                   color=colors)
    (load / reso_int).plot(ax=ax, legend='load', lw=2, color='darkgrey',
                           style='--')
    ax.legend(ncol=4, loc="upper left")

    ax.set_ylabel(resolution)
    ax.set_xlabel("")

    matplotlib.rcParams.update({'font.size': 22})

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()


Instruction:
Can you generate the documentation for the following Python 3 function
def plot_gen_diff(
    networkA,
    networkB,
    leave_out_carriers=[
        'geothermal',
        'oil',
        'other_non_renewable',
        'reservoir',
        'waste']):
    """
    Plot difference in generation between two networks grouped by carrier type

    Parameters
    ----------
    networkA : PyPSA network container with switches
    networkB : PyPSA network container without switches
    leave_out_carriers : list of carriers to leave out (default to all small
    carriers)

    Returns
    -------
    Plot
    """
    def gen_by_c(network):
        gen = pd.concat([network.generators_t.p.mul(
                        network.snapshot_weightings, axis=0)[network.generators
                        [network.generators.control != 'Slack'].index],
                        network.generators_t.p.mul(
                        network.snapshot_weightings, axis=0)[network.generators
                        [network. generators.control == 'Slack'].index]
                        .iloc[:, 0].apply(lambda x: x if x > 0 else 0)],
                        axis=1)\
                        .groupby(network.generators.carrier,axis=1).sum()
        return gen

    gen = gen_by_c(networkB)
    gen_switches = gen_by_c(networkA)
    diff = gen_switches - gen

    colors = coloring()
    diff.drop(leave_out_carriers, axis=1, inplace=True)
    colors = [colors[col] for col in diff.columns]

    plot = diff.plot(kind='line', color=colors, use_index=False)
    plot.legend(loc='upper left', ncol=5, prop={'size': 8})
    x = []
    for i in range(0, len(diff)):
        x.append(i)
    plt.xticks(x, x)
    plot.set_xlabel('Timesteps')
    plot.set_ylabel('Difference in Generation in MW')
    plot.set_title('Difference in Generation')
    plt.tight_layout()

Response: Plot difference in generation between two networks grouped by carrier type and other non - renewable ones.


Instruction:
Can you generate the documentation for the following Python 3 function
def plot_voltage(network, boundaries=[]):

    x = np.array(network.buses['x'])
    y = np.array(network.buses['y'])

    alpha = np.array(network.buses_t.v_mag_pu.loc[network.snapshots[0]])

    fig, ax = plt.subplots(1, 1)
    fig.set_size_inches(6, 4)
    cmap = plt.cm.jet
    if not boundaries:
        plt.hexbin(x, y, C=alpha, cmap=cmap, gridsize=100)
        cb = plt.colorbar()
    elif boundaries:
        v = np.linspace(boundaries[0], boundaries[1], 101)
        norm = matplotlib.colors.BoundaryNorm(v, cmap.N)
        plt.hexbin(x, y, C=alpha, cmap=cmap, gridsize=100, norm=norm)
        cb = plt.colorbar(boundaries=v, ticks=v[0:101:10], norm=norm)
        cb.set_clim(vmin=boundaries[0], vmax=boundaries[1])
    cb.set_label('Voltage Magnitude per unit of v_nom')

    network.plot(
        ax=ax, line_widths=pd.Series(0.5, network.lines.index), bus_sizes=0)
    plt.show()

Response: Plot voltage at buses as hexbin


Instruction:
Write a Python 3 script to
plot the curtailment of the selected carrier.

Response:
def curtailment(network, carrier='solar', filename=None):
    """
    Plot curtailment of selected carrier

    Parameters
    ----------
    network : PyPSA network container
        Holds topology of grid including results from powerflow analysis
    carrier: str
        Plot curtailemt of this carrier
    filename: str or None
        Save figure in this direction

    Returns
    -------
    Plot
    """
    p_by_carrier = network.generators_t.p.groupby\
        (network.generators.carrier, axis=1).sum()
    capacity = network.generators.groupby("carrier").sum().at[carrier, "p_nom"]
    p_available = network.generators_t.p_max_pu.multiply(
            network.generators["p_nom"])
    p_available_by_carrier = p_available.groupby(
        network.generators.carrier, axis=1).sum()
    p_curtailed_by_carrier = p_available_by_carrier - p_by_carrier
    print(p_curtailed_by_carrier.sum())
    p_df = pd.DataFrame({carrier +
                         " available": p_available_by_carrier[carrier],
                         carrier +
                         " dispatched": p_by_carrier[carrier], carrier +
                         " curtailed": p_curtailed_by_carrier[carrier]})

    p_df[carrier + " capacity"] = capacity
    p_df[carrier + " curtailed"][p_df[carrier + " curtailed"] < 0.] = 0.

    fig, ax = plt.subplots(1, 1)
    fig.set_size_inches(12, 6)
    p_df[[carrier + " dispatched", carrier + " curtailed"]
         ].plot(kind="area", ax=ax, linewidth=3)
    p_df[[carrier + " available", carrier + " capacity"]
         ].plot(ax=ax, linewidth=3)

    ax.set_xlabel("")
    ax.set_ylabel("Power [MW]")
    ax.set_ylim([0, capacity * 1.1])
    ax.legend()
    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()


Instruction:
How would you explain what the following Python 3 function does
def storage_distribution(network, scaling=1, filename=None):

    stores = network.storage_units
    storage_distribution = network.storage_units.p_nom_opt[stores.index]\
            .groupby(network.storage_units.bus)\
            .sum().reindex(network.buses.index, fill_value=0.)

    fig, ax = plt.subplots(1, 1)
    fig.set_size_inches(6, 6)

    msd_max = storage_distribution.max()
    msd_median = storage_distribution[storage_distribution != 0].median()
    msd_min = storage_distribution[storage_distribution > 1].min()

    if msd_max != 0:
        LabelVal = int(log10(msd_max))
    else:
        LabelVal = 0
    if LabelVal < 0:
        LabelUnit = 'kW'
        msd_max, msd_median, msd_min = msd_max * \
            1000, msd_median * 1000, msd_min * 1000
        storage_distribution = storage_distribution * 1000
    elif LabelVal < 3:
        LabelUnit = 'MW'
    else:
        LabelUnit = 'GW'
        msd_max, msd_median, msd_min = msd_max / \
            1000, msd_median / 1000, msd_min / 1000
        storage_distribution = storage_distribution / 1000

    if sum(storage_distribution) == 0:
        network.plot(bus_sizes=0, ax=ax, title="No storages")
    else:
        network.plot(
            bus_sizes=storage_distribution * scaling,
            ax=ax,
            line_widths=0.3,
            title="Storage distribution")

    # Here we create a legend:
    # we'll plot empty lists with the desired size and label
    for area in [msd_max, msd_median, msd_min]:
        plt.scatter([], [], c='white', s=area * scaling,
                    label='= ' + str(round(area, 0)) + LabelUnit + ' ')
    plt.legend(scatterpoints=1, labelspacing=1, title='Storage size')

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()

Response: Plots storage distribution as circles on grid nodes.


Instruction:
Explain what the following Python 3 code does
def storage_expansion(network, basemap=True, scaling=1, filename=None):

    stores = network.storage_units[network.storage_units.carrier ==
                                   'extendable_storage']
    batteries = stores[stores.max_hours == 6]
    hydrogen = stores[stores.max_hours == 168]
    storage_distribution =\
        network.storage_units.p_nom_opt[stores.index].groupby(
        network.storage_units.bus).sum().reindex(
                network.buses.index, fill_value=0.)
    battery_distribution =\
        network.storage_units.p_nom_opt[batteries.index].groupby(
        network.storage_units.bus).sum().reindex(
                network.buses.index, fill_value=0.)
    hydrogen_distribution =\
        network.storage_units.p_nom_opt[hydrogen.index].groupby(
        network.storage_units.bus).sum().reindex(
                network.buses.index, fill_value=0.)

    sbatt = network.storage_units.index[
        (network.storage_units.p_nom_opt > 1) & (
                network.storage_units.capital_cost > 10) & (
                    network.storage_units.max_hours == 6)]
    shydr = network.storage_units.index[
        (network.storage_units.p_nom_opt > 1) & (
                network.storage_units.capital_cost > 10) & (
                    network.storage_units.max_hours == 168)]

    fig, ax = plt.subplots(1, 1)
    fig.set_size_inches(6, 6)

    msd_max = storage_distribution.max()
    msd_max_bat = battery_distribution.max()
    msd_max_hyd = hydrogen_distribution.max()

    if msd_max != 0:
        LabelVal = int(log10(msd_max))
    else:
        LabelVal = 0
    if LabelVal < 0:
        LabelUnit = 'kW'
        msd_max, msd_max_bat, msd_max_hyd = msd_max * \
            1000, msd_max_bat * 1000, msd_max_hyd * 1000
        battery_distribution = battery_distribution * 1000
        hydrogen_distribution = hydrogen_distribution * 1000
    elif LabelVal < 3:
        LabelUnit = 'MW'
    else:
        LabelUnit = 'GW'
        msd_max, msd_max_bat, msd_max_hyd = msd_max / \
            1000, msd_max_bat / 1000, msd_max_hyd / 1000
        battery_distribution = battery_distribution / 1000
        hydrogen_distribution = hydrogen_distribution / 1000

    if network.storage_units.p_nom_opt[sbatt].sum() < 1 and\
    network.storage_units.p_nom_opt[shydr].sum() < 1:
        print("No storage unit to plot")
    elif network.storage_units.p_nom_opt[sbatt].sum() > 1 and\
    network.storage_units.p_nom_opt[shydr].sum() < 1:
        network.plot(bus_sizes=battery_distribution * scaling,
                     bus_colors='orangered', ax=ax, line_widths=0.3)
    elif network.storage_units.p_nom_opt[sbatt].sum() < 1 and\
    network.storage_units.p_nom_opt[shydr].sum() > 1:
        network.plot(bus_sizes=hydrogen_distribution * scaling,
                     bus_colors='teal', ax=ax, line_widths=0.3)
    else:
        network.plot(bus_sizes=battery_distribution * scaling,
                     bus_colors='orangered', ax=ax, line_widths=0.3)
        network.plot(bus_sizes=hydrogen_distribution * scaling,
                     bus_colors='teal', ax=ax, line_widths=0.3)

    if basemap and basemap_present:
        x = network.buses["x"]
        y = network.buses["y"]
        x1 = min(x)
        x2 = max(x)
        y1 = min(y)
        y2 = max(y)

        bmap = Basemap(resolution='l', epsg=network.srid, llcrnrlat=y1, urcrnrlat=y2, llcrnrlon=x1, urcrnrlon=x2, ax=ax)
        bmap.drawcountries()
        bmap.drawcoastlines()

    if msd_max_hyd !=0:
        plt.scatter([], [], c='teal', s=msd_max_hyd * scaling,
                label='= ' + str(round(msd_max_hyd, 0)) + LabelUnit + ' hydrogen storage')
    if msd_max_bat !=0:
        plt.scatter([], [], c='orangered', s=msd_max_bat * scaling,
                label='= ' + str(round(msd_max_bat, 0)) + LabelUnit + ' battery storage')
    plt.legend(scatterpoints=1, labelspacing=1, title='Storage size and technology', borderpad=1.3, loc=2)
    ax.set_title("Storage expansion")

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()

    return

Response: Plots the storage expansion of the given network.


Instruction:
Implement a function in Python 3 to
generate the difference between two sets of nodes in the generation distribution.

Response:
def gen_dist_diff(
        networkA,
        networkB,
        techs=None,
        snapshot=0,
        n_cols=3,
        gen_size=0.2,
        filename=None,
        buscmap=plt.cm.jet):
    """
    Difference in generation distribution
    Green/Yellow/Red colors mean that the generation at a location
    is bigger with switches than without
    Blue colors mean that the generation at a location is smaller with switches
    than without

    Parameters
    ----------
    networkA : PyPSA network container
        Holds topology of grid with switches
        including results from powerflow analysis
    networkB : PyPSA network container
        Holds topology of grid without switches
        including results from powerflow analysis
    techs : dict
        type of technologies which shall be plotted
    snapshot : int
        snapshot
    n_cols : int
        number of columns of the plot
    gen_size : num
        size of generation bubbles at the buses
    filename : str
        Specify filename
        If not given, figure will be show directly
    """
    if techs is None:
        techs = networkA.generators.carrier.unique()
    else:
        techs = techs

    n_graphs = len(techs)
    n_cols = n_cols

    if n_graphs % n_cols == 0:
        n_rows = n_graphs // n_cols
    else:
        n_rows = n_graphs // n_cols + 1

    fig, axes = plt.subplots(nrows=n_rows, ncols=n_cols)

    size = 4

    fig.set_size_inches(size * n_cols, size * n_rows)

    for i, tech in enumerate(techs):
        i_row = i // n_cols
        i_col = i % n_cols

        ax = axes[i_row, i_col]

        gensA = networkA.generators[networkA.generators.carrier == tech]
        gensB = networkB.generators[networkB.generators.carrier == tech]

        gen_distribution =\
            networkA.generators_t.p.mul(networkA.snapshot_weightings, axis=0)\
            [gensA.index].loc[networkA.snapshots[snapshot]].groupby(
            networkA.generators.bus).sum().reindex(
            networkA.buses.index, fill_value=0.) -\
            networkB.generators_t.p.mul(networkB.snapshot_weightings, axis=0)\
            [gensB.index].loc[networkB.snapshots[snapshot]].groupby(
            networkB.generators.bus).sum().reindex(
            networkB.buses.index, fill_value=0.)

        networkA.plot(
            ax=ax,
            bus_sizes=gen_size * abs(gen_distribution),
            bus_colors=gen_distribution,
            line_widths=0.1,
            bus_cmap=buscmap)

        ax.set_title(tech)

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()


Instruction:
How would you explain what the following Python 3 function does
def gen_dist(
        network,
        techs=None,
        snapshot=1,
        n_cols=3,
        gen_size=0.2,
        filename=None):
    """
    Generation distribution

    Parameters
    ----------
    network : PyPSA network container
        Holds topology of grid including results from powerflow analysis
    techs : dict
        type of technologies which shall be plotted
    snapshot : int
        snapshot
    n_cols : int
        number of columns of the plot
    gen_size : num
        size of generation bubbles at the buses
    filename : str
        Specify filename
        If not given, figure will be show directly
    """
    if techs is None:
        techs = network.generators.carrier.unique()
    else:
        techs = techs

    n_graphs = len(techs)
    n_cols = n_cols

    if n_graphs % n_cols == 0:
        n_rows = n_graphs // n_cols
    else:
        n_rows = n_graphs // n_cols + 1

    fig, axes = plt.subplots(nrows=n_rows, ncols=n_cols)

    size = 4

    fig.set_size_inches(size * n_cols, size * n_rows)

    for i, tech in enumerate(techs):
        i_row = i // n_cols
        i_col = i % n_cols

        ax = axes[i_row, i_col]

        gens = network.generators[network.generators.carrier == tech]
        gen_distribution = network.generators_t.p.mul(network.
                snapshot_weightings, axis=0)\
                [gens.index].loc[network.snapshots[snapshot]].groupby(
                        network.generators.bus).sum().reindex(
                                network.buses.index, fill_value=0.)

        network.plot(
            ax=ax,
            bus_sizes=gen_size * gen_distribution,
            line_widths=0.1)

        ax.set_title(tech)
    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()

Response: Generate the distribution of the bus bubbles at a particular snapshot.


Instruction:
Can you generate the documentation for the following Python 3 function
def nodal_gen_dispatch(
        network,
        networkB=None,
        techs=['wind_onshore', 'solar'],
        item='energy',
        direction=None,
        scaling=1,
        filename=None):
    """
    Plot nodal dispatch or capacity. If networkB is given, difference in
    dispatch is plotted.

    Parameters
    ----------
    network : PyPSA network container
        Holds topology of grid including results from powerflow analysis
    networkB : PyPSA network container
        If given and item is 'energy', difference in dispatch between network
        and networkB is plotted. If item is 'capacity', networkB is ignored.
        default None
    techs : None or list,
        Techs to plot. If None, all techs are plotted.
        default ['wind_onshore', 'solar']
    item : str
        Specifies the plotted item. Options are 'energy' and 'capacity'.
        default 'energy'
    direction : str
        Only considered if networkB is given and item is 'energy'. Specifies
        the direction of change in dispatch between network and networkB.
        If 'positive', generation per tech which is higher in network than in
        networkB is plotted.
        If 'negative', generation per tech whcih is lower in network than
        in networkB is plotted.
        If 'absolute', total change per node is plotted.
        Green nodes have higher dispatch in network than in networkB.
        Red nodes have lower dispatch in network than in networkB.
        default None
    scaling : int
        Scaling to change plot sizes.
        default 1
    filename : path to folder
    """

    if techs:
        gens = network.generators[network.generators.carrier.isin(techs)]
    elif techs is None:
        gens = network.generators
        techs = gens.carrier.unique()
    if item == 'capacity':
        dispatch = gens.p_nom.groupby([network.generators.bus,
                                            network.generators.carrier]).sum()
    elif item == 'energy':
        if networkB:
            dispatch_network =\
                    network.generators_t.p[gens.index].mul(
                            network.snapshot_weightings, axis=0).groupby(
                    [network.generators.bus, network.generators.carrier],
                    axis=1).sum()
            dispatch_networkB =\
                    networkB.generators_t.p[gens.index].mul(
                            networkB.snapshot_weightings, axis=0).groupby(
                    [networkB.generators.bus, networkB.generators.carrier],
                    axis=1).sum()
            dispatch = dispatch_network - dispatch_networkB

            if direction == 'positive':
                dispatch = dispatch[dispatch > 0].fillna(0)
            elif direction == 'negative':
                dispatch = dispatch[dispatch < 0].fillna(0)
            elif direction == 'absolute':
                pass
            else:
                return('No valid direction given.')
            dispatch = dispatch.sum()

        elif networkB is None:
            dispatch =\
                    network.generators_t.p[gens.index].mul(
                            network.snapshot_weightings, axis=0).sum().groupby(
                    [network.generators.bus, network.generators.carrier]).sum()

    fig, ax = plt.subplots(1, 1)
    scaling = 1/(max(abs(dispatch.groupby(level=0).sum())))*scaling
    if direction != 'absolute':
        colors = coloring()
        subcolors = {a: colors[a] for a in techs}
        dispatch = dispatch.abs() + 1e-9
    else:
        dispatch = dispatch.sum(level=0)
        colors = {s[0]: 'green' if s[1] > 0 else 'red'
                  for s in dispatch.iteritems()}
        dispatch = dispatch.abs()
        subcolors = {'negative': 'red', 'positive': 'green'}

    network.plot(
            bus_sizes=dispatch * scaling,
            bus_colors=colors,
            line_widths=0.2,
            margin=0.01,
            ax=ax)

    fig.subplots_adjust(right=0.8)
    plt.subplots_adjust(wspace=0, hspace=0.001)

    patchList = []
    for key in subcolors:
        data_key = mpatches.Patch(color=subcolors[key], label=key)
        patchList.append(data_key)

    ax.legend(handles=patchList, loc='upper left')
    ax.autoscale()

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()

    return

Response: Plot nodal dispatch or capacity.


Instruction:
Can you generate the documentation for the following Python 3 function
def nodal_production_balance(
        network,
        snapshot='all',
        scaling=0.00001,
        filename=None):
    """
    Plots the nodal difference between generation and consumption.

    Parameters
    ----------
    network : PyPSA network container
        Holds topology of grid including results from powerflow analysis
    snapshot : int or 'all'
        Snapshot to plot.
        default 'all'
    scaling : int
        Scaling to change plot sizes.
        default 0.0001
    filename : path to folder

    """
    fig, ax = plt.subplots(1, 1)
    gen = network.generators_t.p.groupby(network.generators.bus, axis=1).sum()
    load = network.loads_t.p.groupby(network.loads.bus, axis=1).sum()

    if snapshot == 'all':
        diff = (gen - load).sum()
    else:
        timestep = network.snapshots[snapshot]
        diff = (gen - load).loc[timestep]

    colors = {s[0]: 'green' if s[1] > 0 else 'red'
                  for s in diff.iteritems()}
    subcolors = {'Net Consumer': 'red', 'Net Producer': 'green'}
    diff = diff.abs()
    network.plot(
            bus_sizes=diff * scaling,
            bus_colors=colors,
            line_widths=0.2,
            margin=0.01,
            ax=ax)

    patchList = []
    for key in subcolors:
        data_key = mpatches.Patch(color=subcolors[key], label=key)
        patchList.append(data_key)

    ax.legend(handles=patchList, loc='upper left')
    ax.autoscale()
    if filename:
        plt.savefig(filename)
        plt.close()

    return

Response: Plots the nodal difference between generation and consumption of a given node.


Instruction:
Here you have a function in Python 3, explain what it does
def storage_p_soc(network, mean='1H', filename = None):

    sbatt = network.storage_units.index[(network.storage_units.p_nom_opt > 1)
        & (network.storage_units.capital_cost > 10) &
        (network.storage_units.max_hours == 6)]
    shydr = network.storage_units.index[(network.storage_units.p_nom_opt > 1)
        & (network.storage_units.capital_cost > 10) &
        (network.storage_units.max_hours == 168)]

    cap_batt = (network.storage_units.max_hours[sbatt] *
                network.storage_units.p_nom_opt[sbatt]).sum()
    cap_hydr = (network.storage_units.max_hours[shydr] *
                network.storage_units.p_nom_opt[shydr]).sum()

    fig, ax = plt.subplots(1, 1)

    if network.storage_units.p_nom_opt[sbatt].sum() < 1 and \
        network.storage_units.p_nom_opt[shydr].sum() < 1:
        print("No storage unit to plot")

    elif network.storage_units.p_nom_opt[sbatt].sum() > 1 and \
        network.storage_units.p_nom_opt[shydr].sum() < 1:

        (network.storage_units_t.p[sbatt].resample(mean).mean().sum(axis=1) / \
         network.storage_units.p_nom_opt[sbatt].sum()).plot(
                 ax=ax, label="Battery dispatch", color='orangered')
        # instantiate a second axes that shares the same x-axis
        ax2 = ax.twinx()
        ((network.storage_units_t.state_of_charge[sbatt].resample(mean).\
          mean().sum(axis=1) / cap_batt)*100).plot(ax=ax2,
        label="Battery state of charge", color='blue')
    elif network.storage_units.p_nom_opt[sbatt].sum() < 1 and\
        network.storage_units.p_nom_opt[shydr].sum() > 1:
        (network.storage_units_t.p[shydr].resample(mean).mean().sum(axis=1) /\
         network.storage_units.p_nom_opt[shydr].sum()).plot(
                 ax=ax, label="Hydrogen dispatch", color='teal')
        # instantiate a second axes that shares the same x-axis
        ax2 = ax.twinx()
        ((network.storage_units_t.state_of_charge[shydr].resample(mean).\
          mean().sum(axis=1) / cap_hydr)*100).plot(
        ax=ax2, label="Hydrogen state of charge", color='green')
    else:
        (network.storage_units_t.p[sbatt].resample(mean).mean().sum(axis=1) / \
         network.storage_units.p_nom_opt[sbatt].sum()).plot(
                 ax=ax, label="Battery dispatch", color='orangered')

        (network.storage_units_t.p[shydr].resample(mean).mean().sum(axis=1) /\
         network.storage_units.p_nom_opt[shydr].sum()).plot(
                 ax=ax, label="Hydrogen dispatch", color='teal')
        # instantiate a second axes that shares the same x-axis
        ax2 = ax.twinx()
        ((network.storage_units_t.state_of_charge[shydr].resample(mean).\
          mean().sum(axis=1) / cap_hydr)*100).plot(
        ax=ax2, label="Hydrogen state of charge", color='green')

        ((network.storage_units_t.state_of_charge[sbatt].resample(mean).\
          mean().sum(axis=1) / cap_batt)*100).plot(
        ax=ax2, label="Battery state of charge", color='blue')

    ax.set_xlabel("")
    ax.set_ylabel("Storage dispatch in p.u. \n <- charge - discharge ->")
    ax2.set_ylabel("Storage state of charge in % ")
    ax2.set_ylim([0, 100])
    ax.set_ylim([-1,1])
    ax.legend(loc=2)
    ax2.legend(loc=1)
    ax.set_title("Storage dispatch and state of charge")

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename)
        plt.close()

    return

Response: Plots the dispatch and state of charge of extendable storages.


Instruction:
Create a Python 3 function for
plotting the soc of extendable storages in a sorted order.

Response:
def storage_soc_sorted(network, filename = None):
    """
    Plots the soc (state-pf-charge) of extendable storages

    Parameters
    ----------
    network : PyPSA network container
        Holds topology of grid including results from powerflow analysis

    filename : path to folder

    """
    sbatt = network.storage_units.index[(network.storage_units.p_nom_opt>1) &
                                    (network.storage_units.capital_cost>10) &
                                    (network.storage_units.max_hours==6)]
    shydr = network.storage_units.index[(network.storage_units.p_nom_opt>1) &
                                    (network.storage_units.capital_cost>10)
                                    & (network.storage_units.max_hours==168)]

    cap_batt = (network.storage_units.max_hours[sbatt] *
                network.storage_units.p_nom_opt[sbatt]).sum()
    cap_hydr = (network.storage_units.max_hours[shydr] *
                network.storage_units.p_nom_opt[shydr]).sum()

    fig, ax = plt.subplots(1, 1)

    if network.storage_units.p_nom_opt[sbatt].sum() < 1 and \
        network.storage_units.p_nom_opt[shydr].sum() < 1:
        print("No storage unit to plot")
    elif network.storage_units.p_nom_opt[sbatt].sum() > 1 and \
        network.storage_units.p_nom_opt[shydr].sum() < 1:
        (network.storage_units_t.p[sbatt].sum(axis=1).sort_values(
                ascending=False).reset_index() / \
        network.storage_units.p_nom_opt[sbatt].sum())[0].plot(
                ax=ax, label="Battery storage", color='orangered')
    elif network.storage_units.p_nom_opt[sbatt].sum() < 1 and \
        network.storage_units.p_nom_opt[shydr].sum() > 1:
        (network.storage_units_t.p[shydr].sum(axis=1).sort_values(
                ascending=False).reset_index() / \
        network.storage_units.p_nom_opt[shydr].sum())[0].plot(
                ax=ax, label="Hydrogen storage", color='teal')
    else:
        (network.storage_units_t.p[sbatt].sum(axis=1).sort_values(
                ascending=False).reset_index() / \
        network.storage_units.p_nom_opt[sbatt].sum())[0].plot(
                ax=ax, label="Battery storage", color='orangered')
        (network.storage_units_t.p[shydr].sum(axis=1).sort_values(
                ascending=False).reset_index() / \
        network.storage_units.p_nom_opt[shydr].sum())[0].plot(
                ax=ax, label="Hydrogen storage", color='teal')

    ax.set_xlabel("")
    ax.set_ylabel("Storage dispatch in p.u. \n <- charge - discharge ->")
    ax.set_ylim([-1.05,1.05])
    ax.legend()
    ax.set_title("Sorted duration curve of storage dispatch")

    if filename is None:
        plt.show()
    else:
        plt.savefig(filename,figsize=(3,4),bbox_inches='tight')
        plt.close()

    return


Instruction:
Can you generate the documentation for the following Python 3 function
def register(self):
        # logger.debug("StateMachineEditionChangeHistory register state_machine old/new sm_id %s/%s" %
        #              (self.__my_selected_sm_id, self.model.selected_state_machine_id))

        # relieve old models
        if self.__my_selected_sm_id is not None:  # no old models available
            self.relieve_model(self._selected_sm_model.history)

        if self.model.selected_state_machine_id is not None and global_gui_config.get_config_value('HISTORY_ENABLED'):

            # set own selected state machine id
            self.__my_selected_sm_id = self.model.selected_state_machine_id

            # observe new models
            self._selected_sm_model = self.model.state_machines[self.__my_selected_sm_id]
            if self._selected_sm_model.history:
                self.observe_model(self._selected_sm_model.history)
                self.update(None, None, None)
            else:
                logger.warning("The history is enabled but not generated {0}. {1}"
                               "".format(self._selected_sm_model.state_machine.state_machine_id,
                                         self._selected_sm_model.state_machine.file_system_path))
        else:
            if self.__my_selected_sm_id is not None:
                self.doing_update = True
                self.history_tree_store.clear()
                self.doing_update = False
            self.__my_selected_sm_id = None
            self._selected_sm_model = None

Response: Registers the state machine that is observed for new selected states to the selected state machine.


Instruction:
Can you implement a function in Python 3 that
registers callback methods for triggered actions

Response:
def register_actions(self, shortcut_manager):
        """Register callback methods for triggered actions

        :param rafcon.gui.shortcut_manager.ShortcutManager shortcut_manager:
        """
        shortcut_manager.add_callback_for_action("undo", self.undo)
        shortcut_manager.add_callback_for_action("redo", self.redo)


Instruction:
Implement a Python 3 function for
undoing for selected state - machine.

Response:
def undo(self, key_value, modifier_mask):
        """Undo for selected state-machine if no state-source-editor is open and focused in states-editor-controller.

        :return: True if a undo was performed, False if focus on source-editor.
        :rtype: bool
        """
        # TODO re-organize as request to controller which holds source-editor-view or any parent to it
        for key, tab in gui_singletons.main_window_controller.get_controller('states_editor_ctrl').tabs.items():
            if tab['controller'].get_controller('source_ctrl') is not None and \
                    react_to_event(self.view, tab['controller'].get_controller('source_ctrl').view.textview,
                                   (key_value, modifier_mask)) or \
                tab['controller'].get_controller('description_ctrl') is not None and \
                    react_to_event(self.view, tab['controller'].get_controller('description_ctrl').view.textview,
                                   (key_value, modifier_mask)):
                return False
        if self._selected_sm_model is not None:
            self._selected_sm_model.history.undo()
            return True
        else:
            logger.debug("Undo is not possible now as long as no state_machine is selected.")