I am trying to get a simple bar chart on my QGIS 2.6 map. I have done that with diagrams.
It seems to me it is not possible to add simple values to each bar (say there are three bars at a point). I have tried the Dialog plugin, but it only creates a picture file in the print composer. Any ideas?
[GIS] QGIS bar chart with labels
qgis
Related Solutions
As directly using a Openlayers plugin layer in a programatically created print composition is not possible (see the accepted answer), this approach can at least be used to create a stationary image file (jpg/png) from a desired Openlayers map extent. Maybe this is helpful to somebody somehow...
It is based on the basemap2Image script which I modified slightly to make it callable from within a PyQGIS script running in the Python console. To use it, you need the following helper functions.
Getting the edge coordinates of a vector layer extent:
###################################
# function to get coordinates of a layer extent
###################################
def getCoordinatesOfLayerExtent(layer):
print 'getting coordinates of layer extent'
layerRectangle = layer.extent()
coordinates = [layerRectangle.xMinimum(), layerRectangle.yMinimum(), layerRectangle.xMaximum(), layerRectangle.yMaximum()]
return coordinates
Call it by providing a QgsVectorLayer object, e.g.
vectorLayerCoordinates = getCoordinatesOfLayerExtent(myFavoriteVectorLayer)
Coordinates have to be passed to the script in EPSG:3857, so if your vector layer does not use that CRS by default, use the following function to transform the coordinates first:
###################################
# function to transform a set of coordinates from one CRS to another
###################################
def transformCoordinates(coordinates, fromCRS, toCRS):
print 'transforming coordinates between crs'
crsSrc = QgsCoordinateReferenceSystem(fromCRS)
crsDest = QgsCoordinateReferenceSystem(toCRS)
xform = QgsCoordinateTransform(crsSrc, crsDest)
# convert list of coordinates to QgsPoint objects
coordinatesAsPoints = [QgsPoint(coordinates[0], coordinates[1]), QgsPoint(coordinates[2], coordinates[3])]
# do transformation for each point
transformedCoordinatesAsPoints = [xform.transform(point) for point in coordinatesAsPoints]
# transform the QgsPoint objects back to a list of coordinates
transformedCoordinates = [transformedCoordinatesAsPoints[0].x(), transformedCoordinatesAsPoints[0].y(), transformedCoordinatesAsPoints[1].x(), transformedCoordinatesAsPoints[1].y()]
return transformedCoordinates
Call it by providing your list of coordinates, the origin CRS and the desired destination CRS, e.g.:
transformedCoordinates = transformCoordinates(coordinates, 4326, 3857)
Now create an empty file called __init__.py
next to your script (this is necessary for importing functions from other scripts within the same folder) and another one, looking like this (this is the modified basemap2Image script):
#!/usr/bin/env python
# Nov 30, 2012
# Angel Joyce Torres Ramirez
# joys.tower@gmail.com
# I am not responsible for any use you give to this program, I did self-study and study purposes
# License:
# BaseMap2Image is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
import sys
import signal
from qgis.core import *
from qgis.utils import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
from functools import partial
def main(htmlDirectory, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8):
print arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
def onLoadFinished(result):
global repaintEnd
global xMin
global yMin
global xMax
global yMax
global width
global height
global fileOut
global fileFormat
if not result:
print "Request failed"
web.close()
action = "map.zoomToExtent(new OpenLayers.Bounds("+xMin+", "+yMin+", "+xMax+", "+yMax+"), true);"
web.page().mainFrame().evaluateJavaScript(action)
repaintEnd = None
pauseReq()
img = QImage(web.page().mainFrame().contentsSize(), QImage.Format_ARGB32_Premultiplied)
imgPainter = QPainter(img)
web.page().mainFrame().render(imgPainter)
imgPainter.end()
img = img.scaled(width, height, Qt.KeepAspectRatio, Qt.SmoothTransformation )
img.save( fileOut, fileFormat)
print 'saving basemap'
web.close()
def pauseReq():
global repaintEnd
timerMax.start()
while not repaintEnd:
qApp.processEvents()
timerMax.stop()
def endTimer():
global repaintEnd
repaintEnd = True
def resolutions():
if olResolutions == None:
resVariant = web.page().mainFrame().evaluateJavaScript("map.layers[0].resolutions")
olResolutions = []
for res in resVariant.toList():
olResolutions.append(res.toDouble()[0])
return olResolutions
global layer
layer = arg1
global xMin
xMin = arg2
global yMin
yMin = arg3
global xMax
xMax = arg4
global yMax
yMax = arg5
global fileOut
fileOut = arg6
global fileFormat
fileFormat="png"
if fileOut.find(".") != -1:
fileFormat = fileOut.split('.')[1]
if fileFormat == "jpg":
fileFormat = "jpeg"
timeWait = 2000
global width
width = float(arg7)
global height
height= float(arg8)
web = QWebView()
timerMax = QTimer()
global repaintEnd
repaintEnd = None
olResolutions = None
timerMax.setSingleShot(True)
timerMax.setInterval(int(timeWait))
QObject.connect(timerMax, SIGNAL("timeout()"), endTimer)
web.setFixedSize(width,height)
pathUrl = "file:///%s/%s.html" % (htmlDirectory, layer)
web.connect(web, SIGNAL("loadFinished(bool)"), onLoadFinished)
web.load(QUrl(pathUrl))
web.show()
To call the main function of this script, you have to pass the following arguments:
htmlDirectory: path to the
html
directory that was part of the github package (clone the repository or download as zip, then copy the html directory to a convenient location)mapProvider: choose one from the
html
directory to which a corresponding .html file exists, e.g. 'google_streets' or 'osm'xMin: coordinates of layer extent in EPSG:3857
yMin: coordinates of layer extent in EPSG:3857
xMax: coordinates of layer extent in EPSG:3857
yMax: coordinates of layer extent in EPSG:3857
filename: path and filename of the output image file
width: width of the output image file
height: height of the output image file
Make sure to pass all arguments as strings since the script was originally developed to be used from the command line where no other types exist. An examplary call could look something like this:
basemap2Image.main(r'c:\PyQGIS\html', 'osm', str(transformedCoordinates[0]), str(transformedCoordinates[1]), str(transformedCoordinates[2]), str(transformedCoordinates[3]), r'c:\PyQGIS\basemap.png', '1600', '1200')
Last but not least, in order to run other Python scripts from a running Python console script, you have to tell the console where to look for it. The easiest and most permanent way for me to do this was searching for the file console.py
in my QGIS folder and add the line sys.path.append('/path/to/basemap2Image script')
under the import section (restart your QGIS to make it aware of the change).
A lot of work for such a simple feature... however, when running this as described above, a window should pop up, showing you a worldmap of your desired Openlayers provider, then zooming to the given extent, save the content to the given filename and then close the window again. This image file could then be used as a basemap or whatever else in a print composition.
You might want to look at the D3 Render Plugin, which is documented here. I haven't used it much, but it looks promising.
This creates an interactive web page, where clicking on a feature will show a bar graph in a popup window (very simple example below). This has the advantage of not cluttering up your map with bar charts.
It also has a lot of options for projections (some of which QGIS/GDAL don't support!) and has a lot more types of diagram than are available with the standard QGIS Drawing functions.
The output is a javascript web application; if you have JavaScript skills, you can modify this quite easily to get the look you want. (Although numbers aren't added to the bars, that could be done in Javascript)
Best Answer
You can add a HTML frame from Google Charts in QGIS
Note: If you update your chart attributes you need to click 'Refresh HTML' before exporting again in the print composer.