PyQGIS 3.18.2 Removing Band Name from Symbology - gdal

I recently updated my QGIS and I noticed the styles now show the band Band 1(Gray)
The issue is it now shows within my print layout:
Using PYQGIS, how can I remove just the Band 1 (Gray)?
For reference, here is how I am currently setting the legend in the layout:
def set_legend(layout: QgsPrintLayout, tree: QgsLayerTree, layer: QgsLayer, item_id: str):
'''Sets the Legend items'''
logging.info(f'setting legend: {item_id}')
item = layout.itemById(item_id)
# set layer as root for legend
tree.addLayer(layer)
item.model().setRootGroup(tree)
node = item.model().rootGroup().findLayer(layer)
# hide the node title
QgsLegendRenderer.setNodeLegendStyle(node, QgsLegendStyle.Hidden)
Thank you!

Here's my solution after digging StackOverflow and the API:
root = model.rootGroup().findLayer(layer)
# hide the node with label: Band 1 (Gray)
if isinstance(layer, QgsRasterLayer):
nodes = model.layerLegendNodes(root)
if nodes[0].data(0) == 'Band 1 (Gray)':
indexes = list(range(1, len(nodes)))
QgsMapLayerLegendUtils.setLegendNodeOrder(root, indexes)
model.refreshLayerLegend(root)

Related

How to specify position of common.legend in ggarrange function

I am trying to combine 3 plots created by ggplot2. I am using the ggarrange function from ggpubr package:
myplot <-ggarrange(baseline_plot_Eng+rremove("xlab")+rremove("ylab"),
baseline_plot_Fr+rremove("xlab")+rremove("ylab"),
baseline_plot_Per+rremove("xlab")+rremove("ylab"),
ncol = 3, nrow = 1,
font.label=list(color="black",size=12),
common.legend = T,legend = "top",
align = "hv")
The problem is the common legend (condition below) is not centred and appears on the top right.
Is there some way I can fix this, please?
Thank you!

Own drag icon with same color and font settings as the default drag icon in a Gtk.TreeView

The Gtk.TreeView implements a default drag icon. It use the background color of the TreeView, it's font and the complete row-content as string.
I want the same (background-color, font-face, font-size, font-color) but with a shorter string (only the second of three columns).
In the example below create my own cairo.Surface to create such an icon. But color and font is a problem. I don't know how to set them up or (much more important) to ask the TreeView or Gtk itself for the current color and font values.
How does the TreeView get this values?
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
import cairo
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TreeView Drag and Drop")
self.connect("delete-event", Gtk.main_quit)
self.box = Gtk.Box()
self.add(self.box)
# "model" with dummy data
self.store = Gtk.TreeStore(int, str, int)
for i in range(5):
self.store.append(None, [i, 'Item {}'.format(i), i]) # treeview
self.tree = Gtk.TreeView(model=self.store)
self.box.pack_start(self.tree, True, True, 0)
# build columns
colA = Gtk.TreeViewColumn('Col A', Gtk.CellRendererText(), text=0)
self.tree.append_column(colA)
colB = Gtk.TreeViewColumn('Col B', Gtk.CellRendererText(), text=1)
self.tree.append_column(colB)
colC = Gtk.TreeViewColumn('Col C', Gtk.CellRendererText(), text=2)
self.tree.append_column(colC)
# enable default drag and drop
self.tree.set_reorderable(True)
# DnD events
self.tree.connect_after("drag-begin", self.drag_begin)
def drag_begin(self, widget, context):
model, path = widget.get_selection().get_selected_rows()
text = model[path][1]
# dummy surface/context
surface = cairo.ImageSurface(cairo.Format.RGB24, 0, 0)
cr = cairo.Context(surface)
# calculate text size
txtext = cr.text_extents(text)
width = int(txtext.width)
height = int(txtext.height)
offset = 10
# creal surface/context
surface = cairo.ImageSurface(cairo.Format.RGB24,
width + (offset*2),
height + (offset*2))
cr = cairo.Context(surface)
cr.set_source_rgb(1, 1, 1) # text color: white
cr.move_to(0+offset, height+offset)
cr.show_text(text)
# use the surface as drag icon
Gtk.drag_set_icon_surface(context, surface)
win = MainWindow()
win.show_all()
Gtk.main()
What I tried (but not worked) was cairo.Surface.create_similar()',cairo.Surface.create_similar_image()andGtk.TreeView.create_row_drag_icon()`.
This answer is based on a foreign mailing list posting.
The widget has a Gtk.StyleContext. A Pango.Layout is used to render the text based on the style informations in the Gtk.StyleContext.
def drag_begin(self, widget, context):
model, path = widget.get_selection().get_selected_rows()
text = model[path][1]
stylecontext = widget.get_style_context()
# new pango layout
pl = widget.create_pango_layout(text)
ink_rec, log_rect = pl.get_pixel_extents()
padding = 5
# create surface/context
surface = cairo.ImageSurface(cairo.Format.RGB24,
log_rect.width + (padding*2),
log_rect.height + (padding*2))
cr = cairo.Context(surface)
Gtk.render_background(stylecontext, cr, 0, 0,
log_rect.width + (padding*2),
log_rect.height + (padding*2))
Gtk.render_layout(stylecontext, cr, padding, padding, pl)
# border
line_width = cr.get_line_width()
cr.rectangle(-1+line_width, -1+line_width,
log_rect.width+(padding*2)-line_width,
log_rect.height+(padding*2)-line_width)
cr.stroke()
# use the surface as drag icon
Gtk.drag_set_icon_surface(context, surface)

How to exchange colors between 2 images?

I have an image of spectacles with black background that I need to overlay onto a face image. To do so, I am taking the part of face image with shape same as spectacles; and put the colors of face image on black parts of the spectacles image. Then this small part of image can be put back. But I am not being able to take the correct colors from face image for the spectacles image. I tried this :
specs[np.where((hmd == [0,0,0,0]).all(axis=2))] = sub_face
specs image:
face image:
I need to put a resized specs image to face. I have resized specs image and also know the position where I will place the specs on face image. I just need to remove black background from specs and add relevant face colors so it looks like there are specs on face in a natural way.
Code I am using :
import cv2
specs = cv2.imread("rot_h0v0z0.png")
face = cv2.imread("~/Downloads/celebA/000001.png")
specs = cv2.resize(image, None, fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA)
sub_face = face[0:specs.shape[0], 0:specs.shape[1]]
specs[np.where((hmd == [0,0,0,0]).all(axis=2))] = sub_face
Was able to solve it, turned out pretty simple :P
(b,g,r) = cv2.split(specs)
indices = np.where(b == [0])
for i,j in zip(indices[0], indices[1]):
specs[i,j] = sub_face[i,j]
Was able to solve it, turned out pretty simple :P
(b,g,r) = cv2.split(specs)
indices = np.where(b == [0])
for i,j in zip(indices[0], indices[1]):
specs[i,j] = sub_face[i,j]

Break document sections into list for export Python

I am very new to Python, and I am trying to break some legal documents into sections for export into SQL. I need to do two things:
Define the section numbers by the table of contents, and
Break up the document given the defined section numbers
The table of contents lists section numbers: 1.1, 1.2, 1.3, etc.
Then the document itself is broken up by those section numbers:
1.1 "...Text...",
1.2 "...Text...",
1.3 "...Text...", etc.
Similar to the chapters of a book, but delimited by ascending decimal numbers.
I have the document parsed using Tika, and I've been able to create a list of sections with some basic regex:
import tika
import re
from tika import parser
parsed = parser.from_file('test.pdf')
content = (parsed["content"])
headers = re.findall("[0-9]*[.][0-9]",content)
Now I need to do something like this:
splitsections = content.split() by headers
var_string = ', '.join('?' * len(splitsections))
query_string = 'INSERT INTO table VALUES (%s);' % var_string
cursor.execute(query_string, splitsections)
Sorry if all this is unclear. Still very new to this.
Any help you can provide would be most appreciated.
Everything tested except the last part with DB. Also the code can be improved, but this is another task. The main task is done.
In the list split_content there are all pieces of info you wanted (i.e. the text between 2.1 and 2.2, then 2.2 and 2.3, and so on, EXCLUDING num+name of sections itself (i.e. excluding 2.1 Continuation, 2.2 Name and so on).
I replaced tika by PyPDF2, as tika does not provide instruments needed for this task (i.e. I did not find how to provide the num of page I need and get its content).
def get_pdf_content(pdf_path,
start_page_table_contents, end_page_table_contents,
first_parsing_page, last_phrase_to_stop):
"""
:param pdf_path: Full path to the PDF file
:param start_page_table_contents: The page where the "Contents table" starts
:param end_page_table_contents: The page where the "Contents Table" ends
(i.e. the number of the page where Contents Table ENDs, i.e. not the next one)
:param first_parsing_page: The 1st page where we need to start data grabbing
:param last_phrase_to_stop: The phrase that tells the code where to stop grabbing.
The phrase must match exactly what is written in PDF.
This phrase will be excluded from the grabbed data.
:return:
"""
# ======== GRAB TABLE OF CONTENTS ========
start_page = start_page_table_contents
end_page = end_page_table_contents
table_of_contents_page_nums = range(start_page-1, end_page)
sections_of_articles = [] # ['2.1 Continuation', '2.2 Name', ... ]
open_file = open(pdf_path, "rb")
pdf = PyPDF2.PdfFileReader(open_file)
for page_num in table_of_contents_page_nums:
page_content = pdf.getPage(page_num).extractText()
page_sections = re.findall("[\d]+[.][\d][™\s\w;,-]+", page_content)
for section in page_sections:
cleared_section = section.replace('\n', '').strip()
sections_of_articles.append(cleared_section)
# ======== GRAB ALL NECESSARY CONTENT (MERGE ALL PAGES) ========
total_num_pages = pdf.getNumPages()
parsing_pages = range(first_parsing_page-1, total_num_pages)
full_parsing_content = '' # Merged pages
for parsing_page in parsing_pages:
page_content = pdf.getPage(parsing_page).extractText()
cleared_page = page_content.replace('\n', '')
# Remove page num from the start of "page_content"
# Covers the case with the page 65, 71 and others when the "page_content" starts
# with, for example, "616.6 Liability to Partners. (a) It is understood that"
# i.e. "61" is the page num and "6.6 Liability ..." is the section data
already_cleared = False
first_50_chars = cleared_page[:51]
for section in sections_of_articles:
if section in first_50_chars:
indx = cleared_page.index(section)
cleared_page = cleared_page[indx:]
already_cleared = True
break
# Covers all other cases
if not already_cleared:
page_num_to_remove = re.match(r'^\d+', cleared_page)
if page_num_to_remove:
cleared_page = cleared_page[len(str(page_num_to_remove.group(0))):]
full_parsing_content += cleared_page
# ======== BREAK ALL CONTENT INTO PIECES ACCORDING TO TABLE CONTENTS ========
split_content = []
num_sections = len(sections_of_articles)
for num_section in range(num_sections):
start = sections_of_articles[num_section]
# Get the last piece, i.e. "11.16 FATCA" (as there is no any "end" section after "11.16 FATCA", so we cant use
# the logic like "grab info between sections 11.1 and 11.2, 11.2 and 11.3 and so on")
if num_section == num_sections-1:
end = last_phrase_to_stop
else:
end = sections_of_articles[num_section + 1]
content = re.search('%s(.*)%s' % (start, end), full_parsing_content).group(1)
cleared_piece = content.replace('™', "'").strip()
if cleared_piece[0:3] == '. ':
cleared_piece = cleared_piece[3:]
# There are few appearances of "[Signature Page Follows]", as a "last_phrase_to_stop".
# We need the text between "11.16 FATCA" and the 1st appearance of "[Signature Page Follows]"
try:
indx = cleared_piece.index(end)
cleared_piece = cleared_piece[:indx]
except ValueError:
pass
split_content.append(cleared_piece)
# ======== INSERT TO DB ========
# Did not test this section
for piece in split_content:
var_string = ', '.join('?' * len(piece))
query_string = 'INSERT INTO table VALUES (%s);' % var_string
cursor.execute(query_string, parts)
How to use: (one of the possible way):
1) Save the code above in my_pdf_code.py
2) In the python shell:
import path.to.my_pdf_code as the_code
the_code.get_pdf_content('/home/username/Apollo_Investment_Fund_VIII_LPA_S1.pdf', 2, 4, 24, '[Signature Page Follows]')

wxPython - drawing on transparent/alpha background (for custom widgets/panels)

I'm learning wxPython on Ubuntu Linux - and I would like to define my own widget, which is basically a line, which I'd like to move around the window.. I'm getting somewhere, but the problem is that I cannot get the 'widget' to 'draw' on a transparent background; best I can get is something like this (the yellow line should be an independent widget with a transparent background - but the background there is black with noise):
The code I came up with is below. I don't want the whole window transparent (wxpython - Python drawing on screen - Stack Overflow); I'm aware wx.TRANSPARENT is only for text, and I should try wx.GCDC, which I did, but it isn't working (wx.PaintDC and SetBackgroundMode( wx.TRANSPARENT ) support - wxPython-users | Google Groups), and apparently, this, on "wxGTK it is not possible" (wxPython-users - transparent background for a panel widget)...
It seems the only way would be to use a transparent bitmap/Image, and then use that as background for a custom widget, would that be correct? If so, is there a possibility to generate this bitmap/image directly in wxPython (I'm aiming for a self-contained script, I'd hate to make it dependent on an external .png :)) ? And if this is a possible approach, can someone point me to a minimal working example (as I cannot find any examples for this kind of use at all)..
Thanks in advance for any help,
Cheers!
code that generated image above:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import wx
class CustomLine(wx.Panel): #PyControl
"""
A custom class for a line
Modified from http://wiki.wxpython.org/CreatingCustomControls
"""
def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_BORDER, validator=wx.DefaultValidator,
name="CustomLine"):
"""
Default class constructor.
#param parent: Parent window. Must not be None.
#param id: CustomLine identifier. A value of -1 indicates a default value.
#param label: Text to be displayed next to the checkbox.
#param pos: CustomLine position. If the position (-1, -1) is specified
then a default position is chosen.
#param size: CustomLine size. If the default size (-1, -1) is specified
then a default size is chosen.
#param style: not used in this demo, CustomLine has only 2 state
#param validator: Window validator.
#param name: Window name.
"""
#~ wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name)
wx.Panel.__init__(self, parent, id, pos, size, style)
# Bind the events related to our control: first of all, we use a
# combination of wx.BufferedPaintDC and an empty handler for
# wx.EVT_ERASE_BACKGROUND (see later) to reduce flicker
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.lpen = wx.Pen('yellow', 2, wx.SOLID)
self.imagebkg = wx.EmptyImage( 10, 10 )
#~ self.imagebkg.SetData((255,255,255))
#~ self.imagebkg.SetAlphaData((1))
def OnPaint(self, event):
""" Handles the wx.EVT_PAINT event for CustomLine. """
# If you want to reduce flicker, a good starting point is to
# use wx.BufferedPaintDC.
pdc = wx.BufferedPaintDC(self)
dc = wx.GCDC(pdc)
# Is is advisable that you don't overcrowd the OnPaint event
# (or any other event) with a lot of code, so let's do the
# actual drawing in the Draw() method, passing the newly
# initialized wx.BufferedPaintDC
self.Draw(dc)
def Draw(self, dc):
"""
Actually performs the drawing operations, for the bitmap and
for the text, positioning them centered vertically.
"""
# Get the actual client size of ourselves
width, height = self.GetClientSize()
if not width or not height:
# Nothing to do, we still don't have dimensions!
return
# Initialize the wx.BufferedPaintDC, assigning a background
# colour and a foreground colour (to draw the text)
#~ backColour = self.GetBackgroundColour()
#~ backBrush = wx.Brush((1,1,1,150), wx.TRANSPARENT) # backColour
#~ backBrush = wx.Brush((10,10,1,150)) # backColour
dc.SetBackground(wx.TRANSPARENT_BRUSH) #() backBrush
#~ dc.SetBackgroundMode(wx.TRANSPARENT)
dc.Clear()
dc.SetPen(self.lpen)
dc.DrawLine(0, 0, 100, 100)
def OnEraseBackground(self, event):
""" Handles the wx.EVT_ERASE_BACKGROUND event for CustomLine. """
# This is intentionally empty, because we are using the combination
# of wx.BufferedPaintDC + an empty OnEraseBackground event to
# reduce flicker
pass
class MyTestFrame(wx.Frame):
def __init__(self, parent, title):
super(MyTestFrame, self).__init__(parent, title=title,
size=(250, 150))
# the master panel of the frame - "Add a panel so it looks correct on all platforms"
self.panel = wx.Panel(self, wx.ID_ANY)
# self.panel.SetBackgroundColour(wx.Colour(124, 224, 124)) # to confirm the square is the panel
self.mpanelA = wx.Panel(self.panel, -1, size=(200,50))
self.mpanelA.SetBackgroundColour((200,100,200))
self.mpanelB = wx.Panel(self.panel, -1, size=(50,200), pos=(50,30))
self.mpanelB.SetBackgroundColour(wx.Colour(200,100,100,100))
self.cline = CustomLine(self.panel, -1, size=(-1,200))
self.Centre()
self.Show()
if __name__ == '__main__':
app = wx.App()
MyTestFrame(None, 'Test')
app.MainLoop()
maybe you should have a look at GraphicsContext istead of dc (DrawingContext). It has better support for transparency, like drawing transparent rectangles on to of a panel.