Using Python and xlsxwriter to concatenate cell references with cell count - python

Hi I have a working script to generate a line chart using Xlsxwriter, however I am looking for a way to concatenate an earlier hit count with the cell range for my generated chart as the script is used to iterate over several similar files in the directory so the overall 'hit count' varies for each file.
The script first looks through a text file for a string and collects some stats using line spitting drops the collected figures into Excel and and generates a hit count each time the particular string is found (total)
Then charts are generated using thee collected stats..
Here's my chart generating section...
chart1 = workbook.add_chart({'type': 'line'})
chart1.add_series({
'name': 'My Chart',
'categories': '=Sheet1!$A$2:$A$2200',
'values': '=Sheet1!$B$2:$B$2200',
'line': {'color': 'purple'},
})
I am hoping to generate the chart by referencing the 'total' count in the row count. So I am looking for something along the lines of
'categories': '=Sheet1!$A$2:$A$'+total,
'values': '=Sheet1!$B$2:$B$'+total,
I hope this makes sense? Basically I am looking to have a varying cell row range dependent on the count of hits, is this possible? Or alternatively is there a 'last row' reference in xlsxwriter for this type of circumstance?
Thanks,
MikG

The chart.add_series() method also accepts a list of values so you can do something like this:
chart1.add_series({
'name': 'My Chart',
'categories': ['Sheet1', 1, 0, total -1, 0],
'values': ['Sheet1', 1, 1, total -1, 1],
'line': {'color': 'purple'},
})

Related

Scrap data from multiple categories

I am scraping a product at softsurroundings.com
This is the product link: https://www.softsurroundings.com/p/estelle-dress/
This product has 3 types of size categories["Misses","Petites","Women"]. Each size category has furthur sizes. i.e.
for "Misses" we has ["XS","S","M","L","XL"]
for "Petites" we has ["PXS","PS","PM","PL","PXL"]
for "Women" we has ["1X","2X","3X"]
I am confused on the css to get the sizes of all three categories.
I get the size of only Misses category because when website loads only Misses category shows
The current code I have is
raw_skus = []
for sku_sel in response.css('.dtlFormBulk.flexItem .size[class="box size"]'):
sku = {
'sku_id': sku_sel.css('.size ::attr(id)').get(),
'size': sku_sel.css('.size ::text').get()
}
raw_skus.append(sku)
return raw_skus
the above code returns me
[
{'sku_id': 'size_501', 'size': 'XS'},
{'sku_id': 'size_601', 'size': 'S'},
{'sku_id': 'size_701', 'size': 'M'},
{'sku_id': 'size_801', 'size': 'L'},
{'sku_id': 'size_901', 'size': 'XL'}
]
I am only getting sizes from Misses category I need sizes from other two categories appended in the list too.
Please help.

How can one update the secondary Y-axis of a Plotly chart through an update menu

I'm looking for what the keyword is to update the secondary axis label in a Plotly chart using buttons and an updatemenu. Everything else is working like I want. The button setup code is below. The goal is to change the left and right y variables the using information from the DataFrame. The data, primary axis and both legend names changed as desired but I can't find an option to replace my made up 'secondary_axis' keyword when making the right buttons.
# above here make subplots, add traces, etc.
left_buttons = []
for option in axis_options:
left_buttons.append({'method': 'update',
'label': option,
'args': [{'y': [df[option]], 'name': [option]}, {'yaxis': {'title': option}}, [0]]})
right_buttons = []
for option in axis_options:
right_buttons.append({'method': 'update',
'label': option,
'args': [{'y': [df[option]], 'name': [option]}, {'secondary_yaxis': {'title': option}}, [1]]})
# figure.update_layout(...
Figured it out eventually, I'm assuming that the 2 suffix goes with the trace number but I couldn't confirm that with any documentation yet. I needed to add the overlaying and side parameters to get it where I wanted it to go. Got some weird overlaps and missing data otherwise.
# above here make subplots, add traces, etc.
left_buttons = []
for option in axis_options:
left_buttons.append({'method': 'update',
'label': option,
'args': [{'y': [df[option]],
'name': [option]},
{'yaxis': {'title': option}},
[0]]
})
right_buttons = []
for option in axis_options:
right_buttons.append({'method': 'update',
'label': option,
'args': [{'y': [df[option]],
'name': [option]},
{'yaxis2': {'title': option, 'overlaying': 'y', 'side': 'right'}},
[1]]
})
# figure.update_layout(...

Returning an empty dictionary for the datasource of a datatable in plotly/dash

My callback function reads a value selected by the user (site name) and then queries data for that site and returns 3 figures and one dictionary (df.to_dict('records') to supply the data for a datatable.
If the user selects a site for which there is no data, I return {}. That seems to break it. If I select a site, the data table fills in properly, switch to another site, same thing. Once I select a site with no data, the data table will no longer update, no matter which site I select.
Some relevant code:
The output is defined as:
Output('emission_table','data'),
The return from the callback is:
return time_series_figure,emissions_df.to_dict('records'),site_map,hotspot_figure
html.Div(style={'float':'left','padding':'5px','width':'49%'}, children = [
dash_table.DataTable(id='emission_table', data=[],columns=[
# {'id': "site", 'name': "Site"},
{'id': "dateformatted", 'name': "date"},
{'id': "device", 'name': "device"},
{'id': "emission", 'name': "Emission"},
{'id': "methane", 'name': "CH4"},
{'id': "wdir", 'name': "WDIR"},
{'id': "wspd", 'name': "WSPD"},
{'id': "wd_std", 'name': "WVAR"}],
# {'id': "url", 'name':'(Link for Google Maps)','presentation':'markdown'}],
fixed_rows={'headers': True},
row_selectable='multi',
style_table={'height': '500px', 'overflowY': 'auto'},
style_cell={'textAlign': 'left'})
]),
Any ideas what is happening? Is there a better way for the callback to return an empty data source for the datatable?
Thanks!
You haven't shared enough of your code (your callback specifically) to see what is happening exactly, however:
If the user selects a site for which there is no data, I return {}
is at least one reason why it doesn't work. The data property of a Dash Datatable needs to be a list and not a dictionary. You can however put dictionaries inside the list. Each dictionary inside the list corresponds to a row in the Data Table.
So to re-iterate and more directly answer your question:
Is there a better way for the callback to return an empty data source for the datatable?
Yes you can return a list with any number of dictionaries inside.

xlsxwriter chart create dynamic rows

I'm trying to create charts with xlsxwriter python module.
It works fine, but I would like to not have to hard code the row amount
This example will chart 30 rows.
chart.add_series({
'name': 'SNR of old AP',
'values': '=Depart!$D$2:$D$30',
'marker': {'type': 'circle'},
'data_labels': {'value': True,'num_format':'#,##0'},
})
For values': I would like the row count to be dynamic. How do I do this?
Thanks.
It works fine, but I would like to not have to hard code the row amount
XlsxWriter supports a list syntax in add_series() for this exact case. So your example could be written as:
chart.add_series({
'name': 'SNR of old AP',
'values': ['Depart', 1, 3, 29, 3],
'marker': {'type': 'circle'},
'data_labels': {'value': True, 'num_format':'#,##0'},
})
And then you can set any of the first_row, first_col, last_row, last_col parameters programmatically.
See the docs for add_series().

xlswriter formatting a range

In xlswriter, once a format is defined, how can you apply it to a range and not to the whole column or the whole row?
for example:
perc_fmt = workbook.add_format({'num_format': '0.00%','align': 'center'})
worksheet.set_column('B:B', 10.00, perc_fmt)
this gets applied it to the whole "B" column, but how can this "perc_fmt" applied to a range, for example, if I do:
range2 = "B2:C15"
worksheet2.write(range2, perc_fmt)
it says:
TypeError: Unsupported type <class 'xlsxwriter.format.Format'> in write()
Actually I found a workaround that avoids doing the loop.
You just need to use the conditional formatting (that takes a range as an input) and just format all cases. For example:
worksheet2.conditional_format(color_range2, {'type': 'cell',
'criteria': '>=',
'value': 0, 'format': perc_fmt})
worksheet2.conditional_format(color_range2, {'type': 'cell',
'criteria': '<',
'value': 0, 'format': perc_fmt})
In xlswriter, once a format is defined, how can you apply it to a range and not to the whole column or the whole row?
There isn't a helper function to do this. You will need to loop over the range and apply the data and formatting to each cell.
It took me quite a time to find this answer, so thank you. I would offer up the additional solution with just one block when your range includes blanks and text fields. This turns the range A2:N5 to my format of peach coloring I defined earlier in my code. Of course you have to make the number more negative if you actually have large negative numbers in your dataset.
worksheet.conditional_format('A2:N5', {'type': 'cell',
'criteria' : '>',
'value' : -99999999999,
'format' : peach_format})
I originally tried 'criteria' : '<>', 'value' : 0 but that did not catch the blank cells. If you use the < 99999999999 it would code the text fields as False and would not code them.
you can use:
{
'type': 'cell',
'criteria': 'between',
'minimum': -10000,
'maximum': 10000,
'format': perc_fmt
}
This will save you one line of code

Categories

Resources