How to make Graphviz use ~/.config/fontconfig/fonts.conf by default?

It’s an abstraction for a dynamically expanding string.

I don’t know. Though there was a precursor to libcgraph called libagraph, so perhaps the ag prefix came from there.

agxbput_n writes a string of known length to the buffer. vagxbprint writes formatted input. Analogous to fwrite vs vfprintf.

Yes… I’m not really sure I understand your question. If I have the integer int x = 42 and want to append it to an agxbuf, I can only do this with agxbprint (agxbprint(&buf, "%d", x)), not agxbput_n.

Thank you, I’ve kind of noticed, but still good to have it confirmed. I asked specifically about their purpose, because I don’t know C development that good (and Graphviz’s code, for that matter). I wasn’t sure if the functionality they provide is really needed in Graphviz, I mean beyond what can be done with the existing printf family of functions. So maybe this agxbuf had a specific purpose I didn’t realize. Now I think they may be needed just because of the way Graphviz is implemented: it gradually adds to a buffer instead of printing everything right away. Well, at least when it comes to the font handling code. You know, I’m still in the process of discovering Graphviz’s code. I think that over the course of it I should improve on seeing their purpose.

Thank you. I just found @scnorth’s What does the "c" in "cgraph" stand for? - #7 by scnorth. And I know there’s this PDF https://www.graphviz.org/pdf/cgraph.pdf. So ag be for “attributed graph”. Then there’s that “x” left to be discovered. I see that in the mentioned PDF the string agx occurs only 2 times: in the names agxget and agxset, so that file doesn’t help. In https://www.graphviz.org/pdf/cgraph.3.pdf we read about the difference between agget, agset and agxget, agxset, namely

agget and agset allow fetching and updating a string attribute for an object taking the attribute name as an argument. agxget and agxset do this but with an attribute symbol table entry as an argument (to avoid the cost of the string lookup).

But I don’t see any relation between this difference and the presence of the letter “x”. Maybe I would need to learn more about the cgraph library (that’s not my current goal).

What my question is about, is the purpose of implementing both of those functions instead of a single function, in the same sense as for the whole buffer implementation, of what I mentioned above. I know I could (should) just analyze the code of those functions, or maybe at least analyze the differences between fwrite, printf, and so on (as I mentioned, I don’t know C development that good). Well, now I think that there may be cases in which, e.g., some parameters don’t go together semantically, so you need to create two functions instead of one. Especially in C. Generally, for now I take for granted that what matters are the details (or, equivalently, use cases).

Ah, now I think I see what you’re getting at. You’re right, that you could replace agxbput_n(&buf, x, y) with agxbprint(&buf, "%.*s", (int)y, x). However varargs functions like agxbprint have somewhat uneven performance. In particular, (1) the implementation of a varargs function is expensive on some platforms and (2) some compilers are unwilling to inline calls to varargs functions or optimise across this boundary. Whether these concerns are relevant on modern platforms is debatable. But Graphviz runs in some very obscure places.

Yes, ag is the prefix for exported attributed graph foundation functions.

In that context, agxset and agxget are like agset and agget but take an attribute symbol pointer argument instead of the string name of an attribute. The x was meant to suggest “indexed” because the symbol has the index of the attribute.

My understanding is agxbuf refers to “ag” because it’s at the attributed graph foundation library level, and maybe xbuf because it’s an expandable buffer?

When exploring the code, in general, you’re likely to find inconsistencies (because of a lack of discipline or judgment, on my part at least), a little too much focus sometimes on optimization that doesn’t really help enough to be worth it (partly because of too much seat-of-the-pants engineering, and partly because our target platforms were 4.2BSD on VAX, early SunOS, and some experiments with porting to Windows where early x86 machines might not even have hardware floating point). We vaguely envisioned the graph libraries (libgraph, libagraph, libcgraph developed in that sequence) needing to scale well to millions of graph objects, but even today that really isn’t so relevant.

Stephen, what do you mean by “even today that really isn’t so relevant”? Do you assume that Graphviz, or those libraries alone?, won’t be used for million-object graphs?

With the benefit of hindsight, not too much.

Even in Graphviz sfdp, I think Yifan Hu’s large graph gallery was generated by reading graphs in a simple text format (numeric IDs and adjacency lists) and loading them into sparse matrices, bypassing our foundation library.

When we embarked on our project, we had some ideas about building a full graph database and analysis system, but we went down the rabbit hole and never came back. Eventually Neo4J realized that vision, along with its competitors.

A million is a lot of graph objects, or anything. (At some point I asked the stats people in our lab what they used for million-point scatterplots, and they laughed.)

I saw a million-point scatterplot recently. It’s quite the feat of engineering to make it support realtime queries: https://adsb.exposed/?dataset=Planes&zoom=12&lat=-33.9512&lng=151.1353&query=73b927066308d68c8c6d1ebba06673b9

That’s amazing! The realtime geographic queries are so quick.

In the 2000s, we engineered an interactive viewer to show customer events at full network scale, i.e. call attempts and other SS7 events for the AT&T network. (Eventually it was applied to show enterprise customer VPNs, and used graphviz for some of the detail views.) It’s exciting to see what’s being done now.

Where is the function pango_textlayout, defined in plugin/pango/gvtextlayout_pango.c:65, called?

It’s called through the plugin interface, for example, from textspan_size. There’s probably somewhere else where it’s called for final rendering. Here’s where we might use a modern IDE to quickly find places where a given type is referenced!

Thank you. Maybe. I’m still using just Vim and grep in my debugging journey. I like them, but I appreciate your reminder. I’ll see if I can improve my workflow.


Update. I tried to install QT Creator. My repositories hold an outdated version, so I downloaded and tried to install the newest one (18.0.0). Apparently, both online and offline installers required having some account, and I didn’t want to create one. So, I downloaded the source and tried to build it. That turned out to require me to have newer versions of CMake and QT than available in my repositories. So I downloaded their newest sources and tried to build them. I managed to build CMake (4.1.2), but QT’s compilation failed while running the whole night. I’ve no motivation to debug the error I received, and so I’m going to look for another IDE.

I don’t use an IDE with Graphviz. either. I intended to try Jetbrains - have used it very successfully with Scala, but it requires a licensed plugin for C/C++, and I didn’t go through the proper steps to validate it in the 30-day free trial period, and sort of balked at the (admittedly modest) advertising endorsement needed to get an open source project license (though another project founder thought it was no big deal). Visual Studio and Xcode are other reasonable candidates. It’s the learning curve that stops me, I guess.

I’m still on automake, personally.

I install Qt and CMake via Homebrew, though I’ve tried the official standalone version of Qt, too. I’ve had trouble getting graphviz automake to recognize Qt6, so I modified configure.ac to simplify and improve Qt detection, but I got stuck because creating an MR would mean dealing with all the platforms we support, and our CI is still on Qt5, so I didn’t feel very confident about all that.

I think you are going down an extremely pain-filled path here, but to lesson your pain CMake at least provide statically linked binaries of most recent releases. These will run, with no external dependencies, from any directory.

Stephen, thanks for the options. For now I’ve already installed and am going to try Visual Studio Code.

What do you mean if I may ask?

What’s Qt used in Graphviz for? I see gvedit referencing types from it, anything else?

Thank you. I may consider this in the future. Yes, there is some pain, especially the deeper the recursion of building applications that are dependencies of other applications… So I always prefer to use the versions of applications from the repositories if I can. Anyway, fortunately, I don’t need to build things that often.


Update. I’m now in the funtion gvplugin_install (lib/gvc/gvplugin.c:73), having come from its call in lib/gvc/gvconfig.c:230. It looks as if it have no side effects. Moreover, the return value is not used in lib/gvc/gvconfig.c:230 either. How does it work then? What don’t I see?

An update of my diagram of the font supply chain from version 2 to version 3:

I think what you’re missing is that the following is a side effect:

*pnext = plugin;

pnext is pointing to a node in a linked list. gvplugin_install is adding an item to the linked list.

Thank you. Now I see I didn’t notice that what’s crucial is the line lib/gvc/gvplugin.c:89, that is

pnext = &gvc->apis[api];

Here, pnext becomes what is ultimately held by gvc, and gvc is a parameter of the function.

Here are two new Issues, based in these comments:

Steve, I’m grateful you’ve taken your time to move this thread forward by creating those issues. I’m still in the process of investigating how fonts are handled in the code, but a few days ago I have paused it. I seem to be too busy with other things. I don’t know if I’ll be able to get back anytime soon.