Related Plugins and Tags

QGIS Planet

Function editor for QGIS expressions

A new feature for QGIS 2.8 is a function editor for expressions. Being able to define your own custom functions has be possible for a while now, over a year, I even have a plugin (Expressions+) that adds some extra ones, however it wasn’t easy for new users and required you to create files that lived on python path while also editing the startup.py file for QGIS so that functions got registed at start up. Way too much effort for my liking.

This feature is now exposed via the expression builder on the Function Editor tab. The function editor will create new Python files in qgis2\python\expressions and will auto load all functions defined when starting QGIS. I remember Sean Gillies saying that Python support in a field calculator should be a gateway to full Python programming, can’t get any more Python then full Python modules.

The best way to show this feature is a quick video so here it is

The play button in the editor will run the current editor file in the QGIS session and register any functions it finds, it will also save the file in the expressions folder.

You can make a new file by pressing the new file button which will add the basic function template, changing the name in the combobox and hitting save will save the file.

The function editor allows you have to define reuseable functions for your QGIS. If you want to share a function you simply share the .py file from the expressions folder and give it to another user. In future versions of QGIS we might have a way to download other users functions.

Auto expanding values

You can also use the args="auto" keyword in place of the number of args which will let QGIS work it out and expand the arguments for you.

Here is an example

@qgsfunction(args="auto", group='Custom')
def myfunc(value1, value2 feature, parent):
    pass

and can be used like this:

myfunc('test1', 'test2')

QGIS will workout how many arguments your function takes based on what you have defined. Note: The last arguments should always be feature, parent, these are not included in the count.

Raising errors

If you need to report a error from a function simply use the raise method like normal in QGIS and raise an exception.

@qgsfunction(args="auto", group='Custom')
def myfunc(value1, value2 feature, parent):
    raise Expection("Hahah Nope!")

The function wrapper will catch the exception and raise it though the expression engine.

A couple of things to note

  • New functions are only saved in the expressions folder and not in the project file. If you have a project that uses one of your custom functions you will need to also share the .py file in the expressions folder.
  • The editor doesn’t unregister any functions. If you define a function called test, hit play, change the name to test_2, hit play, both functions will exist until you reload QGIS.

Filed under: Open Source

Waiting for QGIS 2.2: Highlighting current Atlas feature

A new feature coming up in QGIS 2.2 will be the ability to style the current active atlas feature with a different symbol. This also extends to styling other layers based on the current feature geometry. This post is a quick preview of the upcoming 2.2 feature.

When a layer has been enabled for Atlas in the composer two new variables will be created $atlasfeatureid and $atlasgeometry. This are static expression variables so once set they are available anywhere in QGIS. These two new static variables will now be set for each feature when printing using the Atlas feature. This also means we can access them in the rule and label expressions to do some pretty cool styled maps.

Once defined we can then create a rule using the rule based renderer to highlight the active layer. We do this by using the expression $id = $atlasfeatureid. Simply put "Does this feature ID match the current atlas one"

Alt Text

Alt Text

That's pretty cool. The current feature (ID 0) in this case is green and the rest is gray. You will also note another new feature in 2.2 which is the ELSE rule. This rule will run when none of the other rules on it's level have passed or evaluated to true. We can use this ELSE rule to just style everything else as gray.

Why don't we one up this a little and just label the current active one.

Alt Text

Alt Text

You could also use a CASE expression do the same thing CASE WHEN $id = $atlasfeatureid THEN "name" END. Take your pick on which one you like the most.

What if we wanted to just show other layers features that are within the area, maybe we want to style them different if they are within an area, or outside of that area. Lets take a look at styling a tree layer that is only within the current atlas geometry.

We have geometry functions in the expression engine so lets use those here on our street trees layer:

Alt Text

Alt Text

I have nested the rule so that we can style the trees differently based on status but only if they are within the active atlas feature.

Remember this is dynamic so there is going to be a performance hit if you try and run this type of expression on many features. The expressions will run once per feature per map redraw so just be aware of how expensive this can become.

When we render the output to files we get what was expected.

Alt Text

Waiting for QGIS 2.2: Highlighting current Atlas feature

A new feature coming up in QGIS 2.2 will be the ability to style the current active atlas feature with a different symbol. This also extends to styling other layers based on the current feature geometry. This post is a quick preview of the upcoming 2.2 feature.

When a layer has been enabled for Atlas in the composer two new variables will be created $atlasfeatureid and $atlasgeometry. This are static expression variables so once set they are available anywhere in QGIS. These two new static variables will now be set for each feature when printing using the Atlas feature. This also means we can access them in the rule and label expressions to do some pretty cool styled maps.

Once defined we can then create a rule using the rule based renderer to highlight the active layer. We do this by using the expression $id = $atlasfeatureid. Simply put "Does this feature ID match the current atlas one"

atlasrule.png

atlasruleresult.png

That's pretty cool. The current feature (ID 0) in this case is green and the rest is gray. You will also note another new feature in 2.2 which is the ELSE rule. This rule will run when none of the other rules on it's level have passed or evaluated to true. We can use this ELSE rule to just style everything else as gray.

Why don't we one up this a little and just label the current active one.

atlaslabelexpression.png

atlaslabelexpressionresult.png

You could also use a CASE expression do the same thing CASE WHEN $id = $atlasfeatureid THEN "name" END. Take your pick on which one you like the most.

What if we wanted to just show other layers features that are within the area, maybe we want to style them different if they are within an area, or outside of that area. Lets take a look at styling a tree layer that is only within the current atlas geometry.

We have geometry functions in the expression engine so lets use those here on our street trees layer:

atlastrees.png

atlastreesresult.png

I have nested the rule so that we can style the trees differently based on status but only if they are within the active atlas feature.

Remember this is dynamic so there is going to be a performance hit if you try and run this type of expression on many features. The expressions will run once per feature per map redraw so just be aware of how expensive this can become.

When we render the output to files we get what was expected.

atlasoutput.png

Waiting for QGIS 2.2: Highlighting current Atlas feature

A new feature coming up in QGIS 2.2 will be the ability to style the current active atlas feature with a different symbol. This also extends to styling other layers based on the current feature geometry. This post is a quick preview of the upcoming 2.2 feature.

When a layer has been enabled for Atlas in the composer two new variables will be created $atlasfeatureid and $atlasgeometry. This are static expression variables so once set they are available anywhere in QGIS. These two new static variables will now be set for each feature when printing using the Atlas feature. This also means we can access them in the rule and label expressions to do some pretty cool styled maps.

Once defined we can then create a rule using the rule based renderer to highlight the active layer. We do this by using the expression $id = $atlasfeatureid. Simply put "Does this feature ID match the current atlas one"

Alt Text

Alt Text

That's pretty cool. The current feature (ID 0) in this case is green and the rest is gray. You will also note another new feature in 2.2 which is the ELSE rule. This rule will run when none of the other rules on it's level have passed or evaluated to true. We can use this ELSE rule to just style everything else as gray.

Why don't we one up this a little and just label the current active one.

Alt Text

Alt Text

You could also use a CASE expression do the same thing CASE WHEN $id = $atlasfeatureid THEN "name" END. Take your pick on which one you like the most.

What if we wanted to just show other layers features that are within the area, maybe we want to style them different if they are within an area, or outside of that area. Lets take a look at styling a tree layer that is only within the current atlas geometry.

We have geometry functions in the expression engine so lets use those here on our street trees layer:

Alt Text

Alt Text

I have nested the rule so that we can style the trees differently based on status but only if they are within the active atlas feature.

Remember this is dynamic so there is going to be a performance hit if you try and run this type of expression on many features. The expressions will run once per feature per map redraw so just be aware of how expensive this can become.

When we render the output to files we get what was expected.

Alt Text

The death of your child

Today was Eloise's due date but she has already been and gone. Three weeks now. Sometimes it doesn't feel real - a bad dream that we can't escape from. There is no rewind in life, you can only push forward and try to make things better.

Eloise died at around 8:30am on the 16th of October, just 10 days after being born. Her heart stopped and she passed away in Stacey's arms while we both held her. We knew it was coming, it was just a matter of time. Stace and I had broken sleep that night listening for the alarms and watching her oxygen levels fall to the floor taking longer and longer to come back up. At one stage she was never going to come back and at 8:30am that is what happened. It was expected she would only last a few days and we stayed at the hospital, sleeping beside her, ever day until that morning.

It started about a month before Eloise was born. The ultrasound said she might have T21 (Downs), T18, or T13, and that she had a major heart defect. T21 was the biggest concern, the idea a bit scary, but the feeling of worry passed as we came to peace with the idea that having a Downs child would be fine. Each time Stace panicked I told her not to worry, T18 and T13 have other markers and the risk is so small it couldn't happen to us. Apart from her being small and the heart defect, Eloise looked fine. Surely this just means Downs. Surely it will be fine.

After Eloise was born the doctors told us there was some markers for T18. At this point you try to hide the fear but I'm sure people can see right though. I left Stace at the hospital to come back home for a shower and get some clothes. Once I got to the car the reality of what could happen had started to kick in. You try to be strong but any thoughts of what could happen just break you. I think the half and hour shower was the only good thing about the night, a time just to think without noise or anyone else around.

As the days passed we tired to find excuses for the "markers". Trying to reassure ourself that it's fine. They are just little quirks that she has. I'm sure those tests will come back negative. I'm sure they will. Of course they will.

Due to Eloise being born on a Sunday and the Monday being a public holiday the blood samples didn't get to the lab until late Tuesday. A test that normally only takes three days is now looking like a week return. One of the longest weeks we have ever done. Stace would express and I would run milk down to Eloise's room every three hours - nights not excluded. Doing a little check. Talking to the nurse about how Eloise is doing. Reassuring myself of the markers.

We came to the hospital on Saturday knowing the results would come in. It was D-Day and I had a feeling this wasn't going to end well. We had lunch trying to ignore the gravity of the situation. After lunch the doctor came into our room and closed the door, the tell tale sign that something is wrong. "The tests have come back. I'm sorry the news isn't good. Eloise has T18". Stace fell apart and there is only so long that you can watch your wife before it starts to cut into you and you soon follow. The doctor left us and we cried for about half and hour - or what felt like it. There is nothing else you can do. Your world just started to fall apart and you are powerless against it.

Eloise was put into palliative care. The heart medication was stopped. She was going to die and we just had to watch her. How can you just sit there an watch your child die? The nights were the hardest, they were long and uncomfortable. We didn't want to sleep but knew we had to in order to have the energy the next day. The option was given to switch off the monitors so no alarms would sound if she started to decline. The thought of not being able to hold Eloise as she passed was too much for Stace to bare so we left the alarms on, watching them for any drops. The alarms became more frequent as the days went on; the idea that she was going to die become more real with each time.

It finally came the morning of the 16th. Her heart started to slow and her oxygen dropped. It didn't show any signs of coming back up and we watched her go.

Why couldn't it have just been Downs!?

How do you cope? Well you do and you don't. There are days you are really good and can focus, and then there are days when your brain is just mush. It happens, I doubt it ever goes away maybe you just grow to live with it and push forward. The emotions on the day of the service in the faces of relatives and close friends who have also lost children shows it never really goes away, and as quickly as you forgot the pain it can all come back in an instant.


The most important thing I think in all this is support. Having people that could support us and our family. We are very lucky to have good friends and family who were able to support us though everything, some traveling a long way to attend the service. I am also very thankful to DMS who showed us great support with their thoughts and much much more, more then I could ever ask. To the folks on Twitter and Google+ for letting us know we are in their thoughts. It all helps, even just the small stuff.

We are very grateful for our son, who is too young to understand although I'm sure he knows something is missing. He helps to keep the hopes up on the shit days. The stupid noises, the stupid faces he pulls, all help to take your mind away from the pain and into a happy place. When no one else is around he helps to bind us.

<3 Mummy, Daddy, and big brother

Alt Text

The death of your child

Today was Eloise's due date but she has already been and gone. Three weeks now. Sometimes it doesn't feel real - a bad dream that we can't escape from. There is no rewind in life, you can only push forward and try to make things better.

Eloise died at around 8:30am on the 16th of October, just 10 days after being born. Her heart stopped and she passed away in Stacey's arms while we both held her. We knew it was coming, it was just a matter of time. Stace and I had broken sleep that night listening for the alarms and watching her oxygen levels fall to the floor taking longer and longer to come back up. At one stage she was never going to come back and at 8:30am that is what happened. It was expected she would only last a few days and we stayed at the hospital, sleeping beside her, ever day until that morning.

It started about a month before Eloise was born. The ultrasound said she might have T21 (Downs), T18, or T13, and that she had a major heart defect. T21 was the biggest concern, the idea a bit scary, but the feeling of worry passed as we came to peace with the idea that having a Downs child would be fine. Each time Stace panicked I told her not to worry, T18 and T13 have other markers and the risk is so small it couldn't happen to us. Apart from her being small and the heart defect, Eloise looked fine. Surely this just means Downs. Surely it will be fine.

After Eloise was born the doctors told us there was some markers for T18. At this point you try to hide the fear but I'm sure people can see right though. I left Stace at the hospital to come back home for a shower and get some clothes. Once I got to the car the reality of what could happen had started to kick in. You try to be strong but any thoughts of what could happen just break you. I think the half and hour shower was the only good thing about the night, a time just to think without noise or anyone else around.

As the days passed we tired to find excuses for the "markers". Trying to reassure ourself that it's fine. They are just little quirks that she has. I'm sure those tests will come back negative. I'm sure they will. Of course they will.

Due to Eloise being born on a Sunday and the Monday being a public holiday the blood samples didn't get to the lab until late Tuesday. A test that normally only takes three days is now looking like a week return. One of the longest weeks we have ever done. Stace would express and I would run milk down to Eloise's room every three hours - nights not excluded. Doing a little check. Talking to the nurse about how Eloise is doing. Reassuring myself of the markers.

We came to the hospital on Saturday knowing the results would come in. It was D-Day and I had a feeling this wasn't going to end well. We had lunch trying to ignore the gravity of the situation. After lunch the doctor came into our room and closed the door, the tell tale sign that something is wrong. "The tests have come back. I'm sorry the news isn't good. Eloise has T18". Stace fell apart and there is only so long that you can watch your wife before it starts to cut into you and you soon follow. The doctor left us and we cried for about half and hour - or what felt like it. There is nothing else you can do. Your world just started to fall apart and you are powerless against it.

Eloise was put into palliative care. The heart medication was stopped. She was going to die and we just had to watch her. How can you just sit there an watch your child die? The nights were the hardest, they were long and uncomfortable. We didn't want to sleep but knew we had to in order to have the energy the next day. The option was given to switch off the monitors so no alarms would sound if she started to decline. The thought of not being able to hold Eloise as she passed was too much for Stace to bare so we left the alarms on, watching them for any drops. The alarms became more frequent as the days went on; the idea that she was going to die become more real with each time.

It finally came the morning of the 16th. Her heart started to slow and her oxygen dropped. It didn't show any signs of coming back up and we watched her go.

Why couldn't it have just been Downs!?

How do you cope? Well you do and you don't. There are days you are really good and can focus, and then there are days when your brain is just mush. It happens, I doubt it ever goes away maybe you just grow to live with it and push forward. The emotions on the day of the service in the faces of relatives and close friends who have also lost children shows it never really goes away, and as quickly as you forgot the pain it can all come back in an instant.


The most important thing I think in all this is support. Having people that could support us and our family. We are very lucky to have good friends and family who were able to support us though everything, some traveling a long way to attend the service. I am also very thankful to DMS who showed us great support with their thoughts and much much more, more then I could ever ask. To the folks on Twitter and Google+ for letting us know we are in their thoughts. It all helps, even just the small stuff.

We are very grateful for our son, who is too young to understand although I'm sure he knows something is missing. He helps to keep the hopes up on the shit days. The stupid noises, the stupid faces he pulls, all help to take your mind away from the pain and into a happy place. When no one else is around he helps to bind us.

<3 Mummy, Daddy, and big brother

Alt Text

The death of your child

Today was Eloise's due date but she has already been and gone. Three weeks now. Sometimes it doesn't feel real - a bad dream that we can't escape from. There is no rewind in life, you can only push forward and try to make things better.

Eloise died at around 8:30am on the 16th of October, just 10 days after being born. Her heart stopped and she passed away in Stacey's arms while we both held her. We knew it was coming, it was just a matter of time. Stace and I had broken sleep that night listening for the alarms and watching her oxygen levels fall to the floor taking longer and longer to come back up. At one stage she was never going to come back and at 8:30am that is what happened. It was expected she would only last a few days and we stayed at the hospital, sleeping beside her, ever day until that morning.


It started about a month before Eloise was born. The ultrasound said she might have T21 (Downs), T18, or T13, and that she had a major heart defect. T21 was the biggest concern, the idea a bit scary, but the feeling of worry passed as we came to peace with the idea that having a Downs child would be fine. Each time Stace panicked I told her not to worry, T18 and T13 have other markers and the risk is so small it couldn't happen to us. Apart from her being small and the heart defect, Eloise looked fine. Surely this just means Downs. Surely it will be fine.

After Eloise was born the doctors told us there was some markers for T18. At this point you try to hide the fear but I'm sure people can see right though. I left Stace at the hospital to come back home for a shower and get some clothes. Once I got to the car the reality of what could happen had started to kick in. You try to be strong but any thoughts of what could happen just break you. I think the half and hour shower was the only good thing about the night, a time just to think without noise or anyone else around.

As the days passed we tired to find excuses for the "markers". Trying to reassure ourself that it's fine. They are just little quirks that she has. I'm sure those tests will come back negative. I'm sure they will. Of course they will.

Due to Eloise being born on a Sunday and the Monday being a public holiday the blood samples didn't get to the lab until late Tuesday. A test that normally only takes three days is now looking like a week return. One of the longest weeks we have ever done. Stace would express and I would run milk down to Eloise's room every three hours - nights not excluded. Doing a little check. Talking to the nurse about how Eloise is doing. Reassuring myself of the markers.

We came to the hospital on Saturday knowing the results would come in. It was D-Day and I had a feeling this wasn't going to end well. We had lunch trying to ignore the gravity of the situation. After lunch the doctor came into our room and closed the door, the tell tale sign that something is wrong. "The tests have come back. I'm sorry the news isn't good. Eloise has T18". Stace fell apart and there is only so long that you can watch your wife before it starts to cut into you and you soon follow. The doctor left us and we cried for about half and hour - or what felt like it. There is nothing else you can do. Your world just started to fall apart and you are powerless against it.

Eloise was put into palliative care. The heart medication was stopped. She was going to die and we just had to watch her. How can you just sit there an watch your child die? The nights were the hardest, they were long and uncomfortable. We didn't want to sleep but knew we had to in order to have the energy the next day. The option was given to switch off the monitors so no alarms would sound if she started to decline. The thought of not being able to hold Eloise as she passed was too much for Stace to bare so we left the alarms on, watching them for any drops. The alarms became more frequent as the days went on; the idea that she was going to die become more real with each time.

It finally came the morning of the 16th. Her heart started to slow and her oxygen dropped. It didn't show any signs of coming back up and we watched her go.

Why couldn't it have just been Downs!?


How do you cope? Well you do and you don't. There are days you are really good and can focus, and then there are days when your brain is just mush. It happens, I doubt it ever goes away maybe you just grow to live with it and push forward. The emotions on the day of the service in the faces of relatives and close friends who have also lost children shows it never really goes away, and as quickly as you forgot the pain it can all come back in an instant.


The most important thing I think in all this is support. Having people that could support us and our family. We are very lucky to have good friends and family who were able to support us though everything, some traveling a long way to attend the service. I am also very thankful to DMS who showed us great support with their thoughts and much much more, more then I could ever ask. To the folks on Twitter and Google+ for letting us know we are in their thoughts. It all helps, even just the small stuff.

We are very grateful for our son, who is too young to understand although I'm sure he knows something is missing. He helps to keep the hopes up on the shit days. The stupid noises, the stupid faces he pulls, all help to take your mind away from the pain and into a happy place. When no one else is around he helps to bind us.


<3 Mummy, Daddy, and big brother

Ellie.jpg

Hardest day of our life

Last Sunday, the 6th of October, Eloise Woodrow was born by emergency caesarean. We had run into a few speed bumps along the way during the pregnancy so we knew there might be some issues when she was born. They had found she was small for her gestational age and also had a VSD (heart defect), this kind of thing, we didn't find out till later, can be linked to chromosomal issues. The most common issue being Downs Syndrome. There are also two other chromosomal issues, T13 and T18, both which have grim outcomes. It was fine, we told ourselves, we can live with a child with Downs, we have known and been friends with plenty of Downs children it wasn't really a concern. In the end the chance of T13 and T18 is so rare that it isn't going to happen to us. Well it was nice to believe that.

Yesterday our worst fear come true. Eloise has T18. The survival rate for babies with T18 is extremely low, and most don't make it past age one. They don't do the heart operation because of the poor survival rate. This means she has no chance and will die. Maybe in a few days, or weeks, but not months.

As a parent this is not something that we have ever wanted to deal with. Not so soon. Not ever. It's hard enough losing a friend or a relative let alone your own child. Every parent knows they would throw themselves under a bus for their children. If you could take the pain yourself and free them you would. But you can't and that makes it harder.

To the dumb question "Why me?" the cosmos barely bothers to return the reply: why not?

Christopher Hitchens

Not being a believer in any gods, or devine power, sometimes bad things just happen to good people for no reason. Others have to deal with this kind of pain so why not us too. We will get though it. We will try again.

The only solace that I can take from it all is that it's a (mostly) random event that no one could predict or prevent. It's not anyone's fault. Just a bad thing that happened.

For now the only thing we can do is be with her, love her, and make sure she is comfortable.

Mummy, Daddy, and Harry love you baby girl

Eloise.jpg

Hardest day of our life

Last Sunday, the 6th of October, Eloise Woodrow was born by emergency caesarean. We had run into a few speed bumps along the way during the pregnancy so we knew there might be some issues when she was born. They had found she was small for her gestational age and also had a VSD (heart defect), this kind of thing, we didn't find out till later, can be linked to chromosomal issues. The most common issue being Downs Syndrome. There are also two other chromosomal issues, T13 and T18, both which have grim outcomes. It was fine, we told ourselves, we can live with a child with Downs, we have known and been friends with plenty of Downs children it wasn't really a concern. In the end the chance of T13 and T18 is so rare that it isn't going to happen to us. Well it was nice to believe that.

Yesterday our worst fear come true. Eloise has T18. The survival rate for babies with T18 is extremely low, and most don't make it past age one. They don't do the heart operation because of the poor survival rate. This means she has no chance and will die. Maybe in a few days, or weeks, but not months.

As a parent this is not something that we have ever wanted to deal with. Not so soon. Not ever. It's hard enough losing a friend or a relative let alone your own child. Every parent knows they would throw themselves under a bus for their children. If you could take the pain yourself and free them you would. But you can't and that makes it harder.

To the dumb question "Why me?" the cosmos barely bothers to return the reply: why not?

Christopher Hitchens

Not being a believer in any gods, or devine power, sometimes bad things just happen to good people for no reason. Others have to deal with this kind of pain so why not us too. We will get though it. We will try again.

The only solace that I can take from it all is that it's a (mostly) random event that no one could predict or prevent. It's not anyone's fault. Just a bad thing that happened.

For now the only thing we can do is be with her, love her, and make sure she is comfortable.

Mummy, Daddy, and Harry love you baby girl

Alt Text

Hardest day of our life

Last Sunday, the 6th of October, Eloise Woodrow was born by emergency caesarean. We had run into a few speed bumps along the way during the pregnancy so we knew there might be some issues when she was born. They had found she was small for her gestational age and also had a VSD (heart defect), this kind of thing, we didn't find out till later, can be linked to chromosomal issues. The most common issue being Downs Syndrome. There are also two other chromosomal issues, T13 and T18, both which have grim outcomes. It was fine, we told ourselves, we can live with a child with Downs, we have known and been friends with plenty of Downs children it wasn't really a concern. In the end the chance of T13 and T18 is so rare that it isn't going to happen to us. Well it was nice to believe that.

Yesterday our worst fear come true. Eloise has T18. The survival rate for babies with T18 is extremely low, and most don't make it past age one. They don't do the heart operation because of the poor survival rate. This means she has no chance and will die. Maybe in a few days, or weeks, but not months.

As a parent this is not something that we have ever wanted to deal with. Not so soon. Not ever. It's hard enough losing a friend or a relative let alone your own child. Every parent knows they would throw themselves under a bus for their children. If you could take the pain yourself and free them you would. But you can't and that makes it harder.

To the dumb question "Why me?" the cosmos barely bothers to return the reply: why not?

Christopher Hitchens

Not being a believer in any gods, or devine power, sometimes bad things just happen to good people for no reason. Others have to deal with this kind of pain so why not us too. We will get though it. We will try again.

The only solace that I can take from it all is that it's a (mostly) random event that no one could predict or prevent. It's not anyone's fault. Just a bad thing that happened.

For now the only thing we can do is be with her, love her, and make sure she is comfortable.

Mummy, Daddy, and Harry love you baby girl

Alt Text

Oh God my plugins! My precious QGIS plugins

tl;dr

The API had to change. We don't like breaking plugins. It makes us sad. We did it now to save pain in the future. You will like the new version better. Trust me.

What happened to my cheese?

When updating to QGIS 2.0 you might have noticed two things. (Apart from all the new awesome stuff!)

  1. All your settings have been set back to defaults
  2. Some of your plugins are gone, or missing in the installer.

Resetting of settings is caused by QGIS now storing its 2.0 settings in a different folder then we used for 1.8. In 1.8, all your plugins, etc, were stored in the ./qgis folder in your home directory, in 2.0 these are now stored in ./qgis2. The reason will become evident later. All user settings, the UI layout, database connections, etc, are now stored in a QGIS location. In windows this in the registry key HKEY_CURRENT_USER\Software\QGIS\QGIS2. So this explains why your settings are missing when you first load QGIS 2.0.

Why did we have to move the settings location?

Good question.

2.0 is very different from 1.8. There has been a lot of work to make this the best version we have ever made, new features, more bug fixes, a bigger dev team, and a even bigger community. Being the next major release we had to make some calls to remove some of the old code and features that were weighing us down. Features such as the old labelling engine, old symbol engine, the old vector API. Carrying old code and old out dated features into the future can sometimes really hurt a project and they have to be cut loose. Because of the massive amount of changes in 2.0 people needed to be able to run 2.0 and 1.8 on the same machine without causing any issues. If they both store settings in the same location this would have had bad results.

Why move the settings. Part 2

Moving the settings was also a result of having non backwards compatible plugins between 1.x and 2.x. If we kept both plugins in the same folder it just wouldn't work. You would install a 1.8 version of a plugin, I would update my plugin to 2.0, you then install the same plugin in 2.0, and now you 1.8 version is broken. Fun!. To avoid this we moved all QGIS 2.0 stuff into ./qgis2.

Why did my plugins break anyway. Why not just leave them be.

In 1.x we were using SIP v1. This meant the framework we used, PyQt, felt more like C++ then it did Python. If you are a Python developer then this isn't a very fun thing to deal with. In SIP v1 you need to tell PyQt, and our QGIS API, what to convert the type to. feature['mycolumn'].toInt() that is pretty gross. In V2 you can just do feature['mycolumn'] and SIP will auto convert the type for you. This makes our API feel more like Python and less like C++. There are other changes when using SIP V2 but you get the idea. Unfortunately SIP v1 and v2 do not work together so we couldn't make the code backwards compatible. This was also a forced change for us. Once we switch to Python 3 at some stage in the future V2 would be the default and we have to change then. The bright side of this change is most of the time you are removing code. Consider it a good time to go though your code, give it a bit of a polish, and remove anything that is no longer needed.

There was another major API change that needed to happen. Vector API update. In order to allow for multithreading in the future, and we all know everyone is looking forward to that, we needed to change how code can ask for features from a layer. The old method would never work in a multithreaded structure and had to go.

What can I do if I need a plugin?

Having a plugin missing from the plugin installer when you really need it can be a bit of a pain. Plugin authors are working hard to update there plugins. I approve about two a day into the plugin repository. While most plugins might be updated at some stage. There are some things that you can do if you need a plugin update to work with 2.0.

  1. Email the author of the plugin to see where they are at with the update

  2. Email the author and offer your help to update the plugin. Remember a lot of plugins are written by volunteers who just need the plugin to get their work done and wanted to share it with everyone.

  3. If the author has no intention of updating the plugin, or can't be contacted. You are free to update you local copy and offer it back to the community as the updated copy. If you are going to upload it back to the plugin repository please try to contact the author and seek permission first. I will be watching for copies of plugins to make sure we don't end up with 10 versions of the same plugin. The GPL allows for you to modify and share your updated version but it's nice to keep the original author in the loop. If the author no longer wants to maintain the plugin and you are able to then contact me and I will make you the owner of the plugin. Overall be nice not evil, we are all friends here.

  4. If you don't have, or know someone with, the skills to update the plugin. You can contact a developer to help update the plugin for you. Companies like mine, or Faunalia, or a whole range of other open source devs, can normally be contracted to update a plugin if needed.

Moving forward

We like the new API. It makes the Python side of QGIS much cleaner. There is still more work to do, it's never ending, but this is a good step. We don't like breaking plugins, but breaking a few now is better then breaking heaps as the popularity of QGIS continues to grow.

Oh God my plugins! My precious QGIS plugins

tl;dr

The API had to change. We don't like breaking plugins. It makes us sad. We did it now to save pain in the future. You will like the new version better. Trust me.

What happened to my cheese?

When updating to QGIS 2.0 you might have noticed two things. (Apart from all the new awesome stuff!)

  1. All your settings have been set back to defaults
  2. Some of your plugins are gone, or missing in the installer.

Resetting of settings is caused by QGIS now storing its 2.0 settings in a different folder then we used for 1.8. In 1.8, all your plugins, etc, were stored in the ./qgis folder in your home directory, in 2.0 these are now stored in ./qgis2. The reason will become evident later. All user settings, the UI layout, database connections, etc, are now stored in a QGIS location. In windows this in the registry key HKEY_CURRENT_USER\Software\QGIS\QGIS2. So this explains why your settings are missing when you first load QGIS 2.0.

Why did we have to move the settings location?

Good question.

2.0 is very different from 1.8. There has been a lot of work to make this the best version we have ever made, new features, more bug fixes, a bigger dev team, and a even bigger community. Being the next major release we had to make some calls to remove some of the old code and features that were weighing us down. Features such as the old labelling engine, old symbol engine, the old vector API. Carrying old code and old out dated features into the future can sometimes really hurt a project and they have to be cut loose. Because of the massive amount of changes in 2.0 people needed to be able to run 2.0 and 1.8 on the same machine without causing any issues. If they both store settings in the same location this would have had bad results.

Why move the settings. Part 2

Moving the settings was also a result of having non backwards compatible plugins between 1.x and 2.x. If we kept both plugins in the same folder it just wouldn't work. You would install a 1.8 version of a plugin, I would update my plugin to 2.0, you then install the same plugin in 2.0, and now you 1.8 version is broken. Fun!. To avoid this we moved all QGIS 2.0 stuff into ./qgis2.

Why did my plugins break anyway. Why not just leave them be.

In 1.x we were using SIP v1. This meant the framework we used, PyQt, felt more like C++ then it did Python. If you are a Python developer then this isn't a very fun thing to deal with. In SIP v1 you need to tell PyQt, and our QGIS API, what to convert the type to. feature['mycolumn'].toInt() that is pretty gross. In V2 you can just do feature['mycolumn'] and SIP will auto convert the type for you. This makes our API feel more like Python and less like C++. There are other changes when using SIP V2 but you get the idea. Unfortunately SIP v1 and v2 do not work together so we couldn't make the code backwards compatible. This was also a forced change for us. Once we switch to Python 3 at some stage in the future V2 would be the default and we have to change then. The bright side of this change is most of the time you are removing code. Consider it a good time to go though your code, give it a bit of a polish, and remove anything that is no longer needed.

There was another major API change that needed to happen. Vector API update. In order to allow for multithreading in the future, and we all know everyone is looking forward to that, we needed to change how code can ask for features from a layer. The old method would never work in a multithreaded structure and had to go.

What can I do if I need a plugin?

Having a plugin missing from the plugin installer when you really need it can be a bit of a pain. Plugin authors are working hard to update there plugins. I approve about two a day into the plugin repository. While most plugins might be updated at some stage. There are some things that you can do if you need a plugin update to work with 2.0.

  1. Email the author of the plugin to see where they are at with the update

  2. Email the author and offer your help to update the plugin. Remember a lot of plugins are written by volunteers who just need the plugin to get their work done and wanted to share it with everyone.

  3. If the author has no intention of updating the plugin, or can't be contacted. You are free to update you local copy and offer it back to the community as the updated copy. If you are going to upload it back to the plugin repository please try to contact the author and seek permission first. I will be watching for copies of plugins to make sure we don't end up with 10 versions of the same plugin. The GPL allows for you to modify and share your updated version but it's nice to keep the original author in the loop. If the author no longer wants to maintain the plugin and you are able to then contact me and I will make you the owner of the plugin. Overall be nice not evil, we are all friends here.

  4. If you don't have, or know someone with, the skills to update the plugin. You can contact a developer to help update the plugin for you. Companies like mine, or Faunalia, or a whole range of other open source devs, can normally be contracted to update a plugin if needed.

Moving forward

We like the new API. It makes the Python side of QGIS much cleaner. There is still more work to do, it's never ending, but this is a good step. We don't like breaking plugins, but breaking a few now is better then breaking heaps as the popularity of QGIS continues to grow.

Oh God my plugins! My precious QGIS plugins

tl;dr

The API had to change. We don't like breaking plugins. It makes us sad. We did it now to save pain in the future. You will like the new version better. Trust me.

What happened to my cheese?

When updating to QGIS 2.0 you might have noticed two things. (Apart from all the new awesome stuff!)

  1. All your settings have been set back to defaults
  2. Some of your plugins are gone, or missing in the installer.

Resetting of settings is caused by QGIS now storing its 2.0 settings in a different folder then we used for 1.8. In 1.8, all your plugins, etc, were stored in the ./qgis folder in your home directory, in 2.0 these are now stored in ./qgis2. The reason will become evident later. All user settings, the UI layout, database connections, etc, are now stored in a QGIS location. In windows this in the registry key HKEY_CURRENT_USER\Software\QGIS\QGIS2. So this explains why your settings are missing when you first load QGIS 2.0.

Why did we have to move the settings location?

Good question.

2.0 is very different from 1.8. There has been a lot of work to make this the best version we have ever made, new features, more bug fixes, a bigger dev team, and a even bigger community. Being the next major release we had to make some calls to remove some of the old code and features that were weighing us down. Features such as the old labelling engine, old symbol engine, the old vector API. Carrying old code and old out dated features into the future can sometimes really hurt a project and they have to be cut loose. Because of the massive amount of changes in 2.0 people needed to be able to run 2.0 and 1.8 on the same machine without causing any issues. If they both store settings in the same location this would have had bad results.

Why move the settings. Part 2

Moving the settings was also a result of having non backwards compatible plugins between 1.x and 2.x. If we kept both plugins in the same folder it just wouldn't work. You would install a 1.8 version of a plugin, I would update my plugin to 2.0, you then install the same plugin in 2.0, and now you 1.8 version is broken. Fun!. To avoid this we moved all QGIS 2.0 stuff into ./qgis2.

Why did my plugins break anyway. Why not just leave them be.

In 1.x we were using SIP v1. This meant the framework we used, PyQt, felt more like C++ then it did Python. If you are a Python developer then this isn't a very fun thing to deal with. In SIP v1 you need to tell PyQt, and our QGIS API, what to convert the type to. feature['mycolumn'].toInt() that is pretty gross. In V2 you can just do feature['mycolumn'] and SIP will auto convert the type for you. This makes our API feel more like Python and less like C++. There are other changes when using SIP V2 but you get the idea. Unfortunately SIP v1 and v2 do not work together so we couldn't make the code backwards compatible. This was also a forced change for us. Once we switch to Python 3 at some stage in the future V2 would be the default and we have to change then. The bright side of this change is most of the time you are removing code. Consider it a good time to go though your code, give it a bit of a polish, and remove anything that is no longer needed.

There was another major API change that needed to happen. Vector API update. In order to allow for multithreading in the future, and we all know everyone is looking forward to that, we needed to change how code can ask for features from a layer. The old method would never work in a multithreaded structure and had to go.

What can I do if I need a plugin?

Having a plugin missing from the plugin installer when you really need it can be a bit of a pain. Plugin authors are working hard to update there plugins. I approve about two a day into the plugin repository. While most plugins might be updated at some stage. There are some things that you can do if you need a plugin update to work with 2.0.

  1. Email the author of the plugin to see where they are at with the update

  2. Email the author and offer your help to update the plugin. Remember a lot of plugins are written by volunteers who just need the plugin to get their work done and wanted to share it with everyone.

  3. If the author has no intention of updating the plugin, or can't be contacted. You are free to update you local copy and offer it back to the community as the updated copy. If you are going to upload it back to the plugin repository please try to contact the author and seek permission first. I will be watching for copies of plugins to make sure we don't end up with 10 versions of the same plugin. The GPL allows for you to modify and share your updated version but it's nice to keep the original author in the loop. If the author no longer wants to maintain the plugin and you are able to then contact me and I will make you the owner of the plugin. Overall be nice not evil, we are all friends here.

  4. If you don't have, or know someone with, the skills to update the plugin. You can contact a developer to help update the plugin for you. Companies like mine, or Faunalia, or a whole range of other open source devs, can normally be contracted to update a plugin if needed.

Moving forward

We like the new API. It makes the Python side of QGIS much cleaner. There is still more work to do, it's never ending, but this is a good step. We don't like breaking plugins, but breaking a few now is better then breaking heaps as the popularity of QGIS continues to grow.

QGIS 2.0: Dealing with Null values in pyqgis

Nothing in life ever comes free. Each time you make a desision there can sometimes be long a lasting effect. This is exectly the case with the new QGIS 2.0 pyqgis API. Changing to the new api was a big step in order make the API clear and more Pythonic. But there was a small detail to fix.

In QGIS 2.0 we can now just do this to read the attribute value for a field:

>>> feature['yourcolumn']
"Hello World"

What would you expect to get if the value was NULL (not empty string). Would you expect to see None? You would think so. Right? However lets just check that.

>>> feature['yourcolumn']
NULL

NULL? What the heck? That isn't None! What is NULL?

>>> type(NULL)
<class 'PyQt4.QtCore.QPyNullVariant'>

QPyNullVariant WA! WHAAAT! Why didn't we get None? Turns out by removing QVariant from PyQt it had some impact on methods that expected a NULL QVariant - A QVariant with no value. Passing None didn't work because those methods needed the type information that QVariant holds, even when NULL.

When using SIP V2, which is what QGIS 2.0 is using, PyQt will auto convert any Null QVariants to QPyNullVariant.

The NULL you see is a variable masking the QPyNullVariant so that the output is nicer and it's easier to work with. We have also added a bunch of methods to QPyNullVariant in order to make it act as much like None as we can.

If you see a NULL this is how you can deal with it:

>>> feature['yourcolumn']
NULL

>>> if not feature['nullcolumn']:
>>>     print "Was null"
Was null

>>> if feature['nullcolumn'] == NULL:
>>> print "Was null"
Was null

NULL will also return False if boolean checked:

>>> value = NULL
>>> if value:
...  print "This value wasn't null"
... else:
...  print 'This value was null' 
This value was null

It will also be equal to any other NULL aka QPyNullVariant variable

>>> value = NULL
>>> value2 = NULL
>>> value == value2
True
>>> value = 100
>>> value2 = NULL
>>> value == value2
False

Does None is NULL work? No.

One way to check if something is Null in Python is to use value is None however this will not work with our NULL type. Overloading the is operator in Python is not supported and there is no way we can support this - trust me I have tried. is is really doing id(object) == id(object) under the hood:

DO NOT do the following if you are checking for null values in pyqgis unless you know the return type is None:

>>> value = NULL
>>> value is None
false

QGIS 2.0: Dealing with Null values in pyqgis

Nothing in life ever comes free. Each time you make a desision there can sometimes be long a lasting effect. This is exectly the case with the new QGIS 2.0 pyqgis API. Changing to the new api was a big step in order make the API clear and more Pythonic. But there was a small detail to fix.

In QGIS 2.0 we can now just do this to read the attribute value for a field:

>>> feature['yourcolumn']
"Hello World"

What would you expect to get if the value was NULL (not empty string). Would you expect to see None? You would think so. Right? However lets just check that.

>>> feature['yourcolumn']
NULL

NULL? What the heck? That isn't None! What is NULL?

>>> type(NULL)
<class 'PyQt4.QtCore.QPyNullVariant'>

QPyNullVariant WA! WHAAAT! Why didn't we get None? Turns out by removing QVariant from PyQt it had some impact on methods that expected a NULL QVariant - A QVariant with no value. Passing None didn't work because those methods needed the type information that QVariant holds, even when NULL.

When using SIP V2, which is what QGIS 2.0 is using, PyQt will auto convert any Null QVariants to QPyNullVariant.

The NULL you see is a variable masking the QPyNullVariant so that the output is nicer and it's easier to work with. We have also added a bunch of methods to QPyNullVariant in order to make it act as much like None as we can.

If you see a NULL this is how you can deal with it:

>>> feature['yourcolumn']
NULL

>>> if not feature['nullcolumn']:
>>>     print "Was null"
Was null

>>> if feature['nullcolumn'] == NULL:
>>> print "Was null"
Was null 

NULL will also return False if boolean checked:

>>> value = NULL
>>> if value:
... print "This value wasn't null"
... else:
...     print 'This value was null' 
This value was null

It will also be equal to any other NULL aka QPyNullVariant variable

>>> value = NULL
>>> value2 = NULL
>>> value == value2
True
>>> value = 100
>>> value2 = NULL
>>> value == value2
False 

Does None is NULL work? No.

One way to check if something is Null in Python is to use value is None however this will not work with our NULL type. Overloading the is operator in Python is not supported and there is no way we can support this - trust me I have tried. is is really doing id(object) == id(object) under the hood:

DO NOT do the following if you are checking for null values in pyqgis unless you know the return type is None:

>>> value = NULL
>>> value is None
false

QGIS 2.0: Dealing with Null values in pyqgis

Nothing in life ever comes free. Each time you make a desision there can sometimes be long a lasting effect. This is exectly the case with the new QGIS 2.0 pyqgis API. Changing to the new api was a big step in order make the API clear and more Pythonic. But there was a small detail to fix.

In QGIS 2.0 we can now just do this to read the attribute value for a field:

>>> feature['yourcolumn']
"Hello World"

What would you expect to get if the value was NULL (not empty string). Would you expect to see None? You would think so. Right? However lets just check that.

>>> feature['yourcolumn']
NULL

NULL? What the heck? That isn't None! What is NULL?

>>> type(NULL)
<class 'PyQt4.QtCore.QPyNullVariant'>

QPyNullVariant WA! WHAAAT! Why didn't we get None? Turns out by removing QVariant from PyQt it had some impact on methods that expected a NULL QVariant - A QVariant with no value. Passing None didn't work because those methods needed the type information that QVariant holds, even when NULL.

When using SIP V2, which is what QGIS 2.0 is using, PyQt will auto convert any Null QVariants to QPyNullVariant.

The NULL you see is a variable masking the QPyNullVariant so that the output is nicer and it's easier to work with. We have also added a bunch of methods to QPyNullVariant in order to make it act as much like None as we can.

If you see a NULL this is how you can deal with it:

>>> feature['yourcolumn']
NULL

>>> if not feature['nullcolumn']:
>>>     print "Was null"
Was null

>>> if feature['nullcolumn'] == NULL:
>>> print "Was null"
Was null 

NULL will also return False if boolean checked:

>>> value = NULL
>>> if value:
... print "This value wasn't null"
... else:
...     print 'This value was null' 
This value was null

It will also be equal to any other NULL aka QPyNullVariant variable

>>> value = NULL
>>> value2 = NULL
>>> value == value2
True
>>> value = 100
>>> value2 = NULL
>>> value == value2
False 

Does None is NULL work? No.

One way to check if something is Null in Python is to use value is None however this will not work with our NULL type. Overloading the is operator in Python is not supported and there is no way we can support this - trust me I have tried. is is really doing id(object) == id(object) under the hood:

DO NOT do the following if you are checking for null values in pyqgis unless you know the return type is None:

>>> value = NULL
>>> value is None
false

Death to the message box! Use the QGIS messagebar

The good ol' message box. So easy to use. Yet such as stab in the users user experience metaphorical heart. Nothing like working along and getting a nice dialog to tell you can't do something or that the operation has finished

dave.png

info.png

You might think. "Well there isn't really anything wrong with that. I needed to tell the user everything is done". Sure but what you didn't need to do was stop the user and make them acknowledge it. Consider if your car made you OK something you each time your speed changed.

speed.png

speed2.png

speed3.png

Pretty annoying.

What is the alternative then?

Introducing the QGIS message bar

errorbar.png

infobar.png

warningbar.png

If you have been using QGIS 1.9 (the dev version for 2.0) you might have noticed it already. It's a great new way for us to let the user know about something without blocking their work or getting in the way. The best part is your can even access the message bar to post messages from your plugins.

iface.messageBar().pushMessage("Error", "I'm sorry Dave, I'm afraid I can't do that", level=QgsMessageBar.CRITICAL)

errorbar.png

It even has timer to show a message for a limited time.

iface.messageBar().pushMessage("Error", "I'm sorry Dave, ..", level=QgsMessageBar.CRITICAL, duration=3)

errorbar-timed.png

or showing a button for more info

def showError():
    pass

widget = iface.messageBar().createMessage("Missing Layers", "Show Me")
button = QPushButton(widget)
button.setText("Show Me")
button.pressed.connect(showError)
widget.layout().addWidget(button)
iface.messageBar().pushWidget(widget, QgsMessageBar.WARNING)

bar-button.png

In your own widgets

You can even use a message bar in your own dialog so you don't have to show a message box or if it doesn't make sense to show it in the main QGIS window.

class MyDialog(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.bar = QgsMessageBar()
        self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed )
        self.setLayout(QGridLayout())
        self.layout().setContentsMargins(0,0,0,0)
        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok)
        self.buttonbox.accepted.connect(self.run)
        self.layout().addWidget(self.buttonbox , 0,0,2,1)
        self.layout().addWidget(self.bar, 0,0,1,1)
        
    def run(self):
        self.bar.pushMessage("Hello", "World", level=QgsMessageBar.INFO)

dialog-with-bar.png

Don't abuse it

Like anything the message bar can be abused if not careful. Avoid dumping debugging messages to it as this will annoy users rather then help. Use QgsMessageLog.logMessage() if you need to write debugging information. Also consider which messages you post there as posting too many messages will mean the user might just ignore it like they do with message boxes.

Death to the message box! Use the QGIS messagebar

The good ol' message box. So easy to use. Yet such as stab in the users user experience metaphorical heart. Nothing like working along and getting a nice dialog to tell you can't do something or that the operation has finished

Alt Text

Alt Text

You might think. "Well there isn't really anything wrong with that. I needed to tell the user everything is done". Sure but what you didn't need to do was stop the user and make them acknowledge it. Consider if your car made you OK something you each time your speed changed.

Alt Text

Alt Text

Alt Text

Pretty annoying.

What is the alternative then?

Introducing the QGIS message bar

Alt Text

Alt Text

Alt Text

If you have been using QGIS 1.9 (the dev version for 2.0) you might have noticed it already. It's a great new way for us to let the user know about something without blocking their work or getting in the way. The best part is your can even access the message bar to post messages from your plugins.

iface.messageBar().pushMessage("Error", "I'm sorry Dave, I'm afraid I can't do that", level=QgsMessageBar.CRITICAL)

Alt Text

It even has timer to show a message for a limited time.

iface.messageBar().pushMessage("Error", "I'm sorry Dave, ..", level=QgsMessageBar.CRITICAL, duration=3)

Alt Text

or showing a button for more info

def showError():
    pass

widget = iface.messageBar().createMessage("Missing Layers", "Show Me")
button = QPushButton(widget)
button.setText("Show Me")
button.pressed.connect(showError)
widget.layout().addWidget(button)
iface.messageBar().pushWidget(widget, QgsMessageBar.WARNING)

Alt Text

In your own widgets

You can even use a message bar in your own dialog so you don't have to show a message box or if it doesn't make sense to show it in the main QGIS window.

class MyDialog(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.bar = QgsMessageBar()
        self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed )
        self.setLayout(QGridLayout())
        self.layout().setContentsMargins(0,0,0,0)
        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok)
        self.buttonbox.accepted.connect(self.run)
        self.layout().addWidget(self.buttonbox , 0,0,2,1)
        self.layout().addWidget(self.bar, 0,0,1,1)

    def run(self):
        self.bar.pushMessage("Hello", "World", level=QgsMessageBar.INFO)

Alt Text

Don't abuse it

Like anything the message bar can be abused if not careful. Avoid dumping debugging messages to it as this will annoy users rather then help. Use QgsMessageLog.logMessage() if you need to write debugging information. Also consider which messages you post there as posting too many messages will mean the user might just ignore it like they do with message boxes.

Death to the message box! Use the QGIS messagebar

The good ol' message box. So easy to use. Yet such as stab in the users user experience metaphorical heart. Nothing like working along and getting a nice dialog to tell you can't do something or that the operation has finished

Alt Text

Alt Text

You might think. "Well there isn't really anything wrong with that. I needed to tell the user everything is done". Sure but what you didn't need to do was stop the user and make them acknowledge it. Consider if your car made you OK something you each time your speed changed.

Alt Text

Alt Text

Alt Text

Pretty annoying.

What is the alternative then?

Introducing the QGIS message bar

Alt Text

Alt Text

Alt Text

If you have been using QGIS 1.9 (the dev version for 2.0) you might have noticed it already. It's a great new way for us to let the user know about something without blocking their work or getting in the way. The best part is your can even access the message bar to post messages from your plugins.

iface.messageBar().pushMessage("Error", "I'm sorry Dave, I'm afraid I can't do that", level=QgsMessageBar.CRITICAL)

Alt Text

It even has timer to show a message for a limited time.

iface.messageBar().pushMessage("Error", "I'm sorry Dave, ..", level=QgsMessageBar.CRITICAL, duration=3)

Alt Text

or showing a button for more info

def showError():
    pass

widget = iface.messageBar().createMessage("Missing Layers", "Show Me")
button = QPushButton(widget)
button.setText("Show Me")
button.pressed.connect(showError)
widget.layout().addWidget(button)
iface.messageBar().pushWidget(widget, QgsMessageBar.WARNING)

Alt Text

In your own widgets

You can even use a message bar in your own dialog so you don't have to show a message box or if it doesn't make sense to show it in the main QGIS window.

class MyDialog(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.bar = QgsMessageBar()
        self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed )
        self.setLayout(QGridLayout())
        self.layout().setContentsMargins(0,0,0,0)
        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok)
        self.buttonbox.accepted.connect(self.run)
        self.layout().addWidget(self.buttonbox , 0,0,2,1)
        self.layout().addWidget(self.bar, 0,0,1,1)

    def run(self):
        self.bar.pushMessage("Hello", "World", level=QgsMessageBar.INFO)

Alt Text

Don't abuse it

Like anything the message bar can be abused if not careful. Avoid dumping debugging messages to it as this will annoy users rather then help. Use QgsMessageLog.logMessage() if you need to write debugging information. Also consider which messages you post there as posting too many messages will mean the user might just ignore it like they do with message boxes.

The little pyqgis query engine

Sean Gillies has managed to get me addicted to using generators, itertools, map, filter, and a generally more declarative style of programming.

What has this got to do with anything? Well let me explain. A little project I have recently started working on in my free time is a mini query engine for pyqgis to make fetching features easier. The goals are simple.

  • Use a query style syntax to say what I need, not how to get it. The basics of declarative programming.
  • Use generators to save on memory unless the user asks.

Before we go any further, just note that this is just a hobby project of mine. Not feature complete nor bug free but it's evolving.

The code can be found on github or its homepage.

What good is a mini query engine? Lets try with some examples.

Get all the features that match the condition `postcode > 6164 OR postcode < 6167'. We will use QgsExpression because that provides a nice where clause type base for us to use.

exp = QgsExpression("postcode > 6164 OR postcode < 6167")
fields = layer.pendingFields()
exp.prepare(fields)
for feature in layer.getFeatures():
    if exp.evaluate(feature):
        print "Pass"

at best you can reduce it to this:

exp = QgsExpression("postcode > 6164 OR postcode < 6167")
fields = layer.pendingFields()
exp.prepare(fields)
features = filter(exp.evaluate, layer.getFeatures())

Not too bad. But still. it's a bit of a pain because you have to care about QgsExpression and looping all the features to check.

How about something like this?

q = query(layer).where("postcode > 6164 OR postcode < 6167")
for feature in q():
    print feature

Define a query on layer and return only the features that match the .where() condition. Sounds pretty descriptive to me.

Nothing is executed until you call the query object itself q() and the return result is a generator so it will only serve up records as we ask. The return type is a Python dict because they are simple, fast, and work well for a return type.

>>> from query import query
>>> q = query(layer).where("postcode > 6164 OR postcode < 6167")
>>> type(q)
<class 'query.Query'>
>>> results = q()
>>> type(results)
<generator object <genexpr> at 0x1A8DDD78>
>>> results.next()
{
u'old': u'http://www.seabreeze.com.au|mylink', 
u'pin_string': u'286633', 
'qgs_geometry': <qgis.core.QgsGeometry object at 0x1A8DF588>, 
u'bool': u'F', 
u'location': None, 
u'lot': u'LOT 79', 
'qgs_feature': <qgis.core.QgsFeature object at 0x1A8DF0C0>
}

Select support

What is the point of a query if you can't ask it to give you just what you need?

>>> q = (query(layer).where("postcode > 6164 OR postcode < 6167")
                     .select('assessment','address', 'lot',
                              geom = lambda f: f.geometry().buffer(20,3),
                              mylot = lambda f: int(f['house_numb']) * 100))
>>> q().next()
{
'geom': <qgis.core.QgsGeometry object at 0x1A8E64B0>, 
'assessment': u'4309719', 
'mylot': 7900, 
'lot': u'LOT 79', 
'address': u'BIRCHLEY RD'
}

You can use "colname" or any Python callable in the select statement. Using keyword arguments is the same as "Col" AS MyName in SQL.

On the TODO list

I would really like to have some kind of index support in the future to make queries run faster. I had basic index support working using a dict however it was nothing smart and was hard coded. QgsExpression does provide support to walk the generated tree see what the expression includes. In "theory" it would involve walking the expression tree and calculating what should be used for index lookup.

Join support would also be nice. Attribute and spatial.

Helpers welcome

Like I said at the start, this is just a hobby project and it's still only in early days however I am always happy for help if you have ideas, or know how to improve something. If you find it handy that would be cool to know too.

Installing

  • Just download the code from here.
  • Add the files to your Python project
  • from query import query

Back to Top

Sustaining Members