More compact hierarchical layout for dot / Graphviz - graphviz
I produce the following PDF with dot:
My main problem is that the character size is too small even when printed on A3. Also it appears that the graph could be made more compact. E.g. the width is extended by the presence of the blue, green and brown nodes on the upper left corner, but I see no reason why the entire first two rows could not be shifted to the right, to result in an at least 20% reduction of width. I attach the .gv file at the end.
Since I automatically generate the .gv file I can only modify graph-level attributes or attributes for all nodes and edges or change the dot invocation, but I can't fine-tune coordinates or particular nodes.
Do you see any obvious ways I could get a more compact layout that would allow larger character sizes?
The invocation I use is:
dot -Gsize="16.52,11.68" -Gratio="fill" -Glandscape=false -Gsplines=ortho -Tpdf graph.gv -o graph.gv.pdf
graph.gv file
digraph G {
node [
fontname="Times-Bold"
]
concentrate=true
"schemas/toolkit.xsd" [
shape = "record"
style="bold, filled"
fillcolor="cyan"
label = "{toolkit.xsd|vt.edu|OAI/metadata/toolkit}"
]
"schemas/simpledc20021212.xsd" [
shape = "record"
style="bold, filled"
fillcolor="salmon3"
label = "{simpledc20021212.xsd|other domain|http://purl.org/dc/elements/1.1/}"
]
"schemas/stc-v1.30.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{stc-v1.30.xsd|ivoa|STC/stc-v1.30.xsd}"
]
"schemas/oai_dc.xsd" [
shape = "record"
style="bold, filled"
fillcolor="limegreen"
label = "{oai_dc.xsd|openarchives|OAI/2.0/oai_dc/}"
]
"schemas/VOApplication.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{VOApplication.xsd|ivoa|VOApplication/v1.0rc1}"
]
"schemas/xml.xsd" [
shape = "record"
style="bold, filled"
fillcolor="violetred1"
label = "{xml.xsd|w3.org|XML/1998/namespace}"
]
"schemas/xlink.xsd" [
shape = "record"
style="bold, filled"
fillcolor="violetred1"
label = "{xlink.xsd|w3.org|1999/xlink}"
]
"schemas/OpenSkyNode-v0.2.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{OpenSkyNode-v0.2.xsd|ivoa|SkyNode/v0.2}"
]
"schemas/VORegistry-v1.0.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{VORegistry-v1.0.xsd|ivoa|VORegistry/v1.0}"
]
"schemas/VOResource-v1.0.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{VOResource-v1.0.xsd|ivoa|VOResource/v1.0}"
]
"schemas/ConeSearch-v1.0.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{ConeSearch-v1.0.xsd|ivoa|ConeSearch/v1.0}"
]
"schemas/CEAService.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{CEAService.xsd|ivoa|CEA/v1.0rc1}"
]
"schemas/VOTable.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{VOTable.xsd|ivoa|VOTable/v1.1}"
]
"schemas/CEABase.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{CEABase.xsd|ivoa|CEA/base/v1.0rc1}"
]
"schemas/STAP.xsd" [
shape = "record"
style="bold, filled"
fillcolor="yellow"
label = "{STAP.xsd|astrogrid urn|STAP:v1.0}"
]
"schemas/VODataService-v1.0.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{VODataService-v1.0.xsd|ivoa|VODataService/v1.0}"
]
"schemas/SIA-v1.0.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{SIA-v1.0.xsd|ivoa|SIA/v1.0}"
]
"schemas/SSA-v0.4.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{SSA-v0.4.xsd|ivoa|SSA/v0.4}"
]
"schemas/RegistryInterface-v1.0.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{RegistryInterface-v1.0.xsd|ivoa|RegistryInterface/v1.0}"
]
"schemas/SSA-v1.0.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{SSA-v1.0.xsd|ivoa|SSA/v1.0}"
]
"schemas/TAPRegExt-v1.0.xsd" [
shape = "record"
style="bold, filled"
fillcolor="lightskyblue"
label = "{TAPRegExt-v1.0.xsd|ivoa|TAPRegExt/v1.0}"
]
"NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [
shape = "record"
color = "magenta1"
fillcolor = "lemonchiffon1"
style="bold, dashed, rounded, filled"
label = "{ivoa|VOMetadata/v0.1}"
]
"NFhttp://www.w3.org/2001/XMLSchema-instance" [
shape = "record"
color = "magenta1"
fillcolor = "lemonchiffon1"
style="bold, dashed, rounded, filled"
label = "{w3.org|2001/XMLSchema-instance}"
]
"schemas/stc-v1.30.xsd" -> "schemas/xlink.xsd" [color="blue"]
"schemas/oai_dc.xsd" -> "schemas/simpledc20021212.xsd" [color="blue"]
"schemas/VOApplication.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/VOApplication.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/OpenSkyNode-v0.2.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/OpenSkyNode-v0.2.xsd" -> "schemas/VODataService-v1.0.xsd" [color="blue"]
"schemas/OpenSkyNode-v0.2.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/VORegistry-v1.0.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/VORegistry-v1.0.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/VOResource-v1.0.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/ConeSearch-v1.0.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/ConeSearch-v1.0.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/CEAService.xsd" -> "schemas/VOTable.xsd" [color="blue"]
"schemas/CEAService.xsd" -> "schemas/VODataService-v1.0.xsd" [color="blue"]
"schemas/CEAService.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/CEAService.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/CEAService.xsd" -> "schemas/CEABase.xsd" [color="blue"]
"schemas/CEAService.xsd" -> "schemas/VOApplication.xsd" [color="blue"]
"schemas/CEABase.xsd" -> "schemas/VODataService-v1.0.xsd" [color="blue"]
"schemas/STAP.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/VODataService-v1.0.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/VODataService-v1.0.xsd" -> "schemas/stc-v1.30.xsd" [color="blue"]
"schemas/VODataService-v1.0.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/SIA-v1.0.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/SIA-v1.0.xsd" -> "schemas/VODataService-v1.0.xsd" [color="blue"]
"schemas/SIA-v1.0.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/SSA-v0.4.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/SSA-v0.4.xsd" -> "schemas/VODataService-v1.0.xsd" [color="blue"]
"schemas/SSA-v0.4.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/RegistryInterface-v1.0.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/SSA-v1.0.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/SSA-v1.0.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/TAPRegExt-v1.0.xsd" -> "schemas/VOResource-v1.0.xsd" [color="blue"]
"schemas/TAPRegExt-v1.0.xsd" -> "NFhttp://www.ivoa.net/xml/VOMetadata/v0.1" [color="blue"]
"schemas/TAPRegExt-v1.0.xsd" -> "NFhttp://www.w3.org/2001/XMLSchema-instance" [color="blue"]
}
The unflatten utility can lead to a more compact graph.
Try the following command line:
unflatten -f -l 2 graph.gv | dot -Gsize="16.52,11.68" -Gratio="fill" -Glandscape=false -Gsplines=ortho -Tpdf -o graph.gv.pdf
Depending on your various automatically generated graphs, maybe some other values for unflatten are more appropriate to cover all of them.
Related
How to set polygon fill based on imported parameters from postGIS
Have successfully imported polygons in OpenLayers along with popup of pertinent data. Need guidance on assigning fill colors from parameters passed via ajax. your textHoping to assign fill color based on setting parameter in json file. Currently using: var polyStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: [12,240,60] }), stroke: new ol.style.Stroke({ color: [0,0,0], width: 1 }) }); to load the following: const layer = new ol.layer.Vector({ source: new ol.source.Vector({ features:features, projection: 'EPSG: 3857' }), style: polyStyle }); I next tried the following as a test based on the "settings feature the file: // Polygons style var setfcolor = function(features) { console.log(features); var fcolor; if (feature.get("setting")=='Carbonate'){ fcolor = "blue"; } else if (feature.get("setting")=='Clastic: continental'){ fcolor = "yellow"; } else if (feature.get("setting")=='Extrusive: mafic'){ fcolor = "brown"; } }; But it fails and reverts to all black. Snippet of json file is: { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [ [ [ -45.499757432, 60.988125868 ], [ -45.49967049, 60.988157751 ], [ -45.497458466, 60.989470026 ], [ -45.487258845, 60.995518876 ], [ -45.483858593, 60.999870372 ], [ -45.483858591, 60.99987019 ], [ -45.465241806, 60.991366687 ], [ -45.450273556, 60.988997409 ], [ -45.422944921, 60.990687369 ], [ -45.42294477, 60.990687194 ], [ -45.419225021, 60.984549241 ], [ -45.412472331, 60.973399399 ], [ -45.502278621, 60.96070259 ], [ -45.525166866, 60.957726342 ], [ -45.544395412, 60.955624111 ], [ -45.572353843, 60.951692596 ], [ -45.655768925, 60.94244974 ], [ -45.670854236, 60.94123391 ], [ -45.693899808, 60.940200373 ], [ -45.664305174, 60.947778021 ], [ -45.659448977, 60.949020163 ], [ -45.648191047, 60.951923402 ], [ -45.636669092, 60.954825483 ], [ -45.565410441, 60.967827923 ], [ -45.523123774, 60.979977384 ], [ -45.517219284, 60.981999 ], [ -45.517218946, 60.981999115 ], [ -45.5059008, 60.985872696 ], [ -45.499757432, 60.988125868 ] ] ] }, "properties": { "setting_ty": "Supracrustal", "setting": "Sedimentary and/or volcanic: undivided", "lithology": "Basalt, sandstone, conglomerate", "colour_cmy": "20 40 70 0", "colour": "247" } }, [Polygons and popups working](https://i.stack.imgur.com/TqbV8.jpg)
strong text Got a good lead from Mike user:10118270 and applied it.Replaced the following code var polyStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: [12,202,50] }), stroke: new ol.style.Stroke({ color: [0,0,0], width: 1 }) }); with the following code: // Polygons style const fillColors = { 'Slope and deep water': [100,100,100,1], 'Intrusive: syenitic': [240,10,10,1], 'Intrusive: gabbroic': [240,10,10,1], 'Intrusive: anorthositic': [240,10,10,1], 'Intrusive: tonalitic-granodioritic': [240,10,10,1], 'Intrusive: granitic':[240,10,10,1], 'Intrusive: undivided': [230,10,10,1], 'Sedimentary: undivided': [250,250,10,1], 'Clastic: shallow marine': [240,240,20,1], 'Clastic: continental': [255,255,1,1], 'Clastic: deltaic and nearshore': [240,240,20,1], 'Marine sedimentary: undivided': [230,230,10,1], 'Extrusive: mafic': [250,200,10,1], 'Sedimentary and/or volcanic: undivided': [250,120,10,1], 'Carbonate': [10,40,255,1], 'Metamorphic: undivided': [230,10,240,1], 'ice': [250,250,250,1], }; const style = new ol.style.Style({ fill: new ol.style.Fill(), stroke: new ol.style.Stroke({ color: [0, 0, 0, 1], width: 0.5, }), }); strong text The end result is shown on the image. geologic polygon
How do I change the color of my filter text in dash table?
I have this table- html.Div([ dash_table.DataTable( id = 'datatable-interactivity', data = df.to_dict('records'), editable = False, style_filter = { 'backgroundColor': '#252e3f', 'color': 'white' }, style_header = { 'backgroundColor': '#252e3f', 'color': 'white' }, style_data = { 'backgroundColor': '#252e3f', 'color': 'white' }, style_cell = { 'overflow': 'hidden', 'textOverflow': 'ellipsis', 'maxWidth': 0 } )]) ], style = {'background-color': '#1f2630'}) The filter text shows up as a dark gray even though I set the color to white. This includes both the text that I add into the filter cells and the default placeholders. Is there a different argument I should include to change the color?
How to scale and centre all items in a layered topojson map to fit in D3 version 4?
I've read and used Mike Bostock's answer to Center a map in D3 given a geoJSON object, which is a generic way to scale to fit one item in a geojson file based on its bounds in D3 version 3. I've also adapted it to use every item in a GeoJson. Key part of that algorithm is: // Calculate bounding box transforms for entire collection var b = path.bounds( geojson ), s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h), t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2]; // Update the projection, which initially had .translate([0, 0]) .scale(1); projection .scale(s) .translate(t); Using the V4 D3-geo docs I've crudely adapted it to work in with the new/ammended d3.geoPath() function / object in D3 version 4.0. It seems to work in the demo below (I'm using d3.geoPath().bounds(), not yet tried V4's seemingly new d3.geoBounds()). However, I then get stuck with adapting it to get the bounding box across all layers in a multi-layer topojson file that has been converted using topojson.js (i.e. the bounding box of multiple GeoJSON feature collections). d3.geoPath().bounds() seems to only accept one "layer" and d3.geoBounds() appears even more restricted; to one feature. I'm also somewhat concerned about performance - all this seems to involve looping over potentially very many shapes in potentially many layers, I feel like maybe there might be a more efficient approach in D3 V4? Here's a rough demo as a starting point with a very small simple TopoJSON file that should show two islands with a few subregions each (very very simplified versions of Wales and Northern Ireland for a simple demo, each on separate layers). After some trial and error, I've managed to get it to scale and translate the map to centre around the "Wales-like" island, but I can't figure out how to make it centre and scale on all the layers of the TopoJSON. The standard approach to layered TopoJSON seems to be to turn each layer into what's essentially a seperate GeoJSON, so how do I get the bounds across multiple GeoJSONs while still being able to handle them as separate layers? //Width and height var w = 300; var h = 200; //Define map projection var projection = d3.geoEquirectangular() .translate([0, 0]) .scale(1); //Define path generator var path = d3.geoPath() .projection(projection); //Create SVG element var svg = d3.select("body") .append("svg") .attr("width", w) .attr("height", h); //Load in GeoJSON data var json = someUKJSON(); for (var key in json.objects) { if (json.objects.hasOwnProperty(key)) { // Topojson unpacks one layer at a time var layer = json.objects[key]; var geojson = topojson.feature( json, layer ); // Calculate bounding box transforms for entire collection var b = path.bounds(geojson), s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h), t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2]; // Update the projection projection .scale(s) .translate(t); // Bind data and create one path per GeoJSON feature svg.selectAll("path") .data(geojson.features) .enter() .append("path") .attr("d", path) .style("fill", "steelblue"); }; // ...but each iteration will just zoom/centre on the latest // How do we expand the bounding box with each layer? } function someUKJSON(){ return {"type":"Topology","transform":{"scale":[0.0034431267161520807,0.002017902170346754],"translate":[-7.8508544159644345,51.47680014500252]}, "arcs":[[[1366,700],[-216,-155]],[[1150,545],[-121,275],[292,101],[45,-221]],[[1366,700],[23,-449]],[[1389,251],[-77,-96]],[[1312,155],[-75,-18]],[[1237,137],[-62,17]],[[1175,154],[-35,383]],[[1140,537],[10,8]],[[1175,154],[-71,-37]],[[1104,117],[-314,73],[350,347]],[[1237,137],[27,-119]], [[1264,18],[-35,-18]],[[1229,0],[-125,117]],[[1312,155],[28,-118]],[[1340,37],[-76,-19]],[[1385,12],[-45,25]],[[1389,251],[-4,-239]],[[1385,12],[-156,-12]],[[563,1572],[16,-7]],[[579,1565],[-55,-14]],[[524,1551],[39,21]],[[397,1870],[166,-298]],[[524,1551],[-63,-5]],[[461,1546],[-96,-18]], [[365,1528],[-109,10]],[[256,1538],[35,290]],[[291,1828],[106,42]],[[574,1342],[-124,192]],[[450,1534],[6,4],[5,8]],[[579,1565],[-5,-223]],[[365,1528],[85,6]],[[574,1342],[-219,-72],[-162,148]],[[193,1418],[63,120]],[[0,1515],[291,313]],[[193,1418],[-193,97]]], "objects":{"Wales":{"type":"GeometryCollection","geometries":[{"arcs":[[0,1]],"type":"Polygon","id":"Bedr"},{"arcs":[[2,3,4,5,6,7,-1]],"type":"Polygon","id":"Pong"},{"arcs":[[8,9,-7]],"type":"Polygon","id":"Hyda"},{"arcs":[[-6,10,11,12,-9]],"type":"Polygon","id":"Abwg"}, {"arcs":[[13,14,-11,-5]],"type":"Polygon","id":"Cwaf"},{"arcs":[[15,-14,-4,16]],"type":"Polygon","id":"Anan"},{"arcs":[[17,-12,-15,-16]],"type":"Polygon","id":"Cave"}]},"nernIrel":{"type":"GeometryCollection","geometries":[{"arcs":[[18,19,20]],"type":"Polygon","id":"Blft"}, {"arcs":[[21,-21,22,23,24,25,26]],"type":"Polygon","id":"nern"},{"arcs":[[27,28,-23,-20,29]],"type":"Polygon","id":"hern"},{"arcs":[[30,-28,31,32,-25]],"type":"Polygon","id":"sorn"},{"arcs":[[33,-26,-33,34]],"type":"Polygon","id":"wern"}]}}}; }; <script src="https://d3js.org/d3.v4.js"></script> <script src="https://d3js.org/topojson.v1.min.js"></script>
Here's a very simplistic approach. It's the closest any of my attempts at this have come. Leaving it here while hoping someone will come up with something better. Create a throwaway fake geojson-like object purely for calculating the bounds Merge the features arrays of each feature into it Use it to calculate the bounds and adjust the projections once This feels very clunky though, and I can't find a way to draw one layer at a time with this, I'm resorting to using the throwaway flattened collection to draw the paths. Also, strangely d3.merge() doesn't seem to work with geojson.features, which is why I'm using Array.concat() instead. Don't understand that one, but this does get it done. //Width and height var w = 300; var h = 200; //Define map projection var projection = d3.geoEquirectangular() .translate([0, 0]) .scale(1); //Define path generator var path = d3.geoPath() .projection(projection); //Create SVG element var svg = d3.select("body") .append("svg") .attr("width", w) .attr("height", h); //Load in GeoJSON data var json = someUKJSON(); //Create a fake bounds layer var boundsCollection = { type: "FeatureCollection", features: [] } for (var key in json.objects) { if (json.objects.hasOwnProperty(key)) { // Topojson unpacks one layer at a time var layer = json.objects[key]; var geojson = topojson.feature(json, layer); boundsCollection.features = boundsCollection.features.concat( geojson.features ); }; } // Calculate bounding box transforms for entire collection var b = path.bounds(boundsCollection), s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h), t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2]; // Update the projection projection .scale(s) .translate(t); // Bind data and create one path per GeoJSON feature svg.selectAll("path") .data(boundsCollection.features) .enter() .append("path") .attr("d", path) .style("fill", "steelblue"); function someUKJSON() { return { "type": "Topology", "transform": { "scale": [0.0034431267161520807, 0.002017902170346754], "translate": [-7.8508544159644345, 51.47680014500252] }, "arcs": [ [ [1366, 700], [-216, -155] ], [ [1150, 545], [-121, 275], [292, 101], [45, -221] ], [ [1366, 700], [23, -449] ], [ [1389, 251], [-77, -96] ], [ [1312, 155], [-75, -18] ], [ [1237, 137], [-62, 17] ], [ [1175, 154], [-35, 383] ], [ [1140, 537], [10, 8] ], [ [1175, 154], [-71, -37] ], [ [1104, 117], [-314, 73], [350, 347] ], [ [1237, 137], [27, -119] ], [ [1264, 18], [-35, -18] ], [ [1229, 0], [-125, 117] ], [ [1312, 155], [28, -118] ], [ [1340, 37], [-76, -19] ], [ [1385, 12], [-45, 25] ], [ [1389, 251], [-4, -239] ], [ [1385, 12], [-156, -12] ], [ [563, 1572], [16, -7] ], [ [579, 1565], [-55, -14] ], [ [524, 1551], [39, 21] ], [ [397, 1870], [166, -298] ], [ [524, 1551], [-63, -5] ], [ [461, 1546], [-96, -18] ], [ [365, 1528], [-109, 10] ], [ [256, 1538], [35, 290] ], [ [291, 1828], [106, 42] ], [ [574, 1342], [-124, 192] ], [ [450, 1534], [6, 4], [5, 8] ], [ [579, 1565], [-5, -223] ], [ [365, 1528], [85, 6] ], [ [574, 1342], [-219, -72], [-162, 148] ], [ [193, 1418], [63, 120] ], [ [0, 1515], [291, 313] ], [ [193, 1418], [-193, 97] ] ], "objects": { "Wales": { "type": "GeometryCollection", "geometries": [{ "arcs": [ [0, 1] ], "type": "Polygon", "id": "Bedr" }, { "arcs": [ [2, 3, 4, 5, 6, 7, -1] ], "type": "Polygon", "id": "Pong" }, { "arcs": [ [8, 9, -7] ], "type": "Polygon", "id": "Hyda" }, { "arcs": [ [-6, 10, 11, 12, -9] ], "type": "Polygon", "id": "Abwg" }, { "arcs": [ [13, 14, -11, -5] ], "type": "Polygon", "id": "Cwaf" }, { "arcs": [ [15, -14, -4, 16] ], "type": "Polygon", "id": "Anan" }, { "arcs": [ [17, -12, -15, -16] ], "type": "Polygon", "id": "Cave" }] }, "nernIrel": { "type": "GeometryCollection", "geometries": [{ "arcs": [ [18, 19, 20] ], "type": "Polygon", "id": "Blft" }, { "arcs": [ [21, -21, 22, 23, 24, 25, 26] ], "type": "Polygon", "id": "nern" }, { "arcs": [ [27, 28, -23, -20, 29] ], "type": "Polygon", "id": "hern" }, { "arcs": [ [30, -28, 31, 32, -25] ], "type": "Polygon", "id": "sorn" }, { "arcs": [ [33, -26, -33, 34] ], "type": "Polygon", "id": "wern" }] } } }; }; <script src="https://d3js.org/d3.v4.js"></script> <script src="https://d3js.org/topojson.v1.min.js"></script>
Increase separation of edges in graphviz
I am creating several UML activity diagrams with dot-graphviz and the edges/arrows (2+) converge in the same point whenever the target shape is a narrowed rectangle (H=0.5, W=0.05). This problem doesn't occur if the target shape is a square (H=0.5, W=0.5). Here is a reduced dot example: digraph G { graph [ ranksep = 0.5, rankdir = LR ] A4 [ shape = "record", height = 0.5, fontsize = 10, margin = "0.20,0.05", label = "Output\ to\rPreviewer", style = "rounded" ] A5 [ shape = "rectangle", height = 0.5, width = 0.05, margin = "0,0", style = "filled", label = "" ] A4 -> A5 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] A6 [ shape = "diamond", height = 0.5, width = 0.5, margin = "0,0", label = "" ] A6 -> A5 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10, label = "[generate: false]" ] A7 [ shape = "record", height = 0.5, fontsize = 10, margin = "0.20,0.05", label = "Output\ to\rFile", style = "rounded" ] A6 -> A7 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10, label = "[generate: true]" ] A8 [ shape = "doublecircle", height = 0.3, width = 0.3, margin = "0,0", label = "" ] A7 -> A5 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] A5 -> A8 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] } The text above generates the following graph in http://webgraphviz.com The desirable output is the following
I found a tweak that produces a nice output, but requires a lot of processing and edge-count and direction awareness: digraph G { graph [ ranksep = 0.5, rankdir = LR ] A4 [ shape = "record", height = 0.5, fontsize = 10, margin = "0.20,0.05", label = "Output\ to\rPreviewer", style = "rounded" ] A5 [ shape = "record", height = 0.5, width = 0.05, margin = "0,0", style = "filled", label = "<f0>|<f1>|<f2>", fillcolor="black" ] A4 -> A5:f0:w [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] A6 [ shape = "diamond", height = 0.5, width = 0.5, margin = "0,0", label = "" ] A6 -> A5:f1:w [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10, label = "[generate: false]" ] A7 [ shape = "record", height = 0.5, fontsize = 10, margin = "0.20,0.05", label = "Output\ to\rFile", style = "rounded" ] A6 -> A7 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10, label = "[generate: true]" ] A8 [ shape = "doublecircle", height = 0.3, width = 0.3, margin = "0,0", label = "" ] A7 -> A5:f2:w [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] A5 -> A8 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] } This is the output: I still would like to know if there is a simpler solution.
You can specify the output port of all edges to east and get preaty nice result (at least for that case): digraph G { graph [ ranksep = 0.5, rankdir = LR ] edge [tailport=e] # <----- added this line A4 [ shape = "record", height = 0.5, fontsize = 10, margin = "0.20,0.05", label = "Output\ to\rPreviewer", style = "rounded" ] A5 [ shape = "rectangle", height = 0.5, width = 0.05, margin = "0,0", style = "filled", label = "" ] A4 -> A5 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] A6 [ shape = "diamond", height = 0.5, width = 0.5, margin = "0,0", label = "" ] A6 -> A5 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10, label = "[generate: false]" ] A7 [ shape = "record", height = 0.5, fontsize = 10, margin = "0.20,0.05", label = "Output\ to\rFile", style = "rounded" ] A6 -> A7 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10, label = "[generate: true]" ] A8 [ shape = "doublecircle", height = 0.3, width = 0.3, margin = "0,0", label = "" ] A7 -> A5 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] A5 -> A8 [ shape = "edge", dir = "both", style = "solid", arrowtail = "none", arrowhead = "vee", labeldistance = 1, fontsize = 10 ] } produce:
How I can draw the tree with values stored in nodes with graphviz?
I need to draw tree looks like this (with values associated with some nodes): But I find only the way to draw tree like next: I try to use subgraphs, and nested subgraphs, but there is no effect needed. Currently, I use the next gv script: digraph "test-graph" { graph [rankdir=TB dpi=96] subgraph n0 { rank=same; "0_0" [ label = "a" ]; } subgraph n1 { rank=same; "1_0" [ label = "b" ]; "1_1" [ label = "d" ]; "1_2" [ label = "e" ]; subgraph { "v3" [ label = "3", shape = "box" ]; "1_1"->"v3" [ dir = none, constraint = false ]; } } subgraph n2 { rank=same; "2_0" [ label = "g" ]; } subgraph n3 { rank=same; "3_0" [ label = "a" ]; "3_1" [ label = "b" ]; "3_2" [ label = "c" ]; subgraph { "v2" [ label = "2", shape = "box" ]; "3_0"->"v2" [ dir = none, constraint = false ]; "v0" [ label = "0", shape = "box" ]; "3_1"->"v0" [ dir = none, constraint = false ]; "v5" [ label = "5", shape = "box" ]; "3_2"->"v5" [ dir = none, constraint = false ]; } } subgraph n4 { rank=same; "4_0" [ label = "f" ]; subgraph { "v1" [ label = "1", shape = "box" ]; "4_0"->"v1" [ dir = none, constraint = false ]; } } subgraph n5 { rank=same; "5_0" [ label = "c" ]; subgraph { "v4" [ label = "4", shape = "box" ]; "5_0"->"v4" [ dir = none, constraint = false ]; } } "start"->"0_0"; "0_0"->"1_0"; "0_0"->"1_1"; "0_0"->"1_2"; "1_0"->"5_0"; "1_1"->"2_0"; "1_2"->"4_0"; "2_0"->"3_0"; "2_0"->"3_1"; "2_0"->"3_2"; } Using "cluster_" prefix solves some of problems (thanks Anne), but there is important in wich order nodes and it's values folows in the dot script. After all I got new problem - nodes not properly ordered on graph: a, b, c nodes (node 'g' childs) follows in wrong order: Also, is there a way to tell dot place values at right side from nodes? The best, of course, is then the values are placed under nodes, but, how I can find, this is unsolvable problem. Dot script is: digraph "test-graph" { graph [rankdir=TB dpi=96] subgraph cluster_n0 { rank=same; style=invis; "0_0" [ label = "a" ]; } subgraph cluster_n1 { rank=same; style=invis; "1_0" [ label = "b" ]; "1_1" [ label = "d" ]; "v3" [ label = "3", shape = "box", width=.01, height=.01 ]; "1_1"->"v3" [ dir = none, constraint = false ]; "1_2" [ label = "e" ]; } subgraph cluster_n2 { rank=same; style=invis; "2_0" [ label = "g" ]; } subgraph cluster_n3 { rank=same; style=invis; "3_0" [ label = "a" ]; "v2" [ label = "2", shape = "box", width=.01, height=.01 ]; "3_0"->"v2" [ dir = none, constraint = false ]; "3_1" [ label = "b" ]; "v0" [ label = "0", shape = "box", width=.01, height=.01 ]; "3_1"->"v0" [ dir = none, constraint = false ]; "3_2" [ label = "c" ]; "v5" [ label = "5", shape = "box", width=.01, height=.01 ]; "3_2"->"v5" [ dir = none, constraint = false ]; } subgraph cluster_n4 { rank=same; style=invis; "4_0" [ label = "f" ]; "v1" [ label = "1", shape = "box", width=.01, height=.01 ]; "4_0"->"v1" [ dir = none, constraint = false ]; } subgraph cluster_n5 { rank=same; style=invis; "5_0" [ label = "c" ]; "v4" [ label = "4", shape = "box", width=.01, height=.01 ]; "5_0"->"v4" [ dir = none, constraint = false ]; } "start"->"0_0"; "0_0"->"1_0"; "0_0"->"1_1"; "0_0"->"1_2"; "1_0"->"5_0"; "1_1"->"2_0"; "1_2"->"4_0"; "2_0"->"3_0"; "2_0"->"3_1"; "2_0"->"3_2"; }
To group the "value" node with the node, you have to use subgraphs with a name starting by cluster_. For instance: subgraph cluster_n4_0 { rank=same; "4_0" [ label = "f" ]; "v1" [ label = "1", shape = "box" ]; "4_0"->"v1" [ dir = none]; } To have smaller nodes for the values, you can use the width and height attributes. I don't think that you need several level of subgraphs here, using clusters for pairs of node should be enougt.
add an invisiable edge from box to next level node, like following example digraph "test-graph" { graph [rankdir=TB,dpi=96,splines=false] "1_1" [ label = "d" ]; "v3" [ label = "3", shape = "box", width = 0, height = 0]; "2_0" [ label = "g" ]; "1_1"->"v3" [ dir = none]; v3->"2_0"[style=invisible,dir = none]; "1_1"->"2_0"; }