I'm trying to use the libxlsxwriter C library but I'm struggling to make chartsheets on a new excel sheet (and not a basic chart on a sheet between formulas).
Any Ideas ? Even on how-to hardcode this ?
Edit
This is what I've done so far :
lxw_worksheet *ChartWorksheet = workbook_add_worksheet(workbook, "TTime");
lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_SCATTER);
lxw_chart_series *AutoWarmSerie = chart_add_series(chart, "", "");
chart_series_set_name(AutoWarmSerie, "AutoEchauff");
// fill the series
chart_series_set_categories(AutoWarmSerie, DataWorksheet->name, 4, Idx, 4 + m_AutoWarmTime.size(), m_DataColumnIdx); // Time
chart_series_set_values(AutoWarmSerie, DataWorksheet->name, 4, m_DataColumnIdx + 1, 4 + m_AutoWarmTime.size(), m_DataColumnIdx + 1); // Temperature
/* Add a chart title and some axis labels. */
chart_title_set_name(chart, "Results of sample analysis");
chart_axis_set_name(chart->x_axis, "Test number");
chart_axis_set_name(chart->y_axis, "Sample length (mm)");
/* Set an Excel chart style. */
chart_set_style(chart, 11);
/* Insert the chart into the worksheet. */
worksheet_insert_chart(ChartWorksheet, CELL("E2"), chart);
But I only get a single chart box on a sheet, and I dunno how to make the box a whole sheet, so...
Chartsheets aren't currently available in libxlsxwriter but they are a planned feature.
Update: Chartsheet support has been added to libxlsxwriter in version 0.8.0.
Related
I need to create a file containing information on crosselling for my webshop.
In my example file you'll see the tab "Basic Data", this is the data available to me already. Column A contains certain products, column B shows the assigned (product)categories.
The Tab "Starting Point" shows how the final file will be structured and how the function should come into play. It would need to do the following:
Copy the first product from the Unique product list (D2) to A2 (already done here)
Paste a filterfunction into B2 (already done here)
This filterfunction lists all products that belong to the same category like Product 1 except for Product 1 itself
Apply a numerical position tag in tens in Column C to the whole range of products related to Product 1 (in this case B2:B4), starting from 10 (..20, 30, ff) and optimally randomize it. (already done here)
Drag down A2, respectively paste "Product 1" into all cells below A2 until the end of the result of the filterfunction in Columns B is reached (already done here).
Continue the loop by pasting "Product 2" into A5, pasting the filterfunction into B5 and so on.
In "Desired Result" you can see how the end result should look like in this example. There are only 8 products, but I'd need to be able to do this for hundreds of products, that's why a function is needed.
I hope somebody is able to help me here.
Answer
You can get your desired result using Google Apps Script as I suggested.
How to use it:
Open Apps Script clicking on Tools > Script editor and you will see the script editor. It is based on JavaScript and it allows you to create, access, and modify Google Sheets files with a service called Spreadsheet Service.
Paste the following code and click on Run
Code
function main() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheetResult = ss.getSheetByName('Desired Result')
const sheetBasic = ss.getSheetByName('Basic Data')
// write unique products
const val = "=ARRAYFORMULA(UNIQUE('Basic Data'!A2:A))"
sheetResult.getRange('D2').setValue(val)
// get basic data
const lastColumn = sheetBasic.getRange('A:A').getValues().filter(String).length; // number of products
const cat = sheetBasic.getRange('A2:B'+lastColumn).getValues() // product | category
const productGroup = [] // array to store data
// loop each product
for (var j=0; j<cat.length; j++){
const p1 = cat[j]
var k = 1
for (var i=0; i<cat.length; i++){
if (cat[i][1] == p1[1] && cat[i][0] != p1[0]){
const val = [p1[0],cat[i][0],k*10]
k = k + 1
productGroup.push(val)
}
}
}
var n = productGroup.length+1
sheetResult.getRange('A2:C'+n).setValues(productGroup)
}
Some comments
This solution does not randomize the position value. If you need it I can help you with that, but first I want to check that this solution fits you.
Let me know if you can obtain your desired result. Keep in mind that this solution uses the name of the sheets.
Reference
Google Apps Script
Spreadsheet Service
JavaScript
I need to draw multiple matploblib chart using a for loop.
I have a data from with multiple column of data points and a time series 'year'. I need to create chart for each column.
I have the following code:
df=pd.DataFrame({'Time':['2014','2015','2016','2017','2018','2019'],
'A':[1,8,3,10,5,6],
'B':[2,3,5,2,3,5],
'C':[7,4,12,11,8,1],
'D':[3,4,2,2,7,7]})
x_pos=range(len(df['Time']))
m,c = np.polyfit(x_pos,df['A'],1)
plt.scatter(x=x_pos,y='A',data=df)
plt.plot(x_pos,m*x_pos+c,'--r')
any help is appreciated
I was able to figure it out. I used the matplotlib.gridspec to achieve this.
Following is the solution:
df=pd.DataFrame({'Time':['2014','2015','2016','2017','2018','2019'],
'A':[1,8,3,10,5,6],
'B':[2,3,5,2,3,5],
'C':[7,4,12,11,8,1],
'D':[3,4,2,2,7,7]})
#import gridspec to fit subplots
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(10,10))
# set grid size 2*2
ggpec = gridspec.GridSpec(2, 2)
getaxs = []
datacolumns = list(df[['A','B','C','D']])
for i,j in zip(datacolumns,range(1,len(datacolumns)+1)):
xpos=range(len(df['Time']))
getaxs.append(fig.add_subplot(ggpec[j - 1]))
m,c = np.polyfit(x_pos,df['A'],1)
getaxs[-1].scatter(x=xpos,y=i,data=df)
getaxs[-1].plot(x_pos,m*x_pos+c,'--r')
plt.show()
The final result will be something like following:
In a process of writing text to PDF, I'm using TextFragment for setting properties of various fields. Instead of setting for each field separately, how do make use of a loop?
My present code:
TextFragment a = new TextFragment("Hi!");
tf.setPosition(dropDown);
tf.getTextState().setFont(new FontRepository().findFont("Arial"));
tf.getTextState().setFontSize(10.0F);
.
.
.
TextFragment n = new TextFragment("n");
tf.setPosition(dropDown);
tf.getTextState().setFont(new FontRepository().findFont("Arial"));
tf.getTextState().setFontSize(10.0F);
I need something like this:
some loop {
.
.
TextFragment txtFrag = new TextFragment(A);
tf.setPosition(dropDown);
tf.getTextState().setFont(new FontRepository().findFont("Arial"));
tf.getTextState().setFontSize(10.0F);
} //This should set properties for all fields
The string in TextFragment("String") is not same for all the fields. It's different for various form fields.
You may simply add text fragments in your PDF file and once you finish adding text, you may get or set different properties for all the text fragments in a PDF file by using the code below:
// Load document
Document document = new Document( dataDir + "input.pdf");
// Create TextAbsorber object to extract all textFragments
TextFragmentAbsorber textFragmentAbsorber = new TextFragmentAbsorber();
// Accept the absorber for first page of document
document.getPages().accept(textFragmentAbsorber);
// Get the extracted text fragments into collection
TextFragmentCollection textFragmentCollection = textFragmentAbsorber.getTextFragments();
// Loop through the Text fragments
for (TextFragment textFragment : (Iterable<TextFragment>) textFragmentCollection) {
// Iterate through text fragments
System.out.println("Text :- " + textFragment.getText());
textFragment.getTextState().setFont(new FontRepository().findFont("Arial"));
textFragment.getTextState().setFontSize(10.0F);
System.out.println("Position :- " + textFragment.getPosition());
System.out.println("XIndent :- " + textFragment.getPosition().getXIndent());
System.out.println("YIndent :- " + textFragment.getPosition().getYIndent());
System.out.println("Font - Name :- " + textFragment.getTextState().getFont().getFontName());
}
// Save generated document
document.save(dataDir + "input_17.12.pdf");
You may visit Working with Text for more information on this. I hope this will be helpful. Please let us know if you need any further assistance.
I work with Aspose as Developer Evangelist.
I'm trying to create a script that will automatically format a selection based on the formatting of a table in another sheet. The idea is that a user can define a table style for header, rowOdd and rowEven in the Formats sheet, then easily apply it to a selected table using the script.
I've managed to get it working, but only by applying one type of formatting (background colour).
I based my code for reading the code into an array on this article.
As you will hopefully see from my code below, I am only able to read one formatting property into my array.
What I would like to do is read all formatting properties into the array, then apply them to the range in one go. I'm new to this so sorry if my code is a mess!
function formatTable() {
var activeRange = SpreadsheetApp.getActiveSpreadsheet().getActiveRange(); //range to apply formatting to
var arr = new Array(activeRange.getNumRows());
var tableStyleSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Formats"); //location of source styles
var tableColours = {
header: tableStyleSheet.getRange(1, 1, 1).getBackground(),
rowEven: tableStyleSheet.getRange(2, 1, 1).getBackground(),
rowOdd: tableStyleSheet.getRange(3, 1, 1).getBackground()
}
for (var x = 0; x < activeRange.getNumRows(); x++) {
arr[x] = new Array(activeRange.getNumColumns());
for (var y = 0; y < activeRange.getNumColumns(); y++) {
x == 0 ? arr[x][y] = tableColours.header :
x % 2 < 1 ? arr[x][y] = tableColours.rowOdd : arr[x][y] = tableColours.rowEven;
Logger.log(arr);
}
}
activeRange.setBackgrounds(arr);
}
Thanks!
I might be wrong but based from the list of methods given in Class Range, feature to save or store formatting details currently do not exist yet.
However, you may want to try using the following:
copyFormatToRange(gridId, column, columnEnd, row, rowEnd) or copyFormatToRange(sheet, column, columnEnd, row, rowEnd) wherein it copies the formatting of the range to the given location.
moveTo(target) wherein it cuts and paste (both format and values) from this range to the target range.
Did you know that you can get all of the different formatting elements for a range straight into an array?
E.g.
var backgrounds = sheet.getRange("A1:D50").getBackgrounds();
var fonts = sheet.getRange("A1:D50").getFontFamilies();
var fontcolors = sheet.getRange("A1:D50").getFontColors();
etc.
However, there's no way to get all of the formatting in one call unfortunately, so you have to handle each element separately. Then you can apply all of the formats in one go:
targetRng.setFontColors(fontcolors);
targetRng.setBackgrounds(backgrounds);
and so on.
Feeling I had not enough control over the chart if I had used a grouped column chart, I made my own version by just adding different series to the chart. After all the store, the number of series, their colors and such all need to be set dynamically and not hard coded. So basically this is what I have:
chart = Ext.create("Ext.chart.Chart", {
store: dataStore,
axes: dynamicAxes,
series: series
});
I leave out the not interesting stuff such as width, height of the chart etc.
now I have a method whichs returns a series object. This is added to the series array mentioned in the code above. The function has a "item" object parameter and also an idx param which is the index of the item object from the array it comes from, and a max param which is the size of the item array
the function returns something like this:
var w = (typeof (max) !== "undefined" && max !== null) ? this._getWidthByMax(max) : 30;
return {
type: "column",
axis = "left",
xField = "timestamp",
yField = item.id, // store field name equals the id of the item object
style = { stroke: colorCode, "stroke-width": (item.isDefault) ? 2 : 1, fill: colorCode },
width = w,
renderer = function (sprite, rec, attr, bix) {
var nx = idx * w;
return Ext.apply(attr, { translation: { x: nx} });
}
}
now this works fine for the number of columns I want to have. That can be one, two, three... up to seven currently.
However, if I want to hide a series, the following call doesn't work:
chart.series.getAt(idx).hideAll();
while it does work if I render my chart as a line chart.
is this a bug in Ext-js 4 or is it because of how I rendered the series for my column chart?
since nobody has replied to my question and I have found a solution in the meantime, I might as well answer my own question...
the problem occurred in Ext Js 4.0.7.
With version 4.1 RC 2 the hideAll behaved correctly.
So the solution, for anyone who would have the same problem, is to upgrade to 4.1 RC 2 or newer.