I used the code below to create a graphic using dot (graphviz).
digraph
{
node [color=Blue,shape=box]
1.1 [label="Frequency of t exceeds upper threshold"]
2.1 [label="t has d-mutant tiles"]
2.2 [label="Valid"]
3.1 [label="Frequency of t exceeds lower threshold"]
3.2 [label="Frequency of t exceeds lower threshold"]
4.1 [label="Insufficient evidence"]
4.2 [label="Valid"]
4.3 [label="t has only one d-mutant that exceeds lower threshold"]
4.4 [label="Are there any d-mutant tiles with significantly higher frequencies?"]
5.1 [label="Insufficient evidence"]
node [color=Green] 5.2 [label="Correct t to t'"] node [color=Blue]
5.3 [label="t has a d-mutant tile t' that is closer than all other d-mutant tiles and for which a corrected base has a higher quality score"]
5.4 [label="Valid"]
6.1 [label="Insufficient evidence"]
6.2 [label="t' is unique"]
7.1 [label="Insufficient evidence"]
node [color=Green] 7.2 [label="Correct t to t'"] node [color=Blue]
1.1 -> 2.1 [label="no"]
1.1 -> 2.2 [label="yes"]
2.1 -> 3.1 [label="no"]
2.1 -> 3.2 [label="yes"]
3.1 -> 4.1 [label="no"]
3.1 -> 4.2 [label="yes"]
3.2 -> 4.3 [label="no"]
3.2 -> 4.4 [label="yes"]
4.3 -> 5.1 [label="no"]
4.3 -> 5.2 [label="yes"]
4.4 -> 5.3 [label="no"]
4.4 -> 5.4 [label="yes"]
5.3 -> 6.1 [label="no"]
5.3 -> 6.2 [label="yes"]
6.2 -> 7.1 [label="no"]
6.2 -> 7.2 [label="yes"]
}
As you can see, some of the boxes in the graphic have a lot of text in the label. I can insert \n characters to make sure the boxes aren't too wide, but I'm wondering if there is a way I can set the width of the boxes and then have the box labels do a hard wrap. Is this possible?
graphviz doesn't support automatic line breaks. You have to put the \n in manually.
you can set a width and a height to a node and define it as fixedsized - this will
limit the size of the node and draw only as much text as fits into the node
Although graphviz does not support text wrapping by itself,
dot2tex (latex+graphviz) does.
The dot2texi latex package gives an all-in-one solution,
with (from the users point of view) a single call to a single tool to build the graph.
A short example:
\documentclass{standalone}
\usepackage{dot2texi}
\usepackage{tikz}
\usetikzlibrary{shapes,arrows}
\begin{document}
\begin{dot2tex}[dot]
digraph G {
d2toptions ="--autosize"
node [lblstyle="text width=10em,align=center"]
a [texlbl="This text will be automatically wrapped, for example at a fixed width."]
b [texlbl="Manual linebreaks from past century can be avoided!"]
a -> b
}
\end{dot2tex}
\end{document}
This can be compiled invoking for example: pdflatex --shell-escape myFile.tex, the text will be automatically wrapped at the prescribed fixed width.
As a side note, this tool seems a handy workaround for graphviz' limited typesetting control of the nodes contents.
The OP wrote a whole Perl script to achieve this. I found it in his blog: Text wrapping with dot (graphviz).
⚠ Note
This only works if the labels are in the format node [ label=”node label” ]. If the nodes are declared directly (e.g. ”node label”) then it doesn’t work
Perl script:
#!/usr/bin/perl
use strict;
my $usage = "setdotlabelwidth [char-width] < [dotfile]";
my $width = shift() or die("Usage: $usage $!");
while(<STDIN>)
{
if(m/label="(.*?)"/)
{
my $labeltext = $1;
my #words = split(/ /, $labeltext);
my #newtext = ();
my $newline = "";
foreach my $word(#words)
{
if( length($newline) > 0 and
length($newline) + length($word) > $width )
{
push(#newtext, $newline);
$newline = "";
}
$newline .= " " if( length($newline) > 0 );
$newline .= $word;
}
push(#newtext, $newline) if( length($newline) > 0 );
my $newlabel = join("\\n", #newtext);
s/label=".*?"/label="$newlabel"/;
}
print;
}
Save this program as setdotlabelwidth, then simply pipe the output into GraphViz. If for example you want to set the width to 35 characters, then the command is:
./setdotlabelwidth 35 < tile-error-correction.dot | dot -Tpng -o tile-error-correction.png
Before:
After:
Related
After upgrading to version 3.1.4 on Windows 10 (using VS 2017), I see that XPM images with transparency don't show correctly on wxRibbonButtonBar. As an example, the comparison of 3.1.3 and 3.1.4 is shown below:
The code adding image is briefly as follows:
auto ButtonBar_BoxandWhisker = new wxRibbonButtonBar(PanelBoxandWhisker);
ButtonBar_BoxandWhisker->AddButton(ID_PLOT_BOXWHISKER_HOR, "Horizontal", wxBitmap(plot_boxwhiskerchart_xpm), "hor");
I generate XPM images using GIMP. Part of the above-shown XPM image is:
static char * plot_boxwhiskerchart_xpm[] = {
"32 32 4 1",
" c None",
". c #000000",
"+ c #FF7F27",
"# c #880015",
". ",
". ",
Any ideas welcomed.
Situation
Currently I am working on an application for image-processing that uses ffmpeg-light to fetch all the frames of a given video-file so that the program afterwards can apply grayscaling, as well as edge detection alogrithms to each of the frames.
With the help of friendly stackoverflowers I was able to set up a method capable of converting several images into one video file using ffmpeg-lights' frameWriter function.
Problem
The application runs fine to the moment it hits the frameWriterfunction and I don't really know why as there are no errors or exception-messages thrown. (OS: Win 10 64bit)
What did I try?
I tried..
- different versions of ffmpeg (from 3.2 to 3.4).
- ffmpeg.exe using the command line to test if there are any codecs missing, but any conversion I tried worked.
- different EncodingParams-combinations: like.. EncodingParams width height fps (Nothing) (Nothing) "medium"
Question
Unfortunately, none of above worked and the web lacks on information to that specific case. Maybe I missed something essential (like ghc flags or something) or made a bigger mistake within my code. That is why I have to ask you: Do you have any suggestions/advice for me?
Haskell Packages
- ffmpeg-light-0.12.0
- JuicyPixels-3.2.8.3
Code
{--------------------------------------------------------------------------------------------
Applies "juicyToFFmpeg'" and "getFPS" to a list of images and saves the output-video
to a user defined location.
---------------------------------------------------------------------------------------------}
saveVideo :: String -> [Image PixelYA8] -> Int -> IO ()
saveVideo path imgs fps = do
-- program stops after hitting next line --
frame <- frameWriter ep path
------------------------------------------------
Prelude.mapM_ (frame . Just) ffmpegImgs
frame Nothing
where ep = EncodingParams width height fps (Just avCodecIdMpeg4) (Just avPixFmtGray8a) "medium"
width = toCInt $ imageWidth $ head imgs
height = toCInt $ imageHeight $ head imgs
ffmpegImgs = juicyToFFmpeg' imgs
toCInt x = fromIntegral x :: CInt
{--------------------------------------------------------------------------------------------
Converts a single image from JuicyPixel-format to ffmpeg-light-format.
---------------------------------------------------------------------------------------------}
juicyToFFmpeg :: Image PixelYA8 -> (AVPixelFormat, V2 CInt, Vector CUChar)
juicyToFFmpeg img = (avPixFmtGray8a, V2 (toCInt width) (toCInt height), ffmpegData)
where toCInt x = fromIntegral x :: CInt
toCUChar x = fromIntegral x :: CUChar
width = imageWidth img
height = imageHeight img
ffmpegData = VS.map toCUChar (imageData img)
{--------------------------------------------------------------------------------------------
Converts a list of images from JuicyPixel-format to ffmpeg-light-format.
---------------------------------------------------------------------------------------------}
juicyToFFmpeg' :: [Image PixelYA8] -> [(AVPixelFormat, V2 CInt, Vector CUChar)]
juicyToFFmpeg' imgs = Prelude.foldr (\i acc -> acc++[juicyToFFmpeg i]) [] imgs
{--------------------------------------------------------------------------------------------
Simply calculates the FPS for image-to-video conversion.
-> frame :: (Double, DynamicImage) where Double is a timestamp of when it got extracted
---------------------------------------------------------------------------------------------}
getFPS :: [(Double, DynamicImage)] -> Int
getFPS frames = div (ceiling $ lastTimestamp - firstTimestamp) frameCount :: Int
where firstTimestamp = fst $ head frames
lastTimestamp = fst $ last frames
frameCount = length frames
I suspect issue you are having has something to do with Windows environment and usage of ffmpeg from Haskell (i.e. ffmpeg-simple)
I was able to successfully compile and run your module on Ubuntu 16.04, although I did get a runtime error from ffmpeg:
$ ./main
[NULL # 0x1ea6900] Unable to find a suitable output format for 'foo.avi'
main: Couldn't allocate output format context
CallStack (from HasCallStack):
error, called at src/Codec/FFmpeg/Encode.hs:214:17 in ffmpeg-light-
0.12.0-DYHyy7pUAhZ7WHcd6Y2mLO:Codec.FFmpeg.Encode
It seems like the above error can be fixed with some ffmpeg arguments tweaking, but since that is not the issue you are experiencing I decided not to go any further with debugging it.
Just in case my main:
main :: IO ()
main = do
Right (ImageYA8 img) <- readPng "foo_ya.png"
saveVideo "foo.avi" (replicate 10 img) 10
I ran the same thing on Windows 7 64-bit and it seems I was unable to fully satisfy the dependencies.
Compilation and dependency installation done on Windows:
> stack exec -- pacman -Syu
> stack exec -- pacman -S mingw-w64-x86_64-gtk3
> stack exec -- pacman -S mingw-w64-x86_64-pkg-config
> stack exec -- pacman -S mingw-w64-x86_64-ffmpeg
> stack --install-ghc --resolver lts-9.10 exec --package vector --package JuicyPixels --package ffmpeg-light -- ghc main.hs -O2 -threaded
> stack exec -- main.exe
Results in a popup error when ran in cmd (ps simply exits):
The procedure entry point inflateValidate could not be located in the dynamic link library zlib1.dll
I am no expert on development on Windows, so I feel like I am missing something. Hope my attempt will be at least a little bit helpful.
I recently updated XCode to 7.0 and I get this warning message:
Xcode.IDEInterfaceBuilder.Cocoa.NSObject.BroadSystemFontWeights
What does it mean and how do I get rid of it ?
I got the same error when I set the font weight to Semibold to a label with system font. This weight is available for the new system font (San Francisco) but not for the old Helvetica Neue, so I guess that that error means we won't get the right weight on older OS.
Changing the font to a weight available also for Helvetica Neue, Bold in my case, has fixed the error for me.
The problem is not with changing system font weight, the problem is with Xcode not handling this properly – contradicting statement, I know, see full blog post for details. There are three scenarios.
First – explicit typography is not important, regular weight is acceptable. Then stick with Marco's answer and use explicit regular weight.
Second – explicit typography is preferable, but can be compromised on older systems. This is the default behaviour right now, Xcode simply shows a warning and uses regular font on pre-10.11 targets. If you use adaptive layouts, everything should be fine. To get rid of the warning, you can simply set higher target in storyboard inspector:
Note, if your storyboard uses fallback features for earlier targets, they might become disabled, which will cause problems – I haven't come across any so far.
Third – explicit typography is a must. In this case you can use custom textfield with custom inspectable property. Open up identity inspector and set custom class to TextField, preferred font weight attribute will show up in attribute inspector, set the required value, build and enjoy the result.
import AppKit
#IBDesignable public class TextField: NSTextField
{
#IBInspectable public var preferredFontWeight: Int = 0
override public func awakeFromNib() {
if #available(OSX 10.11, *) {
return
}
guard
let weight: Int = self.preferredFontWeight where weight > 0,
let font: NSFont = self.font,
let name: String = font.familyName,
let manager: NSFontManager = NSFontManager.sharedFontManager() else {
return
}
// Full details here – https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSFontManager_Class/#//apple_ref/occ/instm/NSFontManager/convertWeight:ofFont:
//
// 1 – ultralight
// 2 – thin
// 3 – light, extralight
// 4 – book
// 5 – regular, display
// 6 – medium
// 7 – demi, demibold
// 8 – semi, semibold
// 9 – bold
// 10 – extra, extrabold
// 11 – heavy
// 12 – black
// 13 – ultrablack
// 14 – extrablack
if let font: NSFont = manager.fontWithFamily(name, traits: manager.traitsOfFont(font), weight: weight, size: font.pointSize) {
self.font = font
}
}
}
P.S. Bold weight works probably because it uses a slightly different logic – there's boldSystemFontOfSize(_:) that's available since OS X 10.0, unlike many other methods, which storyboard might rely upon.
The node property fixedsize=shape does not seem to be working on my GraphViz graphs. For example, this:
digraph Automaton {
rankdir=LR
node [shape=circle fixedsize=shape label=""]
0;
1 [shape=doublecircle];
2 [shape=doublecircle label="HELLO_12345"];
0 -> { 2 } [label="98 (b)"];
0 -> { 1 } [label="97 (a)"];
1 -> { 1 } [label="97 (a)"];
}
...produces this:
I expected the node labeled HELLO_12345 to be drawn the same size as the other nodes. I tried adding fixedsize=shape to the declaration of that node, to no avail.
When was fixedsize=shape added? The latest version of GraphViz appears to be 2.38, but Ubuntu 14.04 is still at version 2.36.
Turns out GraphViz has a change log. Who'da thought? And yes, fixedsize=shape was added after version 2.36.0 and before version 2.38.0. I don't know what the intermediate version that contained this change was called (the log doesn't say) but this probably explains why it doesn't work on Ubuntu 14.04.
Does there exist a Haskell graphics library or binding to an external library that fulfills the following requirements:
Can be used from ghci, i.e. I don't have to link and restart the program.
Works on MacOS X. (Tricky in conjunction with 1!)
Can do simple vector graphics (lines, polygons, simple fills and strokes).
Can put bitmap images on screen. Example: blit a 17x12 .bmp image.
?
Please include a minimal source code example or a reference to it (just a window on screen, maybe with a green line drawn inside it) so that I can check the points 1. and 2. in particular. Also, if one of these feature requests is more elaborate (for example OpenGL + 4), please include a good reference.
PS: Concerning 1 and 2, I know about the enableGUI trick and I am willing to use it. However, most libraries have the problem that you can't run the main function multiple times and hence don't qualify.
Edit: To avoid wasting your time, here a list of packages that I've tried:
wx - ghci chokes on libstdc++
sdl - redefines main to be a macro. Compile-time only.
GLFW (OpenGL) - Can't run main twice, something about "failing because it can't install mouse event handler".
EDIT: Actually, I'm no longer sure. Several versions later, it seems that GLFW no longer works in GHCi on OS X.
It turns out that GLFW+OpenGL fulfills all four requirements!
You need to invoke ghci with ghci -framework Carbon.
You need the EnableGUI.hs file, which you can get here. Note that you can't load it right into GHCi, you have to comiple it, first.
OpenGL has a 2D projection mode where you can draw lines and polygons.
Bitmaps can be loaded as textures and put on polygons.
Here is a small example that puts a bitmap onto the screen. There are some restrictions on the bitmap: its dimensions must be a power of two (here 256) and it must be a .tga file (here "Bitmap.tga"). But since transparency is supported, this is not much of a problem.
You should be able to call main multiple times without problem. The key point is that you should not call GLFW.terminate.
import Graphics.Rendering.OpenGL as GL
import qualified Graphics.UI.GLFW as GLFW
import Graphics.Rendering.OpenGL (($=))
import Control.Monad
import EnableGUI
main = do
enableGUI
GLFW.initialize
-- open window
GLFW.openWindow (GL.Size 400 400) [GLFW.DisplayAlphaBits 8] GLFW.Window
GLFW.windowTitle $= "Bitmap Test"
-- enable alpha channel
GL.blend $= GL.Enabled
GL.blendFunc $= (GL.SrcAlpha, GL.OneMinusSrcAlpha)
-- set the color to clear background
GL.clearColor $= GL.Color4 0.8 0.8 0.8 0
-- set 2D orthogonal view inside windowSizeCallback because
-- any change to the Window size should result in different
-- OpenGL Viewport.
GLFW.windowSizeCallback $= \ size#(GL.Size w h) ->
do
GL.viewport $= (GL.Position 0 0, size)
GL.matrixMode $= GL.Projection
GL.loadIdentity
GL.ortho2D 0 (realToFrac w) (realToFrac h) 0
render <- initialize
loop render
GLFW.closeWindow
loop render = do
-- draw the entire screen
render
-- swap buffer
GLFW.swapBuffers
-- check whether ESC is pressed for termination
p <- GLFW.getKey GLFW.ESC
unless (p == GLFW.Press) $ do
-- sleep for 1ms to yield CPU to other applications
GLFW.sleep 0.001
-- only continue when the window is not closed
windowOpenStatus <- GLFW.getParam GLFW.Opened
unless (windowOpenStatus == False) $
loop render
-- rendering
initialize = do
-- load texture from file
GL.texture GL.Texture2D $= Enabled
[textureName] <- GL.genObjectNames 1
GL.textureBinding GL.Texture2D $= Just textureName
GL.textureFilter GL.Texture2D $= ((GL.Nearest, Nothing), GL.Nearest)
GLFW.loadTexture2D "Bitmap.tga" []
return $ do
GL.clear [GL.ColorBuffer]
GL.renderPrimitive GL.Quads $ do
GL.texCoord $ texCoord2 0 0
GL.vertex $ vertex3 (0) 256 0
GL.texCoord $ texCoord2 0 1
GL.vertex $ vertex3 (0) (0) 0
GL.texCoord $ texCoord2 1 1
GL.vertex $ vertex3 256 (0) 0
GL.texCoord $ texCoord2 1 0
GL.vertex $ vertex3 256 256 0
-- type signatures to avoid ambiguity
vertex3 :: GLfloat -> GLfloat -> GLfloat -> GL.Vertex3 GLfloat
vertex3 = GL.Vertex3
texCoord2 :: GLfloat -> GLfloat -> GL.TexCoord2 GLfloat
texCoord2 = GL.TexCoord2
color3 :: GLfloat -> GLfloat -> GLfloat -> GL.Color3 GLfloat
color3 = GL.Color3
Here an example bitmap (which you need to convert to .tga).
The Gtk2Hs library fulfills all the requirements if you use the X11 version of the gtk2 framework.
Concerning the requirements:
Using X11 avoids many problems.
Install gtk2 via MacPorts and use the +x11 option (default). (That said, I've had numerous problems installing gtk2 in the past, but this time it seemed to work.)
I would be surprised if GTK+ can't do that.
Ditto.
Here a minimal example
import Graphics.UI.Gtk
hello :: (ButtonClass o) => o -> IO ()
hello b = set b [buttonLabel := "Hello World"]
main :: IO ()
main = do
initGUI
window <- windowNew
button <- buttonNew
set window [windowDefaultWidth := 200, windowDefaultHeight := 200,
containerChild := button, containerBorderWidth := 10]
onClicked button (hello button)
onDestroy window mainQuit
widgetShowAll window
mainGUI
As of early 2014, I wasn't able to use #heinrich-apfelmus answer in Mac OS X. This GLFW-b example (link) however worked.
So, ensure you have:
$ cabal install glfw-b
and, if you tried Apfelmus' answer, you may need to
$ ghc-pkg list
$ ghc-pkg unregister GLFW-x.x.x.x
as both provide Graphics.UI.GLFW, and you will get an "Ambiguous module name 'Graphics.UI.GLFW'" from ghc. Then I just tried the sample program above and it worked (Mac OS X, 10.9, Mavericks)
Have you seen the GLFW as referenced http://plucky.cs.yale.edu/soe/software1.htm
More information on Haskell+GUI+OpenGL is available in this discussion:
http://www.haskell.org/pipermail/haskell-cafe/2011-May/091991.html