예제 #1
0
    def insert(self) -> None:
        """
        This is a standing barchart (bar goes up)
        """
        if DEBUG:
            print("Adding a column chart!")

        # Fix sizing
        size_w, size_h, dpi = utils.convert_plt_size(self.section)
        plt.figure(figsize=(size_w, size_h), dpi=dpi)

        data = self.section.contents
        objects = [i['name'] for i in data]

        y_axis = [i for i in range(len(objects))]
        x_axis = [i['data'][0] for i in data]

        colors = get_colors(self.section.layout, objects)

        rects = plt.bar(y_axis,
                        x_axis,
                        align='center',
                        alpha=DEFAULT_BAR_ALPHA,
                        width=DEFAULT_BAR_WIDTH,
                        color=colors)

        ax = plt.gca()
        remove_plot_borders(ax)

        # Fix the legend values to be "some_value (some_number)" instead of
        # just "some_value"
        ledgend_keys = [
            CHART_LABEL_NONE_STRING if i == '' else i for i in objects
        ]
        fixed_legends = [
            f'{v} ({x_axis[i]})' for i, v in enumerate(ledgend_keys)
        ]

        # Move legend
        legend_location = 'upper center'
        legend_location_relative_to_graph = (0.5, -0.35)
        a = ax.legend(rects,
                      fixed_legends,
                      loc=legend_location,
                      bbox_to_anchor=legend_location_relative_to_graph,
                      handlelength=0.7)

        self.section = change_legend_vertical_alignment(self.section, top=3)
        set_legend_style(a, self.section.layout[LEGEND_STYLE])

        ax.set_xlim(-len(objects), len(objects))

        set_axis_font(ax)
        plt.xticks(y_axis, objects)
        plt.title(self.section.extra['title'], **self.style['title'])

        plt_b64 = utils.plt_t0_b64(plt)

        s = Section('image', plt_b64, {}, {'should_shrink': True})
        image.invoke(self.cell_object, s)
예제 #2
0
    def insert(self):
        if DEBUG:
            print('Adding md (external) image...')

        url = self.section.extra['src']
        image_data = image_contents_from_url(url)
        img_section = Section('image', image_data, {}, {})
        image.invoke(self.cell_object, img_section)
예제 #3
0
    def insert(self):
        if DEBUG:
            print("Adding table...")

        table_data = self.section.contents
        if 'tableColumns' not in self.section.layout:
            return

        if 'readableHeaders' in self.section.layout:
            ordered = self.section.layout['tableColumns']
            readable_headers = self.section.layout['readableHeaders'].values()
            table_columns = fix_order(ordered, readable_headers)
        else:
            table_columns = self.section.layout['tableColumns']

        for i, header_text in enumerate(table_columns):
            if not isinstance(header_text, str):
                table_columns.remove(header_text)

        if 'title' in self.section.extra:
            table = self.cell_object.cell.add_table(rows=2,
                                                    cols=len(table_columns))
            title = table.cell(0, 0)
            title.merge(table.cell(0, len(table_columns) - 1))
            insert_text(title, self.section.extra['title'],
                        self.style['title'])

            hdr_cells = table.rows[1].cells
        else:
            table = self.cell_object.cell.add_table(rows=2,
                                                    cols=len(table_columns))
            hdr_cells = table.rows[0].cells

        table.style = DEFAULT_TABLE_STYLE

        if 'list_style' in self.section.extra and self.section.extra[
                'list_style']:
            table.style = None

        for i, header_text in enumerate(table_columns):
            insert_text(hdr_cells[i], header_text, self.style['text'])

        for r in table_data:
            row_cells = table.add_row().cells
            for i, header_text in enumerate(table_columns):
                if header_text not in r:
                    continue

                # Old json format can have 'Avatars', which are images
                if isinstance(r[header_text], dict) and \
                        r[header_text]['type'] == 'image':
                    row_temp = r[header_text]
                    s = Section(row_temp['type'], row_temp['data'], {}, {})
                    co = CellObject(row_cells[i], add_run=False)
                    image.invoke(co, s)
                else:
                    insert_text(row_cells[i], r[header_text],
                                self.style['text'])
예제 #4
0
    def add_header_logos(self):
        # Find the headers
        section = self.document.sections[0]
        section.header_distance = Pt(0)
        header = section.header
        table = header.add_table(rows=1, cols=2, width=Inches(24))
        table.alignment = WD_TABLE_ALIGNMENT.CENTER
        table.autofit = True

        left_cell = table.cell(0, 0)
        right_cell = table.cell(0, 1)

        # Add the left cell to the header
        left_image = CellObject(left_cell)
        left_cell.paragraphs[-1].alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
        left_cell.vertical_alignment = 1

        # Add the right cell to the header
        right_image = CellObject(right_cell)
        right_cell.paragraphs[-1].alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
        right_cell.vertical_alignment = 1

        # Add the main logo
        left_logo_b64 = self.options.get('demistoLogo', XSOAR_LOGO_BASE64)
        s = Section('image', left_logo_b64, {}, {})
        image.invoke(left_image, s)

        # Add the customer logo
        right_logo_b64 = self.options.get('customerLogo', False)
        if right_logo_b64:
            s = Section(
                'image',
                right_logo_b64,
                {},
                {
                    'max_size': {
                        'height':
                        MAX_CUSTOMER_LOGO_HEIGHT_INCH,  # max size in inches
                        'width': MAX_CUSTOMER_LOGO_WIDTH_INCH
                    }
                })
            image.invoke(right_image, s)
예제 #5
0
    def insert(self):
        if DEBUG:
            print('Adding pie chart: ...')
        size_w, size_h, dpi = utils.convert_plt_size(self.section)
        fig, ax = plt.subplots(figsize=(size_w, size_h), dpi=dpi,
                               subplot_kw=dict(aspect="equal"))

        data = [int(i['data'][0]) for i in self.section.contents]
        objects = [i['name'] for i in self.section.contents]

        # Fix the unassigned key:
        objects = [i if i != "" else "Unassigned" for i in objects]

        # Generate the default colors
        colors = get_colors(self.section.layout, objects)
        unassigned_color = 'darkgrey'

        # If we have predefined colors, use them
        if 'legend' in self.section.layout and self.section.layout['legend']:
            for i in self.section.layout['legend']:
                if 'color' in i:
                    colors.append(i['color'])
                elif 'fill' in i:
                    colors.append(i['fill'])

        color_keys = {}
        for i, k in enumerate(objects):
            color_keys[k] = colors[i]
            if k == 'Unassigned':
                color_keys['Unassigned'] = unassigned_color

        final_colors = [color_keys[k] for k in objects]

        wedges, texts = ax.pie(data,
                               colors=final_colors,
                               startangle=90, pctdistance=0.85,
                               textprops=dict(color="w"), radius=1)

        keys_with_numbers = ['{}: {}'.format(k, data[i]) for i, k in
                             enumerate(objects)]

        # legend_location_relative_to_graph = (1, 0, 0.5, 1)
        # legend_location = self.section.layout['legendStyle']
        legend_location = 'upper center'
        legend_location_relative_to_graph = (0.5, 0)

        legend = ax.legend(wedges, keys_with_numbers,
                           title="",
                           loc=legend_location,
                           bbox_to_anchor=legend_location_relative_to_graph,
                           handlelength=0.7
                           )
        set_legend_style(legend, self.section.layout[LEGEND_STYLE])
        set_axis_font(ax)
        ax.set_title(self.section.extra['title'], **self.style['title'])
        circle = plt.Circle((0, 0), 0.7, fc='white')
        ax.add_artist(circle)

        plt_b64 = utils.plt_t0_b64(plt)

        s = Section('image', plt_b64, {}, {'should_shrink': True})
        image.invoke(self.cell_object, s)
예제 #6
0
def insert_table_image(item, item_key, insertion_cell):
    row_temp = item[item_key]
    s = Section(row_temp['type'], row_temp['data'], {}, {})
    co = CellObject(insertion_cell, add_run=False)
    image.invoke(co, s)
예제 #7
0
    def insert(self):
        """
            This is a bar chart on the side (bar goes right)
        """

        if DEBUG:
            print("Adding a bar chart")

        # Fix sizing
        size_w, size_h, dpi = utils.convert_plt_size(self.section,
                                                     self.cell_object)
        plt.figure(figsize=(size_w, size_h), dpi=dpi)

        data = self.section.contents
        x_axis = None

        if any([True for i in data if 'groups' in i and i['groups']]):
            # Note for future maintainer, I really really... hate stacked
            # bar charts, it made this file look like hell. I hope you cope
            # with matplotlib's shitt* implementation.
            # May the force be with you :pray:

            # Create the stacks
            agg = []
            y_axis = [i['name'] for i in data]
            max_labels_stacked = []
            for v in data:
                names = [i['name'] for i in v['groups']]
                max_labels_stacked = list(set(max_labels_stacked) | set(names))

            labels = sorted(max_labels_stacked)
            colors = get_colors(self.section.layout, labels)

            for v in data:
                current_labels = {i['name']: i['data'][0] for i in v['groups']}
                cols = []
                for l in labels:
                    if l in current_labels:
                        cols.append(current_labels[l])
                    else:
                        cols.append(0)
                agg.append(cols)

            stacked = [i for i in zip(*agg)]

            # Draw each stack
            rects = [
                plt.barh(y_axis,
                         stacked[0],
                         DEFAULT_BAR_WIDTH,
                         color=colors.pop(0))
            ]

            for i in range(1, len(stacked)):
                left_padding = [sum(i) for i in zip(*stacked[:i])]
                rects.append(
                    plt.barh(y_axis,
                             stacked[i],
                             DEFAULT_BAR_WIDTH,
                             left=left_padding,
                             color=colors.pop(0)))

            ax = plt.gca()
            legend_location = 'upper center'
            legend_location_relative_to_graph = (0.5, -0.35)
            a = ax.legend(rects,
                          labels,
                          loc=legend_location,
                          bbox_to_anchor=legend_location_relative_to_graph,
                          handlelength=0.7)

        else:
            objects = [i['name'] for i in data]
            colors = get_colors(self.section.layout, objects)

            y_axis = [i for i in range(len(objects))]
            x_axis = [i['data'][0] for i in data]

            # Fix height of bar when only one present
            if len(objects) == 1:
                plt.margins(y=2)

            rects = plt.barh(y_axis,
                             width=x_axis,
                             align='center',
                             alpha=DEFAULT_BAR_ALPHA,
                             color=colors,
                             height=DEFAULT_BAR_WIDTH)

            # Fix the legend values to be "some_value (some_number)" instead of
            # just "some_value"
            ledgend_keys = [
                CHART_LABEL_NONE_STRING if i == '' else i for i in objects
            ]
            fixed_legends = [
                f'{v} ({x_axis[i]})' for i, v in enumerate(ledgend_keys)
            ]

            # Create and move the legend outside
            ax = plt.gca()
            legend_location = 'upper center'
            legend_location_relative_to_graph = (0.5, -0.35)

            a = ax.legend(rects,
                          fixed_legends,
                          loc=legend_location,
                          bbox_to_anchor=legend_location_relative_to_graph,
                          handlelength=0.7)

            ax.set_yticklabels([])

        # Style the axis and labels
        self.section = change_legend_vertical_alignment(self.section, top=1)
        set_legend_style(a, self.section.layout[LEGEND_STYLE])

        # Fix the axises
        set_axis_font(ax)
        ax.set_yticks(y_axis)
        ax.set_xlabel('')
        ax.invert_yaxis()  # labels read top-to-bottom

        # Fix the xaxis ratio to fit biggest element
        if x_axis:
            ax.set_xlim(0, max(x_axis) + X_AXIS_PADDING)

        # Remove the bottom labels
        remove_plot_borders(ax)
        plt.tick_params(bottom='off')
        plt.title(self.section.extra['title'], **self.style['title'])

        plt_b64 = utils.plt_t0_b64(plt, (size_w, size_h), dpi)

        s = Section('image', plt_b64, {}, {'should_shrink': True})
        image.invoke(self.cell_object, s)
예제 #8
0
    def insert(self):
        if DEBUG:
            print("Adding line chart...")

            # Fix sizing
        size_w, size_h, dpi = utils.convert_plt_size(self.section,
                                                     self.cell_object)
        figure(num=2, figsize=(size_w, size_h), dpi=dpi,
               constrained_layout=False)

        data = self.section.contents

        fix_data(data)

        # Make the groups look like:
        # groups = {
        #   'Type A': {
        #       dates: ['2000', '2001', '2002']
        #       values: ['1', '2', '3']
        #    }
        #   'Type B': {
        #         dates: ['2000', '2001', '2002'],
        #         values : ['4', '5', '6']
        # }
        groups = fix_data(data)

        # Fix empty key
        if '' in groups.keys():
            groups['None'] = groups.pop('')

        # Generate the default colors
        colors = get_colors(self.section.layout, groups.keys())
        unassigned_color = 'darkgrey'

        # If we have predefined colors, use them
        if 'legend' in self.section.layout and self.section.layout['legend']:
            for i in self.section.layout['legend']:
                if 'color' in i:
                    colors.append(i['color'])
                elif 'fill' in i:
                    colors.append(i['fill'])

        color_keys = {}
        for i, k in enumerate(groups.keys()):
            color_keys[k] = colors[i]
            if k == 'Unassigned':
                color_keys['Unassigned'] = unassigned_color

        final_colors = {k: color_keys[k] for k in groups.keys()}

        # Plot the lines
        for group, line in groups.items():
            x_axis = line['dates']
            y_axis = line['values']
            plt.plot(x_axis, y_axis, marker='', color=final_colors[group],
                     linewidth=2)

        # Create and move the legend outside
        ax = plt.gca()

        # Auto rotate the labels
        remove_plot_borders(ax)
        legend_location = 'upper center'
        legend_location_relative_to_graph = (0.5, -0.35)

        handles = [plt.Rectangle((0, 0), 1, 1, fc=final_colors[i]) for i in
                   groups.keys()]

        legend = ax.legend(handles, [i for i in groups.keys()],
                           loc=legend_location,
                           bbox_to_anchor=legend_location_relative_to_graph,
                           handlelength=0.7, handleheight=0.7, ncol=2)

        self.section = change_legend_vertical_alignment(self.section, top=1)

        # Set max ticks in xaxis to be MAX_AXIS_LABELS
        set_legend_max_count(ax, self.cell_object)

        set_legend_style(legend, self.section.layout[LEGEND_STYLE])
        set_axis_font(ax)
        ax.set_title(self.section.extra['title'], **self.style['title'])

        # Add to docx as image
        plt_b64 = utils.plt_t0_b64(plt, (size_w, size_h), dpi)
        s = Section('image', plt_b64, {}, {'should_shrink': True})
        image.invoke(self.cell_object, s)
예제 #9
0
    def insert(self):
        if DEBUG:
            print("Adding table...")

        table_data = self.section.contents

        if isinstance(table_data, dict):
            table_data = table_data.get('data', table_data)

        if 'tableColumns' not in self.section.layout:
            # Quick dirty fix for test - will be refactored in upcoming PR
            self.section.layout['tableColumns'] = list(table_data[0].keys())

        # Fix new lists
        if isinstance(table_data, dict):
            wrapper_table = self.cell_object.cell.add_table(
                rows=2, cols=len(table_data.keys()))
            i = 0

            # Add the wrapping headers
            for wrapper_header, table_contents in table_data.items():
                hdr = wrapper_table.cell(0, i)
                insert_text(hdr, wrapper_header, self.style['title'])
                body = wrapper_table.cell(1, i)
                c = CellObject(body)
                # Hacky but will do the job
                invoke(c, Section('table', table_contents, {}, {}))
                i += 1
            return

        if 'readableHeaders' in self.section.layout:
            ordered = self.section.layout['tableColumns']
            readable_headers = self.section.layout['readableHeaders']
            table_columns = fix_order(ordered, readable_headers)
        else:
            table_columns = self.section.layout['tableColumns']

        # Quick fix, word crashes on more than 64 columns.
        # See: https://stackoverflow.com/questions/36921010/docx-does-not-support-more-than-63-columns-in-a-table
        table_columns = table_columns[0:63]

        for i, header_text in enumerate(table_columns):
            if not isinstance(header_text, str):
                table_columns.remove(header_text)

        if 'title' in self.section.extra:
            table = self.cell_object.cell.add_table(rows=2,
                                                    cols=len(table_columns))
            title = table.cell(0, 0)
            title.merge(table.cell(0, len(table_columns) - 1))
            insert_text(title, self.section.extra['title'],
                        self.style['title'])

            hdr_cells = table.rows[1].cells
        else:
            table = self.cell_object.cell.add_table(rows=2,
                                                    cols=len(table_columns))
            hdr_cells = table.rows[0].cells

        table.style = DEFAULT_TABLE_STYLE

        if 'list_style' in self.section.extra and self.section.extra[
                'list_style']:
            table.style = None

        for i, header_text in enumerate(table_columns):
            insert_text(hdr_cells[i], header_text, self.style['text'])

        if len(table_columns) > 63:
            # TODO: add error.
            pass

        for r in table_data:
            row_cells = table.add_row().cells
            for i, header_text in enumerate(table_columns):
                if header_text not in r:
                    continue

                # Old json format can have 'Avatars', which are images
                if isinstance(r[header_text], dict) and \
                        r[header_text]['type'] == 'image':
                    row_temp = r[header_text]
                    s = Section(row_temp['type'], row_temp['data'], {}, {})
                    co = CellObject(row_cells[i], add_run=False)
                    image.invoke(co, s)
                else:
                    insert_text(row_cells[i], r[header_text],
                                self.style['text'])