Changing table column width using Google-Slide-API and python - python-3.x

I have a Spreadsheet document and by using Google-Sheet-API I'm fetching the data from it. Then by using Google-Slide-API I'm creating a Slide document with 'n' slides. On each slide I'm creating a 2-column table with 'n' rows. Every first column on every slide always contains data from the Spreadsheet's A column. The second columns contain data from the other Spreadsheet's columns (from B to 'n'). Then I'm changing the text size. So far so good.
Now, when I try to adjust the columns width of each table on each slide it doesn't do anything which is an issue because some tables contain more information and therefore the tables don't fit the slide. This is the part of the code that doesn't work:
for i in range(number_of_slides):
regs = [
{'updateTableColumnProperties': {
'objectId': tableID[i],
'columnIndices': [j],
'tableColumnProperties': {
'columnWidth': {'magnitude': mag[j], 'unit': 'PT'}
},
'fields': 'columnWidth'
}
} for j in range(2) ]
SLIDES.presentations().batchUpdate(body={'requests': reqs},
presentationId=deckID).execute()
The tables always remain the same with or without this part so it doesn't have any affect whatsoever. The code doesn't return any errors or messages.

I believe your goal as follows.
You have a Google Slides.
The Google Slides has the several slides, each slide has a table which has 2 columns.
You want to change the column width of 2 columns.
You want to achieve this using googleapis for python.
You have already been able to use the batchUpdate method using Google Slides API.
Modification points:
I think that your request body is correct. But, I would like to propose one modification point. In your script, batchUpdate method is used in a loop. I think that when batchUpdate is used, updateTableColumnProperties for all slides in a Google Slides can be run by one API call.
Although I'm not sure about your values of mag and your whole script, as a sample script for achieving your above goal, how about the following modified script? If this helped you to understand Slides API, I'm glad.
Modified script:
About creds, please use your authorization script. Also, you can see it at Quickstart for python.
service = build('slides', 'v1', credentials=creds)
PRESENTATION_ID = '###' # Please set Google Slides ID.
magnitude = [100, 300] # Please set the widths for the columns A and B in each table. In this sample, 100 and 300 PT are set.
# 1. Retrieve an object for each slides.
presentation = service.presentations().get(presentationId=PRESENTATION_ID).execute()
# 2. Create a request body for the batchUpdate method.
slides = presentation.get('slides')
requests = []
for slide in slides:
pe = slide.get('pageElements')
if pe:
for pageElement in pe:
t = pageElement.get('table')
if t:
for i, m in enumerate(magnitude):
requests.append({
'updateTableColumnProperties': {
'objectId': pageElement['objectId'],
'columnIndices': [i],
'tableColumnProperties': {
'columnWidth': {'magnitude': m, 'unit': 'PT'}
},
'fields': 'columnWidth'
}
})
# 3. Request the request body.
service.presentations().batchUpdate(body={'requests': requests}, presentationId=PRESENTATION_ID).execute()
Note:
When above script is run, the widths of columns "A" and "B" of the table in each slide are modified. In this sample script, 100 and 300 PT are set for the columns "A" and "B", respectively. About this, please modify for your actual situation.
References:
Method: presentations.get
Method: presentations.batchUpdate
UpdateTableColumnPropertiesRequest

Related

Interactive labeling of images in jupyter notebook

I have a list of pictures:
pictures = {im1,im2,im3,im4,im5,im6}
Where
im1:
im2:
im3:
im4:
im5:
im6:
I want to assign the pictures to labels (1,2,3,4 etc.)
For instance, here pictures 1 to 3 belong to label 1, picture 4 belongs to label 2, picture 5 to label 3, and picture 6 to label 4.
-> label = {1,1,1,2,3,4}
Since I need to see the images when I label them, I need a method to do that while labeling them. I was thinking of creating an array of images:
And then I define the ranges by clicking on the first and last picture belonging to the same labels, so for example:
What do you think ? Is this somehow possible ?
I would like to assign different labels to different ranges of pictures.
For instance: When one has finished selecting the first label one could indicate it by a Double-click and then do the selection of the second label range, then Double-click, then do the selection of the third label range, then Double-click, then do the selection of the fourth label range, etc.
It does not have to be Double-clicking to change the selection of the labels, it could also just be a buttom or any other idea that you might have.
In the end one should have the list of labels.
Essentially, most of the interaction you are looking for boils down to being able to display images, and detect clicks on them in real time. As that is the case, you can use the jupyter widgets (aka ipywidgets) module to achieve most (if not all) of what you are looking for.
Take a look at the button widget which is described here with explanation on how to register to its click event. The problem - we can't display an image on a button, and I didn't find any way to do this within the ipywidgets documentation. There is an image widget, but it does not provide an on_click event. So construct a custom layout, with a button underneath each image:
COLS = 4
ROWS = 2
IMAGES = ...
IMG_WIDTH = 200
IMG_HEIGHT = 200
def on_click(index):
print('Image %d clicked' % index)
import ipywidgets as widgets
import functools
rows = []
for row in range(ROWS):
cols = []
for col in range(COLS):
index = row * COLS + col
image = widgets.Image(
value=IMAGES[index], width=IMG_WIDTH, height=IMG_HEIGHT
)
button = widgets.Button(description='Image %d' % index)
# Bind the click event to the on_click function, with our index as argument
button.on_click(functools.partial(on_click, index))
# Create a vertical layout box, image above the button
box = widgets.VBox([image, button])
cols.append(box)
# Create a horizontal layout box, grouping all the columns together
rows.append(widgets.HBox(cols))
# Create a vertical layout box, grouping all the rows together
result = widgets.VBox(rows)
You can technically also write a custom widget to display an image and listen for a click, but I simply don't believe it's worth your time and effort.
Good luck!
The qsl package provides widgets that do this. For your case, the following code would allow you to label images in batches. Full disclosure, qsl is a project I started because I, like you, wanted to label images from inside Jupyter notebooks.
import qsl
from IPython.display import display
labeler = qsl.MediaLabeler(
items=[
{"target": "https://i.stack.imgur.com/cML6z.jpg"},
{"target": "https://i.stack.imgur.com/6EVAP.jpg"},
{"target": "https://i.stack.imgur.com/CAxUw.jpg"},
{"target": "https://i.stack.imgur.com/8fhan.jpg"},
{"target": "https://i.stack.imgur.com/eMXn5.jpg"},
{"target": "https://i.stack.imgur.com/YFBfM.jpg"}
],
# Optional, you can also configure the labeler from
# the UI.
config={
"image": [
{
"name": "Type",
"options": [
{"name": "Foo"},
{"name": "Bar"}
]
}
]
},
# Optional, set to 1 if you want to label
# one image at a time.
batch_size=4,
# Optionally, save labels to JSON. You
# can also get the labels using `labeler.items`.
jsonpath="labels.json"
)
display(labeler)
This generates a UI that looks like this.
Here is a Google Colab notebook that shows how to do this in Google Colab.

Python Docx Table row height

So column width is done using cell width on all cells in one column ike this:
from docx import Document
from docx.shared import Cm
file = /path/to/file/
doc = Document(file)
table = doc.add_table(4,2)
for cell in table.columns[0].cells:
cell.width = Cm(1.85)
however, the row height is done using rows, but I can't remember how I did it last week.
Now I managed to find a way to reference the rows in a table, but can't seem to get back to that way. It is possible to change the height by using the add_row method, but you can't create a table with no rows, so the the top row will always be the default height, which about 1.6cms.
There is a way to access paragraphs without using add_paragraph, does anyone know how to access the rows without using the add_row method because it was that that I used to set row height in a table as a default.
I have tried this but it doesn't work:
row = table.rows
row.height = Cm(0.7)
but although this does not give an error, it also has no effect on the height.
table.rows is a collection, in particular a sequence, so you need to access each row separately:
for row in table.rows:
row.height = Cm(0.7)
Also check out row.height_rule for some related behaviors you have access to:
https://python-docx.readthedocs.io/en/latest/api/table.html#row-objects
When you assign to table.rows.height, it just adds a .height instance attribute that does nothing. It's one of the side-effects of a dynamic language like Python that you encounter a mysterious behavior like this. It goes away as you gain more experience though, at least it has for me :)
Some additional information:
The answer here is correct, but this will give a minimum row height. Using WD_ROW_HEIGHT_RULE.EXACTLY will fix the cell height to the set row height ignoring the contents of the cell, this can result in cropping of the text in an undesirable way.
para = table.cell(0,0).add_paragrph('some text')
SOLUTION:
add_paragraph actually adds a blank line above the text.
Use the following instead to avoid using add_paragraph:
table.cell(0,0).paragraphs[0].text = 'some text'
or using add_run can make it easier to also work with the text:
run = table.cell(0,0).paragraphs[0].add_run('some text')
run.bold = True

Excel - two graphs in one (side by side)

I have two graphs in Excel, but I want to merge the charts into one graph. As you can see, I have reduced the size of the chart in graph1 and I want to move the chart in the graph2 into the empty space in graph1
I think there are many ways to do this in basic excel like jrichall showed you but If you are willing to use an excel add-in to create this double chart, you could try FunFun.
It allow you to code javascript in excel, merging two charts in one is pretty easy in programming languages such as javascript.
Here is a working code I have written for you:
https://www.funfun.io/1/#/edit/5a3d0933b848f771fbcdec96
As you can see, I use a Json file to acquire the data used in the spreadsheet. Once the data is "stored", I can use it with javascript and create my charts.
I use Chart.js library to create those two charts, I basically copied this code twice to get two chart (I just changed the data and the word "bar" by "line"):
var barChart = new Chart(ctx, {
type: "bar",
data: {
// x axis represented by labels
labels: [1, 2, 3, 4, 5, 6],
datasets: dataset
},
options: {
legend: {
display: false
},
scales: {
yAxes: [
{
ticks: {
min: 0,
max: 10
}
}
]
}
},
animation: false
});
The documentation of Chart.js is pretty good and has a lot of examples for different type of charts.
Once you are satisfied with your chart, you can load it in excel by pasting the URL in the Funfun add-in. Here is how it looks like:
I used a css file to correctly align the title (.label).
Disclosure : I’m a developer of funfun
I think a little more info would help. How is your data set up? Are you using pivot tables / pivot charts? I think I can help once I get a better idea of where your data is coming from and how you have it set up.
Edit to add example of how I work with charts:
Multi-graph chart
Second Edit:
Multi Chart 2
Unless I missed something above, I think that we can make this a bit simpler by editing your chart as follows:
Select Chart Tools in the ribbon
Select 'Change Chart Type` icon
Select Combo (last option)
Change one of the axes to be a Secondary axis and change type to Line instead of Bar.

How to encircle Invalid data in Excel?

I want to show a circle around only invalid data.
i have done the complete steps shown in this link
But this circle shown is very big and covers the entire cell.
I want a small circle only covering the data not the entire cell's width.
Data validation is a built in Excel functionality. It checks whole cell value.
So it is not possible, using Data validation, to accomplish what your trying.
It MAY BE POSSIBLE using VBA, shapes, events and (hard) parsing character rendering. In your place, I would be glad with this very big circles!!! :)
I agree with #LS_dev. See this MS Article about changing data validation for printing. Try modifying it to loop through all your data validation and change the width and height.
You can probably do it with this part of the code by changing the width and height:
If Not c.Validation.Value Then
Set o = ActiveSheet.Shapes.AddShape(msoShapeOval, _
c.Left - 2, c.Top - 2, c.Width + 4, c.Height + 4)
o.Fill.Visible = msoFalse
o.Line.ForeColor.SchemeColor = 10
o.Line.Weight = 1.25

Enumerating PowerPoint slides in order

I'm trying to analyze an existing PowerPoint 2010 .pptx file using the OpenXML SDK 2.0.
What I'm trying to achieve is to
enumerate the slides in order (as they appear in the PPTX)
extracting all textual bits from each slide
I've started and gotten so far - I can enumerate the SlideParts from the PresentationPart - but I cannot seem to find a way to make this an ordered enumeration - the slides are being returned in pretty much arbitrary order...
Any trick to get these slides in the order defined in the PPTX file?
using (PresentationDocument doc = PresentationDocument.Open(fileName, false))
{
// Get the presentation part of the document.
PresentationPart presentationPart = doc.PresentationPart;
foreach (var slide in presentationPart.SlideParts)
{
...
}
}
I was hoping to find something like a SlideID or Sequence number or something - some item or property I could use in a Linq expression like
.OrderBy(s => s.SlideID)
on that slideparts collection.
It's a bit more involved than I had hoped for - and the docs are a bit sketchy at times....
Basically, I had to enumerate the SlideIdList on the PresentationPart and do some XML-foo to get from that SlideId to the actual slide in the OpenXML presentation.
Something along the lines of:
using (PresentationDocument doc = PresentationDocument.Open(fileName, false))
{
// Get the presentation part of the document.
PresentationPart presentationPart = doc.PresentationPart;
// get the SlideIdList
var items = presentationPart.Presentation.SlideIdList;
// enumerate over that list
foreach (SlideId item in items)
{
// get the "Part" by its "RelationshipId"
var part = presentationPart.GetPartById(item.RelationshipId);
// this part is really a "SlidePart" and from there, we can get at the actual "Slide"
var slide = (part as SlidePart).Slide;
// do more stuff with your slides here!
}
}
The closest I found was this snippet:
[ISO/IEC 29500-1 1st Edition]
sld (Presentation Slide)
This element specifies a slide within a slide list. The slide list is
used to specify an ordering of slides.
[Example: Consider the following custom show with an ordering of
slides.
<p:custShowLst>
<p:custShow name="Custom Show 1" id="0">
<p:sldLst>
<p:sld r:id="rId4"/>
<p:sld r:id="rId3"/>
<p:sld r:id="rId2"/>
<p:sld r:id="rId5"/>
</p:sldLst>
</p:custShow>
</p:custShowLst>In the above example the order specified to present the slides is slide 4, then 3, 2 and finally 5. end example]
In the MSDN documentation for the slide class
It seems that slides have an r:id of the form rId## where ## is the number of the slide. Maybe that's enough to get you going again?

Resources