【问题标题】:Dynamically produced XLSXWriter charts in python - not referencingpython中动态生成的XLSXWriter图表-不引用
【发布时间】:2015-12-24 16:10:41
【问题描述】:

我正在使用我编写的以下类来尝试动态创建一个包含多个工作表的 Excel 文件,其中每个工作表中都有一个打印的数据框和一个柱形图。

与代码的交互(见下文)应该在您启动工作簿的地方起作用:

test = Workbook('Test Workbook')

然后,您可以添加任意数量的图表:

test.add_chart(df, 'Df Title', 1)
test.add_chart(df2, 'Df2 Title', 1)

然后你生成工作簿:

test.produce()

输入数据帧有标题。第一列是文本类别,后续列(数量不定)是小数形式的数据,以百分比形式绘制。

问题:该代码运行良好,并且似乎将所有工作表与图表分开生成,但某些图表显示为“未引用”,这意味着当我单击柱形图中的条形时,它不突出显示源数据。用代码生成的一些图表,DO引用得当,所以我不确定问题出在哪里,也没有明显的趋势。

import xlsxwriter
import pandas as pd

class Workbook:

def __init__(self, workbook_name):
    self.workbook_name = workbook_name

    self.workbook = xlsxwriter.Workbook(str(self.workbook_name) + '.xlsx')

    self.letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P']

def produce(self):
    self.workbook.close()
    print 'Created ' + str(self.workbook_name) + '.xlsx'

def print_frame(self, worksheet, dataframe, df_width, start_data_index):

    col_as_lists = []
    col_names = list(dataframe.columns.values)    

    # loops through columns in df and converts to list
    for n in range(0, df_width):
        col_n = dataframe[col_names[n]].tolist()

        # checks to see if column has numbers, if so -> convert to float!
        if n < start_data_index:
            col_n.insert(0, col_names[n])

        elif self.is_number(col_n[0]):
            convert = col_n[0:]
            convert = [float(x) for x in convert]
            convert.insert(0, col_names[n])
            col_n = convert
        else:
            col_n.insert(0, col_names[n])

        col_as_lists.append(col_n)

        # Prints each list into the worksheet.
        worksheet.write_column(self.letters[n] + '1', col_as_lists[n])

    #Formats numerical data as percentage
    percentformat = self.workbook.add_format({'num_format': '0%'})
    worksheet.set_column(self.letters[start_data_index] + ':' + self.letters[df_width], None, percentformat)


def add_chart(self, dataframe, tab_name, start_data_index):

    df_width = len(dataframe.columns)

    worksheet = self.workbook.add_worksheet(tab_name)
    self.print_frame(worksheet, dataframe, df_width, start_data_index)

    chart = self.workbook.add_chart({'type': 'column'})
    df_length = (len(dataframe.index))

    for n in range(start_data_index, df_width):

        chart.add_series({
            'name': '=' + tab_name +'!$' + self.letters[n] + '$1',
            'categories': '=' + tab_name +'!$' + self.letters[start_data_index - 1] + '$2:$'+ self.letters[start_data_index - 1] + '$' + str(df_length + 1),
            'values': '=' + tab_name +'!$' + self.letters[n] + '$2:$'+ self.letters[n] + '$' + str(df_length + 1),
            'fill': {'color': '#FFB11E'},
            'data_labels': {'value': True, 'center': True}
        })

    chart.set_title({'name': tab_name})
    chart.set_x_axis({'major_gridlines': {'visible': False}})
    chart.set_y_axis({'major_gridlines': {'visible': False}, 'max': .70})

    worksheet.insert_chart(self.letters[df_width + 2] + '2', chart)

    return

def is_number(self, s):
    """ Function used to help with detecting and converting floats 
    from string to number data types."""
    try:
        float(s)
        return True
    except ValueError:
        return False

【问题讨论】:

  • 看似“未引用”的图表:这些图表是否真的正确,除了当您单击它们时没有突出显示它们的源数据?您的某些工作表名称中是否包含空格,而有些则没有?
  • 哇,是的,这似乎是个问题!当我从工作表名称中删除空格时,所有图表都正确显示!关于您的问题,是的,除了参考问题和显示为小数而不是百分比的数据标签之外,图表显示正确。

标签: python excel xlsxwriter


【解决方案1】:

您的示例调用:

test.add_chart(df, 'Df Title', 1)
test.add_chart(df2, 'Df2 Title', 1)

建议您有时在名称中包含空格。当您尝试类似的操作时,这会导致引用损坏

'name': '=' + tab_name +'!$' + self.letters[n] + '$1',

评估结果为

'name': '=Df Title!$A$1',

(例如,当tab_name 等于'Df Title' 并且n 等于0)。

您应该仍然可以使用带空格的工作表引用,但用单引号括起来,例如

'name': "='Df Title'!$A$1",

所以一种更健壮的编码方式是

'name': "='" + tab_name +"'!$" + self.letters[n] + '$1',

我有点惊讶图表完全可以与损坏的工作表引用一起工作,但我自己并没有真正测试过图表,只是涉及工作表名称的普通单元格公式。

【讨论】:

    【解决方案2】:

    @John Y 是正确的,您没有在图表范围引用中正确引用工作表名称。

    您可以通过使用图表列表语法而不是字符串语法来避免这个问题以及从数字到单元格引用的手动转换:

    chart.add_series({
        'name':       ['Sheet1', 0, col],
        'categories': ['Sheet1', 1, 0,   max_row, 0],
        'values':     ['Sheet1', 1, col, max_row, col],
    })
    

    sn-p 来自this example in the XlsxWriter docs

    这也适用于代码中的其他几个地方。作为 XlsxWriter 中的一般规则,您可以(几乎)在任何可以使用 A1 语法的地方使用 row-column 语法:Working with Cell Notation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-19
      • 2019-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多