Creating layout PDFs by iterating feature selection and setting extent - python-3.x

In ArcGIS Pro 2.4, I need to create a PDF page of a map layout where the map frame is zoomed to each row in a feature class. Each feature in this class is a polygon. I'm relatively new to ArcPy so I'm learning as I'm going.
So far I've been messing with arcpy.SearchCursor, to iterate the selection of the features. Inside the cursor, I need to use mf.camera.setExtent(mf.getLayerExtent(selectedfeature)) and mf.camera.scale *= 1.05 so the polygon shows its surroundings for context. Then I've been trying to export the layout (lyt) to a PDF somewhere. There are 700 of these polgyons (each labelled as a alphanumerical map page) so it's best to do this with arcpy.
import arcpy
aprx = arcpy.mp.ArcGISProject(r"G:\ArcGIS Projects\project.aprx")
m = aprx.listMaps("Map")[0]
lyr = m.listLayers("PLSS Quarter Sections*")[0]
lyt = aprx.listLayouts("Paper Maps*")[0]
mf = lyt.listElements("MAPFRAME_ELEMENT", "Sewer Sections*")[0]
fc = "PLSS Quarter Sections"
fields = ['OBJECTID']
cursor = arcpy.SearchCursor(fc)
row = cursor.next()
for row in cursor:
mf.camera.setExtent(mf.getLayerExtent(row, True, False))
mf.camera.scale *= 1.05
lyt.exportToPDF(r"G:\ArcGIS Projects\output.pdf")
It should move the map frame inside the layout to the selected feature, zoom out, and save that layout to a PDF. All it does it give a TypeError: 1. How would I go about doing this?

After asking around, ArcGIS Pro has a feature called Map Series that lets you make a series of maps based off a certain layer. In my case, it created 700 maps with a single polygon framed in the map frame in my layout. It's also much easier than scripting it by hand.

Related

noUISlider - Any way to place labels within the connect segments

I have a noUiSlider with several handles to allow specifying several contiguous date periods (example = Feb to Apr, May to July, and Aug to Sept). Ideally I would like to have labels that appear centered on the connect divisions to describe what each period relates to (ex. "Current Period", "Next Period"). I was thinking I could do this by setting a centered background image on the noUi-connect divisions.
However, the noUi-connect divisions use transform (translate/scale) styling which results in my background images being scaled which I do not want.
I also thought maybe I could revise the javascript to generate an outer division around each nonUi-connect division, and I would apply the background onto the outer division instead - but I was unable to get the background from the outer division to appear.
Any other ways I could accomplish this? The only other thing I can think of it to have floating divisions defined outside of the noUiSlider object which I would need to reposition whenever I detect changes in the handle positions.
You can add an element outside of the connects and absolutely position it.
A quick version for a slider with two handles (showing the value for the first handle):
var origin = slider.querySelector('.noUi-connects');
var node = document.createElement('div');
node.style.textAlign = 'center';
node.style.position = 'absolute';
node.style.zIndex = '10';
node.style.fontSize = '10px';
origin.appendChild(node);
slider.noUiSlider.on('update', function(values, handle, unencoded, tap, positions) {
node.style.left = positions[0] + '%';
node.style.right = (100 - positions[1]) + '%';
node.innerText = values[0];
});
Just realized another approach is to set the innerHtml of the specific noUi-connect divisions to my label values. Simpler than playing with background images.
But the transform styling still affects the labels, so the end result is not better. Maybe I can load the innerHtml with an inner division that somehow ignores the transform settings but I haven't figure out how to do that yet. transform: none does not make any difference.

Altair chart not showing up in Streamlit with VConcat

I tried to project altair chart using streamlit. My requirement is to project two charts in such a way that if i select few points in the above chart with scattered points i should see the distribution of a variable('notes') in the below chart. For that i have written the below code where i am using vconcat in the function. But, The chart never shows up when i use vconcat. But, It works fine when i try to project single chart.
def altair_graph(embd_1):
selected = alt.selection_single(on="click", empty="none")
brush = alt.selection(type='interval')
dom = ['Other IDs', 'Slected ID','Sel Dims']
rng_clr = ['lightgrey', 'red','blue']
color_point=alt.Color('color', scale=alt.Scale(domain=dom, range=rng_clr))
color = alt.condition(selected, alt.value('red'), color_point,legend=None)
chart = alt.Chart(embd_1).mark_circle(size=30).encode(
x = 'dimention1:Q',
y = 'dimention2:Q',
tooltip=['ID','notes'] ,
color=color
).properties(width=600,height=600).add_selection(brush).add_selection(selected).interactive()
bars = alt.Chart(embd_1).mark_bar().encode(
y='notes:N',
color='notes:N',
x='count(notes):Q'
).transform_filter(brush).interactive()
#final_chart = ((chart & bars))
final_chart = alt.vconcat(chart,bars)
return final_chart
selected=altair_component(altair_chart=altair_graph(embd_1))
From your snippet I assume that you are using the altair-part of the streamlit-vega-lite custom component. Currently it seems like it is not possible to use the streamlit-vega-lite component to retrieve selections from compound charts.
That said, it is not entirely clear to me, why the chart is not showing at all. And without a minimal reproducible example, we can't test. I had a similar case lately, where it worked to plot the charts both, separately, as well as together as a compound. Also the selections work as such, however, values are not reflected back in the event dict that gets returned from the altair_component

Is there a way to change height of tkinter Treeview heading?

I got a problem with changing the height of the Treeview.heading. I have found some answers about the dimensions of Treeview.column, but when I access Treeview.heading in the documentation, there is not a single word about changing the height of the heading dynamically when the text doesn't fit (and wrapping it) or even just hard-coding height of the heading in pixels.
I don't have to split the text to two rows, but when I just keep it that long the whole table (as it has many entries) takes up the whole screen. I want to keep it smaller, therefore I need to split longer entries.
Here is how it looks like:
I can't find any documentation to verify this but it looks like the height of the heading is determined by the heading in the first column.
Reproducing the problem
col_list = ('Name', 'Three\nLine\nHeader', 'Two\nline')
tree = Treeview(parent, columns=col_list[1:])
ix = -1
for col in col_list:
ix += 1
tree.heading(f'#{ix}', text=col)
The fix
col_list = ('Name\n\n', 'Three\nLine\nHeader', 'Two\nline')
or, if you want to make it look prettier
col_list = ('\nName\n', 'Three\nLine\nHeader', 'Two\nline')
The only problem is I haven't figured out how to centre the heading on a two line header
Edit
The newlines work if it is the top level window but not if it is a dialog. Another way of doing this is to set the style. I've got no idea why this works.
style = ttk.Style()
style.configure('Treeview.Heading', foreground='black')
you can use font size to increase the header height for sometimes;
style = ttk.Style()
style.configure('Treeview.Heading', foreground='black', background='white', font=('Arial',25),)

How do I carry over identical texture mapping when exporting to DAE?

I am able to open a 3DS file in MeshLab and when I export to Collada DAE format the textures are visible but they are not being projected onto the mesh in the same way as the preview in MeshLab. For example, the front/back faces of a cube would have the proper texture (suppose it's a polka dot) but the top and bottom have a striped look. How can I apply a single texture and have it appear as intended on all faces, like the imported model before I convert it?
This problem is a result of the end software being used to view the DAE file. It's not a problem with MeshLab.
For example, if loading the file into Away3D be sure to handle the texture materials using the TextureMaterial class instead of the simpler SinglePassMaterialBase such as what you might find in their example code. Here is what I use now, and it displays texture properly:
var material:TextureMaterial = cast(asset, TextureMaterial);
material.ambientColor = 0xffffff;
material.lightPicker = _lightPicker;
material.shadowMethod = new FilteredShadowMapMethod(_light);
material.lightPicker = _lightPicker;
material.gloss = 30;
material.specular = 1;
material.ambient = 1;
material.repeat = true;

Flot pie charts - externally selecting slices

I found this solution.
If type of chart is pie, how specify parameters (x,y) of highlight(x, y)?
Thanks
Sorry for my bad English.
Unfortunately, flot doesn't expose the pie highlighting code to the user. So we are pretty much out of luck, but what may work for you is synthesizing a click event at the appropriate place on the page:
$("#highligher").click(function () {
var e = jQuery.Event('click');
e.pageX = 250; //add a made up x/y coordinate to the click event
e.pageY = 250;
$('#plot canvas:first').trigger(e); //trigger the click event on the canvas
});
Here it is in action: http://jsfiddle.net/ryleyb/mHJm5/
The problem is you have to know where the slice you want to highlight is already. This would be easy enough to set if the graph is static. If it's a dynamic graph, you'd have to dig into the source of the pie code to figure out how to calculate where the pie slice is. It might be easier in that case to just have a copy of all the pie functions and manually draw on the pie overlay.
Just got this working by altering a few things...
I changed highlight and unhighlight in jquery.flot.pie.js to pieHighlight and pieUnhighlight.
Then, after these two lines in jquery.flot.pie.js...
plot.hooks.processOptions.push(function(plot, options) {
if (options.series.pie.show) {
I added...
plot.highlight = pieHighlight;
plot.unhighlight = pieUnhighlight;
We're maintaining selection state outside of the chart (as a backbone model). When a selection event (click) occurs, we set the selected slice in the model. When selection changes, we refresh the chart using a selection color for the pie slices that are selected.
var data = [];
var color = slice.index == selected ? '#FF0000' : '#0000FF';
data.push({label:slice.Label,data:slice.Value,color:color});
The snippet above uses blue for all non-selected slices, red for the selected slice. Your color logic will be more sophisticated.
NOTE: You can also use rgba CSS for the colors, which gives a really nice effect. For example:
var color = slice.index == selected ? 'rgba(0,0,255,1)' : 'rgba(0,0,255,0.5)';

Resources